diff mbox

Go patch committed: Avoid another infinite recursion

Message ID mcrr5d9e3yq.fsf@google.com
State New
Headers show

Commit Message

Ian Lance Taylor Dec. 23, 2010, 12:18 a.m. UTC
This patch to the Go frontend avoids another case of infinite recursion
when dealing with an invalid recursive named type.  Bootstrapped and ran
Go testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

diff -r d9b238b6f568 go/types.cc
--- a/go/types.cc	Wed Dec 22 16:07:10 2010 -0800
+++ b/go/types.cc	Wed Dec 22 16:14:14 2010 -0800
@@ -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;
 }
 
diff -r d9b238b6f568 go/types.h
--- a/go/types.h	Wed Dec 22 16:07:10 2010 -0800
+++ b/go/types.h	Wed Dec 22 16:14:14 2010 -0800
@@ -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