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:
parent
be8de8946e
commit
ecd7b400c9
@ -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:
|
||||
|
@ -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.
|
||||
|
@ -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 "_".
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user