aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/go/ChangeLog5
-rw-r--r--gcc/go/go-gcc.cc4
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/backend.h2
-rw-r--r--gcc/go/gofrontend/expressions.cc44
-rw-r--r--gcc/go/gofrontend/expressions.h14
-rw-r--r--gcc/go/gofrontend/gogo.cc8
-rw-r--r--gcc/go/gofrontend/operator.h6
-rw-r--r--gcc/go/gofrontend/statements.cc77
-rw-r--r--gcc/go/gofrontend/types.cc5
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);
}