{
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:
if (ret != NULL)
{
if (ret->package() != NULL)
- ret->package()->set_used();
+ ret->package()->note_usage();
return ret;
}
}
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.
// 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
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 "_".
return false;
}
- package->package_value()->set_used();
+ package->package_value()->note_usage();
token = this->advance_token();
if (!token->is_identifier())
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);
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;