@@ -2467,7 +2467,7 @@ static tree cp_parser_perform_range_for_lookup
static tree cp_parser_range_for_member_function
(tree, tree);
static tree cp_parser_jump_statement
- (cp_parser *);
+ (cp_parser *, tree &);
static void cp_parser_declaration_statement
(cp_parser *);
@@ -12755,7 +12755,7 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
case RID_CO_RETURN:
case RID_GOTO:
std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
- statement = cp_parser_jump_statement (parser);
+ statement = cp_parser_jump_statement (parser, std_attrs);
break;
/* Objective-C++ exception-handling constructs. */
@@ -14822,10 +14822,11 @@ cp_parser_init_statement (cp_parser *parser, tree *decl)
jump-statement:
goto * expression ;
+ STD_ATTRS are the statement attributes. They can be modified.
Returns the new BREAK_STMT, CONTINUE_STMT, RETURN_EXPR, or GOTO_EXPR. */
static tree
-cp_parser_jump_statement (cp_parser* parser)
+cp_parser_jump_statement (cp_parser* parser, tree &std_attrs)
{
tree statement = error_mark_node;
cp_token *token;
@@ -14902,6 +14903,33 @@ cp_parser_jump_statement (cp_parser* parser)
/* If the next token is a `;', then there is no
expression. */
expr = NULL_TREE;
+
+ if (keyword == RID_RETURN && expr)
+ {
+ bool musttail_p = false;
+ if (lookup_attribute ("gnu", "musttail", std_attrs))
+ {
+ musttail_p = true;
+ std_attrs = remove_attribute ("gnu", "musttail", std_attrs);
+ }
+ /* Support this for compatibility. */
+ if (lookup_attribute ("clang", "musttail", std_attrs))
+ {
+ musttail_p = true;
+ std_attrs = remove_attribute ("clang", "musttail", std_attrs);
+ }
+ if (musttail_p)
+ {
+ tree t = expr;
+ if (t && TREE_CODE (t) == TARGET_EXPR)
+ t = TARGET_EXPR_INITIAL (t);
+ if (t && TREE_CODE (t) != CALL_EXPR)
+ error_at (token->location, "cannot tail-call: return value must be a call");
+ else
+ CALL_EXPR_MUST_TAIL_CALL (t) = 1;
+ }
+ }
+
/* Build the return-statement, check co-return first, since type
deduction is not valid there. */
if (keyword == RID_CO_RETURN)
@@ -21111,12 +21111,17 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
bool op = CALL_EXPR_OPERATOR_SYNTAX (t);
bool ord = CALL_EXPR_ORDERED_ARGS (t);
bool rev = CALL_EXPR_REVERSE_ARGS (t);
- if (op || ord || rev)
+ bool mtc = false;
+ if (TREE_CODE (t) == CALL_EXPR)
+ mtc = CALL_EXPR_MUST_TAIL_CALL (t);
+ if (op || ord || rev || mtc)
if (tree call = extract_call_expr (ret))
{
CALL_EXPR_OPERATOR_SYNTAX (call) = op;
CALL_EXPR_ORDERED_ARGS (call) = ord;
CALL_EXPR_REVERSE_ARGS (call) = rev;
+ if (TREE_CODE (call) == CALL_EXPR)
+ CALL_EXPR_MUST_TAIL_CALL (call) = mtc;
}
if (warning_suppressed_p (t, OPT_Wpessimizing_move))
/* This also suppresses -Wredundant-move. */