aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/c-family/c-attribs.cc20
-rw-r--r--gcc/c-family/c-common.h1
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/parser.cc32
-rw-r--r--gcc/cp/pt.cc9
-rw-r--r--gcc/cp/semantics.cc1
6 files changed, 63 insertions, 4 deletions
diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 5adc7b7..685f212 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -672,6 +672,26 @@ attribute_takes_identifier_p (const_tree attr_id)
return targetm.attribute_takes_identifier_p (attr_id);
}
+/* Set a musttail attribute MUSTTAIL_P on return expression RETVAL
+ at LOC. */
+
+void
+set_musttail_on_return (tree retval, location_t loc, bool musttail_p)
+{
+ if (retval && musttail_p)
+ {
+ tree t = retval;
+ if (TREE_CODE (t) == TARGET_EXPR)
+ t = TARGET_EXPR_INITIAL (t);
+ if (TREE_CODE (t) != CALL_EXPR)
+ error_at (loc, "cannot tail-call: return value must be a call");
+ else
+ CALL_EXPR_MUST_TAIL_CALL (t) = 1;
+ }
+ else if (musttail_p && !retval)
+ error_at (loc, "cannot tail-call: return value must be a call");
+}
+
/* Verify that argument value POS at position ARGNO to attribute NAME
applied to function FN (which is either a function declaration or function
type) refers to a function parameter at position POS and the expected type
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index adee822..2510ee4 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1648,6 +1648,7 @@ extern tree handle_noreturn_attribute (tree *, tree, tree, int, bool *);
extern tree handle_musttail_attribute (tree *, tree, tree, int, bool *);
extern bool has_attribute (location_t, tree, tree, tree (*)(tree));
extern tree build_attr_access_from_parms (tree, bool);
+extern void set_musttail_on_return (tree, location_t, bool);
/* In c-format.cc. */
extern bool valid_format_string_type_p (tree);
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 856699d..e2cec2f 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -4228,6 +4228,10 @@ templated_operator_saved_lookups (tree t)
#define AGGR_INIT_FROM_THUNK_P(NODE) \
(AGGR_INIT_EXPR_CHECK (NODE)->base.protected_flag)
+/* Nonzero means that the call was marked musttail. */
+#define AGGR_INIT_EXPR_MUST_TAIL(NODE) \
+ (AGGR_INIT_EXPR_CHECK (NODE)->base.static_flag)
+
/* AGGR_INIT_EXPR accessors. These are equivalent to the CALL_EXPR
accessors, except for AGGR_INIT_EXPR_SLOT (which takes the place of
CALL_EXPR_STATIC_CHAIN). */
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index efd5d6f..1fa0780 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -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 *);
@@ -12757,7 +12757,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. */
@@ -14845,10 +14845,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;
@@ -14925,6 +14926,31 @@ 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)
+ {
+ 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);
+ }
+
+ tree ret_expr = expr;
+ if (ret_expr && TREE_CODE (ret_expr) == TARGET_EXPR)
+ ret_expr = TARGET_EXPR_INITIAL (ret_expr);
+ if (ret_expr && TREE_CODE (ret_expr) == AGGR_INIT_EXPR)
+ AGGR_INIT_EXPR_MUST_TAIL (ret_expr) = musttail_p;
+ else
+ set_musttail_on_return (expr, token->location, musttail_p);
+ }
+
/* Build the return-statement, check co-return first, since type
deduction is not valid there. */
if (keyword == RID_CO_RETURN)
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 3939132..e102e3e 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -21094,12 +21094,19 @@ 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;
+ else if (TREE_CODE (call) == AGGR_INIT_EXPR)
+ AGGR_INIT_EXPR_MUST_TAIL (call) = mtc;
}
if (warning_suppressed_p (t, OPT_Wpessimizing_move))
/* This also suppresses -Wredundant-move. */
diff --git a/gcc/cp/semantics.cc b/gcc/cp/semantics.cc
index c21572e..0f122b8 100644
--- a/gcc/cp/semantics.cc
+++ b/gcc/cp/semantics.cc
@@ -4979,6 +4979,7 @@ simplify_aggr_init_expr (tree *tp)
= CALL_EXPR_OPERATOR_SYNTAX (aggr_init_expr);
CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (aggr_init_expr);
CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (aggr_init_expr);
+ CALL_EXPR_MUST_TAIL_CALL (call_expr) = AGGR_INIT_EXPR_MUST_TAIL (aggr_init_expr);
if (style == ctor)
{