Commit ecd7b400 by Ian Lance Taylor

compiler: Do not count package uses from ambiguous lookups.

When using dot imports, it is possible to
have an imported symbol name that matches
the name of a struct field in a composite
literal.  Do not consider the imported
package to be used in this situation.
Fixes issue 6427.

From-SVN: r217453
parent be8de894
...@@ -12791,6 +12791,16 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type) ...@@ -12791,6 +12791,16 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
{ {
case EXPRESSION_UNKNOWN_REFERENCE: case EXPRESSION_UNKNOWN_REFERENCE:
name = name_expr->unknown_expression()->name(); name = name_expr->unknown_expression()->name();
if (type->named_type() != NULL)
{
// If the named object found for this field name comes from a
// different package than the struct it is a part of, do not count
// this incorrect lookup as a usage of the object's package.
no = name_expr->unknown_expression()->named_object();
if (no->package() != NULL
&& no->package() != type->named_type()->named_object()->package())
no->package()->forget_usage(name_expr);
}
break; break;
case EXPRESSION_CONST_REFERENCE: case EXPRESSION_CONST_REFERENCE:
......
...@@ -1412,7 +1412,7 @@ Gogo::lookup(const std::string& name, Named_object** pfunction) const ...@@ -1412,7 +1412,7 @@ 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()->set_used(); ret->package()->note_usage();
return ret; return ret;
} }
} }
...@@ -7426,6 +7426,36 @@ Package::set_priority(int priority) ...@@ -7426,6 +7426,36 @@ Package::set_priority(int priority)
this->priority_ = priority; this->priority_ = priority;
} }
// Forget a given usage. If forgetting this usage means this package becomes
// unused, report that error.
void
Package::forget_usage(Expression* usage) const
{
if (this->fake_uses_.empty())
return;
std::set<Expression*>::iterator p = this->fake_uses_.find(usage);
go_assert(p != this->fake_uses_.end());
this->fake_uses_.erase(p);
if (this->fake_uses_.empty())
error_at(this->location(), "imported and not used: %s",
Gogo::message_name(this->package_name()).c_str());
}
// Clear the used field for the next file. If the only usages of this package
// are possibly fake, keep the fake usages for lowering.
void
Package::clear_used()
{
if (this->used_ > this->fake_uses_.size())
this->fake_uses_.clear();
this->used_ = 0;
}
// Determine types of constants. Everything else in a package // Determine types of constants. Everything else in a package
// (variables, function declarations) should already have a fixed // (variables, function declarations) should already have a fixed
// type. Constants may have abstract types. // type. Constants may have abstract types.
......
...@@ -2645,17 +2645,25 @@ class Package ...@@ -2645,17 +2645,25 @@ class Package
// Whether some symbol from the package was used. // Whether some symbol from the package was used.
bool bool
used() const used() const
{ return this->used_; } { return this->used_ > 0; }
// Note that some symbol from this package was used. // Note that some symbol from this package was used.
void void
set_used() const note_usage() const
{ this->used_ = true; } { this->used_++; }
// Note that USAGE might be a fake usage of this package.
void
note_fake_usage(Expression* usage) const
{ this->fake_uses_.insert(usage); }
// Forget a given USAGE of this package.
void
forget_usage(Expression* usage) const;
// Clear the used field for the next file. // Clear the used field for the next file.
void void
clear_used() clear_used();
{ this->used_ = false; }
// Whether this package was imported in the current file. // Whether this package was imported in the current file.
bool bool
...@@ -2749,10 +2757,12 @@ class Package ...@@ -2749,10 +2757,12 @@ class Package
int priority_; int priority_;
// The location of the import statement. // The location of the import statement.
Location location_; Location location_;
// True if some name from this package was used. This is mutable // The amount of times some name from this package was used. This is mutable
// because we can use a package even if we have a const pointer to // because we can use a package even if we have a const pointer to it.
// it. mutable size_t used_;
mutable bool used_; // 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.
mutable std::set<Expression*> fake_uses_;
// True if this package was imported in the current file. // True if this package was imported in the current file.
bool is_imported_; bool is_imported_;
// True if this package was imported with a name of "_". // True if this package was imported with a name of "_".
......
...@@ -199,7 +199,7 @@ Parse::qualified_ident(std::string* pname, Named_object** ppackage) ...@@ -199,7 +199,7 @@ Parse::qualified_ident(std::string* pname, Named_object** ppackage)
return false; return false;
} }
package->package_value()->set_used(); package->package_value()->note_usage();
token = this->advance_token(); token = this->advance_token();
if (!token->is_identifier()) if (!token->is_identifier())
...@@ -2401,7 +2401,7 @@ Parse::operand(bool may_be_sink, bool* is_parenthesized) ...@@ -2401,7 +2401,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->set_used(); package->note_usage();
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);
...@@ -3242,9 +3242,12 @@ Parse::id_to_expression(const std::string& name, Location location, ...@@ -3242,9 +3242,12 @@ Parse::id_to_expression(const std::string& name, Location location,
case Named_object::NAMED_OBJECT_TYPE_DECLARATION: case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
{ {
// These cases can arise for a field name in a composite // These cases can arise for a field name in a composite
// literal. // literal. Keep track of these as they might be fake uses of
// the related package.
Unknown_expression* ue = Unknown_expression* ue =
Expression::make_unknown_reference(named_object, location); Expression::make_unknown_reference(named_object, location);
if (named_object->package() != NULL)
named_object->package()->note_fake_usage(ue);
if (this->is_erroneous_function_) if (this->is_erroneous_function_)
ue->set_no_error_message(); ue->set_no_error_message();
return ue; return ue;
......
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