From ecd7b400c959b1ba0e006e48fac6b82253fe8834 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 13 Nov 2014 00:10:37 +0000 Subject: [PATCH] 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 --- gcc/go/gofrontend/expressions.cc | 10 ++++++++++ gcc/go/gofrontend/gogo.cc | 32 +++++++++++++++++++++++++++++++- gcc/go/gofrontend/gogo.h | 28 +++++++++++++++++++--------- gcc/go/gofrontend/parse.cc | 9 ++++++--- 4 files changed, 66 insertions(+), 13 deletions(-) diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 712464639a5..dba5ea0f9c9 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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: diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index d6ba272dbd4..7c318ab1b89 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -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::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. diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 4453d13c835..10aea696c26 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -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 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 "_". diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index d806b4789f1..57310250c79 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -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; -- 2.30.2