diff mbox

Go patch commtited: Avoid crash with self-referential type

Message ID CAOyqgcX7CUm6rGc1UiS--A7Z72wxXZPOqH0ugxRiZRAPWiKDUA@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor Dec. 1, 2014, 1:29 a.m. UTC
This patch to the Go frontend, by Chris Manghane, avoids crashing on
code with self-referential types like

type T interface {
     m() [unsafe.Sizeof(T(nil).m())]int
}

This kind of code is perverse but of course the compiler should not
crash.  This is http://golang.org/issue/6637.   Bootstrapped and ran
testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

diff -r e5736796c227 go/expressions.cc
--- a/go/expressions.cc	Sun Nov 30 17:03:41 2014 -0800
+++ b/go/expressions.cc	Sun Nov 30 17:27:02 2014 -0800
@@ -8735,7 +8735,11 @@ 
   // Add temporary variables for all arguments that require type
   // conversion.
   Function_type* fntype = this->get_function_type();
-  go_assert(fntype != NULL);
+  if (fntype == NULL)
+    {
+      go_assert(saw_errors());
+      return this;
+    }
   if (this->args_ != NULL && !this->args_->empty()
       && fntype->parameters() != NULL && !fntype->parameters()->empty())
     {
@@ -10901,9 +10905,8 @@ 
 // interface.  So introduce a temporary variable if necessary.
 
 Expression*
-Interface_field_reference_expression::do_lower(Gogo*, Named_object*,
-					       Statement_inserter* inserter,
-					       int)
+Interface_field_reference_expression::do_flatten(Gogo*, Named_object*,
+						 Statement_inserter* inserter)
 {
   if (!this->expr_->is_variable())
     {
diff -r e5736796c227 go/expressions.h
--- a/go/expressions.h	Sun Nov 30 17:03:41 2014 -0800
+++ b/go/expressions.h	Sun Nov 30 17:27:02 2014 -0800
@@ -2397,7 +2397,7 @@ 
   do_traverse(Traverse* traverse);
 
   Expression*
-  do_lower(Gogo*, Named_object*, Statement_inserter*, int);
+  do_flatten(Gogo*, Named_object*, Statement_inserter*);
 
   Type*
   do_type();
diff -r e5736796c227 go/types.cc
--- a/go/types.cc	Sun Nov 30 17:03:41 2014 -0800
+++ b/go/types.cc	Sun Nov 30 17:27:02 2014 -0800
@@ -6361,7 +6361,13 @@ 
       unsigned long val;
       if (!this->length_->numeric_constant_value(&nc)
 	  || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
-	error_at(this->length_->location(), "invalid array length");
+	{
+	  if (!this->issued_length_error_)
+	    {
+	      error_at(this->length_->location(), "invalid array length");
+	      this->issued_length_error_ = true;
+	    }
+	}
       else
 	{
 	  char buf[50];
@@ -6488,7 +6494,13 @@ 
       unsigned long val;
       if (!this->length_->numeric_constant_value(&nc)
 	  || nc.to_unsigned_long(&val) != Numeric_constant::NC_UL_VALID)
-	error_at(this->length_->location(), "invalid array length");
+	{
+	  if (!this->issued_length_error_)
+	    {
+	      error_at(this->length_->location(), "invalid array length");
+	      this->issued_length_error_ = true;
+	    }
+	}
       else
 	{
 	  char buf[50];
@@ -10221,7 +10233,12 @@ 
 Forward_declaration_type::real_type()
 {
   if (this->is_defined())
-    return this->named_object()->type_value();
+    {
+      Named_type* nt = this->named_object()->type_value();
+      if (!nt->is_valid())
+	return Type::make_error_type();
+      return this->named_object()->type_value();
+    }
   else
     {
       this->warn();
@@ -10233,7 +10250,12 @@ 
 Forward_declaration_type::real_type() const
 {
   if (this->is_defined())
-    return this->named_object()->type_value();
+    {
+      const Named_type* nt = this->named_object()->type_value();
+      if (!nt->is_valid())
+	return Type::make_error_type();
+      return this->named_object()->type_value();
+    }
   else
     {
       this->warn();
diff -r e5736796c227 go/types.h
--- a/go/types.h	Sun Nov 30 17:03:41 2014 -0800
+++ b/go/types.h	Sun Nov 30 17:27:02 2014 -0800
@@ -2360,7 +2360,8 @@ 
  public:
   Array_type(Type* element_type, Expression* length)
     : Type(TYPE_ARRAY),
-      element_type_(element_type), length_(length), blength_(NULL)
+      element_type_(element_type), length_(length), blength_(NULL),
+      issued_length_error_(false)
   { }
 
   // Return the element type.
@@ -2479,6 +2480,9 @@ 
   // The backend representation of the length.
   // We only want to compute this once.
   Bexpression* blength_;
+  // Whether or not an invalid length error has been issued for this type,
+  // to avoid knock-on errors.
+  mutable bool issued_length_error_;
 };
 
 // The type of a map.
@@ -2926,6 +2930,11 @@ 
   bool
   is_alias() const;
 
+  // Whether this named type is valid.  A recursive named type is invalid.
+  bool
+  is_valid() const
+  { return !this->is_error_; }
+
   // Whether this is a circular type: a pointer or function type that
   // refers to itself, which is not possible in C.
   bool