This patch by Than McIntosh fixes type traversal in the Go frontend to
avoid compiler crashes for test cases where a type T includes an
expression that refers back to the type without actually explicitly
mentioning T. Examples include:

  var x [uintptr(unsafe.Sizeof(&x))]byte
  var a [len(a)]int

The fix involves expanding the set of types that the traversal code
"remembers" (to avoid cycles) to include array types, and introducing
an additional guard in Builtin_call_expression::do_is_constant to
catch cyclic type constructs.

Fixes https://golang.org/issue/{25299,25679,25315,25680}.

Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu.  Committed
to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 261041)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -1,4 +1,4 @@
-79eca4fd642724d89e9bec8f79889451f6632a46
+8e74a218e11ef6eaaf7014a3ad1cd0b13359c607
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc    (revision 261041)
+++ gcc/go/gofrontend/expressions.cc    (working copy)
@@ -8061,9 +8061,13 @@ Builtin_call_expression::do_is_constant(
          arg_type = arg_type->points_to();
 
        if (arg_type->array_type() != NULL
-           && arg_type->array_type()->length() != NULL
-           && Builtin_call_expression::array_len_is_constant(arg))
-         return true;
+           && arg_type->array_type()->length() != NULL)
+          {
+           this->seen_ = true;
+           bool ret = Builtin_call_expression::array_len_is_constant(arg);
+           this->seen_ = false;
+           return ret;
+          }
 
        if (this->code_ == BUILTIN_LEN && arg_type->is_string_type())
          {
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc   (revision 261041)
+++ gcc/go/gofrontend/gogo.cc   (working copy)
@@ -8258,8 +8258,16 @@ Traverse::remember_type(const Type* type
   // We mostly only have to remember named types.  But it turns out
   // that an interface type can refer to itself without using a name
   // by relying on interface inheritance, as in
-  // type I interface { F() interface{I} }
+  //
+  //         type I interface { F() interface{I} }
+  //
+  // Similarly it is possible for array types to refer to themselves
+  // without a name, e.g.
+  //
+  //         var x [uintptr(unsafe.Sizeof(&x))]byte
+  //
   if (type->classification() != Type::TYPE_NAMED
+      && type->classification() != Type::TYPE_ARRAY
       && type->classification() != Type::TYPE_INTERFACE)
     return false;
   if (this->types_seen_ == NULL)

Reply via email to