https://gcc.gnu.org/g:5fdd38d576c20d5a337b5c7d14108981d0751434
commit r12-10804-g5fdd38d576c20d5a337b5c7d14108981d0751434 Author: Simon Martin <si...@nasilyan.com> Date: Tue Nov 5 10:07:42 2024 +0100 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. 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) Diff: --- 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(-) diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc index ff8f0ef00838..df819701d4a6 100644 --- a/gcc/cp/typeck.cc +++ b/gcc/cp/typeck.cc @@ -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 index 000000000000..6e8ebeb30967 --- /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 000000000000..729362eb5991 --- /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); + } +};