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)