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
This commit is contained in:
Ian Lance Taylor 2014-11-13 00:10:37 +00:00
parent be8de8946e
commit ecd7b400c9
4 changed files with 66 additions and 13 deletions

View File

@ -12791,6 +12791,16 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
{
case EXPRESSION_UNKNOWN_REFERENCE:
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;
case EXPRESSION_CONST_REFERENCE:

View File

@ -1412,7 +1412,7 @@ Gogo::lookup(const std::string& name, Named_object** pfunction) const
if (ret != NULL)
{
if (ret->package() != NULL)
ret->package()->set_used();
ret->package()->note_usage();
return ret;
}
}
@ -7426,6 +7426,36 @@ Package::set_priority(int 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
// (variables, function declarations) should already have a fixed
// type. Constants may have abstract types.

View File

@ -2645,17 +2645,25 @@ class Package
// Whether some symbol from the package was used.
bool
used() const
{ return this->used_; }
{ return this->used_ > 0; }
// Note that some symbol from this package was used.
void
set_used() const
{ this->used_ = true; }
note_usage() const
{ 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.
void
clear_used()
{ this->used_ = false; }
clear_used();
// Whether this package was imported in the current file.
bool
@ -2749,10 +2757,12 @@ class Package
int priority_;
// The location of the import statement.
Location location_;
// True if some name from this package was used. This is mutable
// because we can use a package even if we have a const pointer to
// it.
mutable bool used_;
// 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 it.
mutable size_t 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.
bool is_imported_;
// True if this package was imported with a name of "_".

View File

@ -199,7 +199,7 @@ Parse::qualified_ident(std::string* pname, Named_object** ppackage)
return false;
}
package->package_value()->set_used();
package->package_value()->note_usage();
token = this->advance_token();
if (!token->is_identifier())
@ -2401,7 +2401,7 @@ Parse::operand(bool may_be_sink, bool* is_parenthesized)
return Expression::make_error(location);
}
package = named_object->package_value();
package->set_used();
package->note_usage();
id = this->peek_token()->identifier();
is_exported = this->peek_token()->is_identifier_exported();
packed = this->gogo_->pack_hidden_name(id, is_exported);
@ -3242,9 +3242,12 @@ Parse::id_to_expression(const std::string& name, Location location,
case Named_object::NAMED_OBJECT_TYPE_DECLARATION:
{
// 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 =
Expression::make_unknown_reference(named_object, location);
if (named_object->package() != NULL)
named_object->package()->note_fake_usage(ue);
if (this->is_erroneous_function_)
ue->set_no_error_message();
return ue;