Message ID | 20240718043750.2480283-3-ak@linux.intel.com |
---|---|
State | New |
Headers | show |
Series | [v10,1/3] C++: Support clang compatible [[musttail]] (PR83324) | expand |
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
On Thu, Jul 18, 2024 at 02:19:21PM -0400, Marek Polacek wrote: > 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. Ok. > > || 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. It wasn't there. I will add 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. Yes it can be removed. Is the patchk ok with these changes? -Andi
On Thu, Jul 18, 2024 at 03:11:56PM -0700, Andi Kleen wrote: > On Thu, Jul 18, 2024 at 02:19:21PM -0400, Marek Polacek wrote: > > 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. > > Ok. > > > > || 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. > > It wasn't there. I will add 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. > > Yes it can be removed. > > Is the patchk ok with these changes? Yes, thanks. Marek
> > > > + 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. > > > > Yes it can be removed. Actually I was wrong here, after double checking. The !retval case is needed to diagnose a [[musttail]] set on a plain return (which is not allowed following the clang spec) So the call has to be outside the check. The C frontend did it correctly, but the C++ part did not (fixed now) -Andi
On Thu, Jul 18, 2024 at 04:18:56PM -0700, Andi Kleen wrote: > > > > > + 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. > > > > > > Yes it can be removed. > > Actually I was wrong here, after double checking. The !retval case is > needed to diagnose a [[musttail]] set on a plain return (which is not > allowed following the clang spec) > > So the call has to be outside the check. > > The C frontend did it correctly, but the C++ part did not (fixed now) Ah, fair enough. Just make sure we test it somewhere, thanks. Marek
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 = {}); 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); + } } if (std_attrs && (!c_parser_handle_statement_omp_attributes (parser, std_attrs, &have_std_attrs) @@ -7358,6 +7399,7 @@ c_parser_all_labels (c_parser *parser) } else if (have_std_attrs && c_parser_next_token_is (parser, CPP_SEMICOLON)) c_parser_error (parser, "expected statement"); + return attr; } /* Parse a label (C90 6.6.1, C99 6.8.1, C11 6.8.1). @@ -7601,11 +7643,11 @@ c_parser_label (c_parser *parser, tree std_attrs) static void c_parser_statement (c_parser *parser, bool *if_p, location_t *loc_after_labels) { - c_parser_all_labels (parser); + attr_state a = c_parser_all_labels (parser); if (loc_after_labels) *loc_after_labels = c_parser_peek_token (parser)->location; parser->omp_attrs_forbidden_p = false; - c_parser_statement_after_labels (parser, if_p, NULL); + c_parser_statement_after_labels (parser, if_p, NULL, a); } /* Parse a statement, other than a labeled statement. CHAIN is a vector @@ -7614,11 +7656,11 @@ c_parser_statement (c_parser *parser, bool *if_p, location_t *loc_after_labels) IF_P is used to track whether there's a (possibly labeled) if statement which is not enclosed in braces and has an else clause. This is used to - implement -Wparentheses. */ + implement -Wparentheses. ASTATE is an earlier parsed attribute state. */ static void c_parser_statement_after_labels (c_parser *parser, bool *if_p, - vec<tree> *chain) + vec<tree> *chain, attr_state astate) { location_t loc = c_parser_peek_token (parser)->location; tree stmt = NULL_TREE; @@ -7686,7 +7728,8 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, c_parser_consume_token (parser); if (c_parser_next_token_is (parser, CPP_SEMICOLON)) { - stmt = c_finish_return (loc, NULL_TREE, NULL_TREE); + stmt = c_finish_return (loc, NULL_TREE, NULL_TREE, + astate.musttail_p); c_parser_consume_token (parser); } else @@ -7695,7 +7738,8 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p, struct c_expr expr = c_parser_expression_conv (parser); mark_exp_read (expr.value); stmt = c_finish_return (EXPR_LOC_OR_LOC (expr.value, xloc), - expr.value, expr.original_type); + expr.value, expr.original_type, + astate.musttail_p); goto expect_semicolon; } break; diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h index 15da875a0290..3dc6338bf061 100644 --- a/gcc/c/c-tree.h +++ b/gcc/c/c-tree.h @@ -827,7 +827,7 @@ extern tree c_begin_stmt_expr (void); extern tree c_finish_stmt_expr (location_t, tree); extern tree c_process_expr_stmt (location_t, tree); extern tree c_finish_expr_stmt (location_t, tree); -extern tree c_finish_return (location_t, tree, tree); +extern tree c_finish_return (location_t, tree, tree, bool = false); extern tree c_finish_bc_stmt (location_t, tree, bool); extern tree c_finish_goto_label (location_t, tree); extern tree c_finish_goto_ptr (location_t, c_expr val); diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc index 7e0f01ed22b9..094e41fa2021 100644 --- a/gcc/c/c-typeck.cc +++ b/gcc/c/c-typeck.cc @@ -11725,10 +11725,11 @@ c_finish_goto_ptr (location_t loc, c_expr val) to return, or a null pointer for `return;' with no value. LOC is the location of the return statement, or the location of the expression, if the statement has any. If ORIGTYPE is not NULL_TREE, it - is the original type of RETVAL. */ + is the original type of RETVAL. MUSTTAIL_P indicates a musttail + attribute. */ 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;