On 9/12/26 3:08 PM, Iain Sandoe wrote:
Tested on x86_64-linux, x86_64-darwin (where it fixes the ICEs in 14 simd cases). OK for trunk/backports?
OK.
--- 8< --- In a similar manner to PR102990, we are encountering a call to fold an expression in a template where the NSDMI has already been folded and, as a result, produces expressions which are not handled by the tsubst machinery. PR c++/126811 gcc/cp/ChangeLog: * typeck2.cc (store_init_value): Skip folding CONSTRUCTORs when handling template decls. gcc/testsuite/ChangeLog: * g++.dg/cpp0x/nsdmi-template27.C: New test. Signed-off-by: Iain Sandoe <[email protected]> --- gcc/cp/typeck2.cc | 11 +++++--- gcc/testsuite/g++.dg/cpp0x/nsdmi-template27.C | 25 +++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) create mode 100644 gcc/testsuite/g++.dg/cpp0x/nsdmi-template27.C diff --git a/gcc/cp/typeck2.cc b/gcc/cp/typeck2.cc index 62f583dcf40..f0f59b3b1a3 100644 --- a/gcc/cp/typeck2.cc +++ b/gcc/cp/typeck2.cc @@ -456,7 +456,7 @@ cxx_incomplete_type_inform (const_tree type) else cand = TYPE_NAME (t); } - + if (!COMPLETE_TYPE_P (TREE_TYPE (cand))) continue;@@ -1076,9 +1076,12 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)|| (DECL_IN_AGGR_P (decl) && DECL_INITIALIZED_IN_CLASS_P (decl))) { - value = fold_non_dependent_expr (value, tf_warning_or_error, - /*manifestly_const_eval=*/true, - decl); + /* As in massage_init_elt, do not fold a CONSTRUCTOR in a template + it has already been folded c++/126811. */ + if (!(processing_template_decl && TREE_CODE (value) == CONSTRUCTOR)) + value = fold_non_dependent_expr (value, tf_warning_or_error, + /*manifestly_const_eval=*/true, + decl); if (value == error_mark_node) ; /* Diagnose a non-constant initializer for constexpr variable or diff --git a/gcc/testsuite/g++.dg/cpp0x/nsdmi-template27.C b/gcc/testsuite/g++.dg/cpp0x/nsdmi-template27.C new file mode 100644 index 00000000000..8c2197a7b51 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/nsdmi-template27.C @@ -0,0 +1,25 @@ +// PR c++/126811 +// { dg-do compile { target c++11 } } + +struct M { constexpr M () : x (0) {} int x; }; + +struct A { double m = 1; }; // FLOAT_EXPR +struct B { int m = 1.0; }; // FIX_TRUNC_EXPR +struct C { __complex__ double c = 1; }; // COMPLEX_EXPR +struct D { double a = 1; double m = a; }; // PLACEHOLDER_EXPR +struct E { M m = M (); }; // TARGET_EXPR + +// The initializers must still be constant-evaluated. +template<class T> void g () +{ + constexpr A a = {}; + static_assert (a.m == 1.0, ""); + constexpr B b = {}; + static_assert (b.m == 1, ""); + constexpr C c = {}; + static_assert (__real__ c.c == 1.0, ""); + constexpr D d = {}; + static_assert (d.m == 1.0, ""); + constexpr E e = {}; + static_assert (e.m.x == 0, ""); +}
