Skip to content

Commit

Permalink
compiler: Flatten erroneous subtrees into errors.
Browse files Browse the repository at this point in the history
    
    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


git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@226845 138bc75d-0d04-0410-961f-82ee72b054a4
  • Loading branch information
ian committed Aug 13, 2015
1 parent d1bf727 commit 5bf8be8
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 19 deletions.
2 changes: 1 addition & 1 deletion gcc/go/gofrontend/MERGE
Original file line number Diff line number Diff line change
@@ -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.
163 changes: 145 additions & 18 deletions gcc/go/gofrontend/expressions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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_)
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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*
Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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 =
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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 =
Expand Down Expand Up @@ -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 =
Expand All @@ -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 =
Expand Down Expand Up @@ -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_,
Expand Down Expand Up @@ -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)
Expand Down
5 changes: 5 additions & 0 deletions gcc/go/gofrontend/expressions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
32 changes: 32 additions & 0 deletions gcc/go/gofrontend/statements.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 5bf8be8

Please sign in to comment.