Commit c12df359 by Ian Lance Taylor

compiler: Record each import as a distinct alias.

    
    This patch introduces the Package_alias class which is a
    finer representation of the different between a package and the
    aliases it is imported under.  Each alias keeps track of the location
    of its import statement and how many times that alias has been used.
    This allows the gofrontend to report when a specific import has not
    been used even if a symbol from the package has been used by another
    import.
    
    Fixes golang/go#12326.
    
    Reviewed-on: https://go-review.googlesource.com/14259

From-SVN: r228550
parent ce9f2dc5
d8150af96de991fb79b1bf65ae982a860552c492 3039d79149901d25d89c2412bdd8684f3cbcd09e
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -516,7 +516,6 @@ Gogo::import_package(const std::string& filename, ...@@ -516,7 +516,6 @@ Gogo::import_package(const std::string& filename,
{ {
Package* package = p->second; Package* package = p->second;
package->set_location(location); package->set_location(location);
package->set_is_imported();
std::string ln = local_name; std::string ln = local_name;
bool is_ln_exported = is_local_name_exported; bool is_ln_exported = is_local_name_exported;
if (ln.empty()) if (ln.empty())
...@@ -525,7 +524,9 @@ Gogo::import_package(const std::string& filename, ...@@ -525,7 +524,9 @@ Gogo::import_package(const std::string& filename,
go_assert(!ln.empty()); go_assert(!ln.empty());
is_ln_exported = Lex::is_exported_name(ln); is_ln_exported = Lex::is_exported_name(ln);
} }
if (ln == ".") if (ln == "_")
;
else if (ln == ".")
{ {
Bindings* bindings = package->bindings(); Bindings* bindings = package->bindings();
for (Bindings::const_declarations_iterator p = for (Bindings::const_declarations_iterator p =
...@@ -533,11 +534,12 @@ Gogo::import_package(const std::string& filename, ...@@ -533,11 +534,12 @@ Gogo::import_package(const std::string& filename,
p != bindings->end_declarations(); p != bindings->end_declarations();
++p) ++p)
this->add_dot_import_object(p->second); this->add_dot_import_object(p->second);
std::string dot_alias = "." + package->package_name();
package->add_alias(dot_alias, location);
} }
else if (ln == "_")
package->set_uses_sink_alias();
else else
{ {
package->add_alias(ln, location);
ln = this->pack_hidden_name(ln, is_ln_exported); ln = this->pack_hidden_name(ln, is_ln_exported);
this->package_->bindings()->add_package(ln, package); this->package_->bindings()->add_package(ln, package);
} }
...@@ -563,7 +565,6 @@ Gogo::import_package(const std::string& filename, ...@@ -563,7 +565,6 @@ Gogo::import_package(const std::string& filename,
"being compiled (see -fgo-pkgpath option)")); "being compiled (see -fgo-pkgpath option)"));
this->imports_.insert(std::make_pair(filename, package)); this->imports_.insert(std::make_pair(filename, package));
package->set_is_imported();
} }
delete stream; delete stream;
...@@ -1544,7 +1545,10 @@ Gogo::lookup(const std::string& name, Named_object** pfunction) const ...@@ -1544,7 +1545,10 @@ Gogo::lookup(const std::string& name, Named_object** pfunction) const
if (ret != NULL) if (ret != NULL)
{ {
if (ret->package() != NULL) if (ret->package() != NULL)
ret->package()->note_usage(); {
std::string dot_alias = "." + ret->package()->package_name();
ret->package()->note_usage(dot_alias);
}
return ret; return ret;
} }
} }
...@@ -1594,10 +1598,14 @@ Gogo::add_imported_package(const std::string& real_name, ...@@ -1594,10 +1598,14 @@ Gogo::add_imported_package(const std::string& real_name,
*padd_to_globals = false; *padd_to_globals = false;
if (alias_arg == ".") if (alias_arg == "_")
;
else if (alias_arg == ".")
{
*padd_to_globals = true; *padd_to_globals = true;
else if (alias_arg == "_") std::string dot_alias = "." + real_name;
ret->set_uses_sink_alias(); ret->add_alias(dot_alias, location);
}
else else
{ {
std::string alias = alias_arg; std::string alias = alias_arg;
...@@ -1606,6 +1614,7 @@ Gogo::add_imported_package(const std::string& real_name, ...@@ -1606,6 +1614,7 @@ Gogo::add_imported_package(const std::string& real_name,
alias = real_name; alias = real_name;
is_alias_exported = Lex::is_exported_name(alias); is_alias_exported = Lex::is_exported_name(alias);
} }
ret->add_alias(alias, location);
alias = this->pack_hidden_name(alias, is_alias_exported); alias = this->pack_hidden_name(alias, is_alias_exported);
Named_object* no = this->package_->bindings()->add_package(alias, ret); Named_object* no = this->package_->bindings()->add_package(alias, ret);
if (!no->is_package()) if (!no->is_package())
...@@ -2356,15 +2365,30 @@ Gogo::clear_file_scope() ...@@ -2356,15 +2365,30 @@ Gogo::clear_file_scope()
++p) ++p)
{ {
Package* package = p->second; Package* package = p->second;
if (package != this->package_ if (package != this->package_ && !quiet)
&& package->is_imported() {
&& !package->used() for (Package::Aliases::const_iterator p1 = package->aliases().begin();
&& !package->uses_sink_alias() p1 != package->aliases().end();
&& !quiet) ++p1)
error_at(package->location(), "imported and not used: %s", {
Gogo::message_name(package->package_name()).c_str()); if (!p1->second->used())
package->clear_is_imported(); {
package->clear_uses_sink_alias(); // Give a more refined error message if the alias name is known.
std::string pkg_name = package->package_name();
if (p1->first != pkg_name && p1->first[0] != '.')
{
error_at(p1->second->location(),
"imported and not used: %s as %s",
Gogo::message_name(pkg_name).c_str(),
Gogo::message_name(p1->first).c_str());
}
else
error_at(p1->second->location(),
"imported and not used: %s",
Gogo::message_name(pkg_name).c_str());
}
}
}
package->clear_used(); package->clear_used();
} }
} }
...@@ -7741,8 +7765,7 @@ Package::Package(const std::string& pkgpath, ...@@ -7741,8 +7765,7 @@ Package::Package(const std::string& pkgpath,
const std::string& pkgpath_symbol, Location location) const std::string& pkgpath_symbol, Location location)
: pkgpath_(pkgpath), pkgpath_symbol_(pkgpath_symbol), : pkgpath_(pkgpath), pkgpath_symbol_(pkgpath_symbol),
package_name_(), bindings_(new Bindings(NULL)), priority_(0), package_name_(), bindings_(new Bindings(NULL)), priority_(0),
location_(location), used_(false), is_imported_(false), location_(location)
uses_sink_alias_(false)
{ {
go_assert(!pkgpath.empty()); go_assert(!pkgpath.empty());
...@@ -7796,6 +7819,16 @@ Package::set_priority(int priority) ...@@ -7796,6 +7819,16 @@ Package::set_priority(int priority)
this->priority_ = priority; this->priority_ = priority;
} }
// Note that symbol from this package was and qualified by ALIAS.
void
Package::note_usage(const std::string& alias) const
{
Aliases::const_iterator p = this->aliases_.find(alias);
go_assert(p != this->aliases_.end());
p->second->note_usage();
}
// Forget a given usage. If forgetting this usage means this package becomes // Forget a given usage. If forgetting this usage means this package becomes
// unused, report that error. // unused, report that error.
...@@ -7820,10 +7853,26 @@ Package::forget_usage(Expression* usage) const ...@@ -7820,10 +7853,26 @@ Package::forget_usage(Expression* usage) const
void void
Package::clear_used() Package::clear_used()
{ {
if (this->used_ > this->fake_uses_.size()) std::string dot_alias = "." + this->package_name();
Aliases::const_iterator p = this->aliases_.find(dot_alias);
if (p != this->aliases_.end() && p->second->used() > this->fake_uses_.size())
this->fake_uses_.clear(); this->fake_uses_.clear();
this->used_ = 0; this->aliases_.clear();
}
Package_alias*
Package::add_alias(const std::string& alias, Location location)
{
Aliases::const_iterator p = this->aliases_.find(alias);
if (p == this->aliases_.end())
{
std::pair<Aliases::iterator, bool> ret;
ret = this->aliases_.insert(std::make_pair(alias,
new Package_alias(location)));
p = ret.first;
}
return p->second;
} }
// Determine types of constants. Everything else in a package // Determine types of constants. Everything else in a package
......
...@@ -2771,6 +2771,37 @@ class Unnamed_label ...@@ -2771,6 +2771,37 @@ class Unnamed_label
Blabel* blabel_; Blabel* blabel_;
}; };
// An alias for an imported package.
class Package_alias
{
public:
Package_alias(Location location)
: location_(location), used_(0)
{ }
// The location of the import statement.
Location
location()
{ return this->location_; }
// How many symbols from the package were used under this alias.
size_t
used() const
{ return this->used_; }
// Note that some symbol was used under this alias.
void
note_usage()
{ this->used_++; }
private:
// The location of the import statement.
Location location_;
// The amount of times some name from this package was used under this alias.
size_t used_;
};
// An imported package. // An imported package.
class Package class Package
...@@ -2793,7 +2824,7 @@ class Package ...@@ -2793,7 +2824,7 @@ class Package
void void
set_pkgpath_symbol(const std::string&); set_pkgpath_symbol(const std::string&);
// Return the location of the import statement. // Return the location of the most recent import statement.
Location Location
location() const location() const
{ return this->location_; } { return this->location_; }
...@@ -2829,15 +2860,18 @@ class Package ...@@ -2829,15 +2860,18 @@ class Package
bindings() bindings()
{ return this->bindings_; } { return this->bindings_; }
// Whether some symbol from the package was used. // Type used to map import names to package aliases.
bool typedef std::map<std::string, Package_alias*> Aliases;
used() const
{ return this->used_ > 0; }
// Note that some symbol from this package was used. // Return the set of package aliases.
const Aliases&
aliases() const
{ return this->aliases_; }
// Note that some symbol from this package was used and qualified by ALIAS.
// For dot imports, the ALIAS should be ".PACKAGE_NAME".
void void
note_usage() const note_usage(const std::string& alias) const;
{ this->used_++; }
// Note that USAGE might be a fake usage of this package. // Note that USAGE might be a fake usage of this package.
void void
...@@ -2852,36 +2886,6 @@ class Package ...@@ -2852,36 +2886,6 @@ class Package
void void
clear_used(); clear_used();
// Whether this package was imported in the current file.
bool
is_imported() const
{ return this->is_imported_; }
// Note that this package was imported in the current file.
void
set_is_imported()
{ this->is_imported_ = true; }
// Clear the imported field for the next file.
void
clear_is_imported()
{ this->is_imported_ = false; }
// Whether this package was imported with a name of "_".
bool
uses_sink_alias() const
{ return this->uses_sink_alias_; }
// Note that this package was imported with a name of "_".
void
set_uses_sink_alias()
{ this->uses_sink_alias_ = true; }
// Clear the sink alias field for the next file.
void
clear_uses_sink_alias()
{ this->uses_sink_alias_ = false; }
// Look up a name in the package. Returns NULL if the name is not // Look up a name in the package. Returns NULL if the name is not
// found. // found.
Named_object* Named_object*
...@@ -2898,6 +2902,10 @@ class Package ...@@ -2898,6 +2902,10 @@ class Package
set_location(Location location) set_location(Location location)
{ this->location_ = location; } { this->location_ = location; }
// Add a package name as an ALIAS for this package.
Package_alias*
add_alias(const std::string& alias, Location);
// Add a constant to the package. // Add a constant to the package.
Named_object* Named_object*
add_constant(const Typed_identifier& tid, Expression* expr) add_constant(const Typed_identifier& tid, Expression* expr)
...@@ -2942,18 +2950,13 @@ class Package ...@@ -2942,18 +2950,13 @@ class Package
// than the priority of all of the packages that it imports. This // than the priority of all of the packages that it imports. This
// is used to run init functions in the right order. // is used to run init functions in the right order.
int priority_; int priority_;
// The location of the import statement. // The location of the most recent import statement.
Location location_; Location location_;
// The amount of times some name from this package was used. This is mutable // The set of aliases associated with this package.
// because we can use a package even if we have a const pointer to it. Aliases aliases_;
mutable size_t used_;
// A set of possibly fake uses of this package. This is mutable because we // A set of possibly fake uses of this package. This is mutable because we
// can track fake uses of a package even if we have a const pointer to it. // can track fake uses of a package even if we have a const pointer to it.
mutable std::set<Expression*> fake_uses_; mutable std::set<Expression*> fake_uses_;
// True if this package was imported in the current file.
bool is_imported_;
// True if this package was imported with a name of "_".
bool uses_sink_alias_;
}; };
// Return codes for the traversal functions. This is not an enum // Return codes for the traversal functions. This is not an enum
......
...@@ -198,7 +198,7 @@ Parse::qualified_ident(std::string* pname, Named_object** ppackage) ...@@ -198,7 +198,7 @@ Parse::qualified_ident(std::string* pname, Named_object** ppackage)
return false; return false;
} }
package->package_value()->note_usage(); package->package_value()->note_usage(Gogo::unpack_hidden_name(name));
token = this->advance_token(); token = this->advance_token();
if (!token->is_identifier()) if (!token->is_identifier())
...@@ -2430,7 +2430,7 @@ Parse::operand(bool may_be_sink, bool* is_parenthesized) ...@@ -2430,7 +2430,7 @@ Parse::operand(bool may_be_sink, bool* is_parenthesized)
return Expression::make_error(location); return Expression::make_error(location);
} }
package = named_object->package_value(); package = named_object->package_value();
package->note_usage(); package->note_usage(id);
id = this->peek_token()->identifier(); id = this->peek_token()->identifier();
is_exported = this->peek_token()->is_identifier_exported(); is_exported = this->peek_token()->is_identifier_exported();
packed = this->gogo_->pack_hidden_name(id, is_exported); packed = this->gogo_->pack_hidden_name(id, is_exported);
......
...@@ -32,8 +32,6 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, ...@@ -32,8 +32,6 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported,
} }
package->set_location(location); package->set_location(location);
package->set_is_imported();
this->imports_.insert(std::make_pair("unsafe", package)); this->imports_.insert(std::make_pair("unsafe", package));
Bindings* bindings = package->bindings(); Bindings* bindings = package->bindings();
......
...@@ -2,7 +2,7 @@ package p ...@@ -2,7 +2,7 @@ package p
import ( import (
"./a" // ERROR "imported and not used: \x22a\x22 as surprise|imported and not used: surprise" "./a" // ERROR "imported and not used: \x22a\x22 as surprise|imported and not used: surprise"
"./b" // GC_ERROR "imported and not used: \x22b\x22 as surprise2|imported and not used: surprise2" "./b" // ERROR "imported and not used: \x22b\x22 as surprise2|imported and not used: surprise2"
b "./b" // ERROR "imported and not used: \x22b\x22$|imported and not used: surprise2" b "./b" // ERROR "imported and not used: \x22b\x22$|imported and not used: surprise2"
foo "math" // ERROR "imported and not used: \x22math\x22 as foo|imported and not used: math" foo "math" // ERROR "imported and not used: \x22math\x22 as foo|imported and not used: math"
"fmt" // actually used "fmt" // actually used
......
...@@ -18,7 +18,7 @@ import X "math" // ERROR "imported and not used.*math" ...@@ -18,7 +18,7 @@ import X "math" // ERROR "imported and not used.*math"
import . "bufio" // ERROR "imported and not used.*bufio" import . "bufio" // ERROR "imported and not used.*bufio"
// again, package without anything in it // again, package without anything in it
import "./empty" // GC_ERROR "imported and not used.*empty" import "./empty" // ERROR "imported and not used.*empty"
import Z "./empty" // GC_ERROR "imported and not used.*empty" import Z "./empty" // ERROR "imported and not used.*empty"
import . "./empty" // ERROR "imported and not used.*empty" import . "./empty" // ERROR "imported and not used.*empty"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment