@@ -7763,7 +7763,7 @@ extern void finish_while_stmt (tree);
extern tree begin_do_stmt (void);
extern void finish_do_body (tree);
extern void finish_do_stmt (tree, tree, bool, tree, bool);
-extern tree finish_return_stmt (tree);
+extern tree finish_return_stmt (tree, bool = false);
extern tree begin_for_scope (tree *);
extern tree begin_for_stmt (tree, tree);
extern void finish_init_stmt (tree);
@@ -8275,7 +8275,7 @@ extern tree composite_pointer_type (const op_location_t &,
tsubst_flags_t);
extern tree merge_types (tree, tree);
extern tree strip_array_domain (tree);
-extern tree check_return_expr (tree, bool *, bool *);
+extern tree check_return_expr (tree, bool *, bool *, bool);
extern tree spaceship_type (tree, tsubst_flags_t = tf_warning_or_error);
extern tree genericize_spaceship (location_t, tree, tree, tree);
extern tree cp_build_binary_op (const op_location_t &,
@@ -2462,7 +2462,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 *, bool = false);
static void cp_parser_declaration_statement
(cp_parser *);
@@ -12719,9 +12719,27 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr,
NULL_TREE, false);
break;
+ case RID_RETURN:
+ {
+ bool musttail_p = false;
+ std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
+ 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);
+ }
+ statement = cp_parser_jump_statement (parser, musttail_p);
+ }
+ break;
+
case RID_BREAK:
case RID_CONTINUE:
- case RID_RETURN:
case RID_CO_RETURN:
case RID_GOTO:
std_attrs = process_stmt_hotness_attribute (std_attrs, attrs_loc);
@@ -14767,7 +14785,7 @@ cp_parser_init_statement (cp_parser *parser, tree *decl)
return false;
}
-/* Parse a jump-statement.
+/* Parse a jump-statement. MUSTTAIL_P indicates a musttail attribute.
jump-statement:
break ;
@@ -14785,7 +14803,7 @@ cp_parser_init_statement (cp_parser *parser, tree *decl)
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, bool musttail_p)
{
tree statement = error_mark_node;
cp_token *token;
@@ -14869,7 +14887,7 @@ cp_parser_jump_statement (cp_parser* parser)
else if (FNDECL_USED_AUTO (current_function_decl) && in_discarded_stmt)
/* Don't deduce from a discarded return statement. */;
else
- statement = finish_return_stmt (expr);
+ statement = finish_return_stmt (expr, musttail_p);
/* Look for the final `;'. */
cp_parser_require (parser, CPP_SEMICOLON, RT_SEMICOLON);
}
@@ -30041,7 +30059,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))
{
error_at (token->location, "%qE attribute does not take any arguments",
attr_id);
@@ -1324,16 +1324,16 @@ finish_do_stmt (tree cond, tree do_stmt, bool ivdep, tree unroll,
}
/* Finish a return-statement. The EXPRESSION returned, if any, is as
- indicated. */
+ indicated. MUSTTAIL_P indicates a mustcall attribute. */
tree
-finish_return_stmt (tree expr)
+finish_return_stmt (tree expr, bool musttail_p)
{
tree r;
bool no_warning;
bool dangling;
- expr = check_return_expr (expr, &no_warning, &dangling);
+ expr = check_return_expr (expr, &no_warning, &dangling, musttail_p);
if (error_operand_p (expr)
|| (flag_openmp && !check_omp_return ()))
@@ -11030,10 +11030,12 @@ maybe_warn_pessimizing_move (tree expr, tree type, bool return_p)
the DECL_RESULT for the function. Set *NO_WARNING to true if
code reaches end of non-void function warning shouldn't be issued
on this RETURN_EXPR. Set *DANGLING to true if code returns the
- address of a local variable. */
+ address of a local variable. MUSTTAIL_P indicates a musttail
+ return. */
tree
-check_return_expr (tree retval, bool *no_warning, bool *dangling)
+check_return_expr (tree retval, bool *no_warning, bool *dangling,
+ bool musttail_p)
{
tree result;
/* The type actually returned by the function. */
@@ -11047,6 +11049,20 @@ check_return_expr (tree retval, bool *no_warning, bool *dangling)
*no_warning = false;
*dangling = false;
+ if (musttail_p)
+ {
+ tree t = retval;
+ if (TREE_CODE (t) == TARGET_EXPR)
+ t = TARGET_EXPR_INITIAL (retval);
+ if (TREE_CODE (t) != CALL_EXPR)
+ {
+ error_at (loc, "cannot tail-call: return value must be a call");
+ return error_mark_node;
+ }
+ else
+ CALL_EXPR_MUST_TAIL_CALL (t) = 1;
+ }
+
/* A `volatile' function is one that isn't supposed to return, ever.
(This is a G++ extension, used to get better code for functions
that call the `volatile' function.) */