Avoid infinite recursion checking whether field is exported.
authorIan Lance Taylor <ian@gcc.gnu.org>
Thu, 23 Dec 2010 00:18:50 +0000 (00:18 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Thu, 23 Dec 2010 00:18:50 +0000 (00:18 +0000)
From-SVN: r168191

gcc/go/gofrontend/types.cc
gcc/go/gofrontend/types.h

index 9bdb92612b14b23fc61501eb07018bebee9e2e50..17399659e4cf04166891e3dad3a8abb06ce2b5af 100644 (file)
@@ -7686,8 +7686,10 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
          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 @@ Type::find_field_or_method(const Type* type,
 
 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 @@ Type::is_unexported_field_or_method(Gogo* gogo, const Type* type,
   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 @@ Type::is_unexported_field_or_method(Gogo* gogo, const Type* type,
        {
          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;
 }
 
index 45297e1822fd3cf49ccb2156aeedfb57762140c9..fea864a2e3b4c5f318575ed7f32fccc73ca1fdf6 100644 (file)
@@ -791,7 +791,8 @@ class Type
 
   // 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