aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2015-08-13 01:04:42 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2015-08-13 01:04:42 +0000
commitb02520e94037d26226a0d8da3c577e6ff6d4ffb7 (patch)
treea38ed0948a185084f013a359229cd87e97988d28 /gcc/go
parent2f4fdc09b0e34c96b2283d81971983d65fa02a8f (diff)
downloadgcc-b02520e94037d26226a0d8da3c577e6ff6d4ffb7.zip
gcc-b02520e94037d26226a0d8da3c577e6ff6d4ffb7.tar.gz
gcc-b02520e94037d26226a0d8da3c577e6ff6d4ffb7.tar.bz2
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
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc163
-rw-r--r--gcc/go/gofrontend/expressions.h5
-rw-r--r--gcc/go/gofrontend/statements.cc32
4 files changed, 183 insertions, 19 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index c9e6300..1961c7e 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 3aabbab..9f757a2 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 6d0f6a4..5358b02 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 40b4373..72b41cb 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