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*

Reply via email to