aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/ChangeLog16
-rw-r--r--gcc/c/c-decl.c2
-rw-r--r--gcc/c/c-parser.c97
3 files changed, 107 insertions, 8 deletions
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index cae5c92..642c20c 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,19 @@
+2016-09-26 Marek Polacek <polacek@redhat.com>
+
+ PR c/7652
+ * c-decl.c (pop_scope): Add gcc_fallthrough.
+
+2016-09-26 Marek Polacek <polacek@redhat.com>
+
+ PR c/7652
+ * c-parser.c (struct c_token): Add flags field.
+ (c_lex_one_token): Pass it to c_lex_with_flags.
+ (c_parser_declaration_or_fndef): Turn __attribute__((fallthrough));
+ into IFN_FALLTHROUGH.
+ (c_parser_label): Set FALLTHROUGH_LABEL_P on labels. Handle
+ attribute fallthrough after a case label or default label.
+ (c_parser_statement_after_labels): Handle RID_ATTRIBUTE.
+
2016-09-24 Marek Polacek <polacek@redhat.com>
PR c/77490
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index d15b8f8..9e32be2 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -1328,7 +1328,7 @@ pop_scope (void)
set_type_context (TREE_TYPE (p), context);
}
- /* Fall through. */
+ gcc_fallthrough ();
/* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have
already been put there by store_parm_decls. Unused-
parameter warnings are handled by function.c.
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index 5f610e9..6bc42da 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -193,6 +193,8 @@ struct GTY (()) c_token {
location_t location;
/* The value associated with this token, if any. */
tree value;
+ /* Token flags. */
+ unsigned char flags;
source_range get_range () const
{
@@ -270,7 +272,8 @@ c_lex_one_token (c_parser *parser, c_token *token)
{
timevar_push (TV_LEX);
- token->type = c_lex_with_flags (&token->value, &token->location, NULL,
+ token->type = c_lex_with_flags (&token->value, &token->location,
+ &token->flags,
(parser->lex_untranslated_string
? C_LEX_STRING_NO_TRANSLATE : 0));
token->id_kind = C_ID_NONE;
@@ -1288,7 +1291,8 @@ static void c_parser_external_declaration (c_parser *);
static void c_parser_asm_definition (c_parser *);
static void c_parser_declaration_or_fndef (c_parser *, bool, bool, bool,
bool, bool, tree *, vec<c_token>,
- struct oacc_routine_data * = NULL);
+ struct oacc_routine_data * = NULL,
+ bool * = NULL);
static void c_parser_static_assert_declaration_no_semi (c_parser *);
static void c_parser_static_assert_declaration (c_parser *);
static void c_parser_declspecs (c_parser *, struct c_declspecs *, bool, bool,
@@ -1591,6 +1595,8 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
attributes; otherwise they may not.
OBJC_FOREACH_OBJECT_DECLARATION can be used to get back the parsed
declaration when parsing an Objective-C foreach statement.
+ FALLTHRU_ATTR_P is used to signal whether this function parsed
+ "__attribute__((fallthrough));".
declaration:
declaration-specifiers init-declarator-list[opt] ;
@@ -1618,6 +1624,8 @@ static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
declaration-specifiers declarator declaration-list[opt]
compound-statement
+ attribute ;
+
Objective-C:
attributes objc-class-definition
attributes objc-category-definition
@@ -1652,7 +1660,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
bool nested, bool start_attr_ok,
tree *objc_foreach_object_declaration,
vec<c_token> omp_declare_simd_clauses,
- struct oacc_routine_data *oacc_routine_data)
+ struct oacc_routine_data *oacc_routine_data,
+ bool *fallthru_attr_p)
{
struct c_declspecs *specs;
tree prefix_attrs;
@@ -1749,6 +1758,15 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
{
if (auto_type_p)
error_at (here, "%<__auto_type%> in empty declaration");
+ else if (specs->typespec_kind == ctsk_none
+ && attribute_fallthrough_p (specs->attrs))
+ {
+ if (fallthru_attr_p != NULL)
+ *fallthru_attr_p = true;
+ tree fn = build_call_expr_internal_loc (here, IFN_FALLTHROUGH,
+ void_type_node, 0);
+ add_stmt (fn);
+ }
else if (empty_ok)
shadow_tag (specs);
else
@@ -1851,7 +1869,10 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
break;
}
}
-
+ else if (attribute_fallthrough_p (specs->attrs))
+ warning_at (here, OPT_Wattributes,
+ "%<fallthrough%> attribute not followed by %<;%>");
+
pending_xref_error ();
prefix_attrs = specs->attrs;
all_prefix_attrs = prefix_attrs;
@@ -4841,12 +4862,14 @@ c_parser_compound_statement_nostart (c_parser *parser)
{
last_label = false;
mark_valid_location_for_stdc_pragma (false);
+ bool fallthru_attr_p = false;
c_parser_declaration_or_fndef (parser, true, true, true, true,
- true, NULL, vNULL);
- if (last_stmt)
+ true, NULL, vNULL, NULL,
+ &fallthru_attr_p);
+ if (last_stmt && !fallthru_attr_p)
pedwarn_c90 (loc, OPT_Wdeclaration_after_statement,
"ISO C90 forbids mixed declarations and code");
- last_stmt = false;
+ last_stmt = fallthru_attr_p;
}
else if (!last_label
&& c_parser_next_token_is_keyword (parser, RID_EXTENSION))
@@ -4963,6 +4986,11 @@ c_parser_label (c_parser *parser)
{
location_t loc1 = c_parser_peek_token (parser)->location;
tree label = NULL_TREE;
+
+ /* Remember whether this case or a user-defined label is allowed to fall
+ through to. */
+ bool fallthrough_p = c_parser_peek_token (parser)->flags & PREV_FALLTHROUGH;
+
if (c_parser_next_token_is_keyword (parser, RID_CASE))
{
tree exp1, exp2;
@@ -5009,6 +5037,33 @@ c_parser_label (c_parser *parser)
}
if (label)
{
+ if (TREE_CODE (label) == LABEL_EXPR)
+ FALLTHROUGH_LABEL_P (LABEL_EXPR_LABEL (label)) = fallthrough_p;
+ else
+ FALLTHROUGH_LABEL_P (CASE_LABEL (label)) = fallthrough_p;
+
+ /* Allow '__attribute__((fallthrough));'. */
+ if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ tree attrs = c_parser_attributes (parser);
+ if (attribute_fallthrough_p (attrs))
+ {
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ tree fn = build_call_expr_internal_loc (loc,
+ IFN_FALLTHROUGH,
+ void_type_node, 0);
+ add_stmt (fn);
+ }
+ else
+ warning_at (loc, OPT_Wattributes, "%<fallthrough%> attribute "
+ "not followed by %<;%>");
+ }
+ else if (attrs != NULL_TREE)
+ warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
+ " can be applied to a null statement");
+ }
if (c_parser_next_tokens_start_declaration (parser))
{
error_at (c_parser_peek_token (parser)->location,
@@ -5062,6 +5117,9 @@ c_parser_label (c_parser *parser)
jump-statement:
goto * expression ;
+ expression-statement:
+ attributes ;
+
Objective-C:
statement:
@@ -5323,6 +5381,31 @@ c_parser_statement_after_labels (c_parser *parser, bool *if_p,
gcc_assert (c_dialect_objc ());
c_parser_objc_synchronized_statement (parser);
break;
+ case RID_ATTRIBUTE:
+ {
+ /* Allow '__attribute__((fallthrough));'. */
+ tree attrs = c_parser_attributes (parser);
+ if (attribute_fallthrough_p (attrs))
+ {
+ if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+ {
+ tree fn = build_call_expr_internal_loc (loc,
+ IFN_FALLTHROUGH,
+ void_type_node, 0);
+ add_stmt (fn);
+ /* Eat the ';'. */
+ c_parser_consume_token (parser);
+ }
+ else
+ warning_at (loc, OPT_Wattributes,
+ "%<fallthrough%> attribute not followed "
+ "by %<;%>");
+ }
+ else if (attrs != NULL_TREE)
+ warning_at (loc, OPT_Wattributes, "only attribute %<fallthrough%>"
+ " can be applied to a null statement");
+ break;
+ }
default:
goto expr_stmt;
}