Copying a call expression has to copy the state of whether varargs
have been lowered.  Otherwise the compiler can crash on valid code
like *f() += 1 when f is a varargs function.  This patch from Chris
Manghane fixes the problem.  This is GCC PR 61255.  Bootstrapped and
ran Go testsuite on x86_64-unknown-linux-gnu.  Committed to mainline.

Ian
diff -r 67dd2c649e07 go/expressions.cc
--- a/go/expressions.cc Mon Dec 15 09:32:24 2014 -0800
+++ b/go/expressions.cc Mon Dec 15 12:15:03 2014 -0800
@@ -6552,13 +6552,7 @@
   do_check_types(Gogo*);
 
   Expression*
-  do_copy()
-  {
-    return new Builtin_call_expression(this->gogo_, this->fn()->copy(),
-                                      this->args()->copy(),
-                                      this->is_varargs(),
-                                      this->location());
-  }
+  do_copy();
 
   Bexpression*
   do_get_backend(Translate_context*);
@@ -7986,6 +7980,20 @@
     }
 }
 
+Expression*
+Builtin_call_expression::do_copy()
+{
+  Call_expression* bce =
+    new Builtin_call_expression(this->gogo_, this->fn()->copy(),
+                               this->args()->copy(),
+                               this->is_varargs(),
+                               this->location());
+
+  if (this->varargs_are_lowered())
+    bce->set_varargs_are_lowered();
+  return bce;
+}
+
 // Return the backend representation for a builtin function.
 
 Bexpression*
@@ -9126,6 +9134,21 @@
     }
 }
 
+Expression*
+Call_expression::do_copy()
+{
+  Call_expression* call =
+    Expression::make_call(this->fn_->copy(),
+                         (this->args_ == NULL
+                          ? NULL
+                          : this->args_->copy()),
+                         this->is_varargs_, this->location());
+
+  if (this->varargs_are_lowered_)
+    call->set_varargs_are_lowered();
+  return call;
+}
+
 // Return whether we have to use a temporary variable to ensure that
 // we evaluate this call expression in order.  If the call returns no
 // results then it will inevitably be executed last.
diff -r 67dd2c649e07 go/expressions.h
--- a/go/expressions.h  Mon Dec 15 09:32:24 2014 -0800
+++ b/go/expressions.h  Mon Dec 15 12:15:03 2014 -0800
@@ -1683,6 +1683,11 @@
   is_varargs() const
   { return this->is_varargs_; }
 
+  // Return whether varargs have already been lowered.
+  bool
+  varargs_are_lowered() const
+  { return this->varargs_are_lowered_; }
+
   // Note that varargs have already been lowered.
   void
   set_varargs_are_lowered()
@@ -1738,14 +1743,7 @@
   do_check_types(Gogo*);
 
   Expression*
-  do_copy()
-  {
-    return Expression::make_call(this->fn_->copy(),
-                                (this->args_ == NULL
-                                 ? NULL
-                                 : this->args_->copy()),
-                                this->is_varargs_, this->location());
-  }
+  do_copy();
 
   bool
   do_must_eval_in_order() const;

Reply via email to