From b02520e94037d26226a0d8da3c577e6ff6d4ffb7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 13 Aug 2015 01:04:42 +0000 Subject: [PATCH] compiler: Flatten erroneous subtrees into errors. Between the lowering and flattening passes of the compiler, there are several passes that modify the lowered Go parse tree and as errors are discovered, several nodes transform into error nodes. However, for a higher level node such as a construction expression, the erroneous nodes in the subtrees might not propagate their error. The flatten phase for a node now looks for errors in the subtree and flattens the node into an error node if any are found. Fixes golang/go#11559, golang/go#11536, golang/go#11558. Reviewed-on: https://go-review.googlesource.com/13097 From-SVN: r226845 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 163 +++++++++++++++++++++++++++---- gcc/go/gofrontend/expressions.h | 5 + gcc/go/gofrontend/statements.cc | 32 ++++++ 4 files changed, 183 insertions(+), 19 deletions(-) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index c9e63002c99..1961c7ea6ff 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 3aabbaba4c5..9f757a2aa26 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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*, Named_object*, 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*, Named_object*, 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* gogo, Named_object*, { 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* gogo, Named_object*, 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_flatten(Gogo*, Named_object*, { 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_flatten(Gogo*, Named_object*, { 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(Gogo* gogo, Named_object*, { 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(Gogo* gogo, Named_object*, ++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*, Named_object*, 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) diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 6d0f6a4c011..5358b021339 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1958,6 +1958,11 @@ class Call_expression : public Expression 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 diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 40b437382f0..72b41cb09a3 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -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 -- 2.30.2