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 -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