This patch by Than McIntosh fixes the Go frontend to consistent mark array pointers as l-values when an array index expression is used in an l-value context. Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed to mainline.
Ian
Index: gcc/go/gofrontend/MERGE =================================================================== --- gcc/go/gofrontend/MERGE (revision 248394) +++ gcc/go/gofrontend/MERGE (working copy) @@ -1,4 +1,4 @@ -ec49c69df1df4d62f3751fcd7e930d6508d67bf2 +884df09c3da0f39309ab13f2ad401628fb933050 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 248082) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -6470,7 +6470,8 @@ Expression::comparison(Translate_context && left_type->array_type()->length() == NULL) { Array_type* at = left_type->array_type(); - left = at->get_value_pointer(context->gogo(), left); + bool is_lvalue = false; + left = at->get_value_pointer(context->gogo(), left, is_lvalue); } else if (left_type->interface_type() != NULL) { @@ -11067,7 +11068,8 @@ Array_index_expression::do_get_backend(T { // Slice. Expression* valptr = - array_type->get_value_pointer(gogo, this->array_); + array_type->get_value_pointer(gogo, this->array_, + this->is_lvalue_); Bexpression* ptr = valptr->get_backend(context); ptr = gogo->backend()->pointer_offset_expression(ptr, start, loc); @@ -11143,7 +11145,8 @@ Array_index_expression::do_get_backend(T Bexpression* offset = gogo->backend()->conditional_expression(bfn, int_btype, cond, zero, start, loc); - Expression* valptr = array_type->get_value_pointer(gogo, this->array_); + Expression* valptr = array_type->get_value_pointer(gogo, this->array_, + this->is_lvalue_); Bexpression* val = valptr->get_backend(context); val = gogo->backend()->pointer_offset_expression(val, offset, loc); Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 247848) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -2654,7 +2654,8 @@ class Array_index_expression : public Ex Array_index_expression(Expression* array, Expression* start, Expression* end, Expression* cap, Location location) : Expression(EXPRESSION_ARRAY_INDEX, location), - array_(array), start_(start), end_(end), cap_(cap), type_(NULL) + array_(array), start_(start), end_(end), cap_(cap), type_(NULL), + is_lvalue_(false) { } // Return the array. @@ -2686,6 +2687,18 @@ class Array_index_expression : public Ex end() const { return this->end_; } + // Return whether this array index expression appears in an lvalue + // (left hand side of assignment) context. + bool + is_lvalue() const + { return this->is_lvalue_; } + + // Update this array index expression to indicate that it appears + // in a left-hand-side or lvalue context. + void + set_is_lvalue() + { this->is_lvalue_ = true; } + protected: int do_traverse(Traverse*); @@ -2753,6 +2766,8 @@ class Array_index_expression : public Ex Expression* cap_; // The type of the expression. Type* type_; + // Whether expr appears in an lvalue context. + bool is_lvalue_; }; // A string index. This is used for both indexing and slicing. Index: gcc/go/gofrontend/statements.cc =================================================================== --- gcc/go/gofrontend/statements.cc (revision 247848) +++ gcc/go/gofrontend/statements.cc (working copy) @@ -903,6 +903,7 @@ int Mark_lvalue_varexprs::expression(Exp if (aie != NULL) { Mark_lvalue_varexprs mlve; + aie->set_is_lvalue(); aie->array()->traverse_subexpressions(&mlve); return TRAVERSE_EXIT; } Index: gcc/go/gofrontend/types.cc =================================================================== --- gcc/go/gofrontend/types.cc (revision 248248) +++ gcc/go/gofrontend/types.cc (working copy) @@ -7611,7 +7611,7 @@ Array_type::finish_backend_element(Gogo* // Return an expression for a pointer to the values in ARRAY. Expression* -Array_type::get_value_pointer(Gogo*, Expression* array) const +Array_type::get_value_pointer(Gogo*, Expression* array, bool is_lvalue) const { if (this->length() != NULL) { @@ -7624,6 +7624,19 @@ Array_type::get_value_pointer(Gogo*, Exp } // Slice. + + if (is_lvalue) + { + Temporary_reference_expression* tref = + array->temporary_reference_expression(); + if (tref != NULL) + { + tref = tref->copy()->temporary_reference_expression(); + tref->set_is_lvalue(); + array = tref; + } + } + return Expression::make_slice_info(array, Expression::SLICE_INFO_VALUE_POINTER, array->location()); Index: gcc/go/gofrontend/types.h =================================================================== --- gcc/go/gofrontend/types.h (revision 248248) +++ gcc/go/gofrontend/types.h (working copy) @@ -2517,7 +2517,7 @@ class Array_type : public Type // Return an expression for the pointer to the values in an array. Expression* - get_value_pointer(Gogo*, Expression* array) const; + get_value_pointer(Gogo*, Expression* array, bool is_lvalue) const; // Return an expression for the length of an array with this type. Expression*