diff options
-rw-r--r-- | gcc/go/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/backend.h | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 44 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 14 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 8 | ||||
-rw-r--r-- | gcc/go/gofrontend/operator.h | 6 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 77 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 5 |
10 files changed, 139 insertions, 28 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index bbae1a9f..0b116eb 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,8 @@ +2016-12-06 Than McIntosh <thanm@google.com> + + * go-gcc.cc (Gcc_backend::var_expression): Add Varexpr_context + parameter. + 2016-11-22 Than McIntosh <thanm@google.com> * go-gcc.cc (char_needs_encoding): Remove. diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index dc00413..f1ac522 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -276,7 +276,7 @@ class Gcc_backend : public Backend { return this->make_expression(null_pointer_node); } Bexpression* - var_expression(Bvariable* var, Location); + var_expression(Bvariable* var, Varexpr_context, Location); Bexpression* indirect_expression(Btype*, Bexpression* expr, bool known_valid, Location); @@ -1243,7 +1243,7 @@ Gcc_backend::zero_expression(Btype* btype) // An expression that references a variable. Bexpression* -Gcc_backend::var_expression(Bvariable* var, Location location) +Gcc_backend::var_expression(Bvariable* var, Varexpr_context, Location location) { tree ret = var->get_tree(location); if (ret == error_mark_node) diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 5529002..0cb0f9c 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -b7bad96ce0af50a1129eaab9aa110d68a601917b +2102112e26a21589455f940ec6b409766d942c62 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/backend.h b/gcc/go/gofrontend/backend.h index e93cdfe..e9a1912 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -254,7 +254,7 @@ class Backend // Create a reference to a variable. virtual Bexpression* - var_expression(Bvariable* var, Location) = 0; + var_expression(Bvariable* var, Varexpr_context in_lvalue_pos, Location) = 0; // Create an expression that indirects through the pointer expression EXPR // (i.e., return the expression for *EXPR). KNOWN_VALID is true if the pointer diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 9740d32..24f6b12 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -760,7 +760,8 @@ Var_expression::do_get_backend(Translate_context* context) else go_unreachable(); - Bexpression* ret = context->backend()->var_expression(bvar, loc); + Bexpression* ret = + context->backend()->var_expression(bvar, this->in_lvalue_pos_, loc); if (is_in_heap) ret = context->backend()->indirect_expression(btype, ret, true, loc); return ret; @@ -887,7 +888,10 @@ Temporary_reference_expression::do_get_backend(Translate_context* context) { Gogo* gogo = context->gogo(); Bvariable* bvar = this->statement_->get_backend_variable(context); - Bexpression* ret = gogo->backend()->var_expression(bvar, this->location()); + Varexpr_context ve_ctxt = (this->is_lvalue_ ? VE_lvalue : VE_rvalue); + + Bexpression* ret = gogo->backend()->var_expression(bvar, ve_ctxt, + this->location()); // The backend can't always represent the same set of recursive types // that the Go frontend can. In some cases this means that a @@ -958,11 +962,11 @@ Set_and_use_temporary_expression::do_get_backend(Translate_context* context) Location loc = this->location(); Gogo* gogo = context->gogo(); Bvariable* bvar = this->statement_->get_backend_variable(context); - Bexpression* var_ref = gogo->backend()->var_expression(bvar, loc); + Bexpression* lvar_ref = gogo->backend()->var_expression(bvar, VE_rvalue, loc); Bexpression* bexpr = this->expr_->get_backend(context); - Bstatement* set = gogo->backend()->assignment_statement(var_ref, bexpr, loc); - var_ref = gogo->backend()->var_expression(bvar, loc); + Bstatement* set = gogo->backend()->assignment_statement(lvar_ref, bexpr, loc); + Bexpression* var_ref = gogo->backend()->var_expression(bvar, VE_lvalue, loc); Bexpression* ret = gogo->backend()->compound_expression(set, var_ref, loc); return ret; } @@ -1065,11 +1069,12 @@ Sink_expression::do_get_backend(Translate_context* context) this->bvar_ = gogo->backend()->temporary_variable(fn_ctx, context->bblock(), bt, NULL, false, loc, &decl); - Bexpression* var_ref = gogo->backend()->var_expression(this->bvar_, loc); + Bexpression* var_ref = + gogo->backend()->var_expression(this->bvar_, VE_lvalue, loc); var_ref = gogo->backend()->compound_expression(decl, var_ref, loc); return var_ref; } - return gogo->backend()->var_expression(this->bvar_, loc); + return gogo->backend()->var_expression(this->bvar_, VE_lvalue, loc); } // Ast dump for sink expression. @@ -1276,7 +1281,7 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) Named_object* no = this->fn_; Location loc = no->location(); if (this->dvar_ != NULL) - return context->backend()->var_expression(this->dvar_, loc); + return context->backend()->var_expression(this->dvar_, VE_rvalue, loc); Gogo* gogo = context->gogo(); std::string var_name; @@ -1330,7 +1335,7 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) } this->dvar_ = bvar; - return gogo->backend()->var_expression(bvar, loc); + return gogo->backend()->var_expression(bvar, VE_rvalue, loc); } // Print a function descriptor expression. @@ -4207,7 +4212,8 @@ Unary_expression::do_get_backend(Translate_context* context) { Temporary_statement* temp = sut->temporary(); Bvariable* bvar = temp->get_backend_variable(context); - Bexpression* bvar_expr = gogo->backend()->var_expression(bvar, loc); + Bexpression* bvar_expr = + gogo->backend()->var_expression(bvar, VE_lvalue, loc); Bexpression* bval = sut->expression()->get_backend(context); Bstatement* bassign = @@ -4294,7 +4300,7 @@ Unary_expression::do_get_backend(Translate_context* context) gogo->backend()->implicit_variable_set_init(implicit, buf, btype, true, copy_to_heap, false, bexpr); - bexpr = gogo->backend()->var_expression(implicit, loc); + bexpr = gogo->backend()->var_expression(implicit, VE_lvalue, loc); // If we are not copying a slice initializer to the heap, // then it can be changed by the program, so if it can @@ -4304,7 +4310,7 @@ Unary_expression::do_get_backend(Translate_context* context) && this->expr_->type()->has_pointer()) { Bexpression* root = - gogo->backend()->var_expression(implicit, loc); + gogo->backend()->var_expression(implicit, VE_lvalue, loc); root = gogo->backend()->address_expression(root, loc); Type* type = Type::make_pointer_type(this->expr_->type()); gogo->add_gc_root(Expression::make_backend(root, type, loc)); @@ -4324,7 +4330,7 @@ Unary_expression::do_get_backend(Translate_context* context) true, false, btype, loc); gogo->backend()->immutable_struct_set_init(decl, buf, true, false, btype, loc, bexpr); - bexpr = gogo->backend()->var_expression(decl, loc); + bexpr = gogo->backend()->var_expression(decl, VE_lvalue, loc); } go_assert(!this->create_temp_ || this->expr_->is_variable()); @@ -14116,7 +14122,7 @@ Heap_expression::do_get_backend(Translate_context* context) Bvariable* space_temp = gogo->backend()->temporary_variable(fndecl, context->bblock(), btype, space, true, loc, &decl); - space = gogo->backend()->var_expression(space_temp, loc); + space = gogo->backend()->var_expression(space_temp, VE_lvalue, loc); Btype* expr_btype = this->expr_->type()->get_backend(gogo); Bexpression* ref = gogo->backend()->indirect_expression(expr_btype, space, true, loc); @@ -14124,7 +14130,7 @@ Heap_expression::do_get_backend(Translate_context* context) Bexpression* bexpr = this->expr_->get_backend(context); Bstatement* assn = gogo->backend()->assignment_statement(ref, bexpr, loc); decl = gogo->backend()->compound_statement(decl, assn); - space = gogo->backend()->var_expression(space_temp, loc); + space = gogo->backend()->var_expression(space_temp, VE_rvalue, loc); return gogo->backend()->compound_expression(decl, space, loc); } @@ -15063,7 +15069,8 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) Gogo* gogo = context->gogo(); Location loc = Linemap::predeclared_location(); if (this->bvar_ != NULL) - return gogo->backend()->var_expression(this->bvar_, this->location()); + return gogo->backend()->var_expression(this->bvar_, VE_rvalue, + this->location()); const Typed_identifier_list* interface_methods = this->itype_->methods(); go_assert(!interface_methods->empty()); @@ -15099,7 +15106,8 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) this->bvar_ = gogo->backend()->immutable_struct_reference(mangled_name, asm_name, btype, loc); - return gogo->backend()->var_expression(this->bvar_, this->location()); + return gogo->backend()->var_expression(this->bvar_, VE_rvalue, + this->location()); } // The first element is the type descriptor. @@ -15147,7 +15155,7 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) !is_public, btype, loc); gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false, !is_public, btype, loc, ctor); - return gogo->backend()->var_expression(this->bvar_, loc); + return gogo->backend()->var_expression(this->bvar_, VE_lvalue, loc); } void diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index f31d4a6..98e2115 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1282,7 +1282,7 @@ class Var_expression : public Expression public: Var_expression(Named_object* variable, Location location) : Expression(EXPRESSION_VAR_REFERENCE, location), - variable_(variable) + variable_(variable), in_lvalue_pos_(VE_rvalue) { } // Return the variable. @@ -1290,6 +1290,16 @@ class Var_expression : public Expression named_object() const { return this->variable_; } + // Does this var expression appear in an lvalue (assigned-to) context? + bool + in_lvalue_pos() const + { return this->in_lvalue_pos_ == VE_lvalue; } + + // Mark a var_expression as appearing in an lvalue context. + void + set_in_lvalue_pos() + { this->in_lvalue_pos_ = VE_lvalue; } + protected: Expression* do_lower(Gogo*, Named_object*, Statement_inserter*, int); @@ -1320,6 +1330,8 @@ class Var_expression : public Expression private: // The variable we are referencing. Named_object* variable_; + // Set to TRUE if var expression appears in lvalue context + Varexpr_context in_lvalue_pos_; }; // A reference to a variable within an enclosing function. diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index d685bca..e9cc6b4 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -1369,7 +1369,7 @@ Gogo::write_globals() { Location loc = var->location(); Bexpression* var_expr = - this->backend()->var_expression(bvar, loc); + this->backend()->var_expression(bvar, VE_lvalue, loc); var_init_stmt = this->backend()->assignment_statement(var_expr, var_binit, loc); @@ -5734,7 +5734,8 @@ Function::return_value(Gogo* gogo, Named_object* named_function, { Named_object* no = (*this->results_)[i]; Bvariable* bvar = no->get_backend_variable(gogo, named_function); - Bexpression* val = gogo->backend()->var_expression(bvar, location); + Bexpression* val = gogo->backend()->var_expression(bvar, VE_rvalue, + location); if (no->result_var_value()->is_in_heap()) { Btype* bt = no->result_var_value()->type()->get_backend(gogo); @@ -6563,7 +6564,8 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, Expression* val_expr = Expression::make_cast(this->type(), this->init_, loc); Bexpression* val = val_expr->get_backend(&context); - Bexpression* var_ref = gogo->backend()->var_expression(var_decl, loc); + Bexpression* var_ref = + gogo->backend()->var_expression(var_decl, VE_lvalue, loc); decl_init = gogo->backend()->assignment_statement(var_ref, val, loc); } } diff --git a/gcc/go/gofrontend/operator.h b/gcc/go/gofrontend/operator.h index f3e0fd0..e0a97d0 100644 --- a/gcc/go/gofrontend/operator.h +++ b/gcc/go/gofrontend/operator.h @@ -63,4 +63,10 @@ enum Operator OPERATOR_RSQUARE // ] }; +// Whether a variable expression appears in lvalue (assignment) context. +enum Varexpr_context { + VE_rvalue, + VE_lvalue +}; + #endif // !defined(GO_OPERATOR_H) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index e25fd6b..c7b4fe8 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -825,6 +825,80 @@ Assignment_statement::do_flatten(Gogo*, Named_object*, Block*, return this; } + +// Helper class to locate a root Var_expression within an expression +// tree and mark it as being in an "lvalue" or assignment +// context. Examples: +// +// x, y = 40, foo(w) +// x[2] = bar(v) +// x.z.w[blah(v + u)], y.another = 2, 3 +// +// In the code above, vars "x" and "y" appear in lvalue / assignment +// context, whereas the other vars "v", "u", etc are in rvalue context. +// +// Note: at the moment the Var_expression version of "do_copy()" +// defaults to returning the original object, not a new object, +// meaning that a given Var_expression can be referenced from more +// than one place in the tree. This means that when we want to mark a +// Var_expression as having lvalue semantics, we need to make a copy +// of it. Example: +// +// mystruct.myfield += 42 +// +// When this is lowered to eliminate the += operator, we get a tree +// +// mystruct.myfield = mystruct.field + 42 +// +// in which the "mystruct" same Var_expression is referenced on both +// LHS and RHS subtrees. This in turn means that if we try to mark the +// LHS Var_expression the RHS Var_expression will also be marked. To +// address this issue, the code below clones any var_expression before +// applying an lvalue marking. +// + +class Mark_lvalue_varexprs : public Traverse +{ + public: + Mark_lvalue_varexprs() + : Traverse(traverse_expressions) + { } + + protected: + int + expression(Expression**); + + private: +}; + +int Mark_lvalue_varexprs::expression(Expression** ppexpr) +{ + Expression* e = *ppexpr; + + Var_expression* ve = e->var_expression(); + if (ve) + { + ve = new Var_expression(ve->named_object(), ve->location()); + ve->set_in_lvalue_pos(); + *ppexpr = ve; + return TRAVERSE_EXIT; + } + + Field_reference_expression* fre = e->field_reference_expression(); + if (fre != NULL) + return TRAVERSE_CONTINUE; + + Array_index_expression* aie = e->array_index_expression(); + if (aie != NULL) + { + Mark_lvalue_varexprs mlve; + aie->array()->traverse_subexpressions(&mlve); + return TRAVERSE_EXIT; + } + + return TRAVERSE_EXIT; +} + // Convert an assignment statement to the backend representation. Bstatement* @@ -836,6 +910,9 @@ Assignment_statement::do_get_backend(Translate_context* context) return context->backend()->expression_statement(rhs); } + Mark_lvalue_varexprs mlve; + Expression::traverse(&this->lhs_, &mlve); + Bexpression* lhs = this->lhs_->get_backend(context); Expression* conv = Expression::convert_for_assignment(context->gogo(), this->lhs_->type(), diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 33d3460..d540acb 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -1173,7 +1173,8 @@ Type::type_descriptor_pointer(Gogo* gogo, Location location) go_assert(t->type_descriptor_var_ != NULL); } Bexpression* var_expr = - gogo->backend()->var_expression(t->type_descriptor_var_, location); + gogo->backend()->var_expression(t->type_descriptor_var_, + VE_rvalue, location); return gogo->backend()->address_expression(var_expr, location); } @@ -2146,7 +2147,7 @@ Type::gc_symbol_pointer(Gogo* gogo) } Location bloc = Linemap::predeclared_location(); Bexpression* var_expr = - gogo->backend()->var_expression(t->gc_symbol_var_, bloc); + gogo->backend()->var_expression(t->gc_symbol_var_, VE_rvalue, bloc); return gogo->backend()->address_expression(var_expr, bloc); } |