Patchwork Go patch committed: Check dup methods, avoid endless loops

login
register
mail settings
Submitter Ian Taylor
Date Dec. 14, 2010, 8:54 p.m.
Message ID <mcrhbeg8488.fsf@google.com>
Download mbox | patch
Permalink /patch/75547/
State New
Headers show

Comments

Ian Taylor - Dec. 14, 2010, 8:54 p.m.
This patch to the Go frontend does two things.  First, it checks for
duplicate methods in an interface, which is invalid; previously, the
compiler would simply crash.  Second, it is more careful about type
loops.  Type loops are invalid, but must still be diagnosed.
Previously, the compiler would go into an endless loop chasing the
types.  Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Committed to mainline.

Ian

Patch

diff -r b5cc75949123 go/types.cc
--- a/go/types.cc	Tue Dec 14 11:34:18 2010 -0800
+++ b/go/types.cc	Tue Dec 14 12:47:02 2010 -0800
@@ -53,9 +53,9 @@ 
   switch (this->classification_)
     {
     case TYPE_NAMED:
-      return static_cast<Named_type*>(this)->real_type()->base();
+      return this->named_type()->named_base();
     case TYPE_FORWARD:
-      return static_cast<Forward_declaration_type*>(this)->real_type()->base();
+      return this->forward_declaration_type()->real_type()->base();
     default:
       return this;
     }
@@ -67,13 +67,9 @@ 
   switch (this->classification_)
     {
     case TYPE_NAMED:
-      return static_cast<const Named_type*>(this)->real_type()->base();
+      return this->named_type()->named_base();
     case TYPE_FORWARD:
-      {
-	const Forward_declaration_type* ftype =
-	  static_cast<const Forward_declaration_type*>(this);
-	return ftype->real_type()->base();
-      }
+      return this->forward_declaration_type()->real_type()->base();
     default:
       return this;
     }
@@ -224,7 +220,7 @@ 
     case TYPE_ERROR:
       return true;
     case TYPE_NAMED:
-      return t->named_type()->real_type()->is_error_type();
+      return t->named_type()->is_named_error_type();
     default:
       return false;
     }
@@ -5502,10 +5498,23 @@ 
       const Typed_identifier* p = &this->methods_->at(from);
       if (!p->name().empty())
 	{
-	  if (from != to)
-	    this->methods_->set(to, *p);
+	  size_t i = 0;
+	  for (i = 0; i < to; ++i)
+	    {
+	      if (this->methods_->at(i).name() == p->name())
+		{
+		  error_at(p->location(), "duplicate method %qs",
+			   Gogo::message_name(p->name()).c_str());
+		  break;
+		}
+	    }
+	  if (i == to)
+	    {
+	      if (from != to)
+		this->methods_->set(to, *p);
+	      ++to;
+	    }
 	  ++from;
-	  ++to;
 	  continue;
 	}
       Interface_type* it = p->type()->interface_type();
@@ -6448,6 +6457,45 @@ 
   return this->named_object_->message_name();
 }
 
+// Return the base type for this type.  We have to be careful about
+// circular type definitions, which are invalid but may be seen here.
+
+Type*
+Named_type::named_base()
+{
+  if (this->seen_)
+    return this;
+  this->seen_ = true;
+  Type* ret = this->type_->base();
+  this->seen_ = false;
+  return ret;
+}
+
+const Type*
+Named_type::named_base() const
+{
+  if (this->seen_)
+    return this;
+  this->seen_ = true;
+  const Type* ret = this->type_->base();
+  this->seen_ = false;
+  return ret;
+}
+
+// Return whether this is an error type.  We have to be careful about
+// circular type definitions, which are invalid but may be seen here.
+
+bool
+Named_type::is_named_error_type() const
+{
+  if (this->seen_)
+    return false;
+  this->seen_ = true;
+  bool ret = this->type_->is_error_type();
+  this->seen_ = false;
+  return ret;
+}
+
 // Add a method to this type.
 
 Named_object*
diff -r b5cc75949123 go/types.h
--- a/go/types.h	Tue Dec 14 11:34:18 2010 -0800
+++ b/go/types.h	Tue Dec 14 12:47:02 2010 -0800
@@ -2457,6 +2457,17 @@ 
   is_builtin() const
   { return this->location_ == BUILTINS_LOCATION; }
 
+  // Return the base type for this type.
+  Type*
+  named_base();
+
+  const Type*
+  named_base() const;
+
+  // Return whether this is an error type.
+  bool
+  is_named_error_type() const;
+
   // Add a method to this type.
   Named_object*
   add_method(const std::string& name, Function*);