c++: Fix C++17 eval order for virtual op=.
authorJason Merrill <jason@redhat.com>
Fri, 22 May 2020 21:06:57 +0000 (17:06 -0400)
committerJason Merrill <jason@redhat.com>
Sat, 23 May 2020 00:50:31 +0000 (20:50 -0400)
In a function call expression in C++17 evaluation of the function pointer is
sequenced before evaluation of the function arguments, but that doesn't
apply to function calls that were written using operator syntax.  In
particular, for operators with right-to-left ordering like assignment, we
must not evaluate the LHS to find a virtual function before we evaluate the
RHS.

gcc/cp/ChangeLog:

* cp-gimplify.c (cp_gimplify_expr) [CALL_EXPR]: Don't preevaluate
the function address if the call used operator syntax.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/eval-order9.C: New test.

gcc/cp/cp-gimplify.c
gcc/testsuite/g++.dg/cpp1z/eval-order9.C [new file with mode: 0644]

index 2804958c2464667f288a044bd24ea38c41c36a1c..b60a319283ff3df9a7e6cc63e43e7a9ed8883003 100644 (file)
@@ -852,6 +852,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
       ret = GS_OK;
       if (flag_strong_eval_order == 2
          && CALL_EXPR_FN (*expr_p)
+         && !CALL_EXPR_OPERATOR_SYNTAX (*expr_p)
          && cp_get_callee_fndecl_nofold (*expr_p) == NULL_TREE)
        {
          tree fnptrtype = TREE_TYPE (CALL_EXPR_FN (*expr_p));
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order9.C b/gcc/testsuite/g++.dg/cpp1z/eval-order9.C
new file mode 100644 (file)
index 0000000..7001f5a
--- /dev/null
@@ -0,0 +1,18 @@
+// { dg-do run }
+// { dg-additional-options -fstrong-eval-order=all }
+
+struct A
+{
+  virtual A& operator=(const A&) { return *this; }
+};
+
+int i;
+
+A& f() { if (i != 1) __builtin_abort (); i = 2; static A a; return a; }
+A& g() { if (i != 0) __builtin_abort (); i = 1; static A a; return a; }
+
+int main()
+{
+  f() = g();
+  if (i != 2) __builtin_abort ();
+}