[gcc r16-381] i386: Fix comment typo on truncsfbf2 pattern
https://gcc.gnu.org/g:fd2807173a262a954b76e3fdca605c5c8d1788a2 commit r16-381-gfd2807173a262a954b76e3fdca605c5c8d1788a2 Author: Jakub Jelinek Date: Mon May 5 09:17:21 2025 +0200 i386: Fix comment typo on truncsfbf2 pattern I've noticed a typo on the flag name, fixed thusly. 2025-05-05 Jakub Jelinek * config/i386/i386.md (truncsfbf2): Fix comment typo, unsafte -> unsafe. Diff: --- gcc/config/i386/i386.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index 44ee94a3e419..bb02ab0d4e1c 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -5704,7 +5704,7 @@ /* vcvtneps2bf16 doesn't honor SNAN, and turn sNAN into qNAN quietly, and it always round to even. - flag_unsafte_math_optimization is needed for psrld. + flag_unsafe_math_optimization is needed for psrld. If we don't expect qNaNs nor sNaNs and can assume rounding to nearest, we can expand the conversion inline as (fromi + 0x7fff + ((fromi >> 16) & 1)) >> 16. */
[gcc r16-382] testsuite/120084 - adjust gcc.dg/lto/pr60779_0.c
https://gcc.gnu.org/g:7eeb28717b27d5e3786387b35859bbc5d78ed6b6 commit r16-382-g7eeb28717b27d5e3786387b35859bbc5d78ed6b6 Author: Richard Biener Date: Mon May 5 09:14:13 2025 +0200 testsuite/120084 - adjust gcc.dg/lto/pr60779_0.c Require the linker plugin so functions are properly detected as unused when inlined. PR testsuite/120084 * gcc.dg/lto/pr60779_0.c: Require linker-plugin. Diff: --- gcc/testsuite/gcc.dg/lto/pr60779_0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gcc/testsuite/gcc.dg/lto/pr60779_0.c b/gcc/testsuite/gcc.dg/lto/pr60779_0.c index 360cdc9b51f4..fdeb74c93226 100644 --- a/gcc/testsuite/gcc.dg/lto/pr60779_0.c +++ b/gcc/testsuite/gcc.dg/lto/pr60779_0.c @@ -1,4 +1,5 @@ /* { dg-lto-do link } */ +/* { dg-require-linker-plugin "" } */ /* { dg-lto-options { { -O -flto -fdump-tree-optimized } } } */ _Complex double bar (_Complex double x, _Complex double y);
[gcc r16-384] 'libgomp.c/interop-hsa.c': GCN offloading only
https://gcc.gnu.org/g:85ad0d84fcec720c1d94b9bda9a617ced70ba5d2 commit r16-384-g85ad0d84fcec720c1d94b9bda9a617ced70ba5d2 Author: Thomas Schwinge Date: Mon May 5 10:19:30 2025 +0200 'libgomp.c/interop-hsa.c': GCN offloading only Fix-up for commit 8d84ea28510054fbbb8a2b7441916bd75e29163f "OpenMP, GCN: Add interop-hsa testcase", which added 'libgomp.c/interop-hsa.c'. If nvptx offloading compilation is enabled in addition to GCN, the former ICEs: during RTL pass: final [...]/libgomp.c/interop-hsa.c: In function 'get_kernel_ptr': [...]/libgomp.c/interop-hsa.c:34:1: internal compiler error: RTL check: expected code 'subreg', have 'reg' in nvptx_print_operand, at config/nvptx/nvptx.cc:3082 0x1ccdb96 internal_error(char const*, ...) [...]/gcc/diagnostic-global-context.cc:517 0x7446c3 rtl_check_failed_code1(rtx_def const*, rtx_code, char const*, int, char const*) [...]/gcc/rtl.cc:770 0x7fa533 nvptx_print_operand [...]/gcc/config/nvptx/nvptx.cc:3082 0xb25f34 output_operand(rtx_def*, int) [...]/gcc/final.cc:3641 0xb26f07 output_asm_insn(char const*, rtx_def**) [...]/gcc/final.cc:3534 0xb29d91 output_asm_insn(char const*, rtx_def**) [...]/gcc/final.cc:2639 0xb29d91 final_scan_insn_1 [...]/gcc/final.cc:2642 0xb2a59f final_scan_insn(rtx_insn*, _IO_FILE*, int, int, int*) [...]/gcc/final.cc:2892 0xb2a68c final_1 [...]/gcc/final.cc:1983 0xb2b378 rest_of_handle_final [...]/gcc/final.cc:4250 0xb2b378 execute [...]/gcc/final.cc:4328 Regardless of the issue that nvptx offloading compilation probably shouldn't ICE, the 'asm' insert clearly is valid for GCN only. libgomp/ * testsuite/libgomp.c/interop-hsa.c: GCN offloading only. Diff: --- libgomp/testsuite/libgomp.c/interop-hsa.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libgomp/testsuite/libgomp.c/interop-hsa.c b/libgomp/testsuite/libgomp.c/interop-hsa.c index cf8bc90bb9c0..21ac91c1b58c 100644 --- a/libgomp/testsuite/libgomp.c/interop-hsa.c +++ b/libgomp/testsuite/libgomp.c/interop-hsa.c @@ -1,5 +1,7 @@ /* { dg-additional-options "-ldl" } */ -/* { dg-require-effective-target offload_device_gcn } */ +/* { dg-require-effective-target offload_device_gcn } + The 'asm' insert is valid for GCN only: + { dg-additional-options -foffload=amdgcn-amdhsa } */ #include #include
[gcc r16-385] vect-simd-clone-1[6-8][cd].c: Expect in-branch clones for x86: Fix target selector syntax
https://gcc.gnu.org/g:c9982eec2d3edc5306291d4628f08825ba46d483 commit r16-385-gc9982eec2d3edc5306291d4628f08825ba46d483 Author: Thomas Schwinge Date: Mon May 5 10:21:35 2025 +0200 vect-simd-clone-1[6-8][cd].c: Expect in-branch clones for x86: Fix target selector syntax Fix-up for commit f9f81d5017adc5d860b24f67aeb89b4e79c7ebdb "vect-simd-clone-1[6-8][cd].c: Expect in-branch clones for x86", where we lost the relevant testing, for example, for x86_64, or GCN: PASS: gcc.dg/vect/vect-simd-clone-16c.c (test for excess errors) UNSUPPORTED: gcc.dg/vect/vect-simd-clone-16c.c -flto -ffat-lto-objects PASS: gcc.dg/vect/vect-simd-clone-16c.c execution test -PASS: gcc.dg/vect/vect-simd-clone-16c.c scan-tree-dump-times vect "[\\n\\r] [^\\n]* = foo\\.simdclone" 0 PASS: gcc.dg/vect/vect-simd-clone-16d.c (test for excess errors) UNSUPPORTED: gcc.dg/vect/vect-simd-clone-16d.c -flto -ffat-lto-objects PASS: gcc.dg/vect/vect-simd-clone-16d.c execution test -PASS: gcc.dg/vect/vect-simd-clone-16d.c scan-tree-dump-times vect "[\\n\\r] [^\\n]* = foo\\.simdclone" 0 PASS: gcc.dg/vect/vect-simd-clone-17c.c (test for excess errors) UNSUPPORTED: gcc.dg/vect/vect-simd-clone-17c.c -flto -ffat-lto-objects PASS: gcc.dg/vect/vect-simd-clone-17c.c execution test -PASS: gcc.dg/vect/vect-simd-clone-17c.c scan-tree-dump-times vect "[\\n\\r] [^\\n]* = foo\\.simdclone" 0 PASS: gcc.dg/vect/vect-simd-clone-17d.c (test for excess errors) UNSUPPORTED: gcc.dg/vect/vect-simd-clone-17d.c -flto -ffat-lto-objects PASS: gcc.dg/vect/vect-simd-clone-17d.c execution test -PASS: gcc.dg/vect/vect-simd-clone-17d.c scan-tree-dump-times vect "[\\n\\r] [^\\n]* = foo\\.simdclone" 0 PASS: gcc.dg/vect/vect-simd-clone-18c.c (test for excess errors) UNSUPPORTED: gcc.dg/vect/vect-simd-clone-18c.c -flto -ffat-lto-objects PASS: gcc.dg/vect/vect-simd-clone-18c.c execution test -PASS: gcc.dg/vect/vect-simd-clone-18c.c scan-tree-dump-times vect "[\\n\\r] [^\\n]* = foo\\.simdclone" 0 PASS: gcc.dg/vect/vect-simd-clone-18d.c (test for excess errors) UNSUPPORTED: gcc.dg/vect/vect-simd-clone-18d.c -flto -ffat-lto-objects PASS: gcc.dg/vect/vect-simd-clone-18d.c execution test -PASS: gcc.dg/vect/vect-simd-clone-18d.c scan-tree-dump-times vect "[\\n\\r] [^\\n]* = foo\\.simdclone" 0 ..., which this commit restores. PR middle-end/112877 gcc/testsuite/ * gcc.dg/vect/vect-simd-clone-16c.c: Fix target selector syntax. * gcc.dg/vect/vect-simd-clone-16d.c: Likewise. * gcc.dg/vect/vect-simd-clone-17c.c: Likewise. * gcc.dg/vect/vect-simd-clone-17d.c: Likewise. * gcc.dg/vect/vect-simd-clone-18c.c: Likewise. * gcc.dg/vect/vect-simd-clone-18d.c: Likewise. Diff: --- gcc/testsuite/gcc.dg/vect/vect-simd-clone-16c.c | 2 +- gcc/testsuite/gcc.dg/vect/vect-simd-clone-16d.c | 2 +- gcc/testsuite/gcc.dg/vect/vect-simd-clone-17c.c | 2 +- gcc/testsuite/gcc.dg/vect/vect-simd-clone-17d.c | 2 +- gcc/testsuite/gcc.dg/vect/vect-simd-clone-18c.c | 2 +- gcc/testsuite/gcc.dg/vect/vect-simd-clone-18d.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/gcc/testsuite/gcc.dg/vect/vect-simd-clone-16c.c b/gcc/testsuite/gcc.dg/vect/vect-simd-clone-16c.c index 628d45756739..0f7d17393771 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-simd-clone-16c.c +++ b/gcc/testsuite/gcc.dg/vect/vect-simd-clone-16c.c @@ -7,7 +7,7 @@ /* Ensure the the in-branch simd clones are used on targets that support them. Some targets use another call for the epilogue loops. */ -/* { dg-final { scan-tree-dump-times {[\n\r] [^\n]* = foo\.simdclone} 2 "vect" { target { !aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump-times {[\n\r] [^\n]* = foo\.simdclone} 2 "vect" { target { ! aarch64*-*-* } } } } */ /* { dg-final { scan-tree-dump-times {[\n\r] [^\n]* = foo\.simdclone} 3 "vect" { target { aarch64*-*-* } } } } */ /* The LTO test produces two dump files and we scan the wrong one. */ diff --git a/gcc/testsuite/gcc.dg/vect/vect-simd-clone-16d.c b/gcc/testsuite/gcc.dg/vect/vect-simd-clone-16d.c index d1f85b0703e9..2127fce0c7e6 100644 --- a/gcc/testsuite/gcc.dg/vect/vect-simd-clone-16d.c +++ b/gcc/testsuite/gcc.dg/vect/vect-simd-clone-16d.c @@ -7,7 +7,7 @@ /* Ensure the the in-branch simd clones are used on targets that support them. Some targets use another call for the epilogue loops. */ -/* { dg-final { scan-tree-dump-times {[\n\r] [^\n]* = foo\.simdclone} 2 "vect" { target { !aarch64*-*-* } } } } */ +/* { dg-final { scan-tree-dump-times {[\n\r] [^\n]* = foo\.simdclone} 2 "vect" { target { ! aarch64*-*-* } } } } */ /* { dg-final { scan-tree-dump-times {[\n\r] [^\n]* = foo\.simdclone} 3 "vect" { target { aarch64*-*-
[gcc r16-386] c++: Remove obsolete prototype
https://gcc.gnu.org/g:20c2fc676050ebfcd62af50dad08cd2d2736d1e8 commit r16-386-g20c2fc676050ebfcd62af50dad08cd2d2736d1e8 Author: Simon Martin Date: Mon May 5 10:37:52 2025 +0200 c++: Remove obsolete prototype I noticed while investigating PR c++/119437 that r8-2724-g88b811bd290630 removed parsing_default_capturing_generic_lambda_in_template but not its prototype in cp-tree.h. This patch fixes this. gcc/cp/ChangeLog: * cp-tree.h (parsing_default_capturing_generic_lambda_in_template): Remove obsolete prototype. Diff: --- gcc/cp/cp-tree.h | 1 - 1 file changed, 1 deletion(-) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index af51d67ef9fe..a42c07a330bc 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7632,7 +7632,6 @@ extern void cp_finish_omp_range_for (tree, tree); extern bool cp_maybe_parse_omp_decl (tree, tree); extern bool parsing_nsdmi (void); extern bool parsing_function_declarator (); -extern bool parsing_default_capturing_generic_lambda_in_template (void); extern void inject_this_parameter (tree, cp_cv_quals); extern location_t defparse_location (tree); extern void maybe_show_extern_c_location (void);
[gcc r15-9624] libgomp: Update SVE test
https://gcc.gnu.org/g:941a1b4a00664f23812af00ea56e9795a42a50a4 commit r15-9624-g941a1b4a00664f23812af00ea56e9795a42a50a4 Author: Tejas Belagod Date: Fri Apr 11 10:02:28 2025 +0530 libgomp: Update SVE test Fix udr-sve.c target test that to check for the correct results based on the OpenMP clauses used. The test was first written with a misunderstood functionality of the reduction clause. Tested with aarch64-linux-gnu. OK for trunk? libgomp/ChangeLog: * testsuite/libgomp.c-target/aarch64/udr-sve.c: Fix test. Diff: --- .../testsuite/libgomp.c-target/aarch64/udr-sve.c | 58 ++ 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/libgomp/testsuite/libgomp.c-target/aarch64/udr-sve.c b/libgomp/testsuite/libgomp.c-target/aarch64/udr-sve.c index 03d93cc44b2c..02e02dc04b67 100644 --- a/libgomp/testsuite/libgomp.c-target/aarch64/udr-sve.c +++ b/libgomp/testsuite/libgomp.c-target/aarch64/udr-sve.c @@ -9,8 +9,8 @@ void __attribute__ ((noipa)) parallel_reduction () { - int a[8] = {1 ,1, 1, 1, 1, 1, 1, 1}; - int b[8] = {0 ,0, 0, 0, 0, 0, 0, 0}; + int a[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + int b[8] = {0, 0, 0, 0, 0, 0, 0, 0}; svint32_t va = svld1_s32 (svptrue_b32 (), b); int i = 0; int64_t res; @@ -30,8 +30,8 @@ parallel_reduction () void __attribute__ ((noipa)) for_reduction () { - int a[8] = {1 ,1, 1, 1, 1, 1, 1, 1}; - int b[8] = {0 ,0, 0, 0, 0, 0, 0, 0}; + int a[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + int b[8] = {0, 0, 0, 0, 0, 0, 0, 0}; svint32_t va = svld1_s32 (svptrue_b32 (), b); int j; int64_t res; @@ -58,13 +58,13 @@ simd_reduction () for (j = 0; j < 8; j++) a[j] = 1; - #pragma omp simd reduction (+:va, i) + #pragma omp simd reduction (+:va) for (j = 0; j < 16; j++) -va = svld1_s32 (svptrue_b32 (), a); +va += svld1_s32 (svptrue_b32 (), a); res = svaddv_s32 (svptrue_b32 (), va); - if (res != 8) + if (res != 128) __builtin_abort (); } @@ -72,22 +72,57 @@ void __attribute__ ((noipa)) inscan_reduction_incl () { svint32_t va = svindex_s32 (0, 0); + int a[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + int b[64] = { 0 }; int j; int64_t res = 0; - #pragma omp parallel - #pragma omp for reduction (inscan,+:va) firstprivate (res) lastprivate (res) + #pragma omp parallel for reduction (inscan, +:va) for (j = 0; j < 8; j++) { - va = svindex_s32 (1, 0); + va += svld1_s32 (svptrue_b32 (), a); #pragma omp scan inclusive (va) - res += svaddv_s32 (svptrue_b32 (), va); + svst1_s32 (svptrue_b32 (), b + j * 8, va); +} + + res = svaddv_s32 (svptrue_b32 (), va); + + if (res != 64) +__builtin_abort (); + + for (j = 0; j < 64; j+=8) +if (b[j] != (j / 8 + 1)) + __builtin_abort (); +} + +void __attribute__ ((noipa)) +inscan_reduction_excl () +{ + svint32_t va = svindex_s32 (0, 0); + int a[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + int b[64] = { 0 }; + int j; + int64_t res = 0; + + #pragma omp parallel for reduction (inscan, +:va) + for (j = 0; j < 8; j++) +{ + svst1_s32 (svptrue_b32 (), b + j * 8, va); + #pragma omp scan exclusive (va) + va += svld1_s32 (svptrue_b32 (), a); } + res = svaddv_s32 (svptrue_b32 (), va); + if (res != 64) __builtin_abort (); + + for (j = 0; j < 64; j+=8) +if (b[j] != j / 8) + __builtin_abort (); } + int main () { @@ -95,4 +130,5 @@ main () for_reduction (); simd_reduction (); inscan_reduction_incl (); + inscan_reduction_excl (); }
[gcc r16-397] libgomp: Update SVE test
https://gcc.gnu.org/g:c3979346f963adfdc6c860a43103a0768863cbcf commit r16-397-gc3979346f963adfdc6c860a43103a0768863cbcf Author: Tejas Belagod Date: Fri Apr 11 10:02:28 2025 +0530 libgomp: Update SVE test Fix udr-sve.c target test that to check for the correct results based on the OpenMP clauses used. The test was first written with a misunderstood functionality of the reduction clause. Tested with aarch64-linux-gnu. OK for trunk? libgomp/ChangeLog: * testsuite/libgomp.c-target/aarch64/udr-sve.c: Fix test. Diff: --- .../testsuite/libgomp.c-target/aarch64/udr-sve.c | 58 ++ 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/libgomp/testsuite/libgomp.c-target/aarch64/udr-sve.c b/libgomp/testsuite/libgomp.c-target/aarch64/udr-sve.c index 03d93cc44b2c..02e02dc04b67 100644 --- a/libgomp/testsuite/libgomp.c-target/aarch64/udr-sve.c +++ b/libgomp/testsuite/libgomp.c-target/aarch64/udr-sve.c @@ -9,8 +9,8 @@ void __attribute__ ((noipa)) parallel_reduction () { - int a[8] = {1 ,1, 1, 1, 1, 1, 1, 1}; - int b[8] = {0 ,0, 0, 0, 0, 0, 0, 0}; + int a[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + int b[8] = {0, 0, 0, 0, 0, 0, 0, 0}; svint32_t va = svld1_s32 (svptrue_b32 (), b); int i = 0; int64_t res; @@ -30,8 +30,8 @@ parallel_reduction () void __attribute__ ((noipa)) for_reduction () { - int a[8] = {1 ,1, 1, 1, 1, 1, 1, 1}; - int b[8] = {0 ,0, 0, 0, 0, 0, 0, 0}; + int a[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + int b[8] = {0, 0, 0, 0, 0, 0, 0, 0}; svint32_t va = svld1_s32 (svptrue_b32 (), b); int j; int64_t res; @@ -58,13 +58,13 @@ simd_reduction () for (j = 0; j < 8; j++) a[j] = 1; - #pragma omp simd reduction (+:va, i) + #pragma omp simd reduction (+:va) for (j = 0; j < 16; j++) -va = svld1_s32 (svptrue_b32 (), a); +va += svld1_s32 (svptrue_b32 (), a); res = svaddv_s32 (svptrue_b32 (), va); - if (res != 8) + if (res != 128) __builtin_abort (); } @@ -72,22 +72,57 @@ void __attribute__ ((noipa)) inscan_reduction_incl () { svint32_t va = svindex_s32 (0, 0); + int a[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + int b[64] = { 0 }; int j; int64_t res = 0; - #pragma omp parallel - #pragma omp for reduction (inscan,+:va) firstprivate (res) lastprivate (res) + #pragma omp parallel for reduction (inscan, +:va) for (j = 0; j < 8; j++) { - va = svindex_s32 (1, 0); + va += svld1_s32 (svptrue_b32 (), a); #pragma omp scan inclusive (va) - res += svaddv_s32 (svptrue_b32 (), va); + svst1_s32 (svptrue_b32 (), b + j * 8, va); +} + + res = svaddv_s32 (svptrue_b32 (), va); + + if (res != 64) +__builtin_abort (); + + for (j = 0; j < 64; j+=8) +if (b[j] != (j / 8 + 1)) + __builtin_abort (); +} + +void __attribute__ ((noipa)) +inscan_reduction_excl () +{ + svint32_t va = svindex_s32 (0, 0); + int a[8] = {1, 1, 1, 1, 1, 1, 1, 1}; + int b[64] = { 0 }; + int j; + int64_t res = 0; + + #pragma omp parallel for reduction (inscan, +:va) + for (j = 0; j < 8; j++) +{ + svst1_s32 (svptrue_b32 (), b + j * 8, va); + #pragma omp scan exclusive (va) + va += svld1_s32 (svptrue_b32 (), a); } + res = svaddv_s32 (svptrue_b32 (), va); + if (res != 64) __builtin_abort (); + + for (j = 0; j < 64; j+=8) +if (b[j] != j / 8) + __builtin_abort (); } + int main () { @@ -95,4 +130,5 @@ main () for_reduction (); simd_reduction (); inscan_reduction_incl (); + inscan_reduction_excl (); }
[gcc r16-391] Allow IPA_CP to handle UNDEFINED as VARYING.
https://gcc.gnu.org/g:7f285b7ad7cb89a9b29b52e0d25a7666dc9bd645 commit r16-391-g7f285b7ad7cb89a9b29b52e0d25a7666dc9bd645 Author: Andrew MacLeod Date: Fri May 2 15:48:08 2025 -0400 Allow IPA_CP to handle UNDEFINED as VARYING. When applying a bitmask to reflect ranges, it is sometimes deferred and this can result in an UNDEFINED result. IPA is not expecting this, and add a check for it, and convert to VARYING if encountered. PR tree-optimization/120048 gcc/ * ipa-cp.cc (ipcp_store_vr_results): Check for UNDEFINED. gcc/testsuite/ * gcc.dg/pr120048.c: New. Diff: --- gcc/ipa-cp.cc | 10 ++ gcc/testsuite/gcc.dg/pr120048.c | 12 2 files changed, 22 insertions(+) diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc index f7e5aa9bfd5c..b41148c74de3 100644 --- a/gcc/ipa-cp.cc +++ b/gcc/ipa-cp.cc @@ -6362,6 +6362,11 @@ ipcp_store_vr_results (void) TYPE_PRECISION (type), TYPE_SIGN (type))); tmp.update_bitmask (bm); + // Reflecting the bitmask on the ranges can sometime + // produce an UNDEFINED value if the the bitmask update + // was previously deferred. See PR 120048. + if (tmp.undefined_p ()) + tmp.set_varying (type); ipa_vr vr (tmp); ts->m_vr->quick_push (vr); } @@ -6383,6 +6388,11 @@ ipcp_store_vr_results (void) TYPE_PRECISION (type), TYPE_SIGN (type))); tmp.update_bitmask (bm); + // Reflecting the bitmask on the ranges can sometime + // produce an UNDEFINED value if the the bitmask update + // was previously deferred. See PR 120048. + if (tmp.undefined_p ()) + tmp.set_varying (type); ipa_vr vr (tmp); ts->m_vr->quick_push (vr); } diff --git a/gcc/testsuite/gcc.dg/pr120048.c b/gcc/testsuite/gcc.dg/pr120048.c new file mode 100644 index ..6bb34b0e1689 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr120048.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fno-tree-vrp -fno-tree-fre" } */ + +int a, b, c; +static int d(short e) { return e || (a && e) ? 0 : a; } +static void f(int e) { + if (!e) { +d(0); +b = d(e); + } +} +int main() { f(c | 1); }
[gcc r16-389] dwarf2out: Propagate dtprel into the .debug_addr table in resolve_addr_in_expr
https://gcc.gnu.org/g:662dbe37d9ce479785e6944381d02abb3ecc41db commit r16-389-g662dbe37d9ce479785e6944381d02abb3ecc41db Author: Kyle Huey Date: Thu May 1 17:13:47 2025 -0700 dwarf2out: Propagate dtprel into the .debug_addr table in resolve_addr_in_expr For a debugger to display statically-allocated[0] TLS variables the compiler must communicate information[1] that can be used in conjunction with knowledge of the runtime enviroment[2] to calculate a location for the variable for each thread. That need gives rise to dw_loc_dtprel in dwarf2out, a flag tracking whether the location description is dtprel, or relative to the "dynamic thread pointer". Location descriptions in the .debug_info section for TLS variables need to be relocated by the static linker accordingly, and dw_loc_dtprel controls emission of the needed relocations. This is further complicated by -gsplit-dwarf. -gsplit-dwarf is designed to allow as much debugging information as possible to bypass the static linker to improve linking performance. One of the ways that is done is by introducing a layer of indirection for relocatable values[3]. That gives rise to addr_index_table which ultimately results in the .debug_addr section. While the code handling addr_index_table clearly contemplates the existence of dtprel entries[4] resolve_addr_in_expr does not, and the result is that when using -gsplit-dwarf the DWARF for TLS variables contains an address[5] rather than an offset, and debuggers can't work with that. This is visible on a trivial example. Compile ``` static __thread int tls_var; int main(void) { tls_var = 42; return 0; } ``` with -g and -g -gsplit-dwarf. Run the program under gdb. When examining the value of tls_var before and after the assignment, -g behaves as one would expect but -g -gsplit-dwarf does not. If the user is lucky and the miscalculated address is not mapped, gdb will print "Cannot access memory at address ...". If the user is unlucky and the miscalculated address is mapped, gdb will simply give the wrong value. You can further confirm that the issue is the address calculation by asking gdb for the address of tls_var and comparing that to what one would expect.[6] Thankfully this is trivial to fix by modifying resolve_addr_in_expr to propagate the dtprel character of the location where necessary. gdb begins working as expected and the diff in the generated assembly is clear. ``` .section.debug_addr,"",@progbits .long 0x14 .value 0x5 .byte 0x8 .byte 0 .Ldebug_addr0: - .quad tls_var + .long tls_var@dtpoff, 0 .quad .LFB0 ``` [0] Referring to e.g. __thread as statically-allocated vs. e.g. a dynamically-allocated pthread_key_create() call. [1] Generally an offset in a TLS block. [2] With glibc, provided by libthread_db.so. [3] Relocatable values are moved to a table in the .debug_addr section, those values in .debug_info are replaced with special values that look up indexes in that table, and then the static linker elsewhere assigns a single per-CU starting index in the .debug_addr section, allowing those special values to remain permanently fixed and the resulting data to be ignored by the linker. [4] ate_kind_rtx_dtprel exists, after all, and new_addr_loc_descr does produce it where appropriate. [5] e.g. an address in the .tbss/.tdata section. [6] e.g. on x86-64 by examining %fsbase and the offset in the assembly 2025-05-01 Kyle Huey * dwarf2out.cc (resolve_addr_in_expr): Propagate dtprel into the address table when appropriate. Diff: --- gcc/dwarf2out.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gcc/dwarf2out.cc b/gcc/dwarf2out.cc index 34ffeed86ff1..9aecdb9fd5a1 100644 --- a/gcc/dwarf2out.cc +++ b/gcc/dwarf2out.cc @@ -31068,7 +31068,8 @@ resolve_addr_in_expr (dw_attr_node *a, dw_loc_descr_ref loc) return false; remove_addr_table_entry (loc->dw_loc_oprnd1.val_entry); loc->dw_loc_oprnd1.val_entry - = add_addr_table_entry (rtl, ate_kind_rtx); + = add_addr_table_entry (rtl, loc->dw_loc_dtprel + ? ate_kind_rtx_dtprel : ate_kind_rtx); } break; case DW_OP_const4u:
[gcc r15-9621] ipa/119973 - IPA PTA issue with global initializers
https://gcc.gnu.org/g:b36014e10c95d3ada1dcdf4695626af90fba0a99 commit r15-9621-gb36014e10c95d3ada1dcdf4695626af90fba0a99 Author: Richard Biener Date: Mon Apr 28 11:15:53 2025 +0200 ipa/119973 - IPA PTA issue with global initializers For global initializers with IPA PTA we initialize them from the IPA reference data but that lacks references to the constant pool. The following conservatively considers the whole initializer. PR ipa/119973 * tree-ssa-structalias.cc (create_variable_info_for): Build constraints from DECL_INITIAL directly rather than the IPA reference list which is incomplete. * gcc.dg/torture/pr119973.c: New testcase. (cherry picked from commit 7a16ef443b13fff9537baa533597836c57131262) Diff: --- gcc/testsuite/gcc.dg/torture/pr119973.c | 39 + gcc/tree-ssa-structalias.cc | 10 - 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/gcc/testsuite/gcc.dg/torture/pr119973.c b/gcc/testsuite/gcc.dg/torture/pr119973.c new file mode 100644 index ..a9661a3111ae --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr119973.c @@ -0,0 +1,39 @@ +/* { dg-do run } */ +/* { dg-additional-options "-fipa-pta" } */ + +static int +is_valid_domain_name (const char *string) +{ + const char *s; + + for (s=string; *s; s++) +if (*s == '.') + { +if (string == s) + return 0; + } + + return !!*string; +} + +int +main (void) +{ + static struct + { +const char *name; +int valid; + } testtbl[] = +{ + { ".", 0 }, + { nullptr, 0 } +}; + int idx; + + for (idx=0; testtbl[idx].name; idx++) +{ + if (is_valid_domain_name (testtbl[idx].name) != testtbl[idx].valid) +__builtin_abort (); +} + return 0; +} diff --git a/gcc/tree-ssa-structalias.cc b/gcc/tree-ssa-structalias.cc index d9356a82ad12..f79b54284c64 100644 --- a/gcc/tree-ssa-structalias.cc +++ b/gcc/tree-ssa-structalias.cc @@ -6529,18 +6529,18 @@ create_variable_info_for (tree decl, const char *name, bool add_id) if (!vnode->all_refs_explicit_p ()) make_copy_constraint (vi, nonlocal_id); - /* If this is a global variable with an initializer and we are in -IPA mode generate constraints for it. */ - ipa_ref *ref; - for (unsigned idx = 0; vnode->iterate_reference (idx, ref); ++idx) + /* While we can in theory walk references for the varpool +node that does not cover zero-initialization or references +to the constant pool. */ + if (DECL_INITIAL (decl)) { auto_vec rhsc; struct constraint_expr lhs, *rhsp; unsigned i; - get_constraint_for_address_of (ref->referred->decl, &rhsc); lhs.var = vi->id; lhs.offset = 0; lhs.type = SCALAR; + get_constraint_for (DECL_INITIAL (decl), &rhsc); FOR_EACH_VEC_ELT (rhsc, i, rhsp) process_constraint (new_constraint (lhs, *rhsp)); /* If this is a variable that escapes from the unit
[gcc r16-388] testsuite: Link gcc.dg/lto/modref-2_0 with libm
https://gcc.gnu.org/g:7fae8dca82abf714a055ff505df51a4c8b43c211 commit r16-388-g7fae8dca82abf714a055ff505df51a4c8b43c211 Author: John David Anglin Date: Mon May 5 09:30:45 2025 -0400 testsuite: Link gcc.dg/lto/modref-2_0 with libm 2025-05-05 John David Anglin gcc/testsuite/ChangeLog: PR testsuite/120085 * gcc.dg/lto/modref-2_0.c: Link test with libm. Diff: --- gcc/testsuite/gcc.dg/lto/modref-2_0.c | 1 + 1 file changed, 1 insertion(+) diff --git a/gcc/testsuite/gcc.dg/lto/modref-2_0.c b/gcc/testsuite/gcc.dg/lto/modref-2_0.c index cf84ed95e775..bba4c8df95ea 100644 --- a/gcc/testsuite/gcc.dg/lto/modref-2_0.c +++ b/gcc/testsuite/gcc.dg/lto/modref-2_0.c @@ -1,5 +1,6 @@ /* { dg-lto-do run } */ /* { dg-lto-options {"-O2 -flto-partition=max -flto -fno-ipa-sra"} } */ +/* { dg-extra-ld-options { -lm } } */ __attribute__ ((noinline)) void test (char *a)
[gcc r16-387] Ada: Fix assertion failure on Finalizable aspect for tagged record type
https://gcc.gnu.org/g:e67758cd816978a519d751b618043a8957d67e0e commit r16-387-ge67758cd816978a519d751b618043a8957d67e0e Author: Eric Botcazou Date: Mon May 5 12:58:58 2025 +0200 Ada: Fix assertion failure on Finalizable aspect for tagged record type This is a (benign) assertion failure on the mainline for the new Finalizable aspect put on a tagged record type when not all the primitives are declared. This compiles and runs on the 15 branch because assertions are disabled. gcc/ada/ PR ada/120104 * exp_ch3.adb (Expand_Freeze_Record_Type): For a controlled tagged type, freeze only the controlled primitives that are present. gcc/testsuite/ * gnat.dg/specs/finalizable1.ads: New test. Diff: --- gcc/ada/exp_ch3.adb | 30 ++-- gcc/testsuite/gnat.dg/specs/finalizable1.ads | 11 ++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb index 0dfd8102df18..bc46fd37e0c6 100644 --- a/gcc/ada/exp_ch3.adb +++ b/gcc/ada/exp_ch3.adb @@ -6321,19 +6321,27 @@ package body Exp_Ch3 is -- frozen inside. if Is_Controlled (Typ) then - Append_Freeze_Actions (Typ, - Freeze_Entity - (Find_Controlled_Prim_Op (Typ, Name_Initialize), Typ)); + declare + Prim : Entity_Id; - if not Is_Limited_Type (Typ) then - Append_Freeze_Actions (Typ, -Freeze_Entity - (Find_Controlled_Prim_Op (Typ, Name_Adjust), Typ)); - end if; + begin + Prim := Find_Controlled_Prim_Op (Typ, Name_Initialize); + if Present (Prim) then + Append_Freeze_Actions (Typ, Freeze_Entity (Prim, Typ)); + end if; - Append_Freeze_Actions (Typ, - Freeze_Entity - (Find_Controlled_Prim_Op (Typ, Name_Finalize), Typ)); + if not Is_Limited_Type (Typ) then + Prim := Find_Controlled_Prim_Op (Typ, Name_Adjust); + if Present (Prim) then +Append_Freeze_Actions (Typ, Freeze_Entity (Prim, Typ)); + end if; + end if; + + Prim := Find_Controlled_Prim_Op (Typ, Name_Finalize); + if Present (Prim) then + Append_Freeze_Actions (Typ, Freeze_Entity (Prim, Typ)); + end if; + end; end if; -- Freeze rest of primitive operations. There is no need to handle diff --git a/gcc/testsuite/gnat.dg/specs/finalizable1.ads b/gcc/testsuite/gnat.dg/specs/finalizable1.ads new file mode 100644 index ..5fa8f5cf3c3f --- /dev/null +++ b/gcc/testsuite/gnat.dg/specs/finalizable1.ads @@ -0,0 +1,11 @@ +-- { dg-do compile } +-- { dg-options "-gnatX0" } + +package Finalizable1 is + + type Root is abstract tagged null record +with Finalizable => (Finalize => Finalize); + + procedure Finalize (This : in out Root) is abstract; + +end Finalizable1;
[gcc r15-9620] Ada: Fix assertion failure on Finalizable aspect for tagged record type
https://gcc.gnu.org/g:37c312486186ed9dc2561b2e341fd81f4f1627ec commit r15-9620-g37c312486186ed9dc2561b2e341fd81f4f1627ec Author: Eric Botcazou Date: Mon May 5 12:58:58 2025 +0200 Ada: Fix assertion failure on Finalizable aspect for tagged record type This is a (benign) assertion failure on the mainline for the new Finalizable aspect put on a tagged record type when not all the primitives are declared. This compiles and runs on the 15 branch because assertions are disabled. gcc/ada/ PR ada/120104 * exp_ch3.adb (Expand_Freeze_Record_Type): For a controlled tagged type, freeze only the controlled primitives that are present. gcc/testsuite/ * gnat.dg/specs/finalizable1.ads: New test. Diff: --- gcc/ada/exp_ch3.adb | 30 ++-- gcc/testsuite/gnat.dg/specs/finalizable1.ads | 11 ++ 2 files changed, 30 insertions(+), 11 deletions(-) diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb index 0dfd8102df18..bc46fd37e0c6 100644 --- a/gcc/ada/exp_ch3.adb +++ b/gcc/ada/exp_ch3.adb @@ -6321,19 +6321,27 @@ package body Exp_Ch3 is -- frozen inside. if Is_Controlled (Typ) then - Append_Freeze_Actions (Typ, - Freeze_Entity - (Find_Controlled_Prim_Op (Typ, Name_Initialize), Typ)); + declare + Prim : Entity_Id; - if not Is_Limited_Type (Typ) then - Append_Freeze_Actions (Typ, -Freeze_Entity - (Find_Controlled_Prim_Op (Typ, Name_Adjust), Typ)); - end if; + begin + Prim := Find_Controlled_Prim_Op (Typ, Name_Initialize); + if Present (Prim) then + Append_Freeze_Actions (Typ, Freeze_Entity (Prim, Typ)); + end if; - Append_Freeze_Actions (Typ, - Freeze_Entity - (Find_Controlled_Prim_Op (Typ, Name_Finalize), Typ)); + if not Is_Limited_Type (Typ) then + Prim := Find_Controlled_Prim_Op (Typ, Name_Adjust); + if Present (Prim) then +Append_Freeze_Actions (Typ, Freeze_Entity (Prim, Typ)); + end if; + end if; + + Prim := Find_Controlled_Prim_Op (Typ, Name_Finalize); + if Present (Prim) then + Append_Freeze_Actions (Typ, Freeze_Entity (Prim, Typ)); + end if; + end; end if; -- Freeze rest of primitive operations. There is no need to handle diff --git a/gcc/testsuite/gnat.dg/specs/finalizable1.ads b/gcc/testsuite/gnat.dg/specs/finalizable1.ads new file mode 100644 index ..5fa8f5cf3c3f --- /dev/null +++ b/gcc/testsuite/gnat.dg/specs/finalizable1.ads @@ -0,0 +1,11 @@ +-- { dg-do compile } +-- { dg-options "-gnatX0" } + +package Finalizable1 is + + type Root is abstract tagged null record +with Finalizable => (Finalize => Finalize); + + procedure Finalize (This : in out Root) is abstract; + +end Finalizable1;
[gcc r13-9632] Enable generation of GNU stack notes on Linux
https://gcc.gnu.org/g:10b8d94e7f45608dd896c7a780370136ed975c6f commit r13-9632-g10b8d94e7f45608dd896c7a780370136ed975c6f Author: John David Anglin Date: Mon Nov 6 20:33:15 2023 + Enable generation of GNU stack notes on Linux 2023-11-06 John David Anglin * config/pa/pa-linux.h (NEED_INDICATE_EXEC_STACK): Define to 1. Diff: --- gcc/config/pa/pa-linux.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gcc/config/pa/pa-linux.h b/gcc/config/pa/pa-linux.h index d38f68b1fa54..96c54765ddb9 100644 --- a/gcc/config/pa/pa-linux.h +++ b/gcc/config/pa/pa-linux.h @@ -144,8 +144,7 @@ along with GCC; see the file COPYING3. If not see #define HAVE_sync_compare_and_swapsi 1 #define HAVE_sync_compare_and_swapdi 1 -/* It's not possible to enable GNU_stack notes since the kernel needs - an executable stack for signal returns and syscall restarts. */ +/* Enable GNU stack notes. */ #undef NEED_INDICATE_EXEC_STACK -#define NEED_INDICATE_EXEC_STACK 0 +#define NEED_INDICATE_EXEC_STACK 1
[gcc r12-11087] Enable generation of GNU stack notes on Linux
https://gcc.gnu.org/g:8b26ee407613cdbfc3fb2095c09ae28b4642fd63 commit r12-11087-g8b26ee407613cdbfc3fb2095c09ae28b4642fd63 Author: John David Anglin Date: Mon Nov 6 20:33:15 2023 + Enable generation of GNU stack notes on Linux 2023-11-06 John David Anglin * config/pa/pa-linux.h (NEED_INDICATE_EXEC_STACK): Define to 1. Diff: --- gcc/config/pa/pa-linux.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/gcc/config/pa/pa-linux.h b/gcc/config/pa/pa-linux.h index 5af11a1df804..f467d3acbb99 100644 --- a/gcc/config/pa/pa-linux.h +++ b/gcc/config/pa/pa-linux.h @@ -147,8 +147,7 @@ along with GCC; see the file COPYING3. If not see #define HAVE_sync_compare_and_swapsi 1 #define HAVE_sync_compare_and_swapdi 1 -/* It's not possible to enable GNU_stack notes since the kernel needs - an executable stack for signal returns and syscall restarts. */ +/* Enable GNU stack notes. */ #undef NEED_INDICATE_EXEC_STACK -#define NEED_INDICATE_EXEC_STACK 0 +#define NEED_INDICATE_EXEC_STACK 1
[gcc r16-383] c++: Inhibit subsequent warnings/notes in diagnostic_groups with an inhibited warning [PR118163, PR11
https://gcc.gnu.org/g:0f1d55a75b09c13e3db09654c2b5aaad5741262f commit r16-383-g0f1d55a75b09c13e3db09654c2b5aaad5741262f Author: Simon Martin Date: Mon May 5 10:12:08 2025 +0200 c++: Inhibit subsequent warnings/notes in diagnostic_groups with an inhibited warning [PR118163,PR118392] Those 2 PRs show that even when using a *single* diagnostic_group, it's possible to end up with a warning being inhibited and its associated note still emitted, which leads to puzzling user experience. Example from PR118392: === $ gcc/cc1plus inhibit-warn-3.C -w inhibit-warn-3.C:10:17: note: only here as a ‘friend’ 10 | friend void bar(); | ^~~ === Following a suggestion from ppalka@, this patch keeps track of the "diagnostic depth" at which a warning in inhibited, and makes sure that all subsequent notes at that depth or deeper are inhibited as well, until a subsequent warning or error is accepted at that depth, or the diagnostic_group or nesting level is popped. PR c++/118163 PR c++/118392 gcc/ChangeLog: * diagnostic.cc (diagnostic_context::initialize): Initialize m_diagnostic_groups.m_inhibiting_notes_from. (diagnostic_context::inhibit_notes_in_group): New. (diagnostic_context::notes_inhibited_in_group): New (diagnostic_context::report_diagnostic): Call inhibit_notes_in_group and notes_inhibited_in_group. (diagnostic_context::end_group): Call inhibit_notes_in_group. (diagnostic_context::pop_nesting_level): Ditto. * diagnostic.h (diagnostic_context::m_diagnostic_groups): Add member to track the depth at which a warning has been inhibited. (diagnostic_context::notes_inhibited_in_group): Declare. (diagnostic_context::inhibit_notes_in_group): Declare. * doc/ux.texi: Document diagnostic_group behavior with regards to inhibited warnings. gcc/testsuite/ChangeLog: * g++.dg/diagnostic/incomplete-type-2.C: New test. * g++.dg/diagnostic/incomplete-type-2a.C: New test. * g++.dg/diagnostic/inhibit-warn-3.C: New test. Diff: --- gcc/diagnostic.cc | 67 +- gcc/diagnostic.h | 6 ++ gcc/doc/ux.texi| 5 +- .../g++.dg/diagnostic/incomplete-type-2.C | 7 +++ .../g++.dg/diagnostic/incomplete-type-2a.C | 13 + gcc/testsuite/g++.dg/diagnostic/inhibit-warn-3.C | 15 + 6 files changed, 110 insertions(+), 3 deletions(-) diff --git a/gcc/diagnostic.cc b/gcc/diagnostic.cc index 429c4b1b116a..c3ea1b34d2f2 100644 --- a/gcc/diagnostic.cc +++ b/gcc/diagnostic.cc @@ -282,6 +282,7 @@ diagnostic_context::initialize (int n_opts) m_diagnostic_groups.m_group_nesting_depth = 0; m_diagnostic_groups.m_diagnostic_nesting_level = 0; m_diagnostic_groups.m_emission_count = 0; + m_diagnostic_groups.m_inhibiting_notes_from = 0; m_output_sinks.safe_push (new diagnostic_text_output_format (*this, nullptr, true)); m_set_locations_cb = nullptr; @@ -917,6 +918,7 @@ diagnostic_context::check_max_errors (bool flush) /* Take any action which is expected to happen after the diagnostic is written out. This function does not always return. */ + void diagnostic_context::action_after_output (diagnostic_t diag_kind) { @@ -991,6 +993,50 @@ diagnostic_context::action_after_output (diagnostic_t diag_kind) } } +/* State whether we should inhibit notes in the current diagnostic_group and + its future children if any. */ + +void +diagnostic_context::inhibit_notes_in_group (bool inhibit) +{ + int curr_depth = (m_diagnostic_groups.m_group_nesting_depth + + m_diagnostic_groups.m_diagnostic_nesting_level); + + if (inhibit) +{ + /* If we're already inhibiting, there's nothing to do. */ + if (m_diagnostic_groups.m_inhibiting_notes_from) + return; + + /* Since we're called via warning/error/... that all have their own +diagnostic_group, we must consider that we started inhibiting in their +parent. */ + gcc_assert (m_diagnostic_groups.m_group_nesting_depth > 0); + m_diagnostic_groups.m_inhibiting_notes_from = curr_depth - 1; +} + else if (m_diagnostic_groups.m_inhibiting_notes_from) +{ + /* Only cancel inhibition at the depth that set it up. */ + if (curr_depth >= m_diagnostic_groups.m_inhibiting_notes_from) + return; + + m_diagnostic_groups.m_inhibiting_notes_from = 0; +} +} + +/* Return whether notes must be inhibited in the current diagnostic_group. */ + +bool +diagnostic_context::notes_inhibited_in_group () const +{ + if (m_diagnostic_groups.m_inhibiting_notes_from + && (m_diagnostic_groups.m_group_nesting_depth +
[gcc r14-11735] c++/coro: prevent ICV_STATEMENT diagnostics in temp promotion [PR116502]
https://gcc.gnu.org/g:694b942a179f5fbaee882a5e619e5bbaf64b4d11 commit r14-11735-g694b942a179f5fbaee882a5e619e5bbaf64b4d11 Author: Arsen Arsenović Date: Wed Aug 28 21:59:18 2024 +0200 c++/coro: prevent ICV_STATEMENT diagnostics in temp promotion [PR116502] If such a diagnostic is necessary, it has already been emitted, otherwise, it is not correct and emitting it here is inactionable by the user, and bogus. PR c++/116502 gcc/cp/ChangeLog: * coroutines.cc (maybe_promote_temps): Convert temporary initializers to void without complaining. gcc/testsuite/ChangeLog: * g++.dg/coroutines/maybe-unused-1.C: New test. * g++.dg/coroutines/pr116502.C: New test. (cherry picked from commit 05e4f07cad1eacf869c10622cae2a9cdee3b6a7a) Diff: --- gcc/cp/coroutines.cc | 12 ++--- gcc/testsuite/g++.dg/coroutines/maybe-unused-1.C | 33 gcc/testsuite/g++.dg/coroutines/pr116502.C | 33 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index e0e312265c10..de160bad1a20 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -3323,7 +3323,13 @@ maybe_promote_temps (tree *stmt, void *d) to run the initializer. If the initializer is a conditional expression, we need to collect and declare any promoted variables nested within it. DTORs for such -variables must be run conditionally too. */ +variables must be run conditionally too. + +Since here we're synthetically processing code here, we've already +emitted any Wunused-result warnings. Below, however, we call +finish_expr_stmt, which will convert its operand to void, and could +result in such a diagnostic being emitted. To avoid that, convert to +void ahead of time. */ if (t->var) { tree var = t->var; @@ -,7 +3339,7 @@ maybe_promote_temps (tree *stmt, void *d) if (TREE_CODE (t->init) == COND_EXPR) process_conditional (t, vlist); else - finish_expr_stmt (t->init); + finish_expr_stmt (convert_to_void (t->init, ICV_STATEMENT, tf_none)); if (tree cleanup = cxx_maybe_build_cleanup (var, tf_warning_or_error)) { tree cl = build_stmt (sloc, CLEANUP_STMT, expr_list, cleanup, var); @@ -3352,7 +3358,7 @@ maybe_promote_temps (tree *stmt, void *d) if (TREE_CODE (t->init) == COND_EXPR) process_conditional (t, vlist); else - finish_expr_stmt (t->init); + finish_expr_stmt (convert_to_void (t->init, ICV_STATEMENT, tf_none)); if (expr_list) { if (TREE_CODE (expr_list) != STATEMENT_LIST) diff --git a/gcc/testsuite/g++.dg/coroutines/maybe-unused-1.C b/gcc/testsuite/g++.dg/coroutines/maybe-unused-1.C new file mode 100644 index ..68d59d83e8eb --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/maybe-unused-1.C @@ -0,0 +1,33 @@ +// https://gcc.gnu.org/PR116502 +#include + +struct SuspendNever { + bool await_ready() noexcept; + void await_suspend(std::coroutine_handle<>) noexcept; + void await_resume() noexcept; +}; + +struct Coroutine; + +struct PromiseType { + Coroutine get_return_object(); + SuspendNever initial_suspend(); + SuspendNever final_suspend() noexcept; + void return_void(); + void unhandled_exception(); +}; + +struct Coroutine { + using promise_type = PromiseType; +}; + +struct Awaiter { + bool await_ready(); + void await_suspend(std::coroutine_handle<>); + [[nodiscard]] int& await_resume(); +}; + +Coroutine foo() +{ + co_await Awaiter {}; // { dg-warning "Wunused-result" } +} diff --git a/gcc/testsuite/g++.dg/coroutines/pr116502.C b/gcc/testsuite/g++.dg/coroutines/pr116502.C new file mode 100644 index ..95cc0bc8a983 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr116502.C @@ -0,0 +1,33 @@ +// https://gcc.gnu.org/PR116502 +#include + +struct SuspendNever { + bool await_ready() noexcept; + void await_suspend(std::coroutine_handle<>) noexcept; + void await_resume() noexcept; +}; + +struct Coroutine; + +struct PromiseType { + Coroutine get_return_object(); + SuspendNever initial_suspend(); + SuspendNever final_suspend() noexcept; + void return_void(); + void unhandled_exception(); +}; + +struct Coroutine { + using promise_type = PromiseType; +}; + +struct Awaiter { + bool await_ready(); + void await_suspend(std::coroutine_handle<>); + [[nodiscard]] int& await_resume(); +}; + +Coroutine foo() +{ + (void)co_await Awaiter {}; +}
[gcc r14-11736] c++: simplify handling implicit INDIRECT_REF and co_await in convert_to_void
https://gcc.gnu.org/g:0ff545dbc2fd6ffa6ae544c3754ecaa7f9864a22 commit r14-11736-g0ff545dbc2fd6ffa6ae544c3754ecaa7f9864a22 Author: Arsen Arsenović Date: Fri Sep 20 13:13:02 2024 +0200 c++: simplify handling implicit INDIRECT_REF and co_await in convert_to_void convert_to_void has, so far, when converting a co_await expression to void altered the await_resume expression of a co_await so that it is also converted to void. This meant that the type of the await_resume expression, which is also supposed to be the type of the whole co_await expression, was not the same as the type of the CO_AWAIT_EXPR tree. While this has not caused problems so far, it is unexpected, I think. Also, convert_to_void had a special case when an INDIRECT_REF wrapped a CALL_EXPR. In this case, we also diagnosed maybe_warn_nodiscard. This was a duplication of logic related to converting call expressions to void. Instead, we can generalize a bit, and rather discard the expression that was implicitly dereferenced instead. This patch changes the diagnostic of: void f(struct S* x) { static_cast(*x); } ... from: warning: indirection will not access object of incomplete type 'volatile S' in statement ... to: warning: implicit dereference will not access object of type ‘volatile S’ in statement ... but should have no impact in other cases. gcc/cp/ChangeLog: * coroutines.cc (co_await_get_resume_call): Return a tree directly, rather than a tree pointer. * cp-tree.h (co_await_get_resume_call): Adjust signature accordingly. * cvt.cc (convert_to_void): Do not alter CO_AWAIT_EXPRs when discarding them. Simplify handling implicit INDIRECT_REFs. gcc/testsuite/ChangeLog: * g++.dg/coroutines/nodiscard-1.C: New test. (cherry picked from commit de03ef6337b0a368d61c74b790313b4216c7ed6e) Diff: --- gcc/cp/coroutines.cc | 12 gcc/cp/cp-tree.h | 2 + gcc/cp/cvt.cc | 98 +++ gcc/testsuite/g++.dg/coroutines/nodiscard-1.C | 77 + 4 files changed, 145 insertions(+), 44 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index de160bad1a20..3872e96b7429 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -725,6 +725,18 @@ coro_get_destroy_function (tree decl) return NULL_TREE; } +/* Given a CO_AWAIT_EXPR AWAIT_EXPR, return its resume call. */ + +tree +co_await_get_resume_call (tree await_expr) +{ + gcc_checking_assert (TREE_CODE (await_expr) == CO_AWAIT_EXPR); + tree vec = TREE_OPERAND (await_expr, 3); + if (!vec) +return nullptr; + return TREE_VEC_ELT (vec, 2); +} + /* These functions assumes that the caller has verified that the state for the decl has been initialized, we try to minimize work here. */ diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 19e7b2edede3..1d10c27c676c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -8767,6 +8767,8 @@ extern tree coro_get_actor_function (tree); extern tree coro_get_destroy_function (tree); extern tree coro_get_ramp_function (tree); +extern tree co_await_get_resume_call (tree await_expr); + /* contracts.cc */ extern tree make_postcondition_variable(cp_expr); extern tree make_postcondition_variable(cp_expr, tree); diff --git a/gcc/cp/cvt.cc b/gcc/cp/cvt.cc index b046010e7ff8..dac210d12479 100644 --- a/gcc/cp/cvt.cc +++ b/gcc/cp/cvt.cc @@ -1285,88 +1285,96 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain) complete_type (type); int is_complete = COMPLETE_TYPE_P (type); - /* Can't load the value if we don't know the type. */ - if (is_volatile && !is_complete) + /* Don't load the value if this is an implicit dereference, or if + the type needs to be handled by ctors/dtors. */ + if (is_reference) { -if (complain & tf_warning) +if (is_volatile && (complain & tf_warning) + /* A co_await expression, in its await_resume expression, also + contains an implicit dereference. As a result, we don't + need to warn about them here. */ + && TREE_CODE (TREE_OPERAND (expr, 0)) != CO_AWAIT_EXPR) switch (implicit) { case ICV_CAST: warning_at (loc, 0, "conversion to void will not access " - "object of incomplete type %qT", type); + "object of type %qT", type); break; case ICV_SECOND_OF_COND: - warning_at
[gcc r14-11739] c++: fix conversion issues
https://gcc.gnu.org/g:b6094031eea96c116a386e7112ee79a6bde5207e commit r14-11739-gb6094031eea96c116a386e7112ee79a6bde5207e Author: Jason Merrill Date: Mon Dec 23 19:57:56 2024 -0500 c++: fix conversion issues back-port the coroutine part of this. Some issues caught by a check from another patch: In build_ramp_function, we're assigning REFERENCE_TYPE things, so we need to build the assignment directly rather than rely on functions that implement C++ semantics. gcc/cp/ChangeLog: * coroutines.cc (cp_coroutine_transform::build_ramp_function): Build INIT_EXPR directly. (cherry picked from commit dd3f3c71df66ed6fd3872ab780f5813831100d1c) Diff: --- gcc/cp/coroutines.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 77067be45ad4..09e2f3410627 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -5093,8 +5093,8 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) if (parm.rv_ref || parm.pt_ref) /* Initialise the frame reference field directly. */ - r = cp_build_modify_expr (fn_start, TREE_OPERAND (fld_idx, 0), - INIT_EXPR, arg, tf_warning_or_error); + r = build2 (INIT_EXPR, TREE_TYPE (arg), + TREE_OPERAND (fld_idx, 0), arg); else { r = forward_parm (arg);
[gcc r16-394] [RISC-V][PR target/119971] Avoid losing shift count masking
https://gcc.gnu.org/g:05d75c5bfcf923bc0258b79a08c5861590c5a2b9 commit r16-394-g05d75c5bfcf923bc0258b79a08c5861590c5a2b9 Author: Jeff Law Date: Mon May 5 17:14:29 2025 -0600 [RISC-V][PR target/119971] Avoid losing shift count masking As is outlined in the PR, we have a few define_insn_and_split patterns which optimize away explicit masking of shift/bit positions when the masking matches what the hardware's behavior. A small number of those define_insn_and_split patterns generate a single instruction. It's fairly elegant in that we were essentially just rewriting the RTL to match an existing pattern. In one case we'd do the rewriting and later turn a 32bit shift into a bset. That's not safe because the masking of a 32bit shift uses 0x1f while masking on bset uses 0x3f on rv64. The net was incorrect code as seen in the BZ entry. The fix is pretty simple. There's no real reason we need to use a define_insn_and_split. It was just convenient. Instead we can use a simple define_insn. That avoids a change in the masking behavior for the shift count/bit position and the masking stays in the RTL. I quickly scanned the entire port and didn't see any additional define_insn_and_splits that obviously generated a single instruction outside the shift/rotate space, though in the vector space that's nontrivial to ascertain. This was been run through my tester for the cross configurations, but not the native bootstrap/regression test (yet). PR target/119971 gcc/ * config/riscv/bitmanip.md (rotation with masked count): Rewrite as define_insn patterns. Fix formatting. * config/riscv/riscv.md (shift with masked count): Similarly. gcc/testsuite * gcc.target/riscv/pr119971.c: New test. * gcc.target/riscv/zbb-rol-ror-03.c: Adjust test slightly. Diff: --- gcc/config/riscv/bitmanip.md| 59 + gcc/config/riscv/riscv.md | 19 ++-- gcc/testsuite/gcc.target/riscv/pr119971.c | 24 ++ gcc/testsuite/gcc.target/riscv/zbb-rol-ror-03.c | 2 +- 4 files changed, 59 insertions(+), 45 deletions(-) diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md index d0919ece31f7..20d03dc8792d 100644 --- a/gcc/config/riscv/bitmanip.md +++ b/gcc/config/riscv/bitmanip.md @@ -423,39 +423,40 @@ "rolw\t%0,%1,%2" [(set_attr "type" "bitmanip")]) -(define_insn_and_split "*3_mask" - [(set (match_operand:GPR 0 "register_operand" "= r") -(bitmanip_rotate:GPR -(match_operand:GPR 1 "register_operand" " r") -(match_operator 4 "subreg_lowpart_operator" - [(and:GPR2 - (match_operand:GPR2 2 "register_operand" "r") - (match_operand 3 "" ""))])))] +(define_insn "*3_mask" + [(set (match_operand:X 0 "register_operand" "=r") + (bitmanip_rotate:X + (match_operand:X 1 "register_operand" "r") + (match_operator 4 "subreg_lowpart_operator" + [(and:X (match_operand:X 2 "register_operand" "r") + (match_operand 3 "" ""))])))] "TARGET_ZBB || TARGET_ZBKB" - "#" - "&& 1" - [(set (match_dup 0) -(bitmanip_rotate:GPR (match_dup 1) - (match_dup 2)))] - "operands[2] = gen_lowpart (QImode, operands[2]);" + "\t%0,%1,%2" [(set_attr "type" "bitmanip") - (set_attr "mode" "")]) + (set_attr "mode" "")]) -(define_insn_and_split "*si3_sext_mask" - [(set (match_operand:DI 0 "register_operand" "= r") - (sign_extend:DI (bitmanip_rotate:SI -(match_operand:SI 1 "register_operand" " r") -(match_operator 4 "subreg_lowpart_operator" - [(and:GPR - (match_operand:GPR 2 "register_operand" "r") - (match_operand 3 "const_si_mask_operand"))]] +(define_insn "*3_mask_si" + [(set (match_operand:SI 0 "register_operand" "=r") + (bitmanip_rotate:SI + (match_operand:SI 1 "register_operand" "r") + (match_operator 3 "subreg_lowpart_operator" + [(and:X (match_operand:SI 2 "register_operand" "r") + (const_int 31))])))] "TARGET_64BIT && (TARGET_ZBB || TARGET_ZBKB)" - "#" - "&& 1" - [(set (match_dup 0) - (sign_extend:DI (bitmanip_rotate:SI (match_dup 1) - (match_dup 2] - "operands[2] = gen_lowpart (QImode, operands[2]);" + "w\t%0,%1,%2" + [(set_attr "type" "bitmanip") + (set_attr "mode" "SI")]) + +(define_insn "*si3_sext_mask" + [(set (match_operand:DI 0 "register_operand" "=r") + (sign_extend:DI + (bitmanip_rotate:SI + (match_operand:SI 1 "register_operand" "r") + (match_operator 3 "subreg_lowpart_operator" + [(and:X (match_operand:GPR 2 "register_operand" "r") + (const_int 31))]] + "T
[gcc r14-11733] c++, coroutines: Fix handling of bool await_suspend() [PR115905].
https://gcc.gnu.org/g:eb600ecb6af628e492fb86dee50cda049ac708e3 commit r14-11733-geb600ecb6af628e492fb86dee50cda049ac708e3 Author: Iain Sandoe Date: Fri Sep 6 20:59:43 2024 +0100 c++, coroutines: Fix handling of bool await_suspend() [PR115905]. As noted in the PR the action of the existing implementation was to treat a false value from await_suspend () as equivalent to "do not suspend". Actually it needs to be the equivalent of "resume" - and we need to restart the dispatcher - since the await_suspend() body could have already resumed the coroutine. See also https://github.com/cplusplus/CWG/issues/601 (NAD) for more discussion. Since we need to amend the await expansion and the actor build, take the opportunity to clean up and modernise the code there. Note that we need to make the jump back to the dispatcher without any scope exit cleanups (so we have to use the .CO_SUSPN IFN to do this). PR c++/115905 gcc/cp/ChangeLog: * coroutines.cc (struct coro_aw_data): Add a member for the restart dispatch label. (expand_one_await_expression): Rework to modernise and to handle the boolean await_suspend() case. (build_actor_fn): Rework the dispatcher and allow for a jump back to the dispatcher. gcc/testsuite/ChangeLog: * g++.dg/coroutines/torture/pr115905.C: New test. Signed-off-by: Iain Sandoe (cherry picked from commit 368ba7aed46d57d093c0180baae4dc0e0ba468b6) Diff: --- gcc/cp/coroutines.cc | 219 +++-- gcc/testsuite/g++.dg/coroutines/torture/pr115905.C | 64 ++ 2 files changed, 176 insertions(+), 107 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 8bb46ff5c990..4b13f904ff0e 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1791,6 +1791,7 @@ struct coro_aw_data tree cleanup;/* This is where to go once we complete local destroy. */ tree cororet;/* This is where to go if we suspend. */ tree corocont; /* This is where to go if we continue. */ + tree dispatch; /* This is where we go if we restart the dispatch. */ tree conthand; /* This is the handle for a continuation. */ unsigned index; /* This is our current resume index. */ }; @@ -1835,42 +1836,44 @@ co_await_find_in_subtree (tree *stmt, int *, void *d) in either. */ static tree * -expand_one_await_expression (tree *stmt, tree *await_expr, void *d) +expand_one_await_expression (tree *expr, tree *await_expr, void *d) { coro_aw_data *data = (coro_aw_data *) d; - tree saved_statement = *stmt; + tree saved_statement = *expr; tree saved_co_await = *await_expr; tree actor = data->actor_fn; - location_t loc = EXPR_LOCATION (*stmt); + location_t loc = EXPR_LOCATION (*expr); tree var = TREE_OPERAND (saved_co_await, 1); /* frame slot. */ - tree expr = TREE_OPERAND (saved_co_await, 2); /* initializer. */ + tree init_expr = TREE_OPERAND (saved_co_await, 2); /* initializer. */ tree awaiter_calls = TREE_OPERAND (saved_co_await, 3); tree source = TREE_OPERAND (saved_co_await, 4); bool is_final = (source && TREE_INT_CST_LOW (source) == (int) FINAL_SUSPEND_POINT); - bool needs_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var)); + + /* Build labels for the destinations of the control flow when we are resuming + or destroying. */ int resume_point = data->index; - size_t bufsize = sizeof ("destroy.") + 10; - char *buf = (char *) alloca (bufsize); - snprintf (buf, bufsize, "destroy.%d", resume_point); + char *buf = xasprintf ("destroy.%d", resume_point); tree destroy_label = create_named_label_with_ctx (loc, buf, actor); - snprintf (buf, bufsize, "resume.%d", resume_point); + free (buf); + buf = xasprintf ("resume.%d", resume_point); tree resume_label = create_named_label_with_ctx (loc, buf, actor); - tree empty_list = build_empty_stmt (loc); + free (buf); - tree stmt_list = NULL; - tree r; + /* This will contain our expanded expression and replace the original + expression. */ + tree stmt_list = push_stmt_list (); tree *await_init = NULL; - if (!expr) + bool needs_dtor = TYPE_HAS_NONTRIVIAL_DESTRUCTOR (TREE_TYPE (var)); + if (!init_expr) needs_dtor = false; /* No need, the var's lifetime is managed elsewhere. */ else { - r = coro_build_cvt_void_expr_stmt (expr, loc); - append_to_statement_list_force (r, &stmt_list); + finish_expr_stmt (init_expr); /* We have an initializer, which might itself contain await exprs. */ await_init = tsi_stmt_ptr (tsi_last (stmt_list)); } @@ -1881,18 +1884,15 @@ expand_one_await_expression (tree *stmt, tree *await_expr, void *d) if (TREE_CODE (TREE_TYPE (ready_cond)) != BOOLEAN_TYPE) ready_cond = cp_convert (boolean_type_node, ready_cond,
[gcc r16-396] libphobos: enable for sparc64-unknown-linux-gnu
https://gcc.gnu.org/g:2572d46f0d1e426c1091f9b84861ee5213b84b5a commit r16-396-g2572d46f0d1e426c1091f9b84861ee5213b84b5a Author: Sam James Date: Sun Apr 20 01:43:39 2025 +0100 libphobos: enable for sparc64-unknown-linux-gnu This bootstraps with some test failures but works well enough to build 11..15. libphobos/ChangeLog: * configure.tgt: Add sparc64-unknown-linux-gnu as a supported target. Diff: --- libphobos/configure.tgt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libphobos/configure.tgt b/libphobos/configure.tgt index b32300b52a18..76c09c4640dd 100644 --- a/libphobos/configure.tgt +++ b/libphobos/configure.tgt @@ -58,7 +58,7 @@ case "${target}" in s390*-linux*) LIBPHOBOS_SUPPORTED=yes ;; - sparc*-*-solaris2.11*) + sparc64-*-linux* | sparc*-*-solaris2.11*) LIBPHOBOS_SUPPORTED=yes ;; *-*-darwin9* | *-*-darwin1[01]*)
[gcc r14-11734] c++, coroutines: Revise promise construction/destruction.
https://gcc.gnu.org/g:5dbf5f9f4f83b0048e7c3af8fbaefb503d56928e commit r14-11734-g5dbf5f9f4f83b0048e7c3af8fbaefb503d56928e Author: Iain Sandoe Date: Sat Aug 31 13:08:42 2024 +0100 c++, coroutines: Revise promise construction/destruction. In examining the coroutine testcases for unexpected diagnostic output for 'Wall', I found a 'statement has no effect' warning for the promise construction in one case. In particular, the case is where the users promise type has an implicit CTOR but a user-provided DTOR. Further, the type does not actually need constructing. In very early versions of the coroutines code we used to check TYPE_NEEDS_CONSTRUCTING() to determine whether to attempt to build a constructor call for the promise. During review, it was suggested to use type_build_ctor_call () instead. This latter call checks the constructors in the type (both user-defined and implicit) and returns true, amongst other cases if any of the found CTORs are marked as deprecated. In a number of places (for example [class.copy.ctor] / 6) the standard says that some version of an implicit CTOR is deprecated when the user provides a DTOR. Thus, for this specific arrangement of promise type, type_build_ctor_call returns true, because of (for example) a deprecated implicit copy CTOR. We are not going to use any of the deprecated CTORs and thus will not see warnings from this - however, since the call returned true, we have now determined that we should attempt to build a constructor call. Note as above, the type does not actually require construction and thus one might expect either a NULL_TREE or error_mark_node in response to the build_special_member_call (). However, in practice the function returns the original instance object instead of a call or some error. When we add that as a statement it triggers the 'statement has no effect' warning. The patch here rearranges the promise construction/destruction code to allow for the case that a DTOR is required independently of a CTOR. In addition, we check that the return from build_special_member_call () has side effects before we add it as a statement. gcc/cp/ChangeLog: * coroutines.cc (cp_coroutine_transform::build_ramp_function): Separate the build of promise constructor and destructor. When evaluating the constructor, check that build_special_member_call returns an expression with side effects before adding it. Signed-off-by: Iain Sandoe (cherry picked from commit 7d1483921941d21d91f929ef0d59a9794b1946b4) Diff: --- gcc/cp/coroutines.cc | 31 +-- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 4b13f904ff0e..e0e312265c10 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -5108,16 +5108,12 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) tree p = build_class_member_access_expr (deref_fp, promise_m, NULL_TREE, false, tf_warning_or_error); - tree promise_dtor = NULL_TREE; if (type_build_ctor_call (promise_type)) { - /* Do a placement new constructor for the promise type (we never call -the new operator, just the constructor on the object in place in the -frame). + /* Construct the promise object [dcl.fct.def.coroutine] / 5.7. -First try to find a constructor with the same parameter list as the -original function (if it has params), failing that find a constructor -with no parameter list. */ +First try to find a constructor with an argument list comprised of +the parameter copies. */ if (DECL_ARGUMENTS (orig)) { @@ -5129,20 +5125,27 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) else r = NULL_TREE; + /* If that fails then the promise constructor argument list is empty. */ if (r == NULL_TREE || r == error_mark_node) r = build_special_member_call (p, complete_ctor_identifier, NULL, promise_type, LOOKUP_NORMAL, tf_warning_or_error); - r = coro_build_cvt_void_expr_stmt (r, fn_start); - finish_expr_stmt (r); + /* If type_build_ctor_call() encounters deprecated implicit CTORs it will +return true, and therefore we will execute this code path. However, +we might well not actually require a CTOR and under those conditions +the build call above will not return a call expression, but the +original instance object. Do not attempt to add the statement unless +it has side-effects. */ + if (r && r != error_mark_node && TREE_SIDE_EFFECTS (r)) + finish_expr_stmt (r); +}
[gcc r14-11737] c++/coro: ignore cleanup_point_exprs while expanding awaits [PR116793]
https://gcc.gnu.org/g:b4000f922425f7763bdab7bb8822975c0a669097 commit r14-11737-gb4000f922425f7763bdab7bb8822975c0a669097 Author: Arsen Arsenović Date: Tue Sep 24 18:16:01 2024 +0200 c++/coro: ignore cleanup_point_exprs while expanding awaits [PR116793] If we reach a CLEANUP_POINT_EXPR while trying to walk statements, we actually care about the statement or statement list contained within it. Indeed, such a construction started happening with r15-3513-g964577c31df206, after temporary promotion. In the test case presented in PR116793, the compiler generated:T002_2_3]; int T002 [value-expr: frame_ptr->T002_2_3]; <) >; struct _cleanup_task Aw0 [value-expr: frame_ptr->Aw0_2_3]; <) >; < Aw0 {_cleanup_task::await_ready (&Aw0), _cleanup_task::await_suspend<_task1::promise_type> (&Aw0, TARGET_EXPR ), <<< Unknown tree: aggr_init_expr 4 await_resume D.22443 &Aw0 >>>} 0 >>>) >; <; } D.22467 = 1; int & i [value-expr: frame_ptr->i_1_2]; < (NON_LVALUE_EXPR )) >;>>; ... i.e. a statement list within a cleanup point. In such a case, we don't actually care about the cleanup point, but we do care about the statement inside, so, we can just walk down into the CLEANUP_POINT_EXPR. PR c++/116793 gcc/cp/ChangeLog: * coroutines.cc (await_statement_expander): Just process subtrees if encountering a CLEANUP_POINT_EXPR. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr116793-1.C: New test. (cherry picked from commit d888a8a8dcf391197ae82e2bbf99507effc27950) Diff: --- gcc/cp/coroutines.cc | 4 +++- gcc/testsuite/g++.dg/coroutines/pr116793-1.C | 26 ++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 3872e96b7429..5cacfb0db82d 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -2045,7 +2045,9 @@ await_statement_expander (tree *stmt, int *do_subtree, void *d) tree res = NULL_TREE; /* Process a statement at a time. */ - if (STATEMENT_CLASS_P (*stmt) || TREE_CODE (*stmt) == BIND_EXPR) + if (STATEMENT_CLASS_P (*stmt) + || TREE_CODE (*stmt) == BIND_EXPR + || TREE_CODE (*stmt) == CLEANUP_POINT_EXPR) return NULL_TREE; /* Just process the sub-trees. */ else if (TREE_CODE (*stmt) == STATEMENT_LIST) { diff --git a/gcc/testsuite/g++.dg/coroutines/pr116793-1.C b/gcc/testsuite/g++.dg/coroutines/pr116793-1.C new file mode 100644 index ..ed2bdd26996a --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr116793-1.C @@ -0,0 +1,26 @@ +// https://gcc.gnu.org/PR116793 +#include +#include +struct _cleanup_task { + bool await_ready() const noexcept; + template + bool await_suspend(std::coroutine_handle parent) noexcept; + std::tuple await_resume() noexcept; +}; +struct _task1 { + struct promise_type final { +std::suspend_always initial_suspend() noexcept; +_task1 get_return_object() noexcept; +void unhandled_exception() noexcept; +struct awaiter final { + bool await_ready() noexcept; + void await_resume() noexcept; + void await_suspend(std::coroutine_handle h) noexcept; +}; +awaiter final_suspend() noexcept; + }; +}; +_cleanup_task func(int &&); +_task1 g() { + auto &&[i] = co_await func(3); +}
[gcc r14-11738] c++, coroutines:Ensure bind exprs are visited once [PR98935].
https://gcc.gnu.org/g:bcd0d98c9f8f45c496bc2d0d0b6bda4fefcf9a6a commit r14-11738-gbcd0d98c9f8f45c496bc2d0d0b6bda4fefcf9a6a Author: Iain Sandoe Date: Fri Nov 1 23:30:58 2024 + c++, coroutines:Ensure bind exprs are visited once [PR98935]. Recent changes in the C++ FE and the coroutines implementation have exposed a latent issue in which a bind expression containing a var that we need to capture in the coroutine state gets visited twice. This causes an ICE (from a checking assert). Fixed by adding a pset to the relevant tree walk. Exit the callback early when the tree is not a BIND_EXPR. PR c++/98935 gcc/cp/ChangeLog: * coroutines.cc (register_local_var_uses): Add a pset to the tree walk to avoid visiting the same BIND_EXPR twice. Make an early exit for cases that the callback does not apply. (cp_coroutine_transform::apply_transforms): Add a pset to the tree walk for register_local_vars. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr98935.C: New test. Signed-off-by: Iain Sandoe (cherry picked from commit bd8c7e71f516bae29a5a9e517b266141458f3977) Diff: --- gcc/cp/coroutines.cc | 158 +++--- gcc/testsuite/g++.dg/coroutines/pr98935.C | 27 + 2 files changed, 107 insertions(+), 78 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 5cacfb0db82d..77067be45ad4 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4135,6 +4135,9 @@ struct local_vars_frame_data static tree register_local_var_uses (tree *stmt, int *do_subtree, void *d) { + if (TREE_CODE (*stmt) != BIND_EXPR) +return NULL_TREE; + local_vars_frame_data *lvd = (local_vars_frame_data *) d; /* As we enter a bind expression - record the vars there and then recurse. @@ -4142,88 +4145,86 @@ register_local_var_uses (tree *stmt, int *do_subtree, void *d) The bind index is a growing count of how many bind indices we've seen. We build a space in the frame for each local var. */ - if (TREE_CODE (*stmt) == BIND_EXPR) + tree lvar; + unsigned serial = 0; + for (lvar = BIND_EXPR_VARS (*stmt); lvar != NULL; lvar = DECL_CHAIN (lvar)) { - tree lvar; - unsigned serial = 0; - for (lvar = BIND_EXPR_VARS (*stmt); lvar != NULL; - lvar = DECL_CHAIN (lvar)) - { - bool existed; - local_var_info &local_var - = lvd->local_var_uses->get_or_insert (lvar, &existed); - gcc_checking_assert (!existed); - local_var.def_loc = DECL_SOURCE_LOCATION (lvar); - tree lvtype = TREE_TYPE (lvar); - local_var.frame_type = lvtype; - local_var.field_idx = local_var.field_id = NULL_TREE; - - /* Make sure that we only present vars to the tests below. */ - if (TREE_CODE (lvar) != PARM_DECL - && TREE_CODE (lvar) != VAR_DECL) - continue; - - /* We don't move static vars into the frame. */ - local_var.is_static = TREE_STATIC (lvar); - if (local_var.is_static) - continue; - - poly_uint64 size; - if (TREE_CODE (lvtype) == ARRAY_TYPE - && !poly_int_tree_p (DECL_SIZE_UNIT (lvar), &size)) - { - sorry_at (local_var.def_loc, "variable length arrays are not" - " yet supported in coroutines"); - /* Ignore it, this is broken anyway. */ - continue; - } + bool existed; + local_var_info &local_var + = lvd->local_var_uses->get_or_insert (lvar, &existed); + gcc_checking_assert (!existed); + local_var.def_loc = DECL_SOURCE_LOCATION (lvar); + tree lvtype = TREE_TYPE (lvar); + local_var.frame_type = lvtype; + local_var.field_idx = local_var.field_id = NULL_TREE; + + /* Make sure that we only present vars to the tests below. */ + if (TREE_CODE (lvar) != PARM_DECL + && TREE_CODE (lvar) != VAR_DECL) + continue; - lvd->local_var_seen = true; - /* If this var is a lambda capture proxy, we want to leave it alone, -and later rewrite the DECL_VALUE_EXPR to indirect through the -frame copy of the pointer to the lambda closure object. */ - local_var.is_lambda_capture = is_capture_proxy (lvar); - if (local_var.is_lambda_capture) - continue; - - /* If a variable has a value expression, then that's what needs -to be processed. */ - local_var.has_value_expr_p = DECL_HAS_VALUE_EXPR_P (lvar); - if (local_var.has_value_expr_p) - continue; - - /* Make names depth+index unique, so that we can support nested -scopes with identically named locals and still be able to -identify them in the coroutine frame. */ - tree lvname = DECL_NAME (lvar); - char
[gcc r14-11740] c++/coroutines: Fix awaiter var creation [PR116506]
https://gcc.gnu.org/g:b69209936680dabbb7bbe08e71646a2c25ece0bf commit r14-11740-gb69209936680dabbb7bbe08e71646a2c25ece0bf Author: Iain Sandoe Date: Thu Oct 31 08:40:08 2024 + c++/coroutines: Fix awaiter var creation [PR116506] Awaiters always need to have a coroutine state frame copy since they persist across potential supensions. It simplifies the later analysis considerably to assign these early which we do when building co_await expressions. The cleanups in r15-3146-g47dbd69b1, unfortunately elided some of processing used to cater for cases where the var created from an xvalue, or is a pointer/reference type. Corrected thus. PR c++/116506 PR c++/116880 gcc/cp/ChangeLog: * coroutines.cc (build_co_await): Ensure that xvalues are materialised. Handle references/pointer values in awaiter access expressions. (is_stable_lvalue): New. * decl.cc (cxx_maybe_build_cleanup): Handle null arg. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr116506.C: New test. * g++.dg/coroutines/pr116880.C: New test. Signed-off-by: Iain Sandoe Co-authored-by: Jason Merrill (cherry picked from commit 4c743798b1d4530b327dad7c606c610f3811fdbf) Diff: --- gcc/cp/coroutines.cc | 106 +++-- gcc/cp/decl.cc | 2 +- gcc/testsuite/g++.dg/coroutines/pr116506.C | 53 +++ gcc/testsuite/g++.dg/coroutines/pr116880.C | 36 ++ 4 files changed, 144 insertions(+), 53 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 09e2f3410627..8811d249c025 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -1066,6 +1066,28 @@ build_template_co_await_expr (location_t kw, tree type, tree expr, tree kind) return aw_expr; } +/* Is EXPR an lvalue that will refer to the same object after a resume? + + This is close to asking tree_invariant_p of its address, but that doesn't + distinguish temporaries from other variables. */ + +static bool +is_stable_lvalue (tree expr) +{ + if (TREE_SIDE_EFFECTS (expr)) +return false; + + for (; handled_component_p (expr); + expr = TREE_OPERAND (expr, 0)) +{ + if (TREE_CODE (expr) == ARRAY_REF + && !TREE_CONSTANT (TREE_OPERAND (expr, 1))) + return false; +} + + return (TREE_CODE (expr) == PARM_DECL + || (VAR_P (expr) && !is_local_temp (expr))); +} /* This performs [expr.await] bullet 3.3 and validates the interface obtained. It is also used to build the initial and final suspend points. @@ -1128,7 +1150,7 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind, if (o_type && !VOID_TYPE_P (o_type)) o_type = complete_type_or_else (o_type, o); - if (!o_type) + if (!o_type || o_type == error_mark_node) return error_mark_node; if (TREE_CODE (o_type) != RECORD_TYPE) @@ -1155,56 +1177,35 @@ build_co_await (location_t loc, tree a, suspend_point_kind suspend_kind, if (!awrs_meth || awrs_meth == error_mark_node) return error_mark_node; - /* To complete the lookups, we need an instance of 'e' which is built from - 'o' according to [expr.await] 3.4. - - If we need to materialize this as a temporary, then that will have to be - 'promoted' to a coroutine frame var. However, if the awaitable is a - user variable, parameter or comes from a scope outside this function, - then we must use it directly - or we will see unnecessary copies. - - If o is a variable, find the underlying var. */ - tree e_proxy = STRIP_NOPS (o); - if (INDIRECT_REF_P (e_proxy)) -e_proxy = TREE_OPERAND (e_proxy, 0); - while (TREE_CODE (e_proxy) == COMPONENT_REF) + /* [expr.await]/3.3 If o would be a prvalue, the temporary + materialization conversion ([conv.rval]) is applied. */ + if (!glvalue_p (o)) +o = get_target_expr (o, tf_warning_or_error); + + /* [expr.await]/3.4 e is an lvalue referring to the result of evaluating the + (possibly-converted) o. + + So, either reuse an existing stable lvalue such as a variable or + COMPONENT_REF thereof, or create a new a coroutine state frame variable + for the awaiter, since it must persist across suspension. */ + tree e_var = NULL_TREE; + tree e_proxy = o; + if (is_stable_lvalue (o)) +o = NULL_TREE; /* Use the existing entity. */ + else /* We need a non-temp var. */ { - e_proxy = TREE_OPERAND (e_proxy, 0); - if (INDIRECT_REF_P (e_proxy)) - e_proxy = TREE_OPERAND (e_proxy, 0); - if (TREE_CODE (e_proxy) == CALL_EXPR) + tree p_type = TREE_TYPE (o); + tree o_a = o; + if (glvalue_p (o)) { - /* We could have operator-> here too. */ - tree op = TREE_OPERAND (CALL_EXPR_FN (e_proxy), 0); - if (DECL_OVERLOADED_OPERATOR_P (op) -
[gcc r16-393] i386: Do not use explicit operands for MOVS instructions [PR120019]
https://gcc.gnu.org/g:c182f4d14d65b3e012ad65b5014d86352fabc86f commit r16-393-gc182f4d14d65b3e012ad65b5014d86352fabc86f Author: Uros Bizjak Date: Mon May 5 13:59:43 2025 +0200 i386: Do not use explicit operands for MOVS instructions [PR120019] Some assemblers do not support MOVS instructions with explicit operands. Emit instruction with implicit operands, but prefix the instruction with a segment override prefix if the memory operand refers to ADDR_SPACE_SEG_FS or ADDR_SPACE_SEG_GS named address space. PR target/120019 gcc/ChangeLog: * config/i386/i386.cc (ix86_print_operand): Handle 'v' operand modifier to emit segment override prefix. * config/i386/i386.md (*strmovdi_rex_1): Use %v operand modifier to emit segment override prefix. (*strmovsi_1): Ditto. (*strmovhi_1): Ditto. (*strmovqi_1): Ditto. (*rep_movdi_rex64): Ditto. (*rep_movsi): Ditto. (*rep_movqi): Ditto. gcc/testsuite/ChangeLog: * gcc.target/i386/pr111657-1.c (dg-do): Change to "assemble". (dg-options): Remove -masm=att and add -save-temps. (dg-final): Update scan-assembler and scan-assembler-not strings. Co-authored-by: Rainer Orth Diff: --- gcc/config/i386/i386.cc| 25 - gcc/config/i386/i386.md| 17 + gcc/testsuite/gcc.target/i386/pr111657-1.c | 8 3 files changed, 37 insertions(+), 13 deletions(-) diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc index 5ad47e194348..df3e3efdfd02 100644 --- a/gcc/config/i386/i386.cc +++ b/gcc/config/i386/i386.cc @@ -13738,10 +13738,11 @@ print_reg (rtx x, int code, FILE *file) H -- print a memory address offset by 8; used for sse high-parts Y -- print condition for XOP pcom* instruction. V -- print naked full integer register name without %. + v -- print segment override prefix + -- print a branch hint as 'cs' or 'ds' prefix ; -- print a semicolon (after prefixes due to bug in older gas). ~ -- print "i" if TARGET_AVX2, "f" otherwise. - ^ -- print addr32 prefix if TARGET_64BIT and Pmode != word_mode + ^ -- print addr32 prefix if Pmode != word_mode M -- print addr32 prefix for TARGET_X32 with VSIB address. ! -- print NOTRACK prefix for jxx/call/ret instructions if required. N -- print maskz if it's constant 0 operand. @@ -14243,6 +14244,28 @@ ix86_print_operand (FILE *file, rtx x, int code) return; + case 'v': + if (MEM_P (x)) + { + switch (MEM_ADDR_SPACE (x)) + { + case ADDR_SPACE_GENERIC: + break; + case ADDR_SPACE_SEG_FS: + fputs ("fs ", file); + break; + case ADDR_SPACE_SEG_GS: + fputs ("gs ", file); + break; + default: + gcc_unreachable (); + } + } + else + output_operand_lossage ("operand is not a memory reference, " + "invalid operand code 'v'"); + return; + case '*': if (ASSEMBLER_DIALECT == ASM_ATT) putc ('*', file); diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md index bb02ab0d4e1c..80b2023c088e 100644 --- a/gcc/config/i386/i386.md +++ b/gcc/config/i386/i386.md @@ -58,10 +58,11 @@ ;; H -- print a memory address offset by 8; used for sse high-parts ;; K -- print HLE lock prefix ;; Y -- print condition for XOP pcom* instruction. +;; v -- print segment override prefix ;; + -- print a branch hint as 'cs' or 'ds' prefix ;; ; -- print a semicolon (after prefixes due to bug in older gas). ;; ~ -- print "i" if TARGET_AVX2, "f" otherwise. -;; ^ -- print addr32 prefix if TARGET_64BIT and Pmode != word_mode +;; ^ -- print addr32 prefix if Pmode != word_mode ;; ! -- print NOTRACK prefix for jxx/call/ret instructions if required. (define_c_enum "unspec" [ @@ -25643,7 +25644,7 @@ operands[0] = SET_DEST (exp); operands[1] = SET_SRC (exp); - return "movsq\t{%1, %0|%0, %1}"; + return "%^%v1movsq"; } [(set_attr "type" "str") (set_attr "memory" "both") @@ -25666,7 +25667,7 @@ operands[0] = SET_DEST (exp); operands[1] = SET_SRC (exp); - return "movs{l|d}\t{%1, %0|%0, %1}"; + return "%^%v1movs{l|d}"; } [(set_attr "type" "str") (set_attr "memory" "both") @@ -25689,7 +25690,7 @@ operands[0] = SET_DEST (exp); operands[1] = SET_SRC (exp); - return "movsw\t{%1, %0|%0, %1}"; + return "%^%v1movsw"; } [(set_attr "type" "str") (set_attr "memory" "both") @@ -25712,7 +25713,7 @@ operands[0] = SET_DEST (exp); operands[1] = SET_SRC (exp); - return "movsb\t{%1, %0|%0, %1}"; + return "%^%v1movsb"; } [(set_attr "type" "str") (set_attr "me
[gcc r14-11725] c++, coroutines: Only allow void get_return_object if the ramp is void [PR100476].
https://gcc.gnu.org/g:98364636c194398d5dccb477e5405cb1d02a55f1 commit r14-11725-g98364636c194398d5dccb477e5405cb1d02a55f1 Author: Iain Sandoe Date: Sat Aug 17 15:47:58 2024 +0100 c++, coroutines: Only allow void get_return_object if the ramp is void [PR100476]. Require that the value returned by get_return_object is convertible to the ramp return. This means that the only time we allow a void get_return_object, is when the ramp is also a void function. We diagnose this early to allow us to exit the ramp build if the return values are incompatible. PR c++/100476 gcc/cp/ChangeLog: * coroutines.cc (cp_coroutine_transform::build_ramp_function): Remove special handling of void get_return_object expressions. gcc/testsuite/ChangeLog: * g++.dg/coroutines/coro-bad-gro-01-void-gro-non-class-coro.C: Adjust expected diagnostic. * g++.dg/coroutines/pr102489.C: Avoid void get_return_object. * g++.dg/coroutines/pr103868.C: Likewise. * g++.dg/coroutines/pr94879-folly-1.C: Likewise. * g++.dg/coroutines/pr94883-folly-2.C: Likewise. * g++.dg/coroutines/pr96749-2.C: Likewise. Signed-off-by: Iain Sandoe (cherry picked from commit a0b431033c307982123abbff752045cfe7eda47f) Diff: --- gcc/cp/coroutines.cc | 49 ++ .../coro-bad-gro-01-void-gro-non-class-coro.C | 4 +- gcc/testsuite/g++.dg/coroutines/pr102489.C | 2 +- gcc/testsuite/g++.dg/coroutines/pr103868.C | 2 +- gcc/testsuite/g++.dg/coroutines/pr94879-folly-1.C | 3 +- gcc/testsuite/g++.dg/coroutines/pr94883-folly-2.C | 39 - gcc/testsuite/g++.dg/coroutines/pr96749-2.C| 2 +- 7 files changed, 50 insertions(+), 51 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 3774e5595a0d..a6cbe07d1a28 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4646,8 +4646,9 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) /* Create the coro frame type, as far as it can be known at this stage. 1. Types we already know. */ - tree fn_return_type = TREE_TYPE (TREE_TYPE (orig)); tree promise_type = get_coroutine_promise_type (orig); + tree fn_return_type = TREE_TYPE (TREE_TYPE (orig)); + bool void_ramp_p = VOID_TYPE_P (fn_return_type); /* 2. Types we need to define or look up. */ @@ -4951,7 +4952,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) tree cond = build1 (CONVERT_EXPR, coro_frame_ptr, nullptr_node); cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond); finish_if_stmt_cond (cond, if_stmt); - if (VOID_TYPE_P (fn_return_type)) + if (void_ramp_p) { /* Execute the get-return-object-on-alloc-fail call... */ finish_expr_stmt (grooaf); @@ -5157,7 +5158,7 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) coro_get_return_object_identifier, fn_start, NULL, /*musthave=*/true); /* Without a return object we haven't got much clue what's going on. */ - if (get_ro == error_mark_node) + if (!get_ro || get_ro == error_mark_node) { BIND_EXPR_BODY (ramp_bind) = pop_stmt_list (ramp_body); DECL_SAVED_TREE (orig) = newbody; @@ -5165,10 +5166,20 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) suppress_warning (orig, OPT_Wreturn_type); return false; } + + /* Check for a bad get return object type. + [dcl.fct.def.coroutine] / 7 requires: + The expression promise.get_return_object() is used to initialize the + returned reference or prvalue result object ... */ + tree gro_type = TREE_TYPE (get_ro); + if (VOID_TYPE_P (gro_type) && !void_ramp_p) +{ + error_at (fn_start, "no viable conversion from % provided by" + " % to return type %qT", fn_return_type); + return false; +} tree gro_context_body = push_stmt_list (); - tree gro_type = TREE_TYPE (get_ro); - bool gro_is_void_p = VOID_TYPE_P (gro_type); tree gro = NULL_TREE; tree gro_bind_vars = NULL_TREE; @@ -5177,8 +5188,11 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) tree gro_cleanup_stmt = NULL_TREE; /* We have to sequence the call to get_return_object before initial suspend. */ - if (gro_is_void_p) -r = get_ro; + if (void_ramp_p) +{ + gcc_checking_assert (VOID_TYPE_P (gro_type)); + r = get_ro; +} else if (same_type_p (gro_type, fn_return_type)) { /* [dcl.fct.def.coroutine] / 7 @@ -5264,28 +5278,11 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) for an object of the return type. */ if (same_type_p (gro_type, fn_return_type)) -r = gro_is_void_p ? NULL_TREE : DECL_RESULT (orig); - e
[gcc r14-11731] c++: don't remove labels during coro-early-expand-ifns [PR105104]
https://gcc.gnu.org/g:5a275b5bebdf7746af590fa57378cd48cb8e679a commit r14-11731-g5a275b5bebdf7746af590fa57378cd48cb8e679a Author: Arsen Arsenović Date: Fri Aug 16 19:07:01 2024 +0200 c++: don't remove labels during coro-early-expand-ifns [PR105104] In some scenarios, it is possible for the CFG cleanup to cause one of the labels mentioned in CO_YIELD, which coro-early-expand-ifns intends to remove, to become part of some statement. As a result, when that label is removed, the statement it became part of becomes invalid, crashing the compiler. There doesn't appear to be a reason to remove the labels (anymore, at least), so let's not do that. PR c++/105104 gcc/ChangeLog: * coroutine-passes.cc (execute_early_expand_coro_ifns): Don't remove any labels. gcc/testsuite/ChangeLog: * g++.dg/coroutines/torture/pr105104.C: New test. (cherry picked from commit d9c54e9a036189e8961ec17e118fccf794d7bfab) Diff: --- gcc/coroutine-passes.cc| 26 -- gcc/testsuite/g++.dg/coroutines/torture/pr105104.C | 40 ++ 2 files changed, 40 insertions(+), 26 deletions(-) diff --git a/gcc/coroutine-passes.cc b/gcc/coroutine-passes.cc index c0d6eca7c070..b962d7598c43 100644 --- a/gcc/coroutine-passes.cc +++ b/gcc/coroutine-passes.cc @@ -293,9 +293,6 @@ execute_early_expand_coro_ifns (void) /* Some of the possible YIELD points will hopefully have been removed by earlier optimisations; record the ones that are still present. */ hash_map, tree> destinations; - /* Labels we added to carry the CFG changes, we need to remove these to - avoid confusing EH. */ - hash_set to_remove; /* List of dispatch points to update. */ auto_vec actor_worklist; basic_block bb; @@ -374,8 +371,6 @@ execute_early_expand_coro_ifns (void) } else dst_dest = dst_tgt; - to_remove.add (res_tgt); - to_remove.add (dst_tgt); /* lose the co_yield. */ gsi_remove (&gsi, true); stmt = gsi_stmt (gsi); /* next. */ @@ -463,27 +458,6 @@ execute_early_expand_coro_ifns (void) } } - /* Remove the labels we inserted to map our hidden CFG, this - avoids confusing block merges when there are also EH labels. */ - FOR_EACH_BB_FN (bb, cfun) -for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);) - { - gimple *stmt = gsi_stmt (gsi); - if (glabel *glab = dyn_cast (stmt)) - { - tree rem = gimple_label_label (glab); - if (to_remove.contains (rem)) - { - gsi_remove (&gsi, true); - to_remove.remove (rem); - continue; /* We already moved to the next insn. */ - } - } - else - break; - gsi_next (&gsi); - } - /* Changed the CFG. */ todoflags |= TODO_cleanup_cfg; return todoflags; diff --git a/gcc/testsuite/g++.dg/coroutines/torture/pr105104.C b/gcc/testsuite/g++.dg/coroutines/torture/pr105104.C new file mode 100644 index ..fcc783e3066d --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/torture/pr105104.C @@ -0,0 +1,40 @@ +// https://gcc.gnu.org/PR105104 +// { dg-additional-options "-O" } + +#include + +// ICE during GIMPLE pass: coro-early-expand-ifs. final_awaiter::await_resume is +// non-void, and optimizations are enabled. + +struct return_object +{ + struct promise_type + { +static constexpr std::suspend_always initial_suspend () noexcept +{ + return {}; +} + +struct final_awaiter +{ + static constexpr bool await_ready () noexcept { return false; } + static constexpr void await_suspend (std::coroutine_handle<>) noexcept {} + static constexpr int await_resume () noexcept { return {}; } +}; +static constexpr final_awaiter final_suspend () noexcept { return {}; } + +static void unhandled_exception () { throw; } + +return_object get_return_object () { return {}; } + +static constexpr void return_void () noexcept {} + }; +}; + +return_object +coroutine () +{ + co_return; +} + +return_object f = coroutine ();
[gcc r14-11732] coros: mark .CO_YIELD as LEAF [PR106973]
https://gcc.gnu.org/g:74cfbedd24cfc4bb26b33bdb0b7c55a9139cd757 commit r14-11732-g74cfbedd24cfc4bb26b33bdb0b7c55a9139cd757 Author: Arsen Arsenović Date: Tue Sep 3 17:14:13 2024 +0200 coros: mark .CO_YIELD as LEAF [PR106973] We rely on .CO_YIELD calls being followed by an assignment (optionally) and then a switch/if in the same basic block. This implies that a .CO_YIELD can never end a block. However, since a call to .CO_YIELD is still a call, if the function containing it calls setjmp, GCC thinks that the .CO_YIELD can introduce abnormal control flow, and generates an edge for the call. We know this is not the case; .CO_YIELD calls get removed quite early on and have no effect, and result in no other calls, so .CO_YIELD can be considered a leaf function, preventing generating an edge when calling it. PR c++/106973 - coroutine generator and setjmp PR c++/106973 gcc/ChangeLog: * internal-fn.def (CO_YIELD): Mark as ECF_LEAF. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr106973.C: New test. (cherry picked from commit 7b7ad3f4b2455072f42e7884b93fd96ebb920bc8) Diff: --- gcc/internal-fn.def| 2 +- gcc/testsuite/g++.dg/coroutines/pr106973.C | 22 ++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 848bb9dbff3f..02e5d17d5dd4 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -559,7 +559,7 @@ DEF_INTERNAL_FN (DIVMOD, ECF_CONST | ECF_LEAF, NULL) /* For coroutines. */ DEF_INTERNAL_FN (CO_ACTOR, ECF_NOTHROW | ECF_LEAF, NULL) -DEF_INTERNAL_FN (CO_YIELD, ECF_NOTHROW, NULL) +DEF_INTERNAL_FN (CO_YIELD, ECF_NOTHROW | ECF_LEAF, NULL) DEF_INTERNAL_FN (CO_SUSPN, ECF_NOTHROW, NULL) DEF_INTERNAL_FN (CO_FRAME, ECF_PURE | ECF_NOTHROW | ECF_LEAF, NULL) diff --git a/gcc/testsuite/g++.dg/coroutines/pr106973.C b/gcc/testsuite/g++.dg/coroutines/pr106973.C new file mode 100644 index ..6db6cbc7711a --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr106973.C @@ -0,0 +1,22 @@ +// https://gcc.gnu.org/PR106973 +// { dg-require-effective-target indirect_jumps } +#include +#include + +struct generator; +struct generator_promise { + generator get_return_object(); + std::suspend_always initial_suspend(); + std::suspend_always final_suspend() noexcept; + std::suspend_always yield_value(int); + void unhandled_exception(); +}; + +struct generator { + using promise_type = generator_promise; +}; +jmp_buf foo_env; +generator foo() { + setjmp(foo_env); + co_yield 1; +}
[gcc r16-390] RISC-V: Fix gcc.target/riscv/predef-19.c [PR120054]
https://gcc.gnu.org/g:fcc74146e3e0bfd30f9ccc12359991d73fe928f9 commit r16-390-gfcc74146e3e0bfd30f9ccc12359991d73fe928f9 Author: Kito Cheng Date: Mon May 5 10:08:22 2025 +0800 RISC-V: Fix gcc.target/riscv/predef-19.c [PR120054] gcc/testsuite/ChangeLog: PR target/120054 * gcc.target/riscv/predef-19.c: Adjust testcase. Diff: --- gcc/testsuite/gcc.target/riscv/predef-19.c | 4 1 file changed, 4 deletions(-) diff --git a/gcc/testsuite/gcc.target/riscv/predef-19.c b/gcc/testsuite/gcc.target/riscv/predef-19.c index ca3d57abca90..f2b4d9b30486 100644 --- a/gcc/testsuite/gcc.target/riscv/predef-19.c +++ b/gcc/testsuite/gcc.target/riscv/predef-19.c @@ -27,10 +27,6 @@ int main () { #error "__riscv_zicsr" #endif -#if !defined(_riscv_zmmul) -#error "__riscv_zmmul" -#endif - #if !defined(__riscv_zve32x) #error "__riscv_zve32x" #endif
[gcc(refs/users/mikael/heads/refactor_descriptor_v05)] Correction régression pr77973
https://gcc.gnu.org/g:5fcd9bb0d57e56f70c3291b59b54368372c9c69f commit 5fcd9bb0d57e56f70c3291b59b54368372c9c69f Author: Mikael Morin Date: Mon May 5 13:48:49 2025 +0200 Correction régression pr77973 Diff: --- gcc/fortran/trans-openmp.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc index 01d9263fb838..7e8b51fbf5a6 100644 --- a/gcc/fortran/trans-openmp.cc +++ b/gcc/fortran/trans-openmp.cc @@ -242,7 +242,8 @@ gfc_omp_privatize_by_reference (const_tree decl) || GFC_DECL_GET_SCALAR_ALLOCATABLE (decl) || GFC_DECL_CRAY_POINTEE (decl) || GFC_DECL_ASSOCIATE_VAR_P (decl) - || VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl + || VOID_TYPE_P (TREE_TYPE (TREE_TYPE (decl))) + || !TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (decl return false; if (!DECL_ARTIFICIAL (decl)
[gcc(refs/users/mikael/heads/refactor_descriptor_v05)] Correction régression guality/arg1
https://gcc.gnu.org/g:708eb59b45197553bcfcd8b178fda6716421614e commit 708eb59b45197553bcfcd8b178fda6716421614e Author: Mikael Morin Date: Mon May 5 17:03:44 2025 +0200 Correction régression guality/arg1 Diff: --- gcc/fortran/trans-decl.cc | 9 +++-- gcc/fortran/trans-types.cc | 17 - 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc index 99c53fab755a..92a0ccdb3588 100644 --- a/gcc/fortran/trans-decl.cc +++ b/gcc/fortran/trans-decl.cc @@ -1264,10 +1264,15 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) { tree size, range; + tree lower = TYPE_MIN_VALUE (TYPE_DOMAIN (type)); + if (lower == NULL_TREE) + lower = gfc_index_zero_node; + size = fold_build2_loc (input_location, MINUS_EXPR, gfc_array_index_type, GFC_TYPE_ARRAY_SIZE (type), gfc_index_one_node); - range = build_range_type (gfc_array_index_type, gfc_index_zero_node, - size); + size = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type, + size, lower); + range = build_range_type (gfc_array_index_type, lower, size); TYPE_DOMAIN (type) = range; layout_type (type); } diff --git a/gcc/fortran/trans-types.cc b/gcc/fortran/trans-types.cc index dd8c306b3b32..9568d8f821ab 100644 --- a/gcc/fortran/trans-types.cc +++ b/gcc/fortran/trans-types.cc @@ -1860,6 +1860,7 @@ gfc_get_nodesc_array_type (tree etype, gfc_array_spec * as, gfc_packed packed, mpz_t stride; mpz_t spc; mpz_t delta; + mpz_t *lbound0 = nullptr; gfc_expr *expr; mpz_init_set_ui (offset, 0); @@ -1889,6 +1890,8 @@ gfc_get_nodesc_array_type (tree etype, gfc_array_spec * as, gfc_packed packed, expr = as->lower[n]; if (expr && expr->expr_type == EXPR_CONSTANT) { + if (n == 0) + lbound0 = &expr->value.integer; tmp = gfc_conv_mpz_to_tree (expr->value.integer, gfc_index_integer_kind); } @@ -2004,13 +2007,25 @@ gfc_get_nodesc_array_type (tree etype, gfc_array_spec * as, gfc_packed packed, mpz_t size; mpz_init (size); mpz_sub_ui (size, stride, 1); + if (as->rank == 1 && lbound0) + mpz_add (size, size, *lbound0); + else if (as->rank == 1 && as->lower[0] == nullptr) + mpz_add_ui (size, size, 1); max_idx = gfc_conv_mpz_to_tree (size, gfc_index_integer_kind); } else max_idx = NULL_TREE; + tree lower; + if (as->rank == 1 && lbound0) + lower = gfc_conv_mpz_to_tree (*lbound0, gfc_index_integer_kind); + else if (as->rank == 1 && as && as->lower[0] == nullptr) + lower = gfc_index_one_node; + else + lower = gfc_index_zero_node; + TYPE_DOMAIN (type) = build_range_type (gfc_array_index_type, -gfc_index_zero_node, max_idx); +lower, max_idx); TREE_TYPE (type) = etype; }
[gcc r16-392] PR modula2/120117: ICE when attempting to obtain the MAX of an aliased set type
https://gcc.gnu.org/g:bb83283e5c5c55eab7493a58c5e415aa56f5940c commit r16-392-gbb83283e5c5c55eab7493a58c5e415aa56f5940c Author: Gaius Mulley Date: Mon May 5 18:16:20 2025 +0100 PR modula2/120117: ICE when attempting to obtain the MAX of an aliased set type The ICE occurred because of a bug in M2GenGCC.mod:FoldBecomes which attempted to remove the same quadruple twice. Thereafter cc1gm2 generated an erroneous error type error as PCSymBuild did not skip an aliased set type. The type of the const was set incorrectly (as a set type) rather than the type of the set element. gcc/m2/ChangeLog: PR modula2/120117 * gm2-compiler/M2GenGCC.mod (FoldBecomes): Remove the call to RemoveQuad since this is performed by TypeCheckBecomes. * gm2-compiler/PCSymBuild.mod (buildConstFunction): Rewrite header comment. Check for a set or a type aliased set and appropriately skip type equivalences and obtain the element type. * gm2-compiler/SymbolTable.mod (PutConst): Add call to CheckBreak. gcc/testsuite/ChangeLog: PR modula2/120117 * gm2/pim/pass/highbit.mod: New test. * gm2/pim/pass/highbit2.mod: New test. Signed-off-by: Gaius Mulley Diff: --- gcc/m2/gm2-compiler/M2GenGCC.mod| 3 --- gcc/m2/gm2-compiler/PCSymBuild.mod | 13 +++-- gcc/m2/gm2-compiler/SymbolTable.mod | 1 + gcc/testsuite/gm2/pim/pass/highbit.mod | 13 + gcc/testsuite/gm2/pim/pass/highbit2.mod | 13 + 5 files changed, 34 insertions(+), 9 deletions(-) diff --git a/gcc/m2/gm2-compiler/M2GenGCC.mod b/gcc/m2/gm2-compiler/M2GenGCC.mod index a1e3c07809aa..bc1d588fce6e 100644 --- a/gcc/m2/gm2-compiler/M2GenGCC.mod +++ b/gcc/m2/gm2-compiler/M2GenGCC.mod @@ -2914,9 +2914,6 @@ BEGIN IF TypeCheckBecomes (p, quad) THEN PerformFoldBecomes (p, quad) - ELSE -GetQuad (quad, op, des, op2, expr) ; -RemoveQuad (p, des, quad) END END END diff --git a/gcc/m2/gm2-compiler/PCSymBuild.mod b/gcc/m2/gm2-compiler/PCSymBuild.mod index b124c3ea6729..3bffe8674a4f 100644 --- a/gcc/m2/gm2-compiler/PCSymBuild.mod +++ b/gcc/m2/gm2-compiler/PCSymBuild.mod @@ -64,7 +64,7 @@ FROM SymbolTable IMPORT NulSym, ModeOfAddr, ProcedureKind, GetFromOuterModule, CheckForEnumerationInCurrentModule, GetMode, PutVariableAtAddress, ModeOfAddr, SkipType, -IsSet, PutConstSet, +IsSet, PutConstSet, IsType, IsConst, IsConstructor, PutConst, PutConstructor, PopValue, PushValue, MakeTemporary, PutVar, @@ -1408,9 +1408,10 @@ END TypeToMeta ; (* - buildConstFunction - we are only concerned about resolving the return type o + buildConstFunction - we are only concerned about resolving the return type of a function, so we can ignore all parameters - except -the first one in the case of VAL(type, foo). +the first one in the case of VAL(type, foo) +and the type of bar in MIN (bar) and MAX (bar). buildConstFunction uses a unary exprNode to represent a function. *) @@ -1866,11 +1867,11 @@ BEGIN THEN IF (func=Min) OR (func=Max) THEN - IF IsSet (sym) + IF IsSet (sym) OR (IsType (sym) AND IsSet (SkipType (sym))) THEN - type := SkipType(GetType(sym)) + type := GetType (SkipType (sym)) ELSE - (* sym is the type required for MAX, MIN and VAL *) + (* sym is the type required for MAX, MIN and VAL. *) type := sym END ELSE diff --git a/gcc/m2/gm2-compiler/SymbolTable.mod b/gcc/m2/gm2-compiler/SymbolTable.mod index 551bbecc7886..ff661dcf4e7e 100644 --- a/gcc/m2/gm2-compiler/SymbolTable.mod +++ b/gcc/m2/gm2-compiler/SymbolTable.mod @@ -7265,6 +7265,7 @@ VAR pSym: PtrToSymbol ; BEGIN pSym := GetPsym(Sym) ; + CheckBreak (Sym) ; WITH pSym^ DO CASE SymbolType OF diff --git a/gcc/testsuite/gm2/pim/pass/highbit.mod b/gcc/testsuite/gm2/pim/pass/highbit.mod new file mode 100644 index ..c9c872a62f31 --- /dev/null +++ b/gcc/testsuite/gm2/pim/pass/highbit.mod @@ -0,0 +1,13 @@ +MODULE highbit ; + +FROM libc IMPORT printf ; + +TYPE + set = BITSET ; + +CONST + HighBit = MAX (set) ; + +BEGIN + printf ("the MAX (set) = %d\n", HighBit) +END highbit. diff --git a/gcc/testsuite/gm2/pim/pass/highbit2.mod b/gcc/testsuite/gm2/pim/pass/highbit2.mod new file mode 10064
[gcc/ibm/heads/gcc-14-branch] (1123 commits) ibm: Merge up to top of releases/gcc-14
The branch 'ibm/heads/gcc-14-branch' was updated to point to: e8224a16f678... ibm: Merge up to top of releases/gcc-14 It previously pointed to: 7ea4c6f44d3f... ibm: Merge up to top of releases/gcc-14 Diff: Summary of changes (added commits): --- e8224a1... ibm: Merge up to top of releases/gcc-14 c120e04... Daily bump. (*) 475cec3... Fortran: pure subroutine with pure procedure as dummy [PR10 (*) 30432ff... c++: UNBOUND_CLASS_TEMPLATE context substitution [PR119981] (*) fd9d35f... testsuite: Force -mcmodel=small for gcc.target/aarch64/pr11 (*) 51d7659... Fix GNAT build failure for x86/FreeBSD (*) 1ca1c1f... AVR: target/119989 - Add missing clobbers to xload__l (*) 3418d74... libstdc++: [_GLIBCXX_INLINE_VERSION] Fix tests failures (*) e363940... RISC-V: vsetvl: elide abnormal edges from LCM computations (*) ae6ce4c... RISC-V: Do not lift up vsetvl into non-transparent blocks [ (*) eaa9b75... Daily bump. (*) 96729ba... Remove other processors from X86_TUNE_DEST_FALSE_DEP_FOR_GL (*) d23d35d... libstdc++: Improve optional's <=> constraint recursion work (*) d03c585... libstdc++: Add code comment documenting LWG 4027 change [PR (*) d4f5243... libstdc++: Implement LWG 4027 change to possibly-const-rang (*) d3cb17b... c++: prev declared hidden tmpl friend inst, cont [PR119807] (*) 615e392... Daily bump. (*) 1e91580... c++: format attribute redeclaration [PR116954] (*) 8dce1aa... c++: shortcut constexpr vector ctor [PR113835] (*) 8f4df0d... middle-end: fix masking for partial vectors and early break (*) 9ce3811... aarch64: force operand to fresh register to avoid subreg is (*) 3e44824... Daily bump. (*) 035da7b... Daily bump. (*) 294ed13... Daily bump. (*) 57f930f... libbacktrace: Add hpux fileline support (*) 2a9fd7e... Daily bump. (*) cd7c5d9... sra: Clear grp_same_access_path of acesses created by total (*) 19dd791... sra: Avoid creating TBAA hazards (PR118924) (*) 29004ac... s390: Accept only Pmode for registers AP/FP/RA [PR119235] (*) 8d70737... c++: templates, attributes, #pragma target [PR114772] (*) 8a88414... libcpp: Fix incorrect line numbers in large files [PR108900 (*) 70eaec5... c++: constexpr, trivial, and non-alias target [PR111075] (*) 9ef0cf0... Daily bump. (*) d7b5fe3... [14] Use --param=aarch64-autovec-preference=2 instead of =s (*) 4108c75... tree-optimization/119778 - properly mark abnormal edge sour (*) 2bb4a43... aarch64: Add test case. (*) c8fe937... middle-end/119706 - allow POLY_INT_CST as is_gimple_mem_ref (*) a27f6a4... target/119549 - fixup handling of -mno-sse4 in target attri (*) 97dde42... tree-optimization/119534 - reject bogus emulated vectorized (*) 721c612... Daily bump. (*) 9051989... Daily bump. (*) d338d6c... Daily bump. (*) 88b3c89... d: Fix ICE: type variant differs by TYPE_MAX_VALUE with -g (*) d1b7ee4... d: Fix ICE in dwarf2out_imported_module_or_decl, at dwarf2o (*) aec3b99... d: Fix forward referenced enums missing type names in debug (*) d490c58... libatomic: Fix up libat_{,un}lock_n for mingw [PR119796] (*) 50bd360... libatomic: Fix up libat_{,un}lock_n [PR119796] (*) 40c5065... bitintlower: Fix interaction of gimple_assign_copy_p stmts (*) efb2261... expmed: Always use QImode for init_expmed set_zero_cost [PR (*) 438c4df... driver: On linux hosts disable ASLR during -freport-bug [PR (*) 2aa8123... driver: Fix up -freport-bug for ASLR [PR119727] (*) 056a01f... bitintlower: Fix up handling of SSA_NAME copies in coalesci (*) 008ba21... bitintlower: Fix up handling of nested casts in m_upward_2l (*) 8581982... libquadmath: Fix up THREEp96 constant in expq (*) 293a95b... lto: lto-opts fixes [PR119625] (*) c0946fe... c: Fix ICEs with -fsanitize=pointer-{subtract,compare} [PR1 (*) 7381ea8... combine: Use reg_used_between_p rather than modified_betwee (*) 2048dcc... LoongArch: Change {dg-do-what-default} save and restore log (*) 022ef0b... Daily bump. (*) 459b93d... Daily bump. (*) a295863... libstdc++: Correct preprocessing checks for floatX_t and bf (*) 203bce1... i386: Enable -mnop-mcount for -fpic with PLTs [PR119386] (*) 1500a9c... i386: Prefer PLT indirection for __fentry__ calls under -fP (*) efe332f... Daily bump. (*) 62151c3... Fix wrong optimization of conditional expression with enume (*) c344377... aarch64: Disable sysreg feature gating (*) 8cc672d... x86: Update gcc.target/i386/apx-interrupt-1.c (*) a33e280... APX: Don't use red-zone with 32 GPRs and no caller-saved re (*) d275b37... Extend check-function-bodies to allow label and directives (*) b61acf5... RISC-V: Put jump table in text for large code model (*) 52c1f60... RISC-V: Fix vec_duplicate[bimode] expander [PR119572]. (*) 94ef806... aarch64: Split aarch64_combinev16qi before RA [PR115258] (*) a38e9e0... aarch64: Avoid unnecessary use of 2-input TBLs [PR115258] (*) 2a4b0a1... vect: Enforce dr_with_seg_len::align precon
[gcc(refs/vendors/ibm/heads/gcc-14-branch)] ibm: Merge up to top of releases/gcc-14
https://gcc.gnu.org/g:e8224a16f6789610b8775aed520a24bbb2c01ab0 commit e8224a16f6789610b8775aed520a24bbb2c01ab0 Merge: 7ea4c6f44d3f c120e047ecb5 Author: Surya Kumari Jangala Date: Fri May 2 03:20:33 2025 -0500 ibm: Merge up to top of releases/gcc-14 2025-05-02 Surya Kumari Jangala Merge up to releases/gcc-14 c120e047ecb5f488efffdccbdcacc1ce18e29f3a Diff: gcc/ChangeLog | 3514 + gcc/ChangeLog.ibm | 4 + gcc/DATESTAMP | 2 +- gcc/Makefile.in| 1 + gcc/ada/ChangeLog | 156 + gcc/ada/Makefile.rtl | 1 + gcc/ada/checks.adb |10 +- gcc/ada/exp_aggr.adb |54 +- gcc/ada/exp_aggr.ads | 4 + gcc/ada/exp_ch3.adb|15 +- gcc/ada/exp_ch7.adb| 6 + gcc/ada/exp_put_image.adb | 3 +- gcc/ada/exp_util.adb | 1 + gcc/ada/freeze.adb |26 +- gcc/ada/gcc-interface/decl.cc | 8 + gcc/ada/gcc-interface/trans.cc |16 +- gcc/ada/gen_il-gen-gen_nodes.adb | 2 +- gcc/ada/gnatvsn.ads| 3 +- gcc/ada/libgnarl/s-taprop__dummy.adb |11 +- gcc/ada/libgnat/a-ngcoar.adb |42 +- gcc/ada/libgnat/a-ngrear.adb | 109 +- gcc/ada/libgnat/s-dorepr__freebsd.adb | 172 + gcc/ada/par-ch6.adb| 1 + gcc/ada/sem_ch12.adb |37 +- gcc/ada/sem_res.adb| 2 +- gcc/ada/sem_warn.adb | 4 + gcc/ada/version.c | 5 +- gcc/analyzer/ChangeLog |43 + gcc/analyzer/analyzer.cc |15 +- gcc/analyzer/analyzer.h| 4 +- gcc/analyzer/engine.cc | 2 +- gcc/analyzer/kf.cc |26 + gcc/analyzer/known-function-manager.cc |38 +- gcc/analyzer/known-function-manager.h | 5 + gcc/analyzer/sm-file.cc| 8 + gcc/analyzer/sm-malloc.cc | 1 + gcc/analyzer/sm-signal.cc |11 +- gcc/asan.cc|51 +- gcc/auto-profile.cc| 4 +- gcc/builtins.cc|73 +- gcc/c-family/ChangeLog |70 + gcc/c-family/c-ada-spec.cc | 4 +- gcc/c-family/c-common.cc |11 +- gcc/c-family/c-cppbuiltin.cc |19 +- gcc/c-family/c-pretty-print.cc | 6 +- gcc/c-family/c-warn.cc |20 +- gcc/c/ChangeLog| 108 + gcc/c/c-decl.cc| 123 +- gcc/c/c-objc-common.h | 2 + gcc/c/c-parser.cc |36 +- gcc/c/c-tree.h |21 +- gcc/c/c-typeck.cc | 388 +- gcc/cfgexpand.cc | 7 +- gcc/cgraph.cc |14 +- gcc/combine.cc |38 +- gcc/common/config/i386/cpuinfo.h | 1 + gcc/common/config/i386/i386-common.cc |63 +- gcc/common/config/i386/i386-isas.h | 2 +- gcc/config.in | 7 + gcc/config/aarch64/aarch64-builtins.cc | 190 +- gcc/config/aarch64/aarch64-cores.def | 9 +- gcc/config/aarch64/aarch64-early-ra.cc |57 +- gcc/config/aarch64/aarch64-freebsd.h | 1 + gcc/config/aarch64/aarch64-ldp-fusion.cc | 158 +- gcc/config/aarch64/aarch64-protos.h| 2 + gcc/config/aarch64/aarch64-simd.md | 2 +- gcc/config/aarch64/aarch64-sve-builtins-base.cc|17 +- gcc/config/aarch64/aarch64-sve-builtins-base.def |13 +- gcc/config/aarch64/aarch64-sve-builtins-sve2.cc| 8 +- gcc/config/aarch64/aarch64-sve-builtins-sve2.def | 4 +- gcc/config/aarch64/aarch64-sve-builtins-sve2.h | 4 +- gcc/config/aarch64/aarch64-sve-builtins.cc | 107 +- gcc/config/aarch64/aarch64-sve2.md | 8 +- gcc/config/aarch64/aarch64-tune.md
[gcc r14-11726] c++, coroutines: Allow convertible get_return_on_allocation_fail [PR109682].
https://gcc.gnu.org/g:1b3addb6fe05a80d5e043fbb12cc9c0cc426b0e6 commit r14-11726-g1b3addb6fe05a80d5e043fbb12cc9c0cc426b0e6 Author: Iain Sandoe Date: Sat Aug 17 16:55:29 2024 +0100 c++, coroutines: Allow convertible get_return_on_allocation_fail [PR109682]. We have been requiring the get_return_on_allocation_fail() call to have the same type as the ramp. This is not intended by the standard, so relax that to allow anything convertible to the ramp return. PR c++/109682 gcc/cp/ChangeLog: * coroutines.cc (cp_coroutine_transform::build_ramp_function): Allow for cases where get_return_on_allocation_fail has a type convertible to the ramp return type. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr109682.C: New test. Signed-off-by: Iain Sandoe (cherry picked from commit f4915e6c4cd42e7d6f397dc36fab507cc47dad05) Diff: --- gcc/cp/coroutines.cc | 19 ++- gcc/testsuite/g++.dg/coroutines/pr109682.C | 28 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index a6cbe07d1a28..00a016d1bd31 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4946,25 +4946,18 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) control to the caller of the coroutine and the return value is obtained by a call to T::get_return_object_on_allocation_failure(), where T is the promise type. */ - - gcc_checking_assert (same_type_p (fn_return_type, TREE_TYPE (grooaf))); tree if_stmt = begin_if_stmt (); tree cond = build1 (CONVERT_EXPR, coro_frame_ptr, nullptr_node); cond = build2 (EQ_EXPR, boolean_type_node, coro_fp, cond); finish_if_stmt_cond (cond, if_stmt); + r = NULL_TREE; if (void_ramp_p) - { - /* Execute the get-return-object-on-alloc-fail call... */ - finish_expr_stmt (grooaf); - /* ... but discard the result, since we return void. */ - finish_return_stmt (NULL_TREE); - } + /* Execute the get-return-object-on-alloc-fail call... */ + finish_expr_stmt (grooaf); else - { - /* Get the fallback return object. */ - r = build_cplus_new (fn_return_type, grooaf, tf_warning_or_error); - finish_return_stmt (r); - } + /* Get the fallback return object. */ + r = grooaf; + finish_return_stmt (r); finish_then_clause (if_stmt); finish_if_stmt (if_stmt); } diff --git a/gcc/testsuite/g++.dg/coroutines/pr109682.C b/gcc/testsuite/g++.dg/coroutines/pr109682.C new file mode 100644 index ..24aab921ab22 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr109682.C @@ -0,0 +1,28 @@ + +#include +#include + +struct test +{ + test () {} + test (int) {} + + struct promise_type { +test get_return_object () { return {}; } +// vvv +static int get_return_object_on_allocation_failure () { return {}; } +std::suspend_never initial_suspend () noexcept { return {}; } +std::suspend_never final_suspend () noexcept { return {}; } +void return_void () {} +void unhandled_exception () {} + }; +}; + +test +f () { co_return; } + +int +main () +{ + f (); +}
[gcc r14-11727] c++, coroutines: Rework handling of throwing_cleanups [PR102051].
https://gcc.gnu.org/g:ce3f523f9cb4c20704bc5f41b8fbc34b5b84ed88 commit r14-11727-gce3f523f9cb4c20704bc5f41b8fbc34b5b84ed88 Author: Iain Sandoe Date: Sun Aug 18 22:54:50 2024 +0100 c++, coroutines: Rework handling of throwing_cleanups [PR102051]. In the fix for PR95822 (r11-7402) we set throwing_cleanup false in the top level of the coroutine transform code. However, as the current PR shows, that is not sufficient. Any use of cxx_maybe_build_cleanup() can reset the flag, which causes the check_return_expr () logic to try to add a guard variable and set it. For the coroutine code, we need to handle the cleanups separately, since the responsibility for them changes after the first resume point, which we handle in the ramp exception processing. Fix this by forcing the "throwing_cleanup" flag false right before the processing of the return expression. PR c++/102051 gcc/cp/ChangeLog: * coroutines.cc (cp_coroutine_transform::build_ramp_function): Handle "throwing_cleanup" here instead of ... (cp_coroutine_transform::apply_transforms): ... here. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr102051.C: New test. Signed-off-by: Iain Sandoe (cherry picked from commit f0315f7a325ffccb446fe378fcdfccda6eead8ba) Diff: --- gcc/cp/coroutines.cc | 15 --- gcc/testsuite/g++.dg/coroutines/pr102051.C | 16 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 00a016d1bd31..82ba96f65674 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4632,17 +4632,6 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) TREE_OPERAND (body_start, 0) = push_stmt_list (); } - /* If the original function has a return value with a non-trivial DTOR - and the body contains a var with a DTOR that might throw, the decl is - marked "throwing_cleanup". - We do not [in the ramp, which is synthesised here], use any body var - types with DTORs that might throw. - The original body is transformed into the actor function which only - contains void returns, and is also wrapped in a try-catch block. - So (a) the 'throwing_cleanup' is not correct for the ramp and (b) we do - not need to transfer it to the actor which only contains void returns. */ - cp_function_chain->throwing_cleanup = false; - /* Create the coro frame type, as far as it can be known at this stage. 1. Types we already know. */ @@ -5270,6 +5259,10 @@ morph_fn_to_coro (tree orig, tree *resumer, tree *destroyer) either as the return value (if it's the same type) or to the CTOR for an object of the return type. */ + /* We must manage the cleanups ourselves, because the responsibility for + them changes after the initial suspend. However, any use of + cxx_maybe_build_cleanup () can set the throwing_cleanup flag. */ + cp_function_chain->throwing_cleanup = false; if (same_type_p (gro_type, fn_return_type)) r = void_ramp_p ? NULL_TREE : DECL_RESULT (orig); else diff --git a/gcc/testsuite/g++.dg/coroutines/pr102051.C b/gcc/testsuite/g++.dg/coroutines/pr102051.C new file mode 100644 index ..bba98b691cc2 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr102051.C @@ -0,0 +1,16 @@ +#include + +struct Foo { +~Foo() noexcept(false); // true succeeds +struct promise_type { +Foo get_return_object() { return {}; } +std::suspend_never initial_suspend() { return {}; } +void return_void() {} +void unhandled_exception() {} +std::suspend_always final_suspend() noexcept { return {}; } +}; +}; + +Foo bar() { +co_return; +}
[gcc r14-11728] c++, coroutines: Look through initial_await target exprs [PR110635].
https://gcc.gnu.org/g:4042cecd6245dc773fc150d5fd839968674e4500 commit r14-11728-g4042cecd6245dc773fc150d5fd839968674e4500 Author: Iain Sandoe Date: Mon Aug 19 20:50:54 2024 +0100 c++, coroutines: Look through initial_await target exprs [PR110635]. In the case that the initial awaiter returns an object, the initial await can be a target expression and we need to look at its initializer to cast the await_resume() to void and to wrap in a compound expression that sets the initial_await_resume_called flag. PR c++/110635 gcc/cp/ChangeLog: * coroutines.cc (cp_coroutine_transform::wrap_original_function_body): Look through initial await target expressions to find the actual co_await_expr that we need to update. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr110635.C: New test. Signed-off-by: Iain Sandoe (cherry picked from commit c442a9b78bdbebdbcb4a8f91bc36961eb732fbdf) Diff: --- gcc/cp/coroutines.cc | 8 +++- gcc/testsuite/g++.dg/coroutines/pr110635.C | 72 ++ 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 82ba96f65674..ee0fbc454e6e 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4442,7 +4442,13 @@ coro_rewrite_function_body (location_t fn_start, tree fnbody, tree orig, a reference type, look past the indirection. */ if (INDIRECT_REF_P (initial_await)) initial_await = TREE_OPERAND (initial_await, 0); - tree vec = TREE_OPERAND (initial_await, 3); + /* In the case that the initial_await returns a target expression +we might need to look through that to update the await expr. */ + tree iaw = initial_await; + if (TREE_CODE (iaw) == TARGET_EXPR) + iaw = TARGET_EXPR_INITIAL (iaw); + gcc_checking_assert (TREE_CODE (iaw) == CO_AWAIT_EXPR); + tree vec = TREE_OPERAND (iaw, 3); tree aw_r = TREE_VEC_ELT (vec, 2); aw_r = convert_to_void (aw_r, ICV_STATEMENT, tf_warning_or_error); tree update = build2 (MODIFY_EXPR, boolean_type_node, i_a_r_c, diff --git a/gcc/testsuite/g++.dg/coroutines/pr110635.C b/gcc/testsuite/g++.dg/coroutines/pr110635.C new file mode 100644 index ..ea4e0e853eb5 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr110635.C @@ -0,0 +1,72 @@ + +#define CASE 0 +#include +#include + +struct Coroutine { + +struct promise_type; + +using handler_type = std::coroutine_handle; + +struct initial_suspend_awaiter { + +bool await_ready() noexcept { +std::cout << "await_ready" << std::endl; +return false; +} + +void await_suspend(handler_type h) noexcept { +std::cout << "await_suspend" << std::endl; +} + +#if CASE == 0 +struct await_resume_return_object { +await_resume_return_object() noexcept { +std::cout << "await_resume_return_object" << std::endl; +} + +~await_resume_return_object() noexcept { +std::cout << "~await_resume_return_object" << std::endl; +} +}; +#elif CASE == 1 +using await_resume_return_object = struct{}; +#elif CASE == 2 +using await_resume_return_object = int; +#else +using await_resume_return_object = void; +#endif +await_resume_return_object await_resume() noexcept { +std::cout << "await_resume" << std::endl; +#if CASE == 0 || CASE == 1 || CASE == 2 +return {}; +#endif +} + +initial_suspend_awaiter() noexcept { +std::cout << "initial_suspend_awaiter" << std::endl; +} + +~initial_suspend_awaiter() noexcept { +std::cout << "~initial_suspend_awaiter" << std::endl; +} +}; + +struct promise_type { +void return_void() noexcept {} +void unhandled_exception() noexcept { std::terminate();} +initial_suspend_awaiter initial_suspend() noexcept { return {}; } +std::suspend_never final_suspend() noexcept { return {}; } +Coroutine get_return_object() { +return Coroutine{handler_type::from_promise(*this)}; +} +}; + +handler_type handler; +}; + +int main() { +auto coro = []()->Coroutine { co_return; }(); +coro.handler.resume(); +}
[gcc r14-11729] c++/coros: do not assume coros don't nest [PR113457]
https://gcc.gnu.org/g:805b9914846a1228b84a3c3dd8f9ba2f21f9ff59 commit r14-11729-g805b9914846a1228b84a3c3dd8f9ba2f21f9ff59 Author: Arsen Arsenović Date: Fri Aug 23 20:19:05 2024 +0200 c++/coros: do not assume coros don't nest [PR113457] In the testcase presented in the PR, during template expansion, an tsubst of an operand causes a lambda coroutine to be processed, causing it to get an initial suspend and final suspend. The code for assigning awaitable var names (get_awaitable_var) assumed that the sequence Is -> Is -> Fs -> Fs is impossible (i.e. that one could only 'open' one coroutine before closing it at a time), and reset the counter used for unique numbering each time a final suspend occured. This assumption is false in a few cases, usually when lambdas are involved. Instead of storing this counter in a static-storage variable, we can store it in coroutine_info. This struct is local to each function, so we don't need to worry about "cross-contamination" nor resetting. PR c++/113457 gcc/cp/ChangeLog: * coroutines.cc (struct coroutine_info): Add integer field awaitable_number. This is a counter used for assigning unique names to awaitable temporaries. (get_awaitable_var): Use awaitable_number from coroutine_info instead of the static int awn. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr113457-1.C: New test. * g++.dg/coroutines/pr113457.C: New test. (cherry picked from commit 5cca7517c5868b7b9aa13992145eb6082ac5d5b9) Diff: --- gcc/cp/coroutines.cc | 19 ++- gcc/testsuite/g++.dg/coroutines/pr113457-1.C | 25 gcc/testsuite/g++.dg/coroutines/pr113457.C | 178 +++ 3 files changed, 216 insertions(+), 6 deletions(-) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index ee0fbc454e6e..953297c3c496 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -95,6 +95,10 @@ struct GTY((for_user)) coroutine_info tree return_void; /* The expression for p.return_void() if it exists. */ location_t first_coro_keyword; /* The location of the keyword that made this function into a coroutine. */ + + /* Temporary variable number assigned by get_awaitable_var. */ + int awaitable_number = 0; + /* Flags to avoid repeated errors for per-function issues. */ bool coro_ret_type_error_emitted; bool coro_promise_error_emitted; @@ -981,15 +985,18 @@ enum suspend_point_kind { static tree get_awaitable_var (suspend_point_kind suspend_kind, tree v_type) { - static int awn = 0; + auto cinfo = get_coroutine_info (current_function_decl); + gcc_checking_assert (cinfo); char *buf; switch (suspend_kind) { - default: buf = xasprintf ("Aw%d", awn++); break; - case CO_YIELD_SUSPEND_POINT: buf = xasprintf ("Yd%d", awn++); break; - case INITIAL_SUSPEND_POINT: buf = xasprintf ("Is"); break; - case FINAL_SUSPEND_POINT: buf = xasprintf ("Fs"); awn = 0; break; - } +default: buf = xasprintf ("Aw%d", cinfo->awaitable_number++); break; +case CO_YIELD_SUSPEND_POINT: + buf = xasprintf ("Yd%d", cinfo->awaitable_number++); + break; +case INITIAL_SUSPEND_POINT: buf = xasprintf ("Is"); break; +case FINAL_SUSPEND_POINT: buf = xasprintf ("Fs"); break; +} tree ret = get_identifier (buf); free (buf); ret = build_lang_decl (VAR_DECL, ret, v_type); diff --git a/gcc/testsuite/g++.dg/coroutines/pr113457-1.C b/gcc/testsuite/g++.dg/coroutines/pr113457-1.C new file mode 100644 index ..fcf67e15271c --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr113457-1.C @@ -0,0 +1,25 @@ +// https://gcc.gnu.org/PR113457 +#include + +struct coro +{ + struct promise_type + { +std::suspend_never initial_suspend (); +std::suspend_never final_suspend () noexcept; +void return_void (); +void unhandled_exception (); +coro get_return_object (); + }; +}; + +struct not_quite_suspend_never : std::suspend_never +{}; + +coro +foo () +{ + co_await std::suspend_never{}, +[] () -> coro { co_return; }, +co_await not_quite_suspend_never{}; +} diff --git a/gcc/testsuite/g++.dg/coroutines/pr113457.C b/gcc/testsuite/g++.dg/coroutines/pr113457.C new file mode 100644 index ..add45a2f8921 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr113457.C @@ -0,0 +1,178 @@ +// https://gcc.gnu.org/PR113457 +namespace std { +template _Up __declval(int); +template auto declval() noexcept -> decltype(__declval<_Tp>(0)); +template struct remove_cv { + using type = __remove_cv(_Tp); +}; +template using remove_cv_t = typename remove_cv<_Tp>::type; +template struct remove_reference { + using type = __remove_reference(_Tp); +}; +template +using remove_reference_t = typename remove_reference<_Tp>::type; +template inline constexpr bool is_a
[gcc r14-11730] c++, coroutines: The frame pointer is used in the helpers [PR116482].
https://gcc.gnu.org/g:b2fa7e036e72fa0ed63df602cebd4005b078336e commit r14-11730-gb2fa7e036e72fa0ed63df602cebd4005b078336e Author: Iain Sandoe Date: Mon Aug 26 14:09:40 2024 +0100 c++, coroutines: The frame pointer is used in the helpers [PR116482]. We have a bogus warning about the coroutine state frame pointers being apparently unused in the resume and destroy functions. Fixed by making the parameters DECL_ARTIFICIAL. PR c++/116482 gcc/cp/ChangeLog: * coroutines.cc (coro_build_actor_or_destroy_function): Make the parameter decls DECL_ARTIFICIAL. gcc/testsuite/ChangeLog: * g++.dg/coroutines/pr116482.C: New test. Signed-off-by: Iain Sandoe (cherry picked from commit 8d6d6c864442a1cc987b3e6bcb1d903ceb975e4a) Diff: --- gcc/cp/coroutines.cc | 1 + gcc/testsuite/g++.dg/coroutines/pr116482.C | 30 ++ 2 files changed, 31 insertions(+) diff --git a/gcc/cp/coroutines.cc b/gcc/cp/coroutines.cc index 953297c3c496..8bb46ff5c990 100644 --- a/gcc/cp/coroutines.cc +++ b/gcc/cp/coroutines.cc @@ -4226,6 +4226,7 @@ coro_build_actor_or_destroy_function (tree orig, tree fn_type, tree id = get_identifier ("frame_ptr"); tree fp = build_lang_decl (PARM_DECL, id, coro_frame_ptr); + DECL_ARTIFICIAL (fp) = true; DECL_CONTEXT (fp) = fn; DECL_ARG_TYPE (fp) = type_passed_as (coro_frame_ptr); DECL_ARGUMENTS (fn) = fp; diff --git a/gcc/testsuite/g++.dg/coroutines/pr116482.C b/gcc/testsuite/g++.dg/coroutines/pr116482.C new file mode 100644 index ..702d1e235bb7 --- /dev/null +++ b/gcc/testsuite/g++.dg/coroutines/pr116482.C @@ -0,0 +1,30 @@ +// Override default options. +// { dg-options "-std=c++20 -fno-exceptions -Wall -Wextra" } + +#include + +struct SuspendNever { +bool await_ready(); +void await_suspend(std::coroutine_handle<>); +void await_resume(); +}; + +struct Coroutine; + +struct PromiseType { +Coroutine get_return_object(); +SuspendNever initial_suspend(); +SuspendNever final_suspend(); +#if __cpp_exceptions +void unhandled_exception() { /*std::terminate();*/ }; +#endif +void return_void(); +}; + +struct Coroutine { +using promise_type = PromiseType; +}; + +Coroutine __async_test_input_basic() { +co_return; +}
[gcc r15-9622] ipa/120006 - wrong code with IPA PTA
https://gcc.gnu.org/g:169ad482497ae9c672a825050b8f4b6d54cd5d24 commit r15-9622-g169ad482497ae9c672a825050b8f4b6d54cd5d24 Author: Richard Biener Date: Wed Apr 30 10:01:47 2025 +0200 ipa/120006 - wrong code with IPA PTA When PTA gets support for special-handling more builtins in find_func_aliases the corresponding code in find_func_clobbers needs updating as well since for unhandled cases it assumes the former will populate ESCAPED accordingly. The following fixes a few omissions, the testcase runs into the missing strdup handling. I believe the more advanced handling using modref results and fnspecs opened a larger gap, the proper fix is to merge both functions, gating the clobber/use part on a parameter to avoid diverging. PR ipa/120006 * tree-ssa-structalias.cc (find_func_clobbers): Handle strdup, strndup, realloc, index, strchr, strrchr, memchr, strstr, strpbrk builtins like find_func_aliases does. * gcc.dg/torture/pr120006.c: New testcase. (cherry picked from commit a85b89e26b1f50997701eb428c2dd71668f216ff) Diff: --- gcc/testsuite/gcc.dg/torture/pr120006.c | 31 gcc/tree-ssa-structalias.cc | 36 + 2 files changed, 67 insertions(+) diff --git a/gcc/testsuite/gcc.dg/torture/pr120006.c b/gcc/testsuite/gcc.dg/torture/pr120006.c new file mode 100644 index ..c067f0ef9ca0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr120006.c @@ -0,0 +1,31 @@ +/* { dg-do run } */ +/* { dg-additional-options "-fipa-pta" } */ + +char *b; +int f = 1; + +char *xstrdup(char *i) { + char *c = __builtin_strdup(i); + if (!c) +__builtin_exit(1); + return c; +} + +int main() { + char g; + char h[8]; + + for (int i = 0; i < 2; i++) { +char c = *__builtin_strdup(""); +b = &g; + +if (f) { + h[0] = '-'; + h[1] = 'a'; + h[2] = '\0'; + b = xstrdup(h); + } + } + if (__builtin_strcmp(b, "-a") != 0) +__builtin_abort(); +} diff --git a/gcc/tree-ssa-structalias.cc b/gcc/tree-ssa-structalias.cc index f79b54284c64..3ad0c69930c7 100644 --- a/gcc/tree-ssa-structalias.cc +++ b/gcc/tree-ssa-structalias.cc @@ -5583,6 +5583,42 @@ find_func_clobbers (struct function *fn, gimple *origt) process_ipa_clobber (fi, gimple_call_arg (t, 2)); return; } + /* The following functions use what their first argument +points to. */ + case BUILT_IN_STRDUP: + case BUILT_IN_STRNDUP: + case BUILT_IN_REALLOC: + case BUILT_IN_INDEX: + case BUILT_IN_STRCHR: + case BUILT_IN_STRRCHR: + case BUILT_IN_MEMCHR: + { + tree src = gimple_call_arg (t, 0); + get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc); + lhs = get_function_part_constraint (fi, fi_uses); + struct constraint_expr *rhsp; + FOR_EACH_VEC_ELT (rhsc, i, rhsp) + process_constraint (new_constraint (lhs, *rhsp)); + return; + } + /* The following functions use what their first and second argument +point to. */ + case BUILT_IN_STRSTR: + case BUILT_IN_STRPBRK: + { + tree src = gimple_call_arg (t, 0); + get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc); + lhs = get_function_part_constraint (fi, fi_uses); + struct constraint_expr *rhsp; + FOR_EACH_VEC_ELT (rhsc, i, rhsp) + process_constraint (new_constraint (lhs, *rhsp)); + rhsc.truncate (0); + src = gimple_call_arg (t, 1); + get_constraint_for_ptr_offset (src, NULL_TREE, &rhsc); + FOR_EACH_VEC_ELT (rhsc, i, rhsp) + process_constraint (new_constraint (lhs, *rhsp)); + return; + } /* The following functions neither read nor clobber memory. */ case BUILT_IN_ASSUME_ALIGNED: case BUILT_IN_FREE: