diff options
author | Marek Polacek <polacek@redhat.com> | 2016-09-26 09:42:50 +0000 |
---|---|---|
committer | Marek Polacek <mpolacek@gcc.gnu.org> | 2016-09-26 09:42:50 +0000 |
commit | 81fea426da8c4687bb32e6894dc26f00ae211822 (patch) | |
tree | 8b84b3de175727d09b7dcf1b5703e0d46b64f9e7 /gcc/cp/parser.c | |
parent | 392fa55c799358e198ca85fbea548e60359133c5 (diff) | |
download | gcc-81fea426da8c4687bb32e6894dc26f00ae211822.zip gcc-81fea426da8c4687bb32e6894dc26f00ae211822.tar.gz gcc-81fea426da8c4687bb32e6894dc26f00ae211822.tar.bz2 |
Implement -Wimplicit-fallthrough.
Co-Authored-By: Jakub Jelinek <jakub@redhat.com>
From-SVN: r240485
Diffstat (limited to 'gcc/cp/parser.c')
-rw-r--r-- | gcc/cp/parser.c | 81 |
1 files changed, 74 insertions, 7 deletions
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 168486c..5ec8b1b 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10585,14 +10585,31 @@ cp_parser_statement (cp_parser* parser, tree in_statement_expr, } /* Look for an expression-statement instead. */ statement = cp_parser_expression_statement (parser, in_statement_expr); + + /* Handle [[fallthrough]];. */ + if (attribute_fallthrough_p (std_attrs)) + { + /* The next token after the fallthrough attribute is ';'. */ + if (statement == NULL_TREE) + { + /* Turn [[fallthrough]]; into FALLTHROUGH ();. */ + statement = build_call_expr_internal_loc (statement_location, + IFN_FALLTHROUGH, + void_type_node, 0); + finish_expr_stmt (statement); + } + else + warning_at (statement_location, OPT_Wattributes, + "%<fallthrough%> attribute not followed by %<;%>"); + std_attrs = NULL_TREE; + } } /* Set the line number for the statement. */ if (statement && STATEMENT_CODE_P (TREE_CODE (statement))) SET_EXPR_LOCATION (statement, statement_location); - /* Note that for now, we don't do anything with c++11 statements - parsed at this level. */ + /* Allow "[[fallthrough]];", but warn otherwise. */ if (std_attrs != NULL_TREE) warning_at (attrs_location, OPT_Wattributes, @@ -10628,6 +10645,10 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes) return; } + /* Remember whether this case or a user-defined label is allowed to fall + through to. */ + bool fallthrough_p = token->flags & PREV_FALLTHROUGH; + parser->colon_corrects_to_scope_p = false; switch (token->keyword) { @@ -10659,7 +10680,11 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes) expr_hi = NULL_TREE; if (parser->in_switch_statement_p) - finish_case_label (token->location, expr, expr_hi); + { + tree l = finish_case_label (token->location, expr, expr_hi); + if (l && TREE_CODE (l) == CASE_LABEL_EXPR) + FALLTHROUGH_LABEL_P (CASE_LABEL (l)) = fallthrough_p; + } else error_at (token->location, "case label %qE not within a switch statement", @@ -10672,7 +10697,11 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes) cp_lexer_consume_token (parser->lexer); if (parser->in_switch_statement_p) - finish_case_label (token->location, NULL_TREE, NULL_TREE); + { + tree l = finish_case_label (token->location, NULL_TREE, NULL_TREE); + if (l && TREE_CODE (l) == CASE_LABEL_EXPR) + FALLTHROUGH_LABEL_P (CASE_LABEL (l)) = fallthrough_p; + } else error_at (token->location, "case label not within a switch statement"); break; @@ -10680,6 +10709,8 @@ cp_parser_label_for_labeled_statement (cp_parser* parser, tree attributes) default: /* Anything else must be an ordinary label. */ label = finish_label_stmt (cp_parser_identifier (parser)); + if (label && TREE_CODE (label) == LABEL_DECL) + FALLTHROUGH_LABEL_P (label) = fallthrough_p; break; } @@ -10728,6 +10759,10 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr) { tree statement = NULL_TREE; cp_token *token = cp_lexer_peek_token (parser->lexer); + location_t loc = token->location; + + /* There might be attribute fallthrough. */ + tree attr = cp_parser_gnu_attributes_opt (parser); /* If the next token is a ';', then there is no expression statement. */ @@ -10742,6 +10777,25 @@ cp_parser_expression_statement (cp_parser* parser, tree in_statement_expr) } } + /* Handle [[fallthrough]];. */ + if (attribute_fallthrough_p (attr)) + { + /* The next token after the fallthrough attribute is ';'. */ + if (statement == NULL_TREE) + /* Turn [[fallthrough]]; into FALLTHROUGH ();. */ + statement = build_call_expr_internal_loc (loc, IFN_FALLTHROUGH, + void_type_node, 0); + else + warning_at (loc, OPT_Wattributes, + "%<fallthrough%> attribute not followed by %<;%>"); + attr = NULL_TREE; + } + + /* Allow "[[fallthrough]];", but warn otherwise. */ + if (attr != NULL_TREE) + warning_at (loc, OPT_Wattributes, + "attributes at the beginning of statement are ignored"); + /* Give a helpful message for "A<T>::type t;" and the like. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON) && !cp_parser_uncommitted_to_tentative_parse_p (parser)) @@ -12980,6 +13034,7 @@ cp_parser_storage_class_specifier_opt (cp_parser* parser) if (cxx_dialect != cxx98) return NULL_TREE; /* Fall through for C++98. */ + gcc_fallthrough (); case RID_REGISTER: case RID_STATIC: @@ -24116,7 +24171,7 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) if (is_attribute_p ("noreturn", attr_id)) TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu"); /* C++14 deprecated attribute is equivalent to GNU's. */ - else if (cxx_dialect >= cxx11 && is_attribute_p ("deprecated", attr_id)) + else if (is_attribute_p ("deprecated", attr_id)) { if (cxx_dialect == cxx11) pedwarn (token->location, OPT_Wpedantic, @@ -24124,6 +24179,15 @@ cp_parser_std_attribute (cp_parser *parser, tree attr_ns) " use %<gnu::deprecated%>"); TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu"); } + /* C++17 fallthrough attribute is equivalent to GNU's. */ + else if (is_attribute_p ("fallthrough", attr_id)) + { + if (cxx_dialect < cxx1z) + pedwarn (token->location, OPT_Wpedantic, + "%<fallthrough%> is a C++17 feature;" + " use %<gnu::fallthrough%>"); + TREE_PURPOSE (TREE_PURPOSE (attribute)) = get_identifier ("gnu"); + } /* Transactional Memory TS optimize_for_synchronized attribute is equivalent to GNU transaction_callable. */ else if (is_attribute_p ("optimize_for_synchronized", attr_id)) @@ -24182,11 +24246,11 @@ cp_parser_check_std_attribute (tree attributes, tree attribute) tree name = get_attribute_name (attribute); if (is_attribute_p ("noreturn", name) && lookup_attribute ("noreturn", attributes)) - error ("attribute noreturn can appear at most once " + error ("attribute %<noreturn%> can appear at most once " "in an attribute-list"); else if (is_attribute_p ("deprecated", name) && lookup_attribute ("deprecated", attributes)) - error ("attribute deprecated can appear at most once " + error ("attribute %<deprecated%> can appear at most once " "in an attribute-list"); } } @@ -27303,6 +27367,7 @@ cp_parser_skip_to_end_of_template_parameter_list (cp_parser* parser) } /* Fall through for C++0x, so we handle the second `>' in the `>>'. */ + gcc_fallthrough (); case CPP_GREATER: if (!nesting_depth && level-- == 0) @@ -27760,6 +27825,7 @@ cp_parser_cache_defarg (cp_parser *parser, bool nsdmi) /* Fall through for C++0x, which treats the `>>' operator like two `>' tokens in certain cases. */ + gcc_fallthrough (); case CPP_GREATER: if (depth == 0) @@ -33402,6 +33468,7 @@ cp_parser_omp_for_cond (cp_parser *parser, tree decl, enum tree_code code) if (code == CILK_SIMD || code == CILK_FOR) break; /* Fall through: OpenMP disallows NE_EXPR. */ + gcc_fallthrough (); default: return error_mark_node; } |