https://gcc.gnu.org/g:cb9d160c4dab693a3fc214736db2441ebbee6c35
commit r17-4631-gcb9d160c4dab693a3fc214736db2441ebbee6c35 Author: Jakub Jelinek <[email protected]> Date: Thu Sep 24 18:42:28 2026 +0200 middle-end: Fix up C++26 P2795R5 - Erroneous behavior for uninitialized reads [PR126848] As the following new testcases show, I've messed up the C++26 P2795R5 - Erroneous behavior for uninitialized reads implementation. What the paper requires for C++26 and later (unless user opts out of it with -ftrivial-auto-var-init=uninitialized, which effectively pretends everything that accepts [[indeterminate]] attribute has that attribute) is that multiple reads of the same uninitialized variable yield the same value (whatever it is) and as QoI that such uses are diagnosed with -Wuninitialized or -Wmaybe-uninitialized. The implementation implemented it as a new mode (not directly requestable by users using an option) of -ftrivial-auto-var-init= (the new mode used just for the case where -ftrivial-auto-var-init={zero,pattern} isn't used), with extra code in the FE to deal with vacuous initialization in switch bodies etc. for C++26 and some small changes during gimplification for the new AUTO_INIT_CXX26 mode. On various testcases it worked fine, but this bugreport shows that in the middle-end optimizations we actually need to treat it differently. In order to fullfill the C++26 requirements, we can't treat .DEFERRED_INIT for C++26 and later as something returning something uninitialized where optimizations happily optimize say a PHI with such uninitialized value and some other value as that other value, or some passes consider the result as UNDEFINED rather than VARYING. There is an option to come up with a different internal function for these C++26 uses of .DEFERRED_INIT, but because it has also many similarities with .DEFERRED_INIT (e.g. same expansion) and because the internal function already has an argument which is the flag_trivial_auto_var_init value, this patch just changes AUTO_INIT_CXX26 value from 3 to 4 so that it can be used as a mask, so now we have 6 different modes: AUTO_INIT_UNINITIALIZED (the default for non-C++ or C++ < 26) AUTO_INIT_ZERO (-ftrivial-auto-var-init=zero for non-C++ or C++ < 26) AUTO_INIT_PATTERN (-ftrivial-auto-var-init=pattern for non-C++ or C++ < 26) AUTO_INIT_CXX26 (the default for C++ >= 26) AUTO_INIT_ZERO | AUTO_INIT_CXX26 (-ftrivial-auto-var-init=zero for C++ >= 26) AUTO_INIT_PATTERN | AUTO_INIT_CXX26 (-ftrivial-auto-var-init=pattern for C++ >= 26) The option handling ensures to or in AUTO_INIT_CXX26 for C++26/29 unless -ftrivial-auto-var-init=uninitialized is used explicitly, and the ccp pass and ssa_undefined_value_p is changed so that it treats the AUTO_INIT_CXX26 modes of .DEFERRED_INIT differently (basically as a source of VARYING value). Because the uninit pass uses ssa_undefined_value_p, I had to change also has_undefined_value_p because for -Wuninitialized purposes we want to treat all .DEFERRED_INIT calls the same. 2026-09-24 Jakub Jelinek <[email protected]> PR c++/126848 gcc/ * flag-types.h (enum auto_init_type): Change AUTO_INIT_CXX26 value from 3 to 4. * gimplify.cc (gimplify_decl_expr): Mask off AUTO_INIT_CXX26 bit before comparing to AUTO_INIT_PATTERN. (gimplify_target_expr): Likewise. * internal-fn.cc (expand_DEFERRED_INIT): Likewise. Formatting fix. * opts.cc (finish_options): For -fhardened or in AUTO_INIT_CXX26 bit from previous value if it was set. Mask off AUTO_INIT_CXX26 bit before comparing to AUTO_INIT_ZERO. * tree-ssa-ccp.cc (likely_value): Return VARYING rather than UNDEFINED for .DEFERRED_INIT call with AUTO_INIT_CXX26 bit set in the second argument. * tree-ssa.cc (ssa_undefined_value_p): Return false rather than true for .DEFERRED_INIT call with AUTO_INIT_CXX26 bit set in the second argument. * tree-ssa-uninit.cc (has_undefined_value_p): Return true for SSA_NAMEs with .DEFERRED_INIT call as SSA_NAME_DEF_STMT. gcc/c-family/ * c-opts.cc (c_common_post_options): For -ftrivial-auto-var-init=zero or -ftrivial-auto-var-init=pattern in C++26 or later mode set AUTO_INIT_CXX26 bit in flag_auto_var_init. gcc/testsuite/ * c-c++-common/auto-init-1.c: Use [15] instead of 1 or [26] instead of 2 in regexps matching second .DEFERRED_INIT arguments. * c-c++-common/auto-init-2.c: Likewise. * c-c++-common/auto-init-3.c: Likewise. * c-c++-common/auto-init-4.c: Likewise. * c-c++-common/auto-init-5.c: Likewise. * c-c++-common/auto-init-6.c: Likewise. * c-c++-common/auto-init-7.c: Likewise. * c-c++-common/auto-init-8.c: Likewise. * c-c++-common/auto-init-9.c: Likewise. * c-c++-common/auto-init-10.c: Likewise. * c-c++-common/auto-init-11.c: Likewise. * c-c++-common/auto-init-12.c: Likewise. * c-c++-common/auto-init-13.c: Likewise. * c-c++-common/auto-init-14.c: Likewise. * c-c++-common/auto-init-15.c: Likewise. * c-c++-common/auto-init-16.c: Likewise. * c-c++-common/auto-init-esra.c: Likewise. * c-c++-common/auto-init-padding-1.c: Likewise. * g++.dg/cpp26/erroneous7.C: New test. * g++.dg/cpp26/erroneous8.C: New test. * g++.dg/cpp26/erroneous9.C: New test. Reviewed-by: Richard Biener <[email protected]> Reviewed-by: Jason Merrill <[email protected]> Diff: --- gcc/c-family/c-opts.cc | 9 +++++++-- gcc/flag-types.h | 2 +- gcc/gimplify.cc | 4 ++-- gcc/internal-fn.cc | 10 +++++----- gcc/opts.cc | 6 ++++-- gcc/testsuite/c-c++-common/auto-init-1.c | 20 ++++++++++---------- gcc/testsuite/c-c++-common/auto-init-10.c | 2 +- gcc/testsuite/c-c++-common/auto-init-11.c | 2 +- gcc/testsuite/c-c++-common/auto-init-12.c | 2 +- gcc/testsuite/c-c++-common/auto-init-13.c | 4 ++-- gcc/testsuite/c-c++-common/auto-init-14.c | 4 ++-- gcc/testsuite/c-c++-common/auto-init-15.c | 2 +- gcc/testsuite/c-c++-common/auto-init-16.c | 2 +- gcc/testsuite/c-c++-common/auto-init-2.c | 20 ++++++++++---------- gcc/testsuite/c-c++-common/auto-init-3.c | 6 +++--- gcc/testsuite/c-c++-common/auto-init-4.c | 6 +++--- gcc/testsuite/c-c++-common/auto-init-5.c | 6 +++--- gcc/testsuite/c-c++-common/auto-init-6.c | 6 +++--- gcc/testsuite/c-c++-common/auto-init-7.c | 8 ++++---- gcc/testsuite/c-c++-common/auto-init-8.c | 8 ++++---- gcc/testsuite/c-c++-common/auto-init-9.c | 4 ++-- gcc/testsuite/c-c++-common/auto-init-esra.c | 4 ++-- gcc/testsuite/c-c++-common/auto-init-padding-1.c | 2 +- gcc/testsuite/g++.dg/cpp26/erroneous7.C | 20 ++++++++++++++++++++ gcc/testsuite/g++.dg/cpp26/erroneous8.C | 19 +++++++++++++++++++ gcc/testsuite/g++.dg/cpp26/erroneous9.C | 19 +++++++++++++++++++ gcc/tree-ssa-ccp.cc | 11 +++++++++-- gcc/tree-ssa-uninit.cc | 1 + gcc/tree-ssa.cc | 10 ++++++++-- 29 files changed, 149 insertions(+), 70 deletions(-) diff --git a/gcc/c-family/c-opts.cc b/gcc/c-family/c-opts.cc index 0e2d8bdcfdd7..d27cf3fa6d5f 100644 --- a/gcc/c-family/c-opts.cc +++ b/gcc/c-family/c-opts.cc @@ -925,8 +925,13 @@ c_common_post_options (const char **pfilename) flag_permitted_flt_eval_methods = PERMITTED_FLT_EVAL_METHODS_C11; if (cxx_dialect >= cxx26) - SET_OPTION_IF_UNSET (&global_options, &global_options_set, - flag_auto_var_init, AUTO_INIT_CXX26); + { + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + flag_auto_var_init, AUTO_INIT_CXX26); + if (flag_auto_var_init > AUTO_INIT_UNINITIALIZED) + flag_auto_var_init + = auto_init_type (flag_auto_var_init | AUTO_INIT_CXX26); + } /* The -Wtrivial-auto-var-init warning is useless for C++, where we always add .DEFERRED_INIT calls when some (vacuous) initializers are bypassed diff --git a/gcc/flag-types.h b/gcc/flag-types.h index df983d9d947f..e14dd36707a6 100644 --- a/gcc/flag-types.h +++ b/gcc/flag-types.h @@ -289,7 +289,7 @@ enum auto_init_type { AUTO_INIT_UNINITIALIZED = 0, AUTO_INIT_PATTERN = 1, AUTO_INIT_ZERO = 2, - AUTO_INIT_CXX26 = 3 + AUTO_INIT_CXX26 = 4 }; /* Initialization of padding bits with zeros. */ diff --git a/gcc/gimplify.cc b/gcc/gimplify.cc index 0f8bf533ba75..19cabec33a81 100644 --- a/gcc/gimplify.cc +++ b/gcc/gimplify.cc @@ -2113,7 +2113,7 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p) since __builtin_clear_padding will take the address of the variable. As a result, if a long double/_Complex long double variable will spilled into stack later, its padding is 0XFE. */ - if (flag_auto_var_init == AUTO_INIT_PATTERN + if ((flag_auto_var_init & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN && !is_gimple_reg (decl) && clear_padding_type_may_have_padding_p (TREE_TYPE (decl))) gimple_add_padding_init_for_auto_var (decl, is_vla, seq_p); @@ -8478,7 +8478,7 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) if (var_needs_auto_init_p (temp) && VOID_TYPE_P (TREE_TYPE (init))) { gimple_add_init_for_auto_var (temp, flag_auto_var_init, &init_pre_p); - if (flag_auto_var_init == AUTO_INIT_PATTERN + if ((flag_auto_var_init & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN && !is_gimple_reg (temp) && clear_padding_type_may_have_padding_p (TREE_TYPE (temp))) gimple_add_padding_init_for_auto_var (temp, is_vla, &init_pre_p); diff --git a/gcc/internal-fn.cc b/gcc/internal-fn.cc index 9bfca87588b3..597ccaeb9fef 100644 --- a/gcc/internal-fn.cc +++ b/gcc/internal-fn.cc @@ -3527,7 +3527,7 @@ expand_DEFERRED_INIT (internal_fn, gcall *stmt) mark_addressable (lhs); tree var_addr = build_fold_addr_expr (lhs); - tree value = (init_type == AUTO_INIT_PATTERN) + tree value = ((init_type & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN) ? build_int_cst (integer_type_node, INIT_PATTERN_VALUE) : integer_zero_node; @@ -3544,7 +3544,7 @@ expand_DEFERRED_INIT (internal_fn, gcall *stmt) scalar_int_mode var_mode; if (TREE_CODE (TREE_TYPE (lhs)) != BOOLEAN_TYPE && tree_fits_uhwi_p (var_size) - && (init_type == AUTO_INIT_PATTERN + && ((init_type & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN || !is_gimple_reg_type (var_type)) && int_mode_for_size (tree_to_uhwi (var_size) * BITS_PER_UNIT, 0).exists (&var_mode) @@ -3552,10 +3552,10 @@ expand_DEFERRED_INIT (internal_fn, gcall *stmt) { unsigned HOST_WIDE_INT total_bytes = tree_to_uhwi (var_size); unsigned char *buf = XALLOCAVEC (unsigned char, total_bytes); - memset (buf, (init_type == AUTO_INIT_PATTERN + memset (buf, ((init_type & ~AUTO_INIT_CXX26) == AUTO_INIT_PATTERN ? INIT_PATTERN_VALUE : 0), total_bytes); - tree itype = build_nonstandard_integer_type - (total_bytes * BITS_PER_UNIT, 1); + tree itype + = build_nonstandard_integer_type (total_bytes * BITS_PER_UNIT, 1); wide_int w = wi::from_buffer (buf, total_bytes); init = wide_int_to_tree (itype, w); /* Pun the LHS to make sure its type has constant size diff --git a/gcc/opts.cc b/gcc/opts.cc index 8048264b6099..21a773f8da75 100644 --- a/gcc/opts.cc +++ b/gcc/opts.cc @@ -1164,8 +1164,10 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, if (opts->x_flag_hardened) { if (!opts_set->x_flag_auto_var_init) - opts->x_flag_auto_var_init = AUTO_INIT_ZERO; - else if (opts->x_flag_auto_var_init != AUTO_INIT_ZERO) + opts->x_flag_auto_var_init + = auto_init_type (opts->x_flag_auto_var_init | AUTO_INIT_ZERO); + else if ((opts->x_flag_auto_var_init & ~AUTO_INIT_CXX26) + != AUTO_INIT_ZERO) warning_at (loc, OPT_Whardened, "%<-ftrivial-auto-var-init=zero%> is not enabled by " "%<-fhardened%> because it was specified on the command " diff --git a/gcc/testsuite/c-c++-common/auto-init-1.c b/gcc/testsuite/c-c++-common/auto-init-1.c index 3e6a4984eea2..96dd4be32a8d 100644 --- a/gcc/testsuite/c-c++-common/auto-init-1.c +++ b/gcc/testsuite/c-c++-common/auto-init-1.c @@ -29,13 +29,13 @@ void foo() return; } -/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(1, 2, \&\"temp1\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(2, 2, \&\"temp2\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(4, 2, \&\"temp3\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(4, 2, \&\"temp4\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(4, 2, \&\"temp5\"" "gimple" { target ilp32 } } } */ -/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(8, 2, \&\"temp5\"" "gimple" { target lp64 } } } */ -/* { dg-final { scan-tree-dump "temp6 = .DEFERRED_INIT \\(8, 2, \&\"temp6\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(4, 2, \&\"temp7\"" "gimple" { target ilp32 } } } */ -/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(8, 2, \&\"temp7\"" "gimple" { target lp64 } } } */ -/* { dg-final { scan-tree-dump "temp8 = .DEFERRED_INIT \\(1, 2, \&\"temp8\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(1, \[26], \&\"temp1\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(2, \[26], \&\"temp2\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(4, \[26], \&\"temp3\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(4, \[26], \&\"temp4\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(4, \[26], \&\"temp5\"" "gimple" { target ilp32 } } } */ +/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(8, \[26], \&\"temp5\"" "gimple" { target lp64 } } } */ +/* { dg-final { scan-tree-dump "temp6 = .DEFERRED_INIT \\(8, \[26], \&\"temp6\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(4, \[26], \&\"temp7\"" "gimple" { target ilp32 } } } */ +/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(8, \[26], \&\"temp7\"" "gimple" { target lp64 } } } */ +/* { dg-final { scan-tree-dump "temp8 = .DEFERRED_INIT \\(1, \[26], \&\"temp8\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-10.c b/gcc/testsuite/c-c++-common/auto-init-10.c index dda7ea1e0324..4ec0a2594070 100644 --- a/gcc/testsuite/c-c++-common/auto-init-10.c +++ b/gcc/testsuite/c-c++-common/auto-init-10.c @@ -18,5 +18,5 @@ void foo() return; } -/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(2, 1, \&\"temp1\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(2, \[15], \&\"temp1\"" "gimple" } } */ /* { dg-final { scan-tree-dump-not "temp2 = .DEFERRED_INIT \\(" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-11.c b/gcc/testsuite/c-c++-common/auto-init-11.c index 6eb468785ce1..2114474e68aa 100644 --- a/gcc/testsuite/c-c++-common/auto-init-11.c +++ b/gcc/testsuite/c-c++-common/auto-init-11.c @@ -11,4 +11,4 @@ void foo(int n) return; } -/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(D.\\d*, 2, \&\"arr\"" "gimple" } } */ +/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(D.\\d*, \[26], \&\"arr\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-12.c b/gcc/testsuite/c-c++-common/auto-init-12.c index 964291c5bd94..4eb0f6e50764 100644 --- a/gcc/testsuite/c-c++-common/auto-init-12.c +++ b/gcc/testsuite/c-c++-common/auto-init-12.c @@ -11,4 +11,4 @@ void foo(int n) return; } -/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(D.\\d*, 1, \&\"arr\"" "gimple" } } */ +/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(D.\\d*, \[15], \&\"arr\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-13.c b/gcc/testsuite/c-c++-common/auto-init-13.c index aa5883af770f..b53b2b98e877 100644 --- a/gcc/testsuite/c-c++-common/auto-init-13.c +++ b/gcc/testsuite/c-c++-common/auto-init-13.c @@ -19,5 +19,5 @@ int foo() return d.b + var.bar.b; } -/* { dg-final { scan-tree-dump "d = .DEFERRED_INIT \\(4, 1, \&\"d\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "var = .DEFERRED_INIT \\(4, 1, \&\"var\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "d = .DEFERRED_INIT \\(4, \[15], \&\"d\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "var = .DEFERRED_INIT \\(4, \[15], \&\"var\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-14.c b/gcc/testsuite/c-c++-common/auto-init-14.c index dd1ff3e339d2..90fd57a537f4 100644 --- a/gcc/testsuite/c-c++-common/auto-init-14.c +++ b/gcc/testsuite/c-c++-common/auto-init-14.c @@ -19,5 +19,5 @@ int foo() return d.b + var.bar.b; } -/* { dg-final { scan-tree-dump "d = .DEFERRED_INIT \\(4, 2, \&\"d\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "var = .DEFERRED_INIT \\(4, 2, \&\"var\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "d = .DEFERRED_INIT \\(4, \[26], \&\"d\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "var = .DEFERRED_INIT \\(4, \[26], \&\"var\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-15.c b/gcc/testsuite/c-c++-common/auto-init-15.c index 5857287ecbef..f389b5aa544f 100644 --- a/gcc/testsuite/c-c++-common/auto-init-15.c +++ b/gcc/testsuite/c-c++-common/auto-init-15.c @@ -10,4 +10,4 @@ void foo(int a) g(x); } -/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(D.\\d*, 2, \&\"x\"" "gimple" } } */ +/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(D.\\d*, \[26], \&\"x\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-16.c b/gcc/testsuite/c-c++-common/auto-init-16.c index 1e309959fc5c..b6cc7506c3c2 100644 --- a/gcc/testsuite/c-c++-common/auto-init-16.c +++ b/gcc/testsuite/c-c++-common/auto-init-16.c @@ -10,4 +10,4 @@ void foo(int a) g(x); } -/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(D.\\d*, 1, \&\"x\"" "gimple" } } */ +/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(D.\\d*, \[15], \&\"x\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-2.c b/gcc/testsuite/c-c++-common/auto-init-2.c index d356e508b836..a1f66358e6e2 100644 --- a/gcc/testsuite/c-c++-common/auto-init-2.c +++ b/gcc/testsuite/c-c++-common/auto-init-2.c @@ -29,13 +29,13 @@ void foo() return; } -/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(1, 1, \&\"temp1\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(2, 1, \&\"temp2\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(4, 1, \&\"temp3\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(4, 1, \&\"temp4\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(4, 1, \&\"temp5\"" "gimple" { target ilp32 } } } */ -/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(8, 1, \&\"temp5\"" "gimple" { target lp64 } } } */ -/* { dg-final { scan-tree-dump "temp6 = .DEFERRED_INIT \\(8, 1, \&\"temp6\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(4, 1, \&\"temp7\"" "gimple" { target ilp32 } } } */ -/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(8, 1, \&\"temp7\"" "gimple" { target lp64 } } } */ -/* { dg-final { scan-tree-dump "temp8 = .DEFERRED_INIT \\(1, 1, \&\"temp8\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(1, \[15], \&\"temp1\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(2, \[15], \&\"temp2\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(4, \[15], \&\"temp3\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(4, \[15], \&\"temp4\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(4, \[15], \&\"temp5\"" "gimple" { target ilp32 } } } */ +/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(8, \[15], \&\"temp5\"" "gimple" { target lp64 } } } */ +/* { dg-final { scan-tree-dump "temp6 = .DEFERRED_INIT \\(8, \[15], \&\"temp6\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(4, \[15], \&\"temp7\"" "gimple" { target ilp32 } } } */ +/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(8, \[15], \&\"temp7\"" "gimple" { target lp64 } } } */ +/* { dg-final { scan-tree-dump "temp8 = .DEFERRED_INIT \\(1, \[15], \&\"temp8\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-3.c b/gcc/testsuite/c-c++-common/auto-init-3.c index 9d9c86d8dd08..c2e310f23643 100644 --- a/gcc/testsuite/c-c++-common/auto-init-3.c +++ b/gcc/testsuite/c-c++-common/auto-init-3.c @@ -14,6 +14,6 @@ long double foo() return result; } -/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(4, 2, \&\"temp1\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(8, 2, \&\"temp2\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\((8|12|16), 2, \&\"temp3\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(4, \[26], \&\"temp1\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(8, \[26], \&\"temp2\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\((8|12|16), \[26], \&\"temp3\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-4.c b/gcc/testsuite/c-c++-common/auto-init-4.c index 848df2a0e264..cff11ef3e167 100644 --- a/gcc/testsuite/c-c++-common/auto-init-4.c +++ b/gcc/testsuite/c-c++-common/auto-init-4.c @@ -14,6 +14,6 @@ long double foo() return result; } -/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(4, 1, \&\"temp1\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(8, 1, \&\"temp2\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\((8|12|16), 1, \&\"temp3\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(4, \[15], \&\"temp1\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(8, \[15], \&\"temp2\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\((8|12|16), \[15], \&\"temp3\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-5.c b/gcc/testsuite/c-c++-common/auto-init-5.c index 9c4de6121826..1be200c4428e 100644 --- a/gcc/testsuite/c-c++-common/auto-init-5.c +++ b/gcc/testsuite/c-c++-common/auto-init-5.c @@ -15,7 +15,7 @@ _Complex long double foo() return result; } -/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(8, 2, \&\"temp1\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(16, 2, \&\"temp2\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\((16|24|32), 2, \&\"temp3\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(8, \[26], \&\"temp1\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(16, \[26], \&\"temp2\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\((16|24|32), \[26], \&\"temp3\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-6.c b/gcc/testsuite/c-c++-common/auto-init-6.c index 6a406447f3d9..8f09007c358a 100644 --- a/gcc/testsuite/c-c++-common/auto-init-6.c +++ b/gcc/testsuite/c-c++-common/auto-init-6.c @@ -15,7 +15,7 @@ _Complex long double foo() return result; } -/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(8, 1, \&\"temp1\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(16, 1, \&\"temp2\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\((16|24|32), 1, \&\"temp3\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(8, \[15], \&\"temp1\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(16, \[15], \&\"temp2\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\((16|24|32), \[15], \&\"temp3\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-7.c b/gcc/testsuite/c-c++-common/auto-init-7.c index dd48d691596f..346676304016 100644 --- a/gcc/testsuite/c-c++-common/auto-init-7.c +++ b/gcc/testsuite/c-c++-common/auto-init-7.c @@ -29,7 +29,7 @@ double foo() return result; } -/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(12, 2, \&\"temp1\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(24, 2, \&\"temp2\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(28, 2, \&\"temp3\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\((8|5), 2, \&\"temp4\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(12, \[26], \&\"temp1\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(24, \[26], \&\"temp2\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(28, \[26], \&\"temp3\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\((8|5), \[26], \&\"temp4\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-8.c b/gcc/testsuite/c-c++-common/auto-init-8.c index 863f2ba87d7d..93d37ee6c9ca 100644 --- a/gcc/testsuite/c-c++-common/auto-init-8.c +++ b/gcc/testsuite/c-c++-common/auto-init-8.c @@ -29,7 +29,7 @@ double foo() return result; } -/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(12, 1, \&\"temp1\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(24, 1, \&\"temp2\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(28, 1, \&\"temp3\"" "gimple" } } */ -/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\((8|5), 1, \&\"temp4\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(12, \[15], \&\"temp1\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(24, \[15], \&\"temp2\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(28, \[15], \&\"temp3\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\((8|5), \[15], \&\"temp4\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-9.c b/gcc/testsuite/c-c++-common/auto-init-9.c index 113107ffd5c0..66204285616c 100644 --- a/gcc/testsuite/c-c++-common/auto-init-9.c +++ b/gcc/testsuite/c-c++-common/auto-init-9.c @@ -16,5 +16,5 @@ void foo() return; } -/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(2, 2, \&\"temp1\"" "gimple" } } */ -/* { dg-final { scan-tree-dump-not "temp2 = .DEFERRED_INIT \\(8, 2, \&\"temp2\"" "gimple" } } */ +/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(2, \[26], \&\"temp1\"" "gimple" } } */ +/* { dg-final { scan-tree-dump-not "temp2 = .DEFERRED_INIT \\(8, \[26], \&\"temp2\"" "gimple" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-esra.c b/gcc/testsuite/c-c++-common/auto-init-esra.c index ce6779f20fcd..3471a21aa808 100644 --- a/gcc/testsuite/c-c++-common/auto-init-esra.c +++ b/gcc/testsuite/c-c++-common/auto-init-esra.c @@ -31,5 +31,5 @@ void VCross(VECTOR a, const VECTOR b, const VECTOR c) Assign_Vector(a, tmp); } -/* { dg-final { scan-tree-dump-times "tmp = .DEFERRED_INIT \\(24, 2, \&\"tmp\"" 1 "gimple" } } */ -/* { dg-final { scan-tree-dump-times ".DEFERRED_INIT \\(8, 2, \&\"tmp\"" 3 "esra" } } */ +/* { dg-final { scan-tree-dump-times "tmp = .DEFERRED_INIT \\(24, \[26], \&\"tmp\"" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times ".DEFERRED_INIT \\(8, \[26], \&\"tmp\"" 3 "esra" } } */ diff --git a/gcc/testsuite/c-c++-common/auto-init-padding-1.c b/gcc/testsuite/c-c++-common/auto-init-padding-1.c index d2e322717f0e..dddff37a68bf 100644 --- a/gcc/testsuite/c-c++-common/auto-init-padding-1.c +++ b/gcc/testsuite/c-c++-common/auto-init-padding-1.c @@ -19,5 +19,5 @@ void foo(int a) g(s); } -/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(24, 1, \&\"s\"" "gimple" } } */ +/* { dg-final { scan-tree-dump ".DEFERRED_INIT \\(24, \[15], \&\"s\"" "gimple" } } */ /* { dg-final { scan-tree-dump "__builtin_clear_padding" "gimple" } } */ diff --git a/gcc/testsuite/g++.dg/cpp26/erroneous7.C b/gcc/testsuite/g++.dg/cpp26/erroneous7.C new file mode 100644 index 000000000000..b68b3952768c --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/erroneous7.C @@ -0,0 +1,20 @@ +// PR c++/126848 +// { dg-do run { target c++26 } } +// { dg-skip-if "" { *-*-* } { "-ftrivial-auto-var-init=*" } { "" } } +// { dg-options "-O2 -Wuninitialized" } + +[[gnu::noipa]] +int +foo (int x) +{ + int a; + int b = x ? a : 1; + return b - a; // { dg-warning "'a' is used uninitialized" } +} + +int +main () +{ + if (foo (1) != 0) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp26/erroneous8.C b/gcc/testsuite/g++.dg/cpp26/erroneous8.C new file mode 100644 index 000000000000..8cc6ccada5b8 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/erroneous8.C @@ -0,0 +1,19 @@ +// PR c++/126848 +// { dg-do run { target c++26 } } +// { dg-options "-O2 -ftrivial-auto-var-init=zero -Wuninitialized" } + +[[gnu::noipa]] +int +foo (int x) +{ + int a; + int b = x ? a : 1; + return b - a; // { dg-warning "'a' is used uninitialized" } +} + +int +main () +{ + if (foo (1) != 0) + __builtin_abort (); +} diff --git a/gcc/testsuite/g++.dg/cpp26/erroneous9.C b/gcc/testsuite/g++.dg/cpp26/erroneous9.C new file mode 100644 index 000000000000..2f95fadd99a7 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp26/erroneous9.C @@ -0,0 +1,19 @@ +// PR c++/126848 +// { dg-do run { target c++26 } } +// { dg-options "-O2 -ftrivial-auto-var-init=pattern -Wuninitialized" } + +[[gnu::noipa]] +int +foo (int x) +{ + int a; + int b = x ? a : 1; + return b - a; // { dg-warning "'a' is used uninitialized" } +} + +int +main () +{ + if (foo (1) != 0) + __builtin_abort (); +} diff --git a/gcc/tree-ssa-ccp.cc b/gcc/tree-ssa-ccp.cc index cc1da6540e34..9930d78956fe 100644 --- a/gcc/tree-ssa-ccp.cc +++ b/gcc/tree-ssa-ccp.cc @@ -727,9 +727,16 @@ likely_value (gimple *stmt) if (gimple_has_volatile_ops (stmt)) return VARYING; - /* .DEFERRED_INIT produces undefined. */ + /* .DEFERRED_INIT produces undefined except for AUTO_INIT_CXX26 + which produces varying because it is undefined that needs to have + the same value in all uses. */ if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT)) - return UNDEFINED; + { + if (tree_to_uhwi (gimple_call_arg (stmt, 1)) & AUTO_INIT_CXX26) + return VARYING; + else + return UNDEFINED; + } /* Arrive here for more complex cases. */ has_constant_operand = false; diff --git a/gcc/tree-ssa-uninit.cc b/gcc/tree-ssa-uninit.cc index 1072e1e270bb..7d242ab7530a 100644 --- a/gcc/tree-ssa-uninit.cc +++ b/gcc/tree-ssa-uninit.cc @@ -81,6 +81,7 @@ static bool has_undefined_value_p (tree t) { return (ssa_undefined_value_p (t) + || gimple_call_internal_p (SSA_NAME_DEF_STMT (t), IFN_DEFERRED_INIT) || (possibly_undefined_names && possibly_undefined_names->contains (t))); } diff --git a/gcc/tree-ssa.cc b/gcc/tree-ssa.cc index 5248c0903d45..4f94edb2f4b5 100644 --- a/gcc/tree-ssa.cc +++ b/gcc/tree-ssa.cc @@ -1348,9 +1348,15 @@ ssa_undefined_value_p (tree t, bool partial) return true; /* The value is undefined if the definition statement is a call - to .DEFERRED_INIT function. */ + to .DEFERRED_INIT function. Except for AUTO_INIT_CXX26 which is + undefined but needs to have the same value in all uses. */ if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT)) - return true; + { + if (tree_to_uhwi (gimple_call_arg (def_stmt, 1)) & AUTO_INIT_CXX26) + return false; + else + return true; + } /* The value is partially undefined if the definition statement is a REALPART_EXPR or IMAGPART_EXPR and its operand is defined by
