Hi Jason,

On 1 Nov 2024, at 16:31, Jason Merrill wrote:

> On 11/1/24 5:07 AM, Simon Martin wrote:
>> 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, and end up 
>> calling
>> contains_placeholder_p with a SCOPE_REF, that it does not handle 
>> well.
>>
>> This patch fixes this by skipping the first operand of SCOPE_REFs in
>> contains_placeholder_p.
>
> Code in gcc/ shouldn't refer to tree codes from cp-tree.def.
>
> We probably shouldn't do the strong-eval-order transformation when 
> processing_template_decl anyway.
Thanks, that makes sense. The attached updated patch skips the
wrapping when processing_template_decl, and also adds a test
case checking that -fstrong-eval-order processing is properly
done for instantiated templates.

Successfully tested on x86_64-pc-linux-gnu. OK for trunk?

Thanks, Simon
From b5c8777bc04bd633781d3f3af2a72efd8888e2ab Mon Sep 17 00:00:00 2001
From: Simon Martin <si...@nasilyan.com>
Date: Thu, 31 Oct 2024 09:04:49 +0100
Subject: [PATCH] c++: Defer -fstrong-eval-order processing to template
 instantiation time [PR117158]

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.

Successfully tested on x86_64-pc-linux-gnu.

        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.

---
 gcc/cp/typeck.cc                          |  3 ++-
 gcc/testsuite/g++.dg/cpp1z/eval-order13.C | 29 +++++++++++++++++++++++
 gcc/testsuite/g++.dg/parse/crash77.C      | 13 ++++++++++
 3 files changed, 44 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1z/eval-order13.C
 create mode 100644 gcc/testsuite/g++.dg/parse/crash77.C

diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index 6ce1bb61fe7..439681216be 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -4092,7 +4092,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
index 00000000000..6e8ebeb3096
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/eval-order13.C
@@ -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
index 00000000000..729362eb599
--- /dev/null
+++ b/gcc/testsuite/g++.dg/parse/crash77.C
@@ -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);
+  }
+};
-- 
2.44.0

Reply via email to