]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
c++: Defer -fstrong-eval-order processing to template instantiation time [PR117158]
authorSimon Martin <simon@nasilyan.com>
Tue, 5 Nov 2024 09:07:42 +0000 (10:07 +0100)
committerSimon Martin <simartin@gcc.gnu.org>
Tue, 5 Nov 2024 13:59:04 +0000 (14:59 +0100)
Since r10-3793-g1a37b6d9a7e57c, we ICE upon the following valid code
with -std=c++17 and above

=== cut here ===
struct Base {
  unsigned int *intarray;
};
template <typename T> struct Sub : public Base {
  bool Get(int i) {
    return (Base::intarray[++i] == 0);
  }
};
=== cut here ===

The problem is that from c++17 on, we use -fstrong-eval-order and need
to wrap the array access expression into a SAVE_EXPR. We do so at
template declaration time, and end up calling contains_placeholder_p
with a SCOPE_REF, that it does not handle well.

This patch fixes this by deferring the wrapping into SAVE_EXPR to
instantiation time for templates, when the SCOPE_REF will have been
turned into a COMPONENT_REF.

PR c++/117158

gcc/cp/ChangeLog:

* typeck.cc (cp_build_array_ref): Only wrap array expression
into a SAVE_EXPR at template instantiation time.

gcc/testsuite/ChangeLog:

* g++.dg/cpp1z/eval-order13.C: New test.
* g++.dg/parse/crash77.C: New test.

(cherry picked from commit b1d92aeb8583c8d1491c97703680c5fb88ed1fe4)

gcc/cp/typeck.cc
gcc/testsuite/g++.dg/cpp1z/eval-order13.C [new file with mode: 0644]
gcc/testsuite/g++.dg/parse/crash77.C [new file with mode: 0644]

index ff8f0ef0083847e50bb77a786a0dda51f76c2c2a..df819701d4a69eaa12c8b48e76663c7ac6321c37 100644 (file)
@@ -3919,7 +3919,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
     tree ar = cp_default_conversion (array, complain);
     tree ind = cp_default_conversion (idx, complain);
 
-    if (!first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
+    if (!processing_template_decl
+       && !first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
       ar = first = save_expr (ar);
 
     /* Put the integer in IND to simplify error checking.  */
diff --git a/gcc/testsuite/g++.dg/cpp1z/eval-order13.C b/gcc/testsuite/g++.dg/cpp1z/eval-order13.C
new file mode 100644 (file)
index 0000000..6e8ebeb
--- /dev/null
@@ -0,0 +1,29 @@
+// PR c++/117158 - Similar to eval-order7.C, only with templates.
+// { dg-do run { target c++11 } }
+// { dg-options "-fstrong-eval-order" }
+
+int a[4] = { 1, 2, 3, 4 };
+int b[4] = { 5, 6, 7, 8 };
+
+struct Base {
+  int *intarray;
+};
+
+template <typename T>
+struct Sub : public Base {
+  int Get(int i) {
+    Base::intarray = a;
+    int r = Base::intarray[(Base::intarray = b, i)];
+    if (Base::intarray != b)
+      __builtin_abort ();
+    return r;
+  }
+};
+
+int
+main ()
+{
+  Sub<int> s;
+  if (s.Get (3) != 4)
+    __builtin_abort ();
+}
diff --git a/gcc/testsuite/g++.dg/parse/crash77.C b/gcc/testsuite/g++.dg/parse/crash77.C
new file mode 100644 (file)
index 0000000..729362e
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/117158
+// { dg-do "compile" }
+
+struct Base {
+  unsigned int *intarray;
+};
+
+template <typename T>
+struct Sub : public Base {
+  bool Get(int i) {
+    return (Base::intarray[++i] == 0);
+  }
+};