aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2025-06-04 13:31:02 -0400
committerJason Merrill <jason@redhat.com>2025-06-09 09:22:07 -0400
commit4e4684ca6a79b22fe91acaa81af2d4a00d6e1345 (patch)
tree7f6253a47f2102426724d80563ae73d71517d850
parentd96603a48d338a92b78628016d00cbf11576621e (diff)
downloadgcc-4e4684ca6a79b22fe91acaa81af2d4a00d6e1345.zip
gcc-4e4684ca6a79b22fe91acaa81af2d4a00d6e1345.tar.gz
gcc-4e4684ca6a79b22fe91acaa81af2d4a00d6e1345.tar.bz2
c++: constexpr prvalues vs genericize [PR120502]
Here constexpr evaluation was getting confused by the result of split_nonconstant_init, which leaves an INIT_EXPR from an empty CONSTRUCTOR to be followed by member initialization. As a result CONSTRUCTOR_NO_CLEARING was set for the time_zone, and cxx_eval_store_expression didn't set it again for the initial clobber in the basic_string constructor, so when cxx_fold_indirect_ref wants to check whether the anonymous union active member had type non_trivial_if, we see that we don't currently have a value for the anonymous union, try to add one, and fail. So let's do constexpr evaluation before split_nonconstant_init. PR c++/120502 gcc/cp/ChangeLog: * cp-gimplify.cc (cp_fold_r) [TARGET_EXPR]: Do constexpr evaluation before genericize. * constexpr.cc (cxx_eval_store_expression): Add comment. gcc/testsuite/ChangeLog: * g++.dg/cpp2a/constexpr-prvalue2.C: New test.
-rw-r--r--gcc/cp/constexpr.cc3
-rw-r--r--gcc/cp/cp-gimplify.cc21
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue2.C26
3 files changed, 41 insertions, 9 deletions
diff --git a/gcc/cp/constexpr.cc b/gcc/cp/constexpr.cc
index d647a09..1ed3aba 100644
--- a/gcc/cp/constexpr.cc
+++ b/gcc/cp/constexpr.cc
@@ -6421,7 +6421,8 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
if (TREE_CLOBBER_P (init)
&& CLOBBER_KIND (init) < CLOBBER_OBJECT_END)
- /* Only handle clobbers ending the lifetime of objects. */
+ /* Only handle clobbers ending the lifetime of objects.
+ ??? We should probably set CONSTRUCTOR_NO_CLEARING. */
return void_node;
/* First we figure out where we're storing to. */
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index d2423fd..5363ec8 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -1473,6 +1473,19 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
break;
case TARGET_EXPR:
+ if (!flag_no_inline)
+ if (tree &init = TARGET_EXPR_INITIAL (stmt))
+ {
+ tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt),
+ (data->flags & ff_mce_false
+ ? mce_false : mce_unknown));
+ if (folded != init && TREE_CONSTANT (folded))
+ init = folded;
+ }
+
+ /* This needs to happen between the constexpr evaluation (which wants
+ pre-generic trees) and fold (which wants the cp_genericize_init
+ transformations). */
if (data->flags & ff_genericize)
cp_genericize_target_expr (stmt_p);
@@ -1481,14 +1494,6 @@ cp_fold_r (tree *stmt_p, int *walk_subtrees, void *data_)
cp_walk_tree (&init, cp_fold_r, data, NULL);
cp_walk_tree (&TARGET_EXPR_CLEANUP (stmt), cp_fold_r, data, NULL);
*walk_subtrees = 0;
- if (!flag_no_inline)
- {
- tree folded = maybe_constant_init (init, TARGET_EXPR_SLOT (stmt),
- (data->flags & ff_mce_false
- ? mce_false : mce_unknown));
- if (folded != init && TREE_CONSTANT (folded))
- init = folded;
- }
/* Folding might replace e.g. a COND_EXPR with a TARGET_EXPR; in
that case, strip it in favor of this one. */
if (TREE_CODE (init) == TARGET_EXPR)
diff --git a/gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue2.C b/gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue2.C
new file mode 100644
index 0000000..c2dc7cd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/constexpr-prvalue2.C
@@ -0,0 +1,26 @@
+// PR c++/120502
+// { dg-do compile { target c++20 } }
+// { dg-additional-options -O }
+
+struct non_trivial_if {
+ constexpr non_trivial_if() {}
+};
+struct allocator : non_trivial_if {};
+struct padding {};
+struct __short {
+ [[no_unique_address]] padding p;
+};
+struct basic_string {
+ union {
+ __short s;
+ int l;
+ };
+ [[no_unique_address]] allocator a;
+ constexpr basic_string() {}
+ ~basic_string() {}
+};
+struct time_zone {
+ basic_string __abbrev;
+ long __offset;
+};
+time_zone convert_to_time_zone() { return {}; }