diff options
-rw-r--r-- | gcc/c-family/c-attribs.cc | 20 | ||||
-rw-r--r-- | gcc/c-family/c-common.h | 1 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 4 | ||||
-rw-r--r-- | gcc/cp/parser.cc | 32 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 9 | ||||
-rw-r--r-- | gcc/cp/semantics.cc | 1 |
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) { |