Hi Jason, On Mon, May 06, 2024 at 11:02:20PM -0400, Jason Merrill wrote: > > @@ -30189,7 +30207,7 @@ cp_parser_std_attribute (cp_parser *parser, tree > > attr_ns) > > /* Maybe we don't expect to see any arguments for this attribute. */ > > const attribute_spec *as > > = lookup_attribute_spec (TREE_PURPOSE (attribute)); > > - if (as && as->max_length == 0) > > + if ((as && as->max_length == 0) || is_attribute_p ("musttail", > > attr_id)) > > I'd prefer to add an attribute to the table, rather than special-case it > here; apart from consistency, it seems likely that someone will later want > to apply it to a function.
Just to clarify. I can add it to the table, but it would be a nop there for now because the table is not used for statement attributes by the current parser. > > You need a template testcase; I expect it doesn't work in templates with the > current patch. It's probably enough to copy it in tsubst_expr where we > currently propagate CALL_EXPR_OPERATOR_SYNTAX. I tried it with the appended test case, everything seems to work without changes. Does it cover the cases you were concerned about? > > You also need a testcase where the function returns a class; in that case > the call will often appear as AGGR_INIT_EXPR rather than CALL_EXPR, so > you'll need to handle that as well. And see the places that copy flags like > CALL_EXPR_OPERATOR_SYNTAX between CALL_EXPR and AGGR_INIT_EXPR. Dito. -Andi /* { dg-do compile { target { tail_call } } } */ /* { dg-options "-O2" } */ /* { dg-additional-options "-fdelayed-branch" { target sparc*-*-* } } */ class Foo { public: int a, b; Foo(int a, int b) : a(a), b(b) {} }; Foo __attribute__((noinline,noclone,noipa)) callee (int i) { return Foo(i, i+1); } Foo __attribute__((noinline,noclone,noipa)) caller (int i) { [[gnu::musttail]] return callee (i + 1); } template<typename T> T __attribute__((noinline,noclone,noipa)) foo (T i) { return i + 1; } int caller2 (int k) { [[gnu::musttail]] return foo<int>(1); } template<typename T> T caller3 (T v) { [[gnu::musttail]] return foo<T>(v); } int call3(int i) { [[gnu::musttail]] return caller3<int>(i + 1); } class Bar { int a; public: Bar(int a) : a(a) {} Bar operator+(Bar o) { return Bar(a + o.a); } }; Bar caller3 (Bar k) { [[gnu::musttail]] return caller3<Bar>(Bar(99)); }