This patch by Chris Manghane ignores erroneous trees in the flatten
pass. This avoids various compiler crashes on invalid input, and
fixes https://golang.org/issue/11536 , https://golang.org/issue/11558
, and https://golang.org/issue/11559 . Bootstrapped and ran Go
testsuite on x86_64-unknown-linux-gnu. Committed to mainline.
Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE (revision 226825)
+++ gcc/go/gofrontend/MERGE (working copy)
@@ -1,4 +1,4 @@
-5fc38e74d132cd6f4e7b56e6bcf9fe57031ab203
+fc9da313b4f5c13b4ac3bdddd98e699fd1c89613
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 226596)
+++ gcc/go/gofrontend/expressions.cc (working copy)
@@ -3101,6 +3101,12 @@ Expression*
Type_conversion_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
+ if (this->type()->is_error_type() || this->expr_->is_error_expression())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(this->location());
+ }
+
if (((this->type()->is_string_type()
&& this->expr_->type()->is_slice_type())
|| this->expr_->type()->interface_type() != NULL)
@@ -3585,8 +3591,13 @@ Expression*
Unary_expression::do_flatten(Gogo* gogo, Named_object*,
Statement_inserter* inserter)
{
- if (this->is_error_expression() || this->expr_->is_error_expression())
- return Expression::make_error(this->location());
+ if (this->is_error_expression()
+ || this->expr_->is_error_expression()
+ || this->expr_->type()->is_error_type())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(this->location());
+ }
Location location = this->location();
if (this->op_ == OPERATOR_MULT
@@ -5062,10 +5073,16 @@ Expression*
Binary_expression::do_flatten(Gogo* gogo, Named_object*,
Statement_inserter* inserter)
{
- if (this->classification() == EXPRESSION_ERROR)
- return this;
-
Location loc = this->location();
+ if (this->left_->type()->is_error_type()
+ || this->right_->type()->is_error_type()
+ || this->left_->is_error_expression()
+ || this->right_->is_error_expression())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(loc);
+ }
+
Temporary_statement* temp;
if (this->left_->type()->is_string_type()
&& this->op_ == OPERATOR_PLUS)
@@ -6806,6 +6823,11 @@ Builtin_call_expression::do_flatten(Gogo
Statement_inserter* inserter)
{
Location loc = this->location();
+ if (this->is_erroneous_call())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(loc);
+ }
switch (this->code_)
{
@@ -8733,8 +8755,11 @@ Expression*
Call_expression::do_flatten(Gogo* gogo, Named_object*,
Statement_inserter* inserter)
{
- if (this->classification() == EXPRESSION_ERROR)
- return this;
+ if (this->is_erroneous_call())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(this->location());
+ }
if (this->is_flattened_)
return this;
@@ -8902,6 +8927,27 @@ Call_expression::issue_error()
}
}
+// Whether or not this call contains errors, either in the call or the
+// arguments to the call.
+
+bool
+Call_expression::is_erroneous_call()
+{
+ if (this->is_error_expression() || this->fn()->is_error_expression())
+ return true;
+
+ if (this->args() == NULL)
+ return false;
+ for (Expression_list::iterator pa = this->args()->begin();
+ pa != this->args()->end();
+ ++pa)
+ {
+ if ((*pa)->type()->is_error_type() || (*pa)->is_error_expression())
+ return true;
+ }
+ return false;
+}
+
// Get the type.
Type*
@@ -9848,30 +9894,47 @@ Array_index_expression::do_flatten(Gogo*
Statement_inserter* inserter)
{
Location loc = this->location();
+ Expression* array = this->array_;
+ Expression* start = this->start_;
+ Expression* end = this->end_;
+ Expression* cap = this->cap_;
+ if (array->is_error_expression()
+ || array->type()->is_error_type()
+ || start->is_error_expression()
+ || start->type()->is_error_type()
+ || (end != NULL
+ && (end->is_error_expression() || end->type()->is_error_type()))
+ || (cap != NULL
+ && (cap->is_error_expression() || cap->type()->is_error_type())))
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(loc);
+ }
+
Temporary_statement* temp;
- if (this->array_->type()->is_slice_type() && !this->array_->is_variable())
+ if (array->type()->is_slice_type() && !array->is_variable())
{
- temp = Statement::make_temporary(NULL, this->array_, loc);
+ temp = Statement::make_temporary(NULL, array, loc);
inserter->insert(temp);
this->array_ = Expression::make_temporary_reference(temp, loc);
}
- if (!this->start_->is_variable())
+ if (!start->is_variable())
{
- temp = Statement::make_temporary(NULL, this->start_, loc);
+ temp = Statement::make_temporary(NULL, start, loc);
inserter->insert(temp);
this->start_ = Expression::make_temporary_reference(temp, loc);
}
- if (this->end_ != NULL
- && !this->end_->is_nil_expression()
- && !this->end_->is_variable())
+ if (end != NULL
+ && !end->is_nil_expression()
+ && !end->is_variable())
{
- temp = Statement::make_temporary(NULL, this->end_, loc);
+ temp = Statement::make_temporary(NULL, end, loc);
inserter->insert(temp);
this->end_ = Expression::make_temporary_reference(temp, loc);
}
- if (this->cap_ != NULL && !this->cap_->is_variable())
+ if (cap!= NULL && !cap->is_variable())
{
- temp = Statement::make_temporary(NULL, this->cap_, loc);
+ temp = Statement::make_temporary(NULL, cap, loc);
inserter->insert(temp);
this->cap_ = Expression::make_temporary_reference(temp, loc);
}
@@ -10179,8 +10242,22 @@ Expression*
String_index_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
- Temporary_statement* temp;
Location loc = this->location();
+ Expression* string = this->string_;
+ Expression* start = this->start_;
+ Expression* end = this->end_;
+ if (string->is_error_expression()
+ || string->type()->is_error_type()
+ || start->is_error_expression()
+ || start->type()->is_error_type()
+ || (end != NULL
+ && (end->is_error_expression() || end->type()->is_error_type())))
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(loc);
+ }
+
+ Temporary_statement* temp;
if (!this->string_->is_variable())
{
temp = Statement::make_temporary(NULL, this->string_, loc);
@@ -10419,6 +10496,14 @@ Map_index_expression::do_flatten(Gogo* g
{
Location loc = this->location();
Map_type* mt = this->get_map_type();
+ if (this->index()->is_error_expression()
+ || this->index()->type()->is_error_type()
+ || mt->is_error_type())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(loc);
+ }
+
if (!Type::are_identical(mt->key_type(), this->index_->type(), false, NULL))
{
if (this->index_->type()->interface_type() != NULL
@@ -10443,6 +10528,9 @@ Map_index_expression::do_flatten(Gogo* g
if (this->value_pointer_ == NULL)
this->get_value_pointer(this->is_lvalue_);
+ if (this->value_pointer_->is_error_expression()
+ || this->value_pointer_->type()->is_error_type())
+ return Expression::make_error(loc);
if (!this->value_pointer_->is_variable())
{
Temporary_statement* temp =
@@ -10819,6 +10907,13 @@ Expression*
Interface_field_reference_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
+ if (this->expr_->is_error_expression()
+ || this->expr_->type()->is_error_type())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(this->location());
+ }
+
if (!this->expr_->is_variable())
{
Temporary_statement* temp =
@@ -11598,6 +11693,11 @@ Struct_construction_expression::do_flatt
{
if (*pv != NULL)
{
+ if ((*pv)->is_error_expression() || (*pv)->type()->is_error_type())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(loc);
+ }
if (!(*pv)->is_variable())
{
Temporary_statement* temp =
@@ -11809,6 +11909,11 @@ Array_construction_expression::do_flatte
{
if (*pv != NULL)
{
+ if ((*pv)->is_error_expression() || (*pv)->type()->is_error_type())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(loc);
+ }
if (!(*pv)->is_variable())
{
Temporary_statement* temp =
@@ -12124,6 +12229,11 @@ Map_construction_expression::do_flatten(
{
Expression_list* key_value_pair = new Expression_list();
Expression* key = *pv;
+ if (key->is_error_expression() || key->type()->is_error_type())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(loc);
+ }
if (key->type()->interface_type() != NULL && !key->is_variable())
{
Temporary_statement* temp =
@@ -12135,6 +12245,11 @@ Map_construction_expression::do_flatten(
++pv;
Expression* val = *pv;
+ if (val->is_error_expression() || val->type()->is_error_type())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(loc);
+ }
if (val->type()->interface_type() != NULL && !val->is_variable())
{
Temporary_statement* temp =
@@ -13103,6 +13218,13 @@ Expression*
Type_guard_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
+ if (this->expr_->is_error_expression()
+ || this->expr_->type()->is_error_type())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(this->location());
+ }
+
if (!this->expr_->is_variable())
{
Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_,
@@ -13297,6 +13419,11 @@ Receive_expression::do_flatten(Gogo*, Na
go_assert(saw_errors());
return this;
}
+ else if (this->channel_->is_error_expression())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(this->location());
+ }
Type* element_type = channel_type->element_type();
if (this->temp_receiver_ == NULL)
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h (revision 226510)
+++ gcc/go/gofrontend/expressions.h (working copy)
@@ -1958,6 +1958,11 @@ class Call_expression : public Expressio
bool
issue_error();
+ // Whether or not this call contains errors, either in the call or the
+ // arguments to the call.
+ bool
+ is_erroneous_call();
+
// Whether this call returns multiple results that are used as an
// multi-valued argument.
bool
Index: gcc/go/gofrontend/statements.cc
===================================================================
--- gcc/go/gofrontend/statements.cc (revision 226788)
+++ gcc/go/gofrontend/statements.cc (working copy)
@@ -253,6 +253,14 @@ Statement*
Variable_declaration_statement::do_flatten(Gogo* gogo, Named_object* function,
Block*, Statement_inserter*
inserter)
{
+ Variable* var = this->var_->var_value();
+ if (var->type()->is_error_type()
+ || (var->init() != NULL
+ && var->init()->is_error_expression()))
+ {
+ go_assert(saw_errors());
+ return Statement::make_error_statement(this->location());
+ }
this->var_->var_value()->flatten_init_expression(gogo, function, inserter);
return this;
}
@@ -437,6 +445,14 @@ Statement*
Temporary_statement::do_flatten(Gogo*, Named_object*, Block*,
Statement_inserter* inserter)
{
+ if (this->type()->is_error_type()
+ || (this->init_ != NULL
+ && this->init_->is_error_expression()))
+ {
+ go_assert(saw_errors());
+ return Statement::make_error_statement(this->location());
+ }
+
if (this->type_ != NULL
&& this->init_ != NULL
&& !Type::are_identical(this->type_, this->init_->type(), false, NULL)
@@ -610,6 +626,15 @@ Statement*
Assignment_statement::do_flatten(Gogo*, Named_object*, Block*,
Statement_inserter* inserter)
{
+ if (this->lhs_->is_error_expression()
+ || this->lhs_->type()->is_error_type()
+ || this->rhs_->is_error_expression()
+ || this->rhs_->type()->is_error_type())
+ {
+ go_assert(saw_errors());
+ return Statement::make_error_statement(this->location());
+ }
+
if (!this->lhs_->is_sink_expression()
&& !Type::are_identical(this->lhs_->type(), this->rhs_->type(),
false, NULL)
@@ -4397,6 +4422,13 @@ Statement*
Send_statement::do_flatten(Gogo*, Named_object*, Block*,
Statement_inserter* inserter)
{
+ if (this->channel_->is_error_expression()
+ || this->channel_->type()->is_error_type())
+ {
+ go_assert(saw_errors());
+ return Statement::make_error_statement(this->location());
+ }
+
Type* element_type = this->channel_->type()->channel_type()->element_type();
if (!Type::are_identical(element_type, this->val_->type(), false, NULL)
&& this->val_->type()->interface_type() != NULL