On Tue, Jul 16, 2024 at 06:06:42PM -0400, Jason Merrill wrote: > On 7/16/24 5:55 PM, Andi Kleen wrote: > > On Tue, Jul 16, 2024 at 12:52:31PM -0700, Andi Kleen wrote: > > > On Tue, Jul 16, 2024 at 02:51:13PM -0400, Jason Merrill wrote: > > > > On 7/16/24 12:18 PM, Andi Kleen wrote: > > > > > On Tue, Jul 16, 2024 at 11:17:14AM -0400, Jason Merrill wrote: > > > > > > On 7/16/24 11:15 AM, Andi Kleen wrote: > > > > > > > > In the adjusted test it looks like the types of f and g match, > > > > > > > > so I wouldn't > > > > > > > > expect an error. > > > > > > > > > > > > > > Good point! Missing the forest for the trees. > > > > > > > > > > > > > > Anyways are the C++ patches ok with this change? > > > > > > > > > > > > I'm still looking for a test which does error because the types are > > > > > > different. > > > > > > > > > > Like this? > > > > > > > > Where the called function returns C and the callee function does not. > > > > > > In this case the attribute seems to get lost and it succeeds. > > > > This somewhat hackish patch fixes it here, to handle the case > > of a TARGET_EXPR where the CALL_EXPR is in the cleanup. extract_call > > bails on that. > > The CALL_EXPR in the cleanup is calling the destructor, that's not what > we're trying to tail-call. > > I think the problem here is that the call to f<C> is represented with an > AGGR_INIT_EXPR instead of CALL_EXPR, so you need to handle the flag on that > tree_code as well.
Okay this seems to work (I had to adjust the test case because it now correctly errors out on passing the class at -O0) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 4bb3e9c4989b..5ec8102c1849 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -4245,6 +4245,10 @@ templated_operator_saved_lookups (tree t) #define AGGR_INIT_FROM_THUNK_P(NODE) \ (AGGR_INIT_EXPR_CHECK (NODE)->base.protected_flag) +/* Nonzero means that the call was marked musttail. */ +#define AGGR_INIT_EXPR_MUST_TAIL(NODE) \ + (AGGR_INIT_EXPR_CHECK (NODE)->base.static_flag) + /* AGGR_INIT_EXPR accessors. These are equivalent to the CALL_EXPR accessors, except for AGGR_INIT_EXPR_SLOT (which takes the place of CALL_EXPR_STATIC_CHAIN). */ diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index 3b914089a6e2..d668c5af6a23 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -21124,6 +21124,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl) CALL_EXPR_REVERSE_ARGS (call) = rev; if (TREE_CODE (call) == CALL_EXPR) CALL_EXPR_MUST_TAIL_CALL (call) = mtc; + else if (TREE_CODE (call) == AGGR_INIT_EXPR) + AGGR_INIT_EXPR_MUST_TAIL (call) = mtc; } if (warning_suppressed_p (t, OPT_Wpessimizing_move)) /* This also suppresses -Wredundant-move. */ diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc index cd3df13772db..fb45974cd90f 100644 --- a/gcc/cp/semantics.cc +++ b/gcc/cp/semantics.cc @@ -4979,6 +4979,7 @@ simplify_aggr_init_expr (tree *tp) = CALL_EXPR_OPERATOR_SYNTAX (aggr_init_expr); CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (aggr_init_expr); CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (aggr_init_expr); + CALL_EXPR_MUST_TAIL_CALL (call_expr) = AGGR_INIT_EXPR_MUST_TAIL (aggr_init_expr); if (style == ctor) { diff --git a/gcc/testsuite/g++.dg/musttail10.C b/gcc/testsuite/g++.dg/musttail10.C index e454a6238a06..93ec32db160a 100644 --- a/gcc/testsuite/g++.dg/musttail10.C +++ b/gcc/testsuite/g++.dg/musttail10.C @@ -14,9 +14,11 @@ template <class T> __attribute__((noinline, noclone, noipa)) T g2() { [[gnu::musttail]] return f<T>(); } +#if __OPTIMIZE__ >= 1 template <class T> __attribute__((noinline, noclone, noipa)) T g3() { [[gnu::musttail]] return f<T>(); } +#endif template <class T> __attribute__((noinline, noclone, noipa)) @@ -28,12 +30,20 @@ class C public: C(double x) : x(x) {} ~C() { asm("":::"memory"); } + operator int() { return x; } }; +template <class T> +__attribute__((noinline, noclone, noipa)) +T g5() { [[gnu::musttail]] return f<C>(); } /* { dg-error "cannot tail-call" } */ + int main() { g1<int>(); g2<double>(); +#if __OPTIMIZE__ >= 1 g3<C>(); +#endif g4<int>(); + g5<int>(); }