@@ -7686,8 +7686,10 @@
else
{
std::string unpacked = Gogo::unpack_hidden_name(name);
+ seen.clear();
is_unexported = Type::is_unexported_field_or_method(gogo, type,
- unpacked);
+ unpacked,
+ &seen);
}
if (is_unexported)
error_at(location, "reference to unexported field or method %qs",
@@ -7905,13 +7907,28 @@
bool
Type::is_unexported_field_or_method(Gogo* gogo, const Type* type,
- const std::string& name)
+ const std::string& name,
+ std::vector<const Named_type*>* seen)
{
type = type->deref();
const Named_type* nt = type->named_type();
- if (nt != NULL && nt->is_unexported_local_method(gogo, name))
- return true;
+ if (nt != NULL)
+ {
+ if (nt->is_unexported_local_method(gogo, name))
+ return true;
+
+ for (std::vector<const Named_type*>::const_iterator p = seen->begin();
+ p != seen->end();
+ ++p)
+ {
+ if (*p == nt)
+ {
+ // We've already seen this type.
+ return false;
+ }
+ }
+ }
const Interface_type* it = type->interface_type();
if (it != NULL && it->is_unexported_method(gogo, name))
@@ -7928,6 +7945,9 @@
if (fields == NULL)
return false;
+ if (nt != NULL)
+ seen->push_back(nt);
+
for (Struct_field_list::const_iterator pf = fields->begin();
pf != fields->end();
++pf)
@@ -7938,11 +7958,18 @@
{
Named_type* subtype = pf->type()->deref()->named_type();
gcc_assert(subtype != NULL);
- if (Type::is_unexported_field_or_method(gogo, subtype, name))
- return true;
+ if (Type::is_unexported_field_or_method(gogo, subtype, name, seen))
+ {
+ if (nt != NULL)
+ seen->pop_back();
+ return true;
+ }
}
}
+ if (nt != NULL)
+ seen->pop_back();
+
return false;
}
@@ -791,7 +791,8 @@
// Return true if NAME is an unexported field or method of TYPE.
static bool
- is_unexported_field_or_method(Gogo*, const Type*, const std::string&);
+ is_unexported_field_or_method(Gogo*, const Type*, const std::string&,
+ std::vector<const Named_type*>*);
// This type was passed to the builtin function make. ARGS are the
// arguments passed to make after the type; this may be NULL if