On Wed, Jul 17, 2024 at 09:30:00PM -0700, Andi Kleen wrote: > Implement a C23 clang compatible musttail attribute similar to the earlier > C++ implementation in the C parser. > > gcc/c/ChangeLog: > > PR c/83324 > * c-parser.cc (struct attr_state): Define with musttail_p. > (c_parser_statement_after_labels): Handle [[musttail]]. > (c_parser_std_attribute): Dito. > (c_parser_handle_musttail): Dito. > (c_parser_compound_statement_nostart): Dito. > (c_parser_all_labels): Dito. > (c_parser_statement): Dito. > * c-tree.h (c_finish_return): Add musttail_p flag. > * c-typeck.cc (c_finish_return): Handle musttail_p flag. > --- > gcc/c/c-parser.cc | 70 ++++++++++++++++++++++++++++++++++++++--------- > gcc/c/c-tree.h | 2 +- > gcc/c/c-typeck.cc | 7 +++-- > 3 files changed, 63 insertions(+), 16 deletions(-) > > diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc > index 12c5ed5d92c7..a8848d01f21a 100644 > --- a/gcc/c/c-parser.cc > +++ b/gcc/c/c-parser.cc > @@ -1621,6 +1621,12 @@ struct omp_for_parse_data { > bool fail : 1; > }; > > +struct attr_state > +{ > + /* True if we parsed a musttail attribute for return. */ > + bool musttail_p; > +}; > + > static bool c_parser_nth_token_starts_std_attributes (c_parser *, > unsigned int); > static tree c_parser_std_attribute_specifier_sequence (c_parser *); > @@ -1665,7 +1671,7 @@ static location_t c_parser_compound_statement_nostart > (c_parser *); > static void c_parser_label (c_parser *, tree); > static void c_parser_statement (c_parser *, bool *, location_t * = NULL); > static void c_parser_statement_after_labels (c_parser *, bool *, > - vec<tree> * = NULL); > + vec<tree> * = NULL, attr_state = > {});
Nit: the line seems to go over 80 columns. > static tree c_parser_c99_block_statement (c_parser *, bool *, > location_t * = NULL); > static void c_parser_if_statement (c_parser *, bool *, vec<tree> *); > @@ -6982,6 +6988,29 @@ c_parser_handle_directive_omp_attributes (tree &attrs, > } > } > > +/* Check if STD_ATTR contains a musttail attribute and remove if it > + precedes a return. PARSER is the parser and ATTR is the output > + attr_state. */ > + > +static tree > +c_parser_handle_musttail (c_parser *parser, tree std_attrs, attr_state &attr) > +{ > + if (c_parser_next_token_is_keyword (parser, RID_RETURN)) > + { > + if (lookup_attribute ("gnu", "musttail", std_attrs)) > + { > + std_attrs = remove_attribute ("gnu", "musttail", std_attrs); > + attr.musttail_p = true; > + } > + if (lookup_attribute ("clang", "musttail", std_attrs)) > + { > + std_attrs = remove_attribute ("clang", "musttail", std_attrs); > + attr.musttail_p = true; > + } > + } > + return std_attrs; > +} > + > /* Parse a compound statement except for the opening brace. This is > used for parsing both compound statements and statement expressions > (which follow different paths to handling the opening). */ > @@ -6998,6 +7027,7 @@ c_parser_compound_statement_nostart (c_parser *parser) > bool in_omp_loop_block > = omp_for_parse_state ? omp_for_parse_state->want_nested_loop : false; > tree sl = NULL_TREE; > + attr_state a = {}; > > if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE)) > { > @@ -7138,7 +7168,10 @@ c_parser_compound_statement_nostart (c_parser *parser) > = c_parser_nth_token_starts_std_attributes (parser, 1); > tree std_attrs = NULL_TREE; > if (have_std_attrs) > - std_attrs = c_parser_std_attribute_specifier_sequence (parser); > + { > + std_attrs = c_parser_std_attribute_specifier_sequence (parser); > + std_attrs = c_parser_handle_musttail (parser, std_attrs, a); > + } > if (c_parser_next_token_is_keyword (parser, RID_CASE) > || c_parser_next_token_is_keyword (parser, RID_DEFAULT) > || (c_parser_next_token_is (parser, CPP_NAME) > @@ -7286,7 +7319,7 @@ c_parser_compound_statement_nostart (c_parser *parser) > last_stmt = true; > mark_valid_location_for_stdc_pragma (false); > if (!omp_for_parse_state) > - c_parser_statement_after_labels (parser, NULL); > + c_parser_statement_after_labels (parser, NULL, NULL, a); > else > { > /* In canonical loop nest form, nested loops can only appear > @@ -7328,15 +7361,20 @@ c_parser_compound_statement_nostart (c_parser *parser) > /* Parse all consecutive labels, possibly preceded by standard > attributes. In this context, a statement is required, not a > declaration, so attributes must be followed by a statement that is > - not just a semicolon. */ > + not just a semicolon. Returns an attr_state. */ > > -static void > +static attr_state > c_parser_all_labels (c_parser *parser) > { > + attr_state attr = {}; > bool have_std_attrs; > tree std_attrs = NULL; > if ((have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, > 1))) > - std_attrs = c_parser_std_attribute_specifier_sequence (parser); > + { > + std_attrs = c_parser_std_attribute_specifier_sequence (parser); > + std_attrs = c_parser_handle_musttail (parser, std_attrs, attr); > + } > + > while (c_parser_next_token_is_keyword (parser, RID_CASE) > || c_parser_next_token_is_keyword (parser, RID_DEFAULT) > || (c_parser_next_token_is (parser, CPP_NAME) > @@ -7346,7 +7384,10 @@ c_parser_all_labels (c_parser *parser) > std_attrs = NULL; > if ((have_std_attrs = c_parser_nth_token_starts_std_attributes (parser, > 1))) > - std_attrs = c_parser_std_attribute_specifier_sequence (parser); > + { > + std_attrs = c_parser_std_attribute_specifier_sequence (parser); > + std_attrs = c_parser_handle_musttail (parser, std_attrs, attr); > + } Thanks, I believe this addresses the testcase I mentioned earlier: struct str { int a, b; }; struct str cstruct (int x) { if (x < 10) L: // <==== [[gnu::musttail]] return cstruct (x + 1); return ((struct str){ x, 0 }); } but I didn't see that being tested in your testsuite patch; apologies if I missed it. > tree > -c_finish_return (location_t loc, tree retval, tree origtype) > +c_finish_return (location_t loc, tree retval, tree origtype, bool musttail_p) > { > tree valtype = TREE_TYPE (TREE_TYPE (current_function_decl)), ret_stmt; > bool no_warning = false; > @@ -11742,6 +11743,8 @@ c_finish_return (location_t loc, tree retval, tree > origtype) > warning_at (xloc, 0, > "function declared %<noreturn%> has a %<return%> statement"); > > + set_musttail_on_return (retval, xloc, musttail_p); > + > if (retval) > { > tree semantic_type = NULL_TREE; Is it deliberate that set_musttail_on_return is called outside the if (retval) block? If it can be moved into it, set_musttail_on_return can be simplified to assume that retval is always non-null. Marek