compiler: Do not count package uses from ambiguous lookups.
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 13 Nov 2014 00:10:37 +0000 (00:10 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 13 Nov 2014 00:10:37 +0000 (00:10 +0000)
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
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/parse.cc

index 712464639a5e49be4b5dc1d453448ae3aa71c373..dba5ea0f9c94812d80ecc737bcf28581e45ff396 100644 (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:
index d6ba272dbd4adfd4669e161ad008d561f44a8e54..7c318ab1b897d8219d91fbdcb57e30ff60ffba78 100644 (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.
index 4453d13c835ab245299ebd085c4cc46973d6626f..10aea696c2604dff6ddf053ddcdc319c4d94c45f 100644 (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 "_".
index d806b4789f1474661aa57e4cc731720b8c612f77..57310250c79d88c28e38dd583d59b400d7bfad09 100644 (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;