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;