From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <gentoo-commits+bounces-1733574-garchives=archives.gentoo.org@lists.gentoo.org> Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 4BE251581EE for <garchives@archives.gentoo.org>; Wed, 02 Apr 2025 13:56:28 +0000 (UTC) Received: from lists.gentoo.org (bobolink.gentoo.org [140.211.166.189]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) (Authenticated sender: relay-lists.gentoo.org@gentoo.org) by smtp.gentoo.org (Postfix) with ESMTPSA id 35E673430FD for <garchives@archives.gentoo.org>; Wed, 02 Apr 2025 13:56:28 +0000 (UTC) Received: from bobolink.gentoo.org (localhost [127.0.0.1]) by bobolink.gentoo.org (Postfix) with ESMTP id 2EE341104B3; Wed, 02 Apr 2025 13:56:27 +0000 (UTC) Received: from smtp.gentoo.org (dev.gentoo.org [IPv6:2001:470:ea4a:1:5054:ff:fec7:86e4]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by bobolink.gentoo.org (Postfix) with ESMTPS id 23DCD1104B3 for <gentoo-commits@lists.gentoo.org>; Wed, 02 Apr 2025 13:56:27 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 82FCE3430BD for <gentoo-commits@lists.gentoo.org>; Wed, 02 Apr 2025 13:56:26 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 186272FE for <gentoo-commits@lists.gentoo.org>; Wed, 02 Apr 2025 13:56:25 +0000 (UTC) From: "Sam James" <sam@gentoo.org> To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Sam James" <sam@gentoo.org> Message-ID: <1743602166.966453b927f5030c1b2e858345091d867f78b94c.sam@gentoo> Subject: [gentoo-commits] proj/gcc-patches:master commit in: 15.0.0/gentoo/ X-VCS-Repository: proj/gcc-patches X-VCS-Files: 15.0.0/gentoo/80_all_PR119376-tailc-Don-t-fail-musttail-calls-if-they-use-or-could.patch 15.0.0/gentoo/83_all_PR119491-tailcall-eh.patch 15.0.0/gentoo/README.history X-VCS-Directories: 15.0.0/gentoo/ X-VCS-Committer: sam X-VCS-Committer-Name: Sam James X-VCS-Revision: 966453b927f5030c1b2e858345091d867f78b94c X-VCS-Branch: master Date: Wed, 02 Apr 2025 13:56:25 +0000 (UTC) Precedence: bulk List-Post: <mailto:gentoo-commits@lists.gentoo.org> List-Help: <mailto:gentoo-commits+help@lists.gentoo.org> List-Unsubscribe: <mailto:gentoo-commits+unsubscribe@lists.gentoo.org> List-Subscribe: <mailto:gentoo-commits+subscribe@lists.gentoo.org> List-Id: Gentoo Linux mail <gentoo-commits.gentoo.org> X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 4884d3b1-d6c0-4937-b7d1-4362e742900a X-Archives-Hash: 6c349fbbe7276a2d14daefee05647850 commit: 966453b927f5030c1b2e858345091d867f78b94c Author: Sam James <sam <AT> gentoo <DOT> org> AuthorDate: Wed Apr 2 13:55:41 2025 +0000 Commit: Sam James <sam <AT> gentoo <DOT> org> CommitDate: Wed Apr 2 13:56:06 2025 +0000 URL: https://gitweb.gentoo.org/proj/gcc-patches.git/commit/?id=966453b9 15.0.0: update musttail patches * Drop the "Don't fail" patch (merged upstream) for clang vs gnu::musttail * Update eh musttail patch Signed-off-by: Sam James <sam <AT> gentoo.org> ...-fail-musttail-calls-if-they-use-or-could.patch | 1124 -------------------- 15.0.0/gentoo/83_all_PR119491-tailcall-eh.patch | 339 +++--- 15.0.0/gentoo/README.history | 1 + 3 files changed, 185 insertions(+), 1279 deletions(-) diff --git a/15.0.0/gentoo/80_all_PR119376-tailc-Don-t-fail-musttail-calls-if-they-use-or-could.patch b/15.0.0/gentoo/80_all_PR119376-tailc-Don-t-fail-musttail-calls-if-they-use-or-could.patch deleted file mode 100644 index d906b0c..0000000 --- a/15.0.0/gentoo/80_all_PR119376-tailc-Don-t-fail-musttail-calls-if-they-use-or-could.patch +++ /dev/null @@ -1,1124 +0,0 @@ -https://inbox.sourceware.org/gcc-patches/Z+JccoSNxYWZIPz5@tucnak/ - -From 4c5f092df307ec34b842483b1702d2e173e592a5 Mon Sep 17 00:00:00 2001 -Message-ID: <4c5f092df307ec34b842483b1702d2e173e592a5.1743280205.git.sam@gentoo.org> -From: Jakub Jelinek <jakub@redhat.com> -Date: Tue, 25 Mar 2025 08:34:10 +0100 -Subject: [PATCH] tailc: Don't fail musttail calls if they use or could use - local arguments, instead warn [PR119376] - -Hi! - -As discussed here and in bugzilla, [[clang::musttail]] attribute in clang -not just strongly asks for tail call or error, but changes behavior. -To quote: -https://clang.llvm.org/docs/AttributeReference.html#musttail -"The lifetimes of all local variables and function parameters end immediately -before the call to the function. This means that it is undefined behaviour -to pass a pointer or reference to a local variable to the called function, -which is not the case without the attribute. Clang will emit a warning in -common cases where this happens." - -The GCC behavior was just to error if we can't prove the musttail callee -could not have dereferenced escaped pointers to local vars or parameters -of the caller. That is still the case for variables with non-trivial -destruction (even in clang), like vars with C++ non-trivial destructors or -variables with cleanup attribute. - -The following patch changes the behavior to match that of clang, for all of -[[clang::musttail]], [[gnu::musttail]] and __attribute__((musttail)). - -clang 20 actually added warning for some cases of it in -https://github.com/llvm/llvm-project/pull/109255 -but it is under -Wreturn-stack-address warning. - -Now, gcc doesn't have that warning, but -Wreturn-local-addr instead, and -IMHO it is better to have this under new warnings, because this isn't about -returning local address, but about passing it to a musttail call, or maybe -escaping to a musttail call. And perhaps users will appreciate they can -control it separately as well. - -The patch introduces 2 new warnings. --Wmusttail-local-addr -which is turn on by default and warns for the always dumb cases of passing -an address of a local variable or parameter to musttail call's argument. -And then --Wmaybe-musttail-local-addr -which is only diagnosed if -Wmusttail-local-addr was not diagnosed and -diagnoses at most one (so that we don't emit 100s of warnings for one call -if 100s of vars can escape) case where an address of a local var could have -escaped to the musttail call. This is less severe, the code doesn't have -to be obviously wrong, so the warning is only enabled in -Wextra. - -And I've adjusted also the documentation for this change and addition of -new warnings. - -Bootstrapped/regtested on x86_64-linux and i686-linux (on top of the -just posted patch), ok for trunk? - -2025-03-25 Jakub Jelinek <jakub@redhat.com> - - PR ipa/119376 - * common.opt (Wmusttail-local-addr, Wmaybe-musttail-local-addr): New. - * tree-tailcall.cc (suitable_for_tail_call_opt_p): Don't fail for - TREE_ADDRESSABLE PARM_DECLs for musttail calls if diag_musttail. - Emit -Wmusttail-local-addr warnings. - (maybe_error_musttail): Use gimple_location instead of directly - accessing location member. - (find_tail_calls): For musttail calls if diag_musttail, don't fail - if address of local could escape to the call, instead emit - -Wmaybe-musttail-local-addr warnings. Emit - -Wmaybe-musttail-local-addr warnings also for address taken - parameters. - * common.opt.urls: Regenerate. - * doc/extend.texi (musttail statement attribute): Clarify local - variables without non-trivial destruction are considered out of scope - before the tail call instruction. - * doc/invoke.texi (-Wno-musttail-local-addr, - -Wmaybe-musttail-local-addr): Document. - - * c-c++-common/musttail8.c: Expect a warning rather than error in one - case. - (f4): Add int * argument. - * c-c++-common/musttail15.c: Don't disallow for C++98. - * c-c++-common/musttail16.c: Likewise. - * c-c++-common/musttail17.c: Likewise. - * c-c++-common/musttail18.c: Likewise. - * c-c++-common/musttail19.c: Likewise. Expect a warning rather than - error in one case. - (f4): Add int * argument. - * c-c++-common/musttail20.c: Don't disallow for C++98. - * c-c++-common/musttail21.c: Likewise. - * c-c++-common/musttail28.c: New test. - * c-c++-common/musttail29.c: New test. - * c-c++-common/musttail30.c: New test. - * c-c++-common/musttail31.c: New test. - * g++.dg/ext/musttail1.C: New test. - * g++.dg/ext/musttail2.C: New test. - * g++.dg/ext/musttail3.C: New test. ---- - gcc/common.opt | 8 ++ - gcc/common.opt.urls | 6 ++ - gcc/doc/extend.texi | 49 ++++++++++- - gcc/doc/invoke.texi | 52 ++++++++++- - gcc/testsuite/c-c++-common/musttail15.c | 2 +- - gcc/testsuite/c-c++-common/musttail16.c | 2 +- - gcc/testsuite/c-c++-common/musttail17.c | 2 +- - gcc/testsuite/c-c++-common/musttail18.c | 2 +- - gcc/testsuite/c-c++-common/musttail19.c | 7 +- - gcc/testsuite/c-c++-common/musttail20.c | 2 +- - gcc/testsuite/c-c++-common/musttail21.c | 2 +- - gcc/testsuite/c-c++-common/musttail28.c | 108 +++++++++++++++++++++++ - gcc/testsuite/c-c++-common/musttail29.c | 109 ++++++++++++++++++++++++ - gcc/testsuite/c-c++-common/musttail30.c | 109 ++++++++++++++++++++++++ - gcc/testsuite/c-c++-common/musttail31.c | 109 ++++++++++++++++++++++++ - gcc/testsuite/c-c++-common/musttail8.c | 5 +- - gcc/testsuite/g++.dg/ext/musttail1.C | 38 +++++++++ - gcc/testsuite/g++.dg/ext/musttail2.C | 38 +++++++++ - gcc/testsuite/g++.dg/ext/musttail3.C | 37 ++++++++ - gcc/tree-tailcall.cc | 97 +++++++++++++++++++-- - 20 files changed, 760 insertions(+), 24 deletions(-) - create mode 100644 gcc/testsuite/c-c++-common/musttail28.c - create mode 100644 gcc/testsuite/c-c++-common/musttail29.c - create mode 100644 gcc/testsuite/c-c++-common/musttail30.c - create mode 100644 gcc/testsuite/c-c++-common/musttail31.c - create mode 100644 gcc/testsuite/g++.dg/ext/musttail1.C - create mode 100644 gcc/testsuite/g++.dg/ext/musttail2.C - create mode 100644 gcc/testsuite/g++.dg/ext/musttail3.C - -diff --git a/gcc/common.opt b/gcc/common.opt -index 2da02866ca08..9400c4b94e88 100644 ---- a/gcc/common.opt -+++ b/gcc/common.opt -@@ -693,6 +693,14 @@ Does nothing. Preserved for backward compatibility. - Wmissing-noreturn - Common Warning Alias(Wsuggest-attribute=noreturn) - -+Wmusttail-local-addr -+Common Var(warn_musttail_local_addr) Init(1) Warning -+Warn about passing a pointer/reference to a local or temporary variable to a musttail call argument. -+ -+Wmaybe-musttail-local-addr -+Common Var(warn_maybe_musttail_local_addr) Warning EnabledBy(Wextra) -+Warn about pointer/reference to a local or temporary variable possibly escaping to a musttail call. -+ - Wodr - Common Var(warn_odr_violations) Init(1) Warning - Warn about some C++ One Definition Rule violations during link time optimization. -diff --git a/gcc/common.opt.urls b/gcc/common.opt.urls -index e7900c825c17..860ebd01ace2 100644 ---- a/gcc/common.opt.urls -+++ b/gcc/common.opt.urls -@@ -157,6 +157,12 @@ UrlSuffix(gcc/Warning-Options.html#index-Wno-unsafe-loop-optimizations) - Wmissing-noreturn - UrlSuffix(gcc/Warning-Options.html#index-Wmissing-noreturn) - -+Wmusttail-local-addr -+UrlSuffix(gcc/Warning-Options.html#index-Wno-musttail-local-addr) -+ -+Wmaybe-musttail-local-addr -+UrlSuffix(gcc/Warning-Options.html#index-Wmaybe-musttail-local-addr) -+ - Wodr - UrlSuffix(gcc/Warning-Options.html#index-Wno-odr) - -diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi -index ed766e53dcc4..fcb6df95dcf5 100644 ---- a/gcc/doc/extend.texi -+++ b/gcc/doc/extend.texi -@@ -9282,10 +9282,51 @@ __attribute__((musttail)) return bar(); - - If the compiler cannot generate a @code{musttail} tail call it will report - an error. On some targets tail calls may never be supported. --Tail calls cannot reference locals in memory, which may affect --builds without optimization when passing small structures, or passing --or returning large structures. Enabling @option{-O1} or @option{-O2} can --improve the success of tail calls. -+The user asserts for @code{musttail} tail calls that lifetime of automatic -+variables, function parameters and temporaries (unless they have non-trivial -+destruction) can end before the actual call instruction and that any access -+to those from inside of the called function results is considered undefined -+behavior. Enabling @option{-O1} or @option{-O2} can improve the success of -+tail calls. -+ -+@smallexample -+int foo (int *); -+void bar (int *); -+struct S @{ S (); ~S (); int s; @}; -+ -+int -+baz (int *x) -+@{ -+ if (*x == 1) -+ @{ -+ int a = 42; -+ /* The call will be tail called (would not be without the -+ attribute), dereferencing the pointer in the callee is -+ undefined behavior and there will be a warning emitted -+ for this by default (@option{-Wmusttail-local-addr}). */ -+ [[gnu::musttail]] return foo (&a); -+ @} -+ else if (*x == 2) -+ @{ -+ int a = 42; -+ bar (&a); -+ /* The call will be tail called (would not be without the -+ attribute), if bar stores the pointer anywhere, dereferencing -+ it in foo will be undefined behavior and there will be a warning -+ emitted for this with @option{-Wextra}, which implies -+ @option{-Wmaybe-musttail-local-addr}. */ -+ [[gnu::musttail]] return foo (nullptr); -+ @} -+ else -+ @{ -+ S s; -+ /* The s variable requires non-trivial destruction which ought -+ to be performed after the foo call returns, so this will -+ be rejected. */ -+ [[gnu::musttail]] return foo (&s.s); -+ @} -+@} -+@end smallexample - @end table - - @node Attribute Syntax -diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi -index df4610908243..2617406b7691 100644 ---- a/gcc/doc/invoke.texi -+++ b/gcc/doc/invoke.texi -@@ -394,7 +394,8 @@ Objective-C and Objective-C++ Dialects}. - -Wmemset-elt-size -Wmemset-transposed-args - -Wmisleading-indentation -Wmissing-attributes -Wmissing-braces - -Wmissing-field-initializers -Wmissing-format-attribute ---Wmissing-include-dirs -Wmissing-noreturn -Wno-missing-profile -+-Wmissing-include-dirs -Wmissing-noreturn -Wmusttail-local-addr -+-Wmaybe-musttail-local-addr -Wno-missing-profile - -Wno-multichar -Wmultistatement-macros -Wnonnull -Wnonnull-compare - -Wnormalized=@r{[}none@r{|}id@r{|}nfc@r{|}nfkc@r{]} - -Wnull-dereference -Wno-odr -@@ -6975,6 +6976,55 @@ is only active when @option{-fdelete-null-pointer-checks} is active, - which is enabled by optimizations in most targets. The precision of - the warnings depends on the optimization options used. - -+@opindex Wno-musttail-local-addr -+@opindex -Wmusttail-local-addr -+@item -Wno-musttail-local-addr -+Do not warn about passing a pointer (or in C++, a reference) to a -+local variable or label to argument of a @code{musttail} call. Those -+variables go out of scope before the tail call instruction. -+ -+@opindex Wmaybe-musttail-local-addr -+@opindex -Wno-maybe-musttail-local-addr -+@item -Wmaybe-musttail-local-addr -+Warn when address of a local variable can escape to a @code{musttail} -+call, unless it goes out of scope already before the @code{musttail} -+call. -+ -+@smallexample -+int foo (int *); -+ -+int -+bar (int *x) -+@{ -+ if (x[0] == 1) -+ @{ -+ int a = 42; -+ foo (&a); -+ /* Without the @code{musttail} attribute this call would not -+ be tail called, because address of the @code{a} variable escapes -+ and the second foo call could dereference it. With the attribute -+ the local variables are assumed to go out of scope immediately -+ before the tail call instruction and the compiler warns about -+ this. */ -+ [[gnu::musttail]] return foo (nullptr); -+ @} -+ else -+ @{ -+ @{ -+ int a = 42; -+ foo (&a); -+ @} -+ /* The @code{a} variable isn't already in scope, so even when it -+ escaped, even without @code{musttail} attribute it would be -+ undefined behavior to dereference it and the compiler could -+ turn this into a tail call. No warning is diagnosed here. */ -+ [[gnu::musttail]] return foo (nullptr); -+ @} -+@} -+@end smallexample -+ -+This warning is enabled by @option{-Wextra}. -+ - @opindex Wnrvo - @opindex Wno-nrvo - @item -Wnrvo @r{(C++ and Objective-C++ only)} -diff --git a/gcc/testsuite/c-c++-common/musttail15.c b/gcc/testsuite/c-c++-common/musttail15.c -index 2addc971922c..b8223d77fd56 100644 ---- a/gcc/testsuite/c-c++-common/musttail15.c -+++ b/gcc/testsuite/c-c++-common/musttail15.c -@@ -1,4 +1,4 @@ --/* { dg-do compile { target { musttail && { c || c++11 } } } } */ -+/* { dg-do compile { target musttail } } */ - /* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */ - - int __attribute__((noinline,noclone,noipa)) -diff --git a/gcc/testsuite/c-c++-common/musttail16.c b/gcc/testsuite/c-c++-common/musttail16.c -index b1e2ff3e6dc8..f27a27923314 100644 ---- a/gcc/testsuite/c-c++-common/musttail16.c -+++ b/gcc/testsuite/c-c++-common/musttail16.c -@@ -1,4 +1,4 @@ --/* { dg-do compile { target { musttail && { c || c++11 } } } } */ -+/* { dg-do compile { target musttail } } */ - - struct box { char field[256]; int i; }; - -diff --git a/gcc/testsuite/c-c++-common/musttail17.c b/gcc/testsuite/c-c++-common/musttail17.c -index 490f3c35ca23..58fab84993bf 100644 ---- a/gcc/testsuite/c-c++-common/musttail17.c -+++ b/gcc/testsuite/c-c++-common/musttail17.c -@@ -1,4 +1,4 @@ --/* { dg-do compile { target { musttail && { c || c++11 } } } } */ -+/* { dg-do compile { target musttail } } */ - - struct box { char field[64]; int i; }; - -diff --git a/gcc/testsuite/c-c++-common/musttail18.c b/gcc/testsuite/c-c++-common/musttail18.c -index 4f34a8d27f36..ab608871fd08 100644 ---- a/gcc/testsuite/c-c++-common/musttail18.c -+++ b/gcc/testsuite/c-c++-common/musttail18.c -@@ -1,4 +1,4 @@ --/* { dg-do compile { target { musttail && { c || c++11 } } } } */ -+/* { dg-do compile { target musttail } } */ - /* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */ - - void __attribute__((noipa)) f() {} -diff --git a/gcc/testsuite/c-c++-common/musttail19.c b/gcc/testsuite/c-c++-common/musttail19.c -index 70f9eaff139c..a592b69c1b7c 100644 ---- a/gcc/testsuite/c-c++-common/musttail19.c -+++ b/gcc/testsuite/c-c++-common/musttail19.c -@@ -1,4 +1,4 @@ --/* { dg-do compile { target { musttail && { c || c++11 } } } } */ -+/* { dg-do compile { target musttail } } */ - - float f1(void); - -@@ -10,8 +10,9 @@ int f2(void) - - int f3(int *); - --int f4(void) -+int f4(int *p) - { - int x; -- __attribute__((musttail)) return f3(&x); /* { dg-error "\(refers to locals|other reasons\)" } */ -+ (void) p; -+ __attribute__((musttail)) return f3(&x); /* { dg-warning "address of automatic variable 'x' passed to 'musttail' call argument" } */ - } -diff --git a/gcc/testsuite/c-c++-common/musttail20.c b/gcc/testsuite/c-c++-common/musttail20.c -index 70f14ff2f217..1931f2cc8e4a 100644 ---- a/gcc/testsuite/c-c++-common/musttail20.c -+++ b/gcc/testsuite/c-c++-common/musttail20.c -@@ -1,4 +1,4 @@ --/* { dg-do compile { target { struct_musttail && { c || c++11 } } } } */ -+/* { dg-do compile { target struct_musttail } } */ - /* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */ - - struct str -diff --git a/gcc/testsuite/c-c++-common/musttail21.c b/gcc/testsuite/c-c++-common/musttail21.c -index 954209ddcd51..1a109e1955dc 100644 ---- a/gcc/testsuite/c-c++-common/musttail21.c -+++ b/gcc/testsuite/c-c++-common/musttail21.c -@@ -1,4 +1,4 @@ --/* { dg-do compile { target { c || c++11 } } } */ -+/* { dg-do compile { target musttail } } */ - void f(void) - { - __attribute__((musttail)) return; /* { dg-error "cannot tail-call.*return value must be a call" } */ -diff --git a/gcc/testsuite/c-c++-common/musttail28.c b/gcc/testsuite/c-c++-common/musttail28.c -new file mode 100644 -index 000000000000..d84658aa8a05 ---- /dev/null -+++ b/gcc/testsuite/c-c++-common/musttail28.c -@@ -0,0 +1,108 @@ -+/* { dg-do compile { target { musttail && { c || c++11 } } } } */ -+ -+int foo (int, void *); -+int bar (int, int *); -+struct S { int a, b, c; }; -+struct T { int d; struct S e; }; -+ -+int -+baz (int x, void *y) -+{ -+ [[gnu::musttail]] return bar (2, &x); /* { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } */ -+} -+ -+int -+qux (int x, void *y) -+{ -+ __label__ lab; -+ lab:; -+ if (*(int *) y == 1) -+ [[gnu::musttail]] return foo (1, &&lab); /* { dg-warning "address of label passed to 'musttail' call argument" } */ -+ if (x == 1) -+ [[gnu::musttail]] return foo (3, 0); -+ else if (x == 2) -+ { -+ { -+ int a = 42; -+ bar (4, &a); -+ } -+ [[gnu::musttail]] return bar (5, 0); -+ } -+ else if (x == 3) -+ { -+ int a = 42; -+ bar (4, &a); -+ [[gnu::musttail]] return bar (6, 0); -+ } -+ else if (x == 4) -+ { -+ int a = 42; -+ [[gnu::musttail]] return bar (7, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 5) -+ { -+ struct T b; -+ [[gnu::musttail]] return bar (8, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 6) -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ [[gnu::musttail]] return bar (10, 0); -+ } -+ else if (x == 7) -+ { -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ } -+ [[gnu::musttail]] return bar (11, 0); -+ } -+ else if (x == 8) -+ { -+ { -+ int a = 42; -+ bar (4, &a); -+ } -+ [[gnu::musttail]] return foo (12, 0); -+ } -+ else if (x == 9) -+ { -+ int a = 42; -+ bar (4, &a); -+ [[gnu::musttail]] return foo (13, 0); -+ } -+ else if (x == 10) -+ { -+ int a = 42; -+ [[gnu::musttail]] return foo (14, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 11) -+ { -+ struct T b; -+ [[gnu::musttail]] return foo (15, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 12) -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ [[gnu::musttail]] return foo (16, 0); -+ } -+ else if (x == 13) -+ { -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ } -+ [[gnu::musttail]] return foo (17, 0); -+ } -+ return 0; -+} -+ -+int -+corge (int x, void *y) -+{ -+ if (*(int *) y == 1) -+ bar (18, &x); -+ [[gnu::musttail]] return bar (2, 0); -+} -diff --git a/gcc/testsuite/c-c++-common/musttail29.c b/gcc/testsuite/c-c++-common/musttail29.c -new file mode 100644 -index 000000000000..f6b3d76abe11 ---- /dev/null -+++ b/gcc/testsuite/c-c++-common/musttail29.c -@@ -0,0 +1,109 @@ -+/* { dg-do compile { target { musttail && { c || c++11 } } } } */ -+/* { dg-options "-O2 -Wmusttail-local-addr" } */ -+ -+int foo (int, void *); -+int bar (int, int *); -+struct S { int a, b, c; }; -+struct T { int d; struct S e; }; -+ -+int -+baz (int x, void *y) -+{ -+ [[gnu::musttail]] return bar (2, &x); /* { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } */ -+} -+ -+int -+qux (int x, void *y) -+{ -+ __label__ lab; -+ lab:; -+ if (*(int *) y == 1) -+ [[gnu::musttail]] return foo (1, &&lab); /* { dg-warning "address of label passed to 'musttail' call argument" } */ -+ if (x == 1) -+ [[gnu::musttail]] return foo (3, 0); -+ else if (x == 2) -+ { -+ { -+ int a = 42; -+ bar (4, &a); -+ } -+ [[gnu::musttail]] return bar (5, 0); -+ } -+ else if (x == 3) -+ { -+ int a = 42; -+ bar (4, &a); -+ [[gnu::musttail]] return bar (6, 0); -+ } -+ else if (x == 4) -+ { -+ int a = 42; -+ [[gnu::musttail]] return bar (7, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 5) -+ { -+ struct T b; -+ [[gnu::musttail]] return bar (8, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 6) -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ [[gnu::musttail]] return bar (10, 0); -+ } -+ else if (x == 7) -+ { -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ } -+ [[gnu::musttail]] return bar (11, 0); -+ } -+ else if (x == 8) -+ { -+ { -+ int a = 42; -+ bar (4, &a); -+ } -+ [[gnu::musttail]] return foo (12, 0); -+ } -+ else if (x == 9) -+ { -+ int a = 42; -+ bar (4, &a); -+ [[gnu::musttail]] return foo (13, 0); -+ } -+ else if (x == 10) -+ { -+ int a = 42; -+ [[gnu::musttail]] return foo (14, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 11) -+ { -+ struct T b; -+ [[gnu::musttail]] return foo (15, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 12) -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ [[gnu::musttail]] return foo (16, 0); -+ } -+ else if (x == 13) -+ { -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ } -+ [[gnu::musttail]] return foo (17, 0); -+ } -+ return 0; -+} -+ -+int -+corge (int x, void *y) -+{ -+ if (*(int *) y == 1) -+ bar (18, &x); -+ [[gnu::musttail]] return bar (2, 0); -+} -diff --git a/gcc/testsuite/c-c++-common/musttail30.c b/gcc/testsuite/c-c++-common/musttail30.c -new file mode 100644 -index 000000000000..be1c3daf6af2 ---- /dev/null -+++ b/gcc/testsuite/c-c++-common/musttail30.c -@@ -0,0 +1,109 @@ -+/* { dg-do compile { target { musttail && { c || c++11 } } } } */ -+/* { dg-options "-Wextra" } */ -+ -+int foo (int, void *); -+int bar (int, int *); -+struct S { int a, b, c; }; -+struct T { int d; struct S e; }; -+ -+int -+baz (int x, void *y) -+{ -+ [[gnu::musttail]] return bar (2, &x); /* { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } */ -+} -+ -+int -+qux (int x, void *y) -+{ -+ __label__ lab; -+ lab:; -+ if (*(int *) y == 1) -+ [[gnu::musttail]] return foo (1, &&lab); /* { dg-warning "address of label passed to 'musttail' call argument" } */ -+ if (x == 1) -+ [[gnu::musttail]] return foo (3, 0); -+ else if (x == 2) -+ { -+ { -+ int a = 42; -+ bar (4, &a); -+ } -+ [[gnu::musttail]] return bar (5, 0); -+ } -+ else if (x == 3) -+ { -+ int a = 42; -+ bar (4, &a); -+ [[gnu::musttail]] return bar (6, 0); /* { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" } */ -+ } -+ else if (x == 4) -+ { -+ int a = 42; -+ [[gnu::musttail]] return bar (7, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 5) -+ { -+ struct T b; -+ [[gnu::musttail]] return bar (8, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 6) -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ [[gnu::musttail]] return bar (10, 0); /* { dg-warning "address of automatic variable 'b' can escape to 'musttail' call" } */ -+ } -+ else if (x == 7) -+ { -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ } -+ [[gnu::musttail]] return bar (11, 0); -+ } -+ else if (x == 8) -+ { -+ { -+ int a = 42; -+ bar (4, &a); -+ } -+ [[gnu::musttail]] return foo (12, 0); -+ } -+ else if (x == 9) -+ { -+ int a = 42; -+ bar (4, &a); -+ [[gnu::musttail]] return foo (13, 0); /* { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" } */ -+ } -+ else if (x == 10) -+ { -+ int a = 42; -+ [[gnu::musttail]] return foo (14, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 11) -+ { -+ struct T b; -+ [[gnu::musttail]] return foo (15, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 12) -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ [[gnu::musttail]] return foo (16, 0); /* { dg-warning "address of automatic variable 'b' can escape to 'musttail' call" } */ -+ } -+ else if (x == 13) -+ { -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ } -+ [[gnu::musttail]] return foo (17, 0); -+ } -+ return 0; -+} -+ -+int -+corge (int x, void *y) -+{ -+ if (*(int *) y == 1) -+ bar (18, &x); -+ [[gnu::musttail]] return bar (2, 0); /* { dg-warning "address of parameter 'x' can escape to 'musttail' call" } */ -+} -diff --git a/gcc/testsuite/c-c++-common/musttail31.c b/gcc/testsuite/c-c++-common/musttail31.c -new file mode 100644 -index 000000000000..f44ada4d4733 ---- /dev/null -+++ b/gcc/testsuite/c-c++-common/musttail31.c -@@ -0,0 +1,109 @@ -+/* { dg-do compile { target { musttail && { c || c++11 } } } } */ -+/* { dg-options "-O2 -Wmaybe-musttail-local-addr" } */ -+ -+int foo (int, void *); -+int bar (int, int *); -+struct S { int a, b, c; }; -+struct T { int d; struct S e; }; -+ -+int -+baz (int x, void *y) -+{ -+ [[gnu::musttail]] return bar (2, &x); /* { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } */ -+} -+ -+int -+qux (int x, void *y) -+{ -+ __label__ lab; -+ lab:; -+ if (*(int *) y == 1) -+ [[gnu::musttail]] return foo (1, &&lab); /* { dg-warning "address of label passed to 'musttail' call argument" } */ -+ if (x == 1) -+ [[gnu::musttail]] return foo (3, 0); -+ else if (x == 2) -+ { -+ { -+ int a = 42; -+ bar (4, &a); -+ } -+ [[gnu::musttail]] return bar (5, 0); -+ } -+ else if (x == 3) -+ { -+ int a = 42; -+ bar (4, &a); -+ [[gnu::musttail]] return bar (6, 0); /* { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" } */ -+ } -+ else if (x == 4) -+ { -+ int a = 42; -+ [[gnu::musttail]] return bar (7, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 5) -+ { -+ struct T b; -+ [[gnu::musttail]] return bar (8, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 6) -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ [[gnu::musttail]] return bar (10, 0); /* { dg-warning "address of automatic variable 'b' can escape to 'musttail' call" } */ -+ } -+ else if (x == 7) -+ { -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ } -+ [[gnu::musttail]] return bar (11, 0); -+ } -+ else if (x == 8) -+ { -+ { -+ int a = 42; -+ bar (4, &a); -+ } -+ [[gnu::musttail]] return foo (12, 0); -+ } -+ else if (x == 9) -+ { -+ int a = 42; -+ bar (4, &a); -+ [[gnu::musttail]] return foo (13, 0); /* { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" } */ -+ } -+ else if (x == 10) -+ { -+ int a = 42; -+ [[gnu::musttail]] return foo (14, &a); /* { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 11) -+ { -+ struct T b; -+ [[gnu::musttail]] return foo (15, &b.e.b); /* { dg-warning "address of automatic variable 'b' passed to 'musttail' call argument" } */ -+ } -+ else if (x == 12) -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ [[gnu::musttail]] return foo (16, 0); /* { dg-warning "address of automatic variable 'b' can escape to 'musttail' call" } */ -+ } -+ else if (x == 13) -+ { -+ { -+ struct T b; -+ bar (9, &b.e.a); -+ } -+ [[gnu::musttail]] return foo (17, 0); -+ } -+ return 0; -+} -+ -+int -+corge (int x, void *y) -+{ -+ if (*(int *) y == 1) -+ bar (18, &x); -+ [[gnu::musttail]] return bar (2, 0); /* { dg-warning "address of parameter 'x' can escape to 'musttail' call" } */ -+} -diff --git a/gcc/testsuite/c-c++-common/musttail8.c b/gcc/testsuite/c-c++-common/musttail8.c -index 50ca1ac0dd48..9a29030a3b06 100644 ---- a/gcc/testsuite/c-c++-common/musttail8.c -+++ b/gcc/testsuite/c-c++-common/musttail8.c -@@ -10,8 +10,9 @@ int f2(void) - - int f3(int *); - --int f4(void) -+int f4(int *p) - { - int x; -- [[gnu::musttail]] return f3(&x); /* { dg-error "\(refers to locals|other reasons\)" } */ -+ (void) p; -+ [[gnu::musttail]] return f3(&x); /* { dg-warning "address of automatic variable 'x' passed to 'musttail' call argument" } */ - } -diff --git a/gcc/testsuite/g++.dg/ext/musttail1.C b/gcc/testsuite/g++.dg/ext/musttail1.C -new file mode 100644 -index 000000000000..fd9b386a5974 ---- /dev/null -+++ b/gcc/testsuite/g++.dg/ext/musttail1.C -@@ -0,0 +1,38 @@ -+// PR ipa/119376 -+// { dg-do compile { target { musttail && c++11 } } } -+// { dg-options "-Wmaybe-musttail-local-addr" } -+ -+int foo (int &); -+int bar (int &&); -+int corge (int *); -+ -+int -+baz (int &x) -+{ -+ if (x == 1) -+ [[gnu::musttail]] return foo (x); -+ if (x == 2) -+ { -+ int a = 42; -+ [[gnu::musttail]] return foo (a); // { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } -+ } -+ if (x == 3) -+ { -+ int a = 42; -+ foo (a); -+ [[gnu::musttail]] return foo (x); // { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" } -+ } -+ return 0; -+} -+ -+int -+qux (int &&x) -+{ -+ [[gnu::musttail]] return bar (x + 1); // { dg-warning "address of local variable passed to 'musttail' call argument" } -+} -+ -+int -+freddy (int x) -+{ -+ [[gnu::musttail]] return foo (x); // { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } -+} -diff --git a/gcc/testsuite/g++.dg/ext/musttail2.C b/gcc/testsuite/g++.dg/ext/musttail2.C -new file mode 100644 -index 000000000000..ac99aafb0f0c ---- /dev/null -+++ b/gcc/testsuite/g++.dg/ext/musttail2.C -@@ -0,0 +1,38 @@ -+// PR ipa/119376 -+// { dg-do compile { target { musttail && c++11 } } } -+// { dg-options "-Wextra" } -+ -+int foo (int &); -+int bar (int &&); -+int corge (int *); -+ -+int -+baz (int &x) -+{ -+ if (x == 1) -+ [[clang::musttail]] return foo (x); -+ if (x == 2) -+ { -+ int a = 42; -+ [[clang::musttail]] return foo (a); // { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } -+ } -+ if (x == 3) -+ { -+ int a = 42; -+ foo (a); -+ [[clang::musttail]] return foo (x); // { dg-warning "address of automatic variable 'a' can escape to 'musttail' call" } -+ } -+ return 0; -+} -+ -+int -+qux (int &&x) -+{ -+ [[clang::musttail]] return bar (x + 1); // { dg-warning "address of local variable passed to 'musttail' call argument" } -+} -+ -+int -+freddy (int x) -+{ -+ [[clang::musttail]] return foo (x); // { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } -+} -diff --git a/gcc/testsuite/g++.dg/ext/musttail3.C b/gcc/testsuite/g++.dg/ext/musttail3.C -new file mode 100644 -index 000000000000..1c4b939a2a43 ---- /dev/null -+++ b/gcc/testsuite/g++.dg/ext/musttail3.C -@@ -0,0 +1,37 @@ -+// PR ipa/119376 -+// { dg-do compile { target { musttail && c++11 } } } -+ -+int foo (int &); -+int bar (int &&); -+int corge (int *); -+ -+int -+baz (int &x) -+{ -+ if (x == 1) -+ [[gnu::musttail]] return foo (x); -+ if (x == 2) -+ { -+ int a = 42; -+ [[gnu::musttail]] return foo (a); // { dg-warning "address of automatic variable 'a' passed to 'musttail' call argument" } -+ } -+ if (x == 3) -+ { -+ int a = 42; -+ foo (a); -+ [[gnu::musttail]] return foo (x); -+ } -+ return 0; -+} -+ -+int -+qux (int &&x) -+{ -+ [[gnu::musttail]] return bar (x + 1); // { dg-warning "address of local variable passed to 'musttail' call argument" } -+} -+ -+int -+freddy (int x) -+{ -+ [[gnu::musttail]] return foo (x); // { dg-warning "address of parameter 'x' passed to 'musttail' call argument" } -+} -diff --git a/gcc/tree-tailcall.cc b/gcc/tree-tailcall.cc -index 8ba675221915..e025a1cb78b2 100644 ---- a/gcc/tree-tailcall.cc -+++ b/gcc/tree-tailcall.cc -@@ -206,14 +206,48 @@ suitable_for_tail_call_opt_p (gcall *call, bool diag_musttail) - - /* ??? It is OK if the argument of a function is taken in some cases, - but not in all cases. See PR15387 and PR19616. Revisit for 4.1. */ -- for (param = DECL_ARGUMENTS (current_function_decl); -- param; -- param = DECL_CHAIN (param)) -- if (TREE_ADDRESSABLE (param)) -+ if (!diag_musttail || !gimple_call_must_tail_p (call)) -+ for (param = DECL_ARGUMENTS (current_function_decl); -+ param; param = DECL_CHAIN (param)) -+ if (TREE_ADDRESSABLE (param)) -+ { -+ maybe_error_musttail (call, _("address of caller arguments taken"), -+ diag_musttail); -+ return false; -+ } -+ -+ if (diag_musttail -+ && gimple_call_must_tail_p (call) -+ && warn_musttail_local_addr) -+ for (unsigned int i = 0; i < gimple_call_num_args (call); i++) - { -- maybe_error_musttail (call, _("address of caller arguments taken"), -- diag_musttail); -- return false; -+ tree arg = gimple_call_arg (call, i); -+ if (!POINTER_TYPE_P (TREE_TYPE (arg))) -+ continue; -+ if (TREE_CODE (arg) == ADDR_EXPR) -+ { -+ arg = get_base_address (TREE_OPERAND (arg, 0)); -+ if (auto_var_in_fn_p (arg, current_function_decl)) -+ { -+ if (TREE_CODE (arg) == LABEL_DECL) -+ warning_at (gimple_location (call), OPT_Wmusttail_local_addr, -+ "address of label passed to %<musttail%> " -+ "call argument"); -+ else if (TREE_CODE (arg) == PARM_DECL) -+ warning_at (gimple_location (call), OPT_Wmusttail_local_addr, -+ "address of parameter %qD passed to " -+ "%<musttail%> call argument", arg); -+ else if (!DECL_ARTIFICIAL (arg) && DECL_NAME (arg)) -+ warning_at (gimple_location (call), OPT_Wmusttail_local_addr, -+ "address of automatic variable %qD passed to " -+ "%<musttail%> call argument", arg); -+ else -+ warning_at (gimple_location (call), OPT_Wmusttail_local_addr, -+ "address of local variable passed to " -+ "%<musttail%> call argument"); -+ suppress_warning (call, OPT_Wmaybe_musttail_local_addr); -+ } -+ } - } - - return true; -@@ -443,7 +477,7 @@ maybe_error_musttail (gcall *call, const char *err, bool diag_musttail) - { - if (gimple_call_must_tail_p (call) && diag_musttail) - { -- error_at (call->location, "cannot tail-call: %s", err); -+ error_at (gimple_location (call), "cannot tail-call: %s", err); - /* Avoid another error. ??? If there are multiple reasons why tail - calls fail it might be useful to report them all to avoid - whack-a-mole for the user. But currently there is too much -@@ -728,6 +762,19 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, - { - if (!VAR_P (var)) - { -+ if (diag_musttail && gimple_call_must_tail_p (call)) -+ { -+ auto opt = OPT_Wmaybe_musttail_local_addr; -+ if (!warning_suppressed_p (call, -+ opt)) -+ { -+ warning_at (gimple_location (call), opt, -+ "address of local variable can escape to " -+ "%<musttail%> call"); -+ suppress_warning (call, opt); -+ } -+ continue; -+ } - if (local_live_vars) - BITMAP_FREE (local_live_vars); - maybe_error_musttail (call, -@@ -740,6 +787,24 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, - unsigned int *v = live_vars->get (DECL_UID (var)); - if (bitmap_bit_p (local_live_vars, *v)) - { -+ if (diag_musttail && gimple_call_must_tail_p (call)) -+ { -+ auto opt = OPT_Wmaybe_musttail_local_addr; -+ if (!warning_suppressed_p (call, opt)) -+ { -+ if (!DECL_ARTIFICIAL (var) && DECL_NAME (var)) -+ warning_at (gimple_location (call), opt, -+ "address of automatic variable %qD " -+ "can escape to %<musttail%> call", -+ var); -+ else -+ warning_at (gimple_location (call), opt, -+ "address of local variable can escape " -+ "to %<musttail%> call"); -+ suppress_warning (call, opt); -+ } -+ continue; -+ } - BITMAP_FREE (local_live_vars); - maybe_error_musttail (call, - _("call invocation refers to locals"), -@@ -749,6 +814,22 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, - } - } - } -+ if (diag_musttail -+ && gimple_call_must_tail_p (call) -+ && !warning_suppressed_p (call, OPT_Wmaybe_musttail_local_addr)) -+ for (tree param = DECL_ARGUMENTS (current_function_decl); -+ param; param = DECL_CHAIN (param)) -+ if (may_be_aliased (param) -+ && (ref_maybe_used_by_stmt_p (call, param, false) -+ || call_may_clobber_ref_p (call, param, false))) -+ { -+ auto opt = OPT_Wmaybe_musttail_local_addr; -+ warning_at (gimple_location (call), opt, -+ "address of parameter %qD can escape to " -+ "%<musttail%> call", param); -+ suppress_warning (call, opt); -+ break; -+ } - - if (local_live_vars) - BITMAP_FREE (local_live_vars); - -base-commit: eb26b667518c951d06f3c51118a1d41dcdda8b99 --- -2.49.0 - diff --git a/15.0.0/gentoo/83_all_PR119491-tailcall-eh.patch b/15.0.0/gentoo/83_all_PR119491-tailcall-eh.patch index 339ba64..1873a71 100644 --- a/15.0.0/gentoo/83_all_PR119491-tailcall-eh.patch +++ b/15.0.0/gentoo/83_all_PR119491-tailcall-eh.patch @@ -1,20 +1,22 @@ -https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119491#c4 +https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119491#c5 2025-04-01 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/119491 - * tree-tailcall.cc (independent_of_stmt_p): Use - find_fallthru_edge (bb->succs)->dest instead of single_succ (bb). + * tree-tailcall.cc (single_non_eh_succ_edge): New function. + (independent_of_stmt_p): Use single_non_eh_succ_edge (bb)->dest + instead of single_succ (bb). (empty_eh_cleanup): New function. (find_tail_calls): Diagnose throwing of exceptions which do not propagate only if there are no EDGE_EH successor edges. If there are and the call is musttail, use empty_eh_cleanup to find if the cleanup is not empty. If not or the call is not musttail, use different diagnostics. Set is_noreturn even if there are successor edges. Use - find_fallthru_edge (abb->succs) instead of single_succ_edge (abb). + single_non_eh_succ_edge (abb) instead of single_succ_edge (abb). Punt + on internal noreturn calls. (decrease_profile): Don't assert 0 or 1 successor edges. (eliminate_tail_call): Use - find_fallthru_edge (gsi_bb (t->call_gsi)->succs) instead of + single_non_eh_succ_edge (gsi_bb (t->call_gsi)) instead of single_succ_edge (gsi_bb (t->call_gsi)). (tree_optimize_tail_calls_1): Also look into basic blocks with single succ edge which is EDGE_EH for noreturn musttail calls. @@ -22,164 +24,52 @@ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119491#c4 * g++.dg/opt/musttail3.C: New test. * g++.dg/opt/musttail4.C: New test. * g++.dg/opt/musttail5.C: New test. -diff --git a/gcc/testsuite/g++.dg/opt/musttail3.C b/gcc/testsuite/g++.dg/opt/musttail3.C -new file mode 100644 -index 000000000000..1c4e54952b1e ---- /dev/null -+++ b/gcc/testsuite/g++.dg/opt/musttail3.C -@@ -0,0 +1,41 @@ -+// PR tree-optimization/119491 -+// { dg-do compile { target { external_musttail && c++11 } } } -+// { dg-options "-O2" } -+ -+struct A { -+ struct B {}; -+ A () {} -+}; -+void qux (); -+unsigned char v; -+A w; -+void foo (A); -+ -+template <typename T> -+[[gnu::always_inline]] static inline void -+bar (int &) -+{ -+} -+ -+[[gnu::always_inline]] static inline void -+baz (int *) -+{ -+ int r = 0; -+ bar<int> (r); -+} -+ -+[[gnu::always_inline]] inline void -+corge (A) -+{ -+ if (v) -+ qux (); -+ [[gnu::musttail]] return foo (w); -+} -+ -+void -+freddy (A) -+{ -+ int t; -+ baz (&t); -+ [[gnu::musttail]] return corge (A{}); -+} -diff --git a/gcc/testsuite/g++.dg/opt/musttail4.C b/gcc/testsuite/g++.dg/opt/musttail4.C -new file mode 100644 -index 000000000000..ede2959f7d74 ---- /dev/null -+++ b/gcc/testsuite/g++.dg/opt/musttail4.C -@@ -0,0 +1,35 @@ -+// { dg-do compile { target { external_musttail && c++11 } } } -+// { dg-options "-O2 -fexceptions" } -+ -+struct S { ~S (); }; -+volatile int v; -+struct T { ~T () { v = v + 1; } }; -+struct U { ~U () {} }; -+int foo (); -+ -+int -+bar () noexcept -+{ -+ [[gnu::musttail]] return foo (); // { dg-error "cannot tail-call: call may throw exception that does not propagate" } -+} -+ -+int -+baz () -+{ -+ S s; -+ [[gnu::musttail]] return foo (); // { dg-error "cannot tail-call: other reasons" } -+} -+ -+int -+qux () -+{ -+ T t; -+ [[gnu::musttail]] return foo (); // { dg-error "cannot tail-call: other reasons" } -+} -+ -+int -+corge () -+{ -+ U u; -+ [[gnu::musttail]] return foo (); -+} -diff --git a/gcc/testsuite/g++.dg/opt/musttail5.C b/gcc/testsuite/g++.dg/opt/musttail5.C -new file mode 100644 -index 000000000000..604dd6907aa9 ---- /dev/null -+++ b/gcc/testsuite/g++.dg/opt/musttail5.C -@@ -0,0 +1,41 @@ -+// PR tree-optimization/119491 -+// { dg-do compile { target { external_musttail && c++11 } } } -+// { dg-options "-O2" } -+ -+struct A { -+ struct B {}; -+ A () {} -+}; -+void qux (); -+unsigned char v; -+A w; -+[[noreturn]] void foo (A); -+ -+template <typename T> -+[[gnu::always_inline]] static inline void -+bar (int &) -+{ -+} -+ -+[[gnu::always_inline]] static inline void -+baz (int *) -+{ -+ int r = 0; -+ bar<int> (r); -+} + +--- a/gcc/tree-tailcall.cc 2025-04-01 16:47:30.373502796 +0200 ++++ b/gcc/tree-tailcall.cc 2025-04-02 09:02:35.572760732 +0200 +@@ -219,6 +219,23 @@ suitable_for_tail_call_opt_p (gcall *cal + return true; + } + ++/* Return single successor edge ignoring EDGE_EH edges. */ + -+[[gnu::always_inline]] inline void -+corge (A) ++static edge ++single_non_eh_succ_edge (basic_block bb) +{ -+ if (v) -+ qux (); -+ [[gnu::musttail]] return foo (w); ++ edge e, ret = NULL; ++ edge_iterator ei; ++ FOR_EACH_EDGE (e, ei, bb->succs) ++ if ((e->flags & EDGE_EH) == 0) ++ { ++ gcc_assert (ret == NULL); ++ ret = e; ++ } ++ gcc_assert (ret); ++ return ret; +} + -+void -+freddy (A) -+{ -+ int t; -+ baz (&t); -+ [[gnu::musttail]] return corge (A{}); -+} -diff --git a/gcc/tree-tailcall.cc b/gcc/tree-tailcall.cc -index e71341bfb2bc..b910dce7acbd 100644 ---- a/gcc/tree-tailcall.cc -+++ b/gcc/tree-tailcall.cc -@@ -245,7 +245,7 @@ independent_of_stmt_p (tree expr, gimple *at, gimple_stmt_iterator gsi, + /* Checks whether the expression EXPR in stmt AT is independent of the + statement pointed to by GSI (in a sense that we already know EXPR's value + at GSI). We use the fact that we are only called from the chain of +@@ -245,7 +262,7 @@ independent_of_stmt_p (tree expr, gimple /* Mark the blocks in the chain leading to the end. */ at_bb = gimple_bb (at); call_bb = gimple_bb (gsi_stmt (gsi)); - for (bb = call_bb; bb != at_bb; bb = single_succ (bb)) -+ for (bb = call_bb; bb != at_bb; bb = find_fallthru_edge (bb->succs)->dest) ++ for (bb = call_bb; bb != at_bb; bb = single_non_eh_succ_edge (bb)->dest) bb->aux = &bb->aux; bb->aux = &bb->aux; -@@ -289,7 +289,7 @@ independent_of_stmt_p (tree expr, gimple *at, gimple_stmt_iterator gsi, +@@ -289,7 +306,7 @@ independent_of_stmt_p (tree expr, gimple } /* Unmark the blocks. */ - for (bb = call_bb; bb != at_bb; bb = single_succ (bb)) -+ for (bb = call_bb; bb != at_bb; bb = find_fallthru_edge (bb->succs)->dest) ++ for (bb = call_bb; bb != at_bb; bb = single_non_eh_succ_edge (bb)->dest) bb->aux = NULL; bb->aux = NULL; -@@ -462,6 +462,33 @@ maybe_error_musttail (gcall *call, const char *err, bool diag_musttail) +@@ -462,6 +479,33 @@ maybe_error_musttail (gcall *call, const } } @@ -213,7 +103,7 @@ index e71341bfb2bc..b910dce7acbd 100644 /* Argument for compute_live_vars/live_vars_at_stmt and what compute_live_vars returns. Computed lazily, but just once for the function. */ static live_vars_map *live_vars; -@@ -612,14 +639,35 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, +@@ -612,14 +656,36 @@ find_tail_calls (basic_block bb, struct if ((stmt_could_throw_p (cfun, stmt) && !stmt_can_throw_external (cfun, stmt)) || EDGE_COUNT (bb->succs) > 1) { @@ -247,7 +137,8 @@ index e71341bfb2bc..b910dce7acbd 100644 + } + + if (!gimple_call_must_tail_p (call) -+ || !empty_eh_cleanup (e->dest, 20)) ++ || !empty_eh_cleanup (e->dest, 20) ++ || EDGE_COUNT (bb->succs) > 2) + { + maybe_error_musttail (call, + _("call may throw exception caught locally " @@ -257,7 +148,7 @@ index e71341bfb2bc..b910dce7acbd 100644 } /* If the function returns a value, then at present, the tail call -@@ -763,8 +811,7 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, +@@ -763,8 +829,7 @@ find_tail_calls (basic_block bb, struct a = NULL_TREE; auto_bitmap to_move_defs; auto_vec<gimple *> to_move_stmts; @@ -267,19 +158,31 @@ index e71341bfb2bc..b910dce7acbd 100644 abb = bb; agsi = gsi; -@@ -776,8 +823,9 @@ find_tail_calls (basic_block bb, struct tailcall **ret, bool only_musttail, +@@ -776,8 +841,9 @@ find_tail_calls (basic_block bb, struct while (gsi_end_p (agsi)) { - ass_var = propagate_through_phis (ass_var, single_succ_edge (abb)); - abb = single_succ (abb); -+ edge e = find_fallthru_edge (abb->succs); ++ edge e = single_non_eh_succ_edge (abb); + ass_var = propagate_through_phis (ass_var, e); + abb = e->dest; agsi = gsi_start_bb (abb); } -@@ -1112,11 +1160,6 @@ static void +@@ -851,6 +917,11 @@ find_tail_calls (basic_block bb, struct + /* See if this is a tail call we can handle. */ + if (is_noreturn) + { ++ if (gimple_call_internal_p (call)) ++ { ++ maybe_error_musttail (call, _("internal call"), diag_musttail); ++ return; ++ } + tree rettype = TREE_TYPE (TREE_TYPE (current_function_decl)); + tree calltype = TREE_TYPE (gimple_call_fntype (call)); + if (!VOID_TYPE_P (rettype) +@@ -1112,11 +1183,6 @@ static void decrease_profile (basic_block bb, profile_count count) { bb->count = bb->count - count; @@ -291,16 +194,16 @@ index e71341bfb2bc..b910dce7acbd 100644 } /* Eliminates tail call described by T. TMP_VARS is a list of -@@ -1181,7 +1224,7 @@ eliminate_tail_call (struct tailcall *t, class loop *&new_loop) +@@ -1181,7 +1247,7 @@ eliminate_tail_call (struct tailcall *t, else { /* Number of executions of function has reduced by the tailcall. */ - e = single_succ_edge (gsi_bb (t->call_gsi)); -+ e = find_fallthru_edge (gsi_bb (t->call_gsi)->succs); ++ e = single_non_eh_succ_edge (gsi_bb (t->call_gsi)); profile_count count = e->count (); -@@ -1196,8 +1239,7 @@ eliminate_tail_call (struct tailcall *t, class loop *&new_loop) +@@ -1196,8 +1262,7 @@ eliminate_tail_call (struct tailcall *t, decrease_profile (e->dest, count); /* Replace the call by a jump to the start of function. */ @@ -310,7 +213,7 @@ index e71341bfb2bc..b910dce7acbd 100644 } gcc_assert (e); PENDING_STMT (e) = NULL; -@@ -1362,7 +1404,9 @@ tree_optimize_tail_calls_1 (bool opt_tailcalls, bool only_musttail, +@@ -1362,7 +1427,9 @@ tree_optimize_tail_calls_1 (bool opt_tai { basic_block bb; FOR_EACH_BB_FN (bb, cfun) @@ -321,3 +224,129 @@ index e71341bfb2bc..b910dce7acbd 100644 if (gimple *c = last_nondebug_stmt (bb)) if (is_gimple_call (c) && gimple_call_must_tail_p (as_a <gcall *> (c)) +--- a/gcc/testsuite/g++.dg/opt/musttail3.C 2025-04-01 18:47:10.474945080 +0200 ++++ b/gcc/testsuite/g++.dg/opt/musttail3.C 2025-04-01 18:49:27.063068029 +0200 +@@ -0,0 +1,41 @@ ++// PR tree-optimization/119491 ++// { dg-do compile { target { external_musttail && c++11 } } } ++// { dg-options "-O2" } ++ ++struct A { ++ struct B {}; ++ A () {} ++}; ++void qux (); ++unsigned char v; ++A w; ++void foo (A); ++ ++template <typename T> ++[[gnu::always_inline]] static inline void ++bar (int &) ++{ ++} ++ ++[[gnu::always_inline]] static inline void ++baz (int *) ++{ ++ int r = 0; ++ bar<int> (r); ++} ++ ++[[gnu::always_inline]] inline void ++corge (A) ++{ ++ if (v) ++ qux (); ++ [[gnu::musttail]] return foo (w); ++} ++ ++void ++freddy (A) ++{ ++ int t; ++ baz (&t); ++ [[gnu::musttail]] return corge (A{}); ++} +--- a/gcc/testsuite/g++.dg/opt/musttail4.C 2025-04-01 19:10:56.389350911 +0200 ++++ b/gcc/testsuite/g++.dg/opt/musttail4.C 2025-04-01 19:28:18.285020409 +0200 +@@ -0,0 +1,35 @@ ++// { dg-do compile { target { external_musttail && c++11 } } } ++// { dg-options "-O2 -fexceptions" } ++ ++struct S { ~S (); }; ++volatile int v; ++struct T { ~T () { v = v + 1; } }; ++struct U { ~U () {} }; ++int foo (); ++ ++int ++bar () noexcept ++{ ++ [[gnu::musttail]] return foo (); // { dg-error "cannot tail-call: call may throw exception that does not propagate" } ++} ++ ++int ++baz () ++{ ++ S s; ++ [[gnu::musttail]] return foo (); // { dg-error "cannot tail-call: other reasons" } ++} ++ ++int ++qux () ++{ ++ T t; ++ [[gnu::musttail]] return foo (); // { dg-error "cannot tail-call: other reasons" } ++} ++ ++int ++corge () ++{ ++ U u; ++ [[gnu::musttail]] return foo (); ++} +--- a/gcc/testsuite/g++.dg/opt/musttail5.C 2025-04-01 19:14:50.981127712 +0200 ++++ b/gcc/testsuite/g++.dg/opt/musttail5.C 2025-04-01 19:11:25.249954382 +0200 +@@ -0,0 +1,41 @@ ++// PR tree-optimization/119491 ++// { dg-do compile { target { external_musttail && c++11 } } } ++// { dg-options "-O2" } ++ ++struct A { ++ struct B {}; ++ A () {} ++}; ++void qux (); ++unsigned char v; ++A w; ++[[noreturn]] void foo (A); ++ ++template <typename T> ++[[gnu::always_inline]] static inline void ++bar (int &) ++{ ++} ++ ++[[gnu::always_inline]] static inline void ++baz (int *) ++{ ++ int r = 0; ++ bar<int> (r); ++} ++ ++[[gnu::always_inline]] inline void ++corge (A) ++{ ++ if (v) ++ qux (); ++ [[gnu::musttail]] return foo (w); ++} ++ ++void ++freddy (A) ++{ ++ int t; ++ baz (&t); ++ [[gnu::musttail]] return corge (A{}); ++} diff --git a/15.0.0/gentoo/README.history b/15.0.0/gentoo/README.history index b497164..8223363 100644 --- a/15.0.0/gentoo/README.history +++ b/15.0.0/gentoo/README.history @@ -1,5 +1,6 @@ 51 ???? + - 80_all_PR119376-tailc-Don-t-fail-musttail-calls-if-they-use-or-could.patch + 82_all_PR119318-ipa-cp.patch + 83_all_PR119491-tailcall-eh.patch