From 0c71476f9062878c35ea6fd1afa23a6c4a3ab322 Mon Sep 17 00:00:00 2001 From: mpolacek Date: Tue, 24 May 2016 16:22:31 +0000 Subject: [PATCH 01/16] PR c/71249 * gimplify.c (gimplify_switch_expr): Look into the innermost lexical scope. * c-c++-common/Wswitch-unreachable-2.c: New test. upstream hash: 6ef0143d8a1ce423db0ae0da55760b4fb82f3bdf git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@236649 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: I1270c2aea4e4561f72a9801607bcdfc5edab9a03 --- gcc/gimplify.c | 5 +++-- gcc/testsuite/c-c++-common/Wswitch-unreachable-2.c | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/Wswitch-unreachable-2.c diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 43cf6c0..6c1d994 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1598,8 +1598,9 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) && switch_body_seq != NULL) { gimple_seq seq = switch_body_seq; - if (gimple_code (switch_body_seq) == GIMPLE_BIND) - seq = gimple_bind_body (as_a (switch_body_seq)); + /* Look into the innermost lexical scope. */ + while (gimple_code (seq) == GIMPLE_BIND) + seq = gimple_bind_body (as_a (seq)); gimple *stmt = gimple_seq_first_stmt (seq); enum gimple_code code = gimple_code (stmt); if (code != GIMPLE_LABEL && code != GIMPLE_TRY) diff --git a/gcc/testsuite/c-c++-common/Wswitch-unreachable-2.c b/gcc/testsuite/c-c++-common/Wswitch-unreachable-2.c new file mode 100644 index 0000000..8f57392 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wswitch-unreachable-2.c @@ -0,0 +1,18 @@ +/* PR c/71249 */ +/* { dg-do compile } */ + +int +f (int i) +{ + switch (i) + { + { + int j; + foo: + return i; /* { dg-bogus "statement will never be executed" } */ + }; + case 3: + goto foo; + } + return i; +} -- 2.7.4 From e0a5d0ba0307111e5fc046412c24fe8e6f4baaed Mon Sep 17 00:00:00 2001 From: mpolacek Date: Tue, 31 May 2016 14:55:05 +0000 Subject: [PATCH 02/16] * gimplify.c (gimplify_switch_expr): Also handle GIMPLE_TRY. * c-c++-common/Wswitch-unreachable-3.c: New test. * g++.dg/warn/Wswitch-unreachable-1.C: New test. upstream hash: 4ff7bd215d121cbec262600e2b4bcbff93b8affb git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@236924 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: Ic1e69ef6931e9f4051060cc37bd33c9a86ad2df3 --- gcc/gimplify.c | 13 +++++++-- gcc/testsuite/c-c++-common/Wswitch-unreachable-3.c | 29 ++++++++++++++++++ gcc/testsuite/g++.dg/warn/Wswitch-unreachable-1.C | 34 ++++++++++++++++++++++ 3 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/Wswitch-unreachable-3.c create mode 100644 gcc/testsuite/g++.dg/warn/Wswitch-unreachable-1.C diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 6c1d994..056d5ef 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1602,10 +1602,17 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) while (gimple_code (seq) == GIMPLE_BIND) seq = gimple_bind_body (as_a (seq)); gimple *stmt = gimple_seq_first_stmt (seq); - enum gimple_code code = gimple_code (stmt); - if (code != GIMPLE_LABEL && code != GIMPLE_TRY) + if (gimple_code (stmt) == GIMPLE_TRY) { - if (code == GIMPLE_GOTO + /* A compiler-generated cleanup or a user-written try block. + Try to get the first statement in its try-block, for better + location. */ + if ((seq = gimple_try_eval (stmt))) + stmt = gimple_seq_first_stmt (seq); + } + if (gimple_code (stmt) != GIMPLE_LABEL) + { + if (gimple_code (stmt) == GIMPLE_GOTO && TREE_CODE (gimple_goto_dest (stmt)) == LABEL_DECL && DECL_ARTIFICIAL (gimple_goto_dest (stmt))) /* Don't warn for compiler-generated gotos. These occur diff --git a/gcc/testsuite/c-c++-common/Wswitch-unreachable-3.c b/gcc/testsuite/c-c++-common/Wswitch-unreachable-3.c new file mode 100644 index 0000000..c53cb10 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wswitch-unreachable-3.c @@ -0,0 +1,29 @@ +/* { dg-do compile } */ + +extern void f (int *); + +void +g (int i) +{ + switch (i) + { + int a[3]; + __builtin_memset (a, 0, sizeof a); /* { dg-warning "statement will never be executed" } */ + + default: + f (a); + } + + switch (i) + { + int a[3]; + int b[3]; + int c[3]; + b[1] = 60; /* { dg-warning "statement will never be executed" } */ + + default: + f (a); + f (b); + f (c); + } +} diff --git a/gcc/testsuite/g++.dg/warn/Wswitch-unreachable-1.C b/gcc/testsuite/g++.dg/warn/Wswitch-unreachable-1.C new file mode 100644 index 0000000..99d9a83 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wswitch-unreachable-1.C @@ -0,0 +1,34 @@ +// { dg-do compile } + +extern int j; + +void +f (int i) +{ + switch (i) // { dg-warning "statement will never be executed" } + { + try + { + } + catch (...) + { + } + case 1:; + } +} + +void +g (int i) +{ + switch (i) + { + try + { + j = 42; // { dg-warning "statement will never be executed" } + } + catch (...) + { + } + case 1:; + } +} -- 2.7.4 From 5b32d4548a28e4783a5a965dee1241f41f27a952 Mon Sep 17 00:00:00 2001 From: mpolacek Date: Mon, 13 Jun 2016 08:57:02 +0000 Subject: [PATCH 03/16] PR middle-end/71476 * gimplify.c (maybe_warn_switch_unreachable): Factored out of gimplify_switch_expr. (warn_switch_unreachable_r): New function. * c-c++-common/Wswitch-unreachable-4.c: New test. * gcc.dg/Wswitch-unreachable-2.c: New test. * g++.dg/tm/jump1.C: Move dg-warning. upstream hash: 1a54d3bee5c40687c53b2680d0b110f23a193713 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@237367 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: Ie8bc6fb965fdb08c7e76ee02fe01eec4707336b0 --- gcc/gimplify.c | 102 ++++++++++++++------- gcc/testsuite/c-c++-common/Wswitch-unreachable-4.c | 25 +++++ gcc/testsuite/g++.dg/tm/jump1.C | 4 +- gcc/testsuite/gcc.dg/Wswitch-unreachable-2.c | 12 +++ 4 files changed, 108 insertions(+), 35 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/Wswitch-unreachable-4.c create mode 100644 gcc/testsuite/gcc.dg/Wswitch-unreachable-2.c diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 056d5ef..a66b846 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1552,6 +1552,73 @@ gimplify_statement_list (tree *expr_p, gimple_seq *pre_p) return GS_ALL_DONE; } +/* Callback for walk_gimple_seq. */ + +static tree +warn_switch_unreachable_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, + struct walk_stmt_info *wi) +{ + gimple *stmt = gsi_stmt (*gsi_p); + + *handled_ops_p = true; + switch (gimple_code (stmt)) + { + case GIMPLE_TRY: + /* A compiler-generated cleanup or a user-written try block. + If it's empty, don't dive into it--that would result in + worse location info. */ + if (gimple_try_eval (stmt) == NULL) + { + wi->info = stmt; + return integer_zero_node; + } + /* Fall through. */ + case GIMPLE_BIND: + case GIMPLE_CATCH: + case GIMPLE_EH_FILTER: + case GIMPLE_TRANSACTION: + /* Walk the sub-statements. */ + *handled_ops_p = false; + break; + default: + /* Save the first "real" statement (not a decl/lexical scope/...). */ + wi->info = stmt; + return integer_zero_node; + } + return NULL_TREE; +} + +/* Possibly warn about unreachable statements between switch's controlling + expression and the first case. SEQ is the body of a switch expression. */ + +static void +maybe_warn_switch_unreachable (gimple_seq seq) +{ + if (!warn_switch_unreachable + /* This warning doesn't play well with Fortran when optimizations + are on. */ + || lang_GNU_Fortran () + || seq == NULL) + return; + + struct walk_stmt_info wi; + memset (&wi, 0, sizeof (wi)); + walk_gimple_seq (seq, warn_switch_unreachable_r, NULL, &wi); + gimple *stmt = (gimple *) wi.info; + + if (stmt && gimple_code (stmt) != GIMPLE_LABEL) + { + if (gimple_code (stmt) == GIMPLE_GOTO + && TREE_CODE (gimple_goto_dest (stmt)) == LABEL_DECL + && DECL_ARTIFICIAL (gimple_goto_dest (stmt))) + /* Don't warn for compiler-generated gotos. These occur + in Duff's devices, for example. */; + else + warning_at (gimple_location (stmt), OPT_Wswitch_unreachable, + "statement will never be executed"); + } +} + /* Gimplify a SWITCH_EXPR, and collect the vector of labels it can branch to. */ @@ -1589,39 +1656,8 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) gimplify_stmt (&SWITCH_BODY (switch_expr), &switch_body_seq); - /* Possibly warn about unreachable statements between switch's - controlling expression and the first case. */ - if (warn_switch_unreachable - /* This warning doesn't play well with Fortran when optimizations - are on. */ - && !lang_GNU_Fortran () - && switch_body_seq != NULL) - { - gimple_seq seq = switch_body_seq; - /* Look into the innermost lexical scope. */ - while (gimple_code (seq) == GIMPLE_BIND) - seq = gimple_bind_body (as_a (seq)); - gimple *stmt = gimple_seq_first_stmt (seq); - if (gimple_code (stmt) == GIMPLE_TRY) - { - /* A compiler-generated cleanup or a user-written try block. - Try to get the first statement in its try-block, for better - location. */ - if ((seq = gimple_try_eval (stmt))) - stmt = gimple_seq_first_stmt (seq); - } - if (gimple_code (stmt) != GIMPLE_LABEL) - { - if (gimple_code (stmt) == GIMPLE_GOTO - && TREE_CODE (gimple_goto_dest (stmt)) == LABEL_DECL - && DECL_ARTIFICIAL (gimple_goto_dest (stmt))) - /* Don't warn for compiler-generated gotos. These occur - in Duff's devices, for example. */; - else - warning_at (gimple_location (stmt), OPT_Wswitch_unreachable, - "statement will never be executed"); - } - } + maybe_warn_switch_unreachable (switch_body_seq); + labels = gimplify_ctxp->case_labels; gimplify_ctxp->case_labels = saved_labels; diff --git a/gcc/testsuite/c-c++-common/Wswitch-unreachable-4.c b/gcc/testsuite/c-c++-common/Wswitch-unreachable-4.c new file mode 100644 index 0000000..e7378a7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wswitch-unreachable-4.c @@ -0,0 +1,25 @@ +/* { dg-do compile } */ + +void +foo (int a, int b) +{ + switch (a) + { + { int c; } + { int d; } + { int e; } + b++; /* { dg-warning "statement will never be executed" } */ + case 1: + break; + } + + switch (a) + { + { int c; } + { int d = 1; } /* { dg-warning "statement will never be executed" } */ + { int e; } + b++; + case 1: + break; + } +} diff --git a/gcc/testsuite/g++.dg/tm/jump1.C b/gcc/testsuite/g++.dg/tm/jump1.C index e28282d..a27c201 100644 --- a/gcc/testsuite/g++.dg/tm/jump1.C +++ b/gcc/testsuite/g++.dg/tm/jump1.C @@ -14,8 +14,8 @@ void f() switch (i) { - synchronized { // { dg-warning "statement will never be executed" } - ++i; + synchronized { + ++i; // { dg-warning "statement will never be executed" } case 42: // { dg-error "" } ++i; } diff --git a/gcc/testsuite/gcc.dg/Wswitch-unreachable-2.c b/gcc/testsuite/gcc.dg/Wswitch-unreachable-2.c new file mode 100644 index 0000000..343baea --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wswitch-unreachable-2.c @@ -0,0 +1,12 @@ +/* PR middle-end/71476 */ +/* { dg-do compile } */ +/* { dg-options "-Wswitch-unreachable" } */ + +void +foo (int a) +{ + switch (a) + { + void f (void) { } + } +} -- 2.7.4 From 07d99c4761ee840d74b06aa565bf84930ba16d53 Mon Sep 17 00:00:00 2001 From: tschwinge Date: Thu, 4 Aug 2016 13:35:19 +0000 Subject: [PATCH 04/16] C/C++: Simplify handling of location information for OpenACC routine directives gcc/c/ * c-parser.c (struct oacc_routine_data): New. (c_parser_declaration_or_fndef, c_parser_oacc_routine): Use it. Simplify code. (c_finish_oacc_routine): Likewise. Don't attach clauses to "omp declare target" attribute. gcc/cp/ * parser.h (struct cp_omp_declare_simd_data): New. (struct cp_parser): Use it for oacc_routine member. * parser.c (cp_ensure_no_oacc_routine, cp_parser_oacc_routine) (cp_parser_late_parsing_oacc_routine, cp_finalize_oacc_routine): Use it. Simplify code. (cp_parser_new): Initialize all members pointing to special parsing data structures. (cp_parser_cilk_simd_fn_vector_attrs): Initialize parser->cilk_simd_fn_info->clauses. (cp_parser_omp_declare_simd): Initialize parser->omp_declare_simd->clauses. (cp_parser_late_parsing_omp_declare_simd): Simplify code. upstream hash: 5f429ee2993ea1795d88c5589251c500e6e9062a git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@239127 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: I6e8b2ad2102b50798fd0fb7b373e6c4ccb17acd7 --- gcc/c/c-parser.c | 86 ++++++++++++++++++++++---------------------- gcc/cp/parser.c | 108 ++++++++++++++++++++++++------------------------------- gcc/cp/parser.h | 21 ++++++----- 3 files changed, 103 insertions(+), 112 deletions(-) diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index e8fee53..99a2314 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1267,11 +1267,17 @@ enum c_parser_prec { NUM_PRECS }; +/* Helper data structure for parsing #pragma acc routine. */ +struct oacc_routine_data { + tree clauses; + location_t loc; +}; + 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, - tree = NULL_TREE); + struct oacc_routine_data * = 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, @@ -1363,7 +1369,7 @@ static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *); static void c_parser_omp_end_declare_target (c_parser *); static void c_parser_omp_declare (c_parser *, enum pragma_context); static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *); -static void c_parser_oacc_routine (c_parser *parser, enum pragma_context); +static void c_parser_oacc_routine (c_parser *, enum pragma_context); /* These Objective-C parser functions are only ever called when compiling Objective-C. */ @@ -1555,7 +1561,8 @@ c_parser_external_declaration (c_parser *parser) } static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec); -static void c_finish_oacc_routine (c_parser *, tree, tree, bool, bool, bool); +static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool, + bool, bool); /* Parse a declaration or function definition (C90 6.5, 6.7.1, C99 6.7, 6.9.1). If FNDEF_OK is true, a function definition is @@ -1634,7 +1641,7 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool nested, bool start_attr_ok, tree *objc_foreach_object_declaration, vec omp_declare_simd_clauses, - tree oacc_routine_clauses) + struct oacc_routine_data *oacc_routine_data) { struct c_declspecs *specs; tree prefix_attrs; @@ -1704,9 +1711,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, pedwarn (here, 0, "empty declaration"); } c_parser_consume_token (parser); - if (oacc_routine_clauses) - c_finish_oacc_routine (parser, NULL_TREE, - oacc_routine_clauses, false, true, false); + if (oacc_routine_data) + c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false, true, + false); return; } @@ -1823,9 +1830,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, || !vec_safe_is_empty (parser->cilk_simd_fn_tokens)) c_finish_omp_declare_simd (parser, NULL_TREE, NULL_TREE, omp_declare_simd_clauses); - if (oacc_routine_clauses) - c_finish_oacc_routine (parser, NULL_TREE, - oacc_routine_clauses, + if (oacc_routine_data) + c_finish_oacc_routine (oacc_routine_data, NULL_TREE, false, first, false); c_parser_skip_to_end_of_block_or_statement (parser); return; @@ -1950,8 +1956,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, finish_init (); processing_static_variable = false; } - if (oacc_routine_clauses) - c_finish_oacc_routine (parser, d, oacc_routine_clauses, + if (oacc_routine_data) + c_finish_oacc_routine (oacc_routine_data, d, false, first, false); if (d != error_mark_node) { @@ -1996,8 +2002,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, if (parms) temp_pop_parm_decls (); } - if (oacc_routine_clauses) - c_finish_oacc_routine (parser, d, oacc_routine_clauses, + if (oacc_routine_data) + c_finish_oacc_routine (oacc_routine_data, d, false, first, false); if (d) finish_decl (d, UNKNOWN_LOCATION, NULL_TREE, @@ -2109,9 +2115,9 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, || !vec_safe_is_empty (parser->cilk_simd_fn_tokens)) c_finish_omp_declare_simd (parser, current_function_decl, NULL_TREE, omp_declare_simd_clauses); - if (oacc_routine_clauses) - c_finish_oacc_routine (parser, current_function_decl, - oacc_routine_clauses, false, first, true); + if (oacc_routine_data) + c_finish_oacc_routine (oacc_routine_data, current_function_decl, + false, first, true); DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus = c_parser_peek_token (parser)->location; fnbody = c_parser_compound_statement (parser); @@ -13972,9 +13978,9 @@ static void c_parser_oacc_routine (c_parser *parser, enum pragma_context context) { tree decl = NULL_TREE; - /* Create a dummy claue, to record location. */ - tree c_head = build_omp_clause (c_parser_peek_token (parser)->location, - OMP_CLAUSE_SEQ); + oacc_routine_data data; + data.clauses = NULL_TREE; + data.loc = c_parser_peek_token (parser)->location; if (context != pragma_external) c_parser_error (parser, "%<#pragma acc routine%> not at file scope"); @@ -14010,56 +14016,52 @@ c_parser_oacc_routine (c_parser *parser, enum pragma_context context) /* Build a chain of clauses. */ parser->in_pragma = true; - tree clauses = c_parser_oacc_all_clauses - (parser, OACC_ROUTINE_CLAUSE_MASK, "#pragma acc routine"); + data.clauses + = c_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, + "#pragma acc routine"); - /* Force clauses to be non-null, by attaching context to it. */ - clauses = tree_cons (c_head, clauses, NULL_TREE); - if (decl) - c_finish_oacc_routine (parser, decl, clauses, true, true, false); + c_finish_oacc_routine (&data, decl, true, true, false); else if (c_parser_peek_token (parser)->type == CPP_PRAGMA) /* This will emit an error. */ - c_finish_oacc_routine (parser, NULL_TREE, clauses, false, true, false); + c_finish_oacc_routine (&data, NULL_TREE, false, true, false); else c_parser_declaration_or_fndef (parser, true, false, false, false, - true, NULL, vNULL, clauses); + true, NULL, vNULL, &data); } -/* Finalize an OpenACC routine pragma, applying it to FNDECL. CLAUSES - are the parsed clauses. IS_DEFN is true if we're applying it to - the definition (so expect FNDEF to look somewhat defined. */ +/* Finalize an OpenACC routine pragma, applying it to FNDECL. + IS_DEFN is true if we're applying it to the definition. */ static void -c_finish_oacc_routine (c_parser *ARG_UNUSED (parser), tree fndecl, - tree clauses, bool named, bool first, bool is_defn) +c_finish_oacc_routine (struct oacc_routine_data *data, tree fndecl, + bool named, bool first, bool is_defn) { - location_t loc = OMP_CLAUSE_LOCATION (TREE_PURPOSE (clauses)); - if (!fndecl || TREE_CODE (fndecl) != FUNCTION_DECL || !first) { if (fndecl != error_mark_node) - error_at (loc, "%<#pragma acc routine%> %s", + error_at (data->loc, "%<#pragma acc routine%> %s", named ? "does not refer to a function" : "not followed by single function"); return; } if (get_oacc_fn_attrib (fndecl)) - error_at (loc, "%<#pragma acc routine%> already applied to %D", fndecl); + error_at (data->loc, + "%<#pragma acc routine%> already applied to %D", fndecl); if (TREE_USED (fndecl) || (!is_defn && DECL_SAVED_TREE (fndecl))) - error_at (loc, "%<#pragma acc routine%> must be applied before %s", + error_at (data->loc, "%<#pragma acc routine%> must be applied before %s", TREE_USED (fndecl) ? "use" : "definition"); - /* Process for function attrib */ - tree dims = build_oacc_routine_dims (TREE_VALUE (clauses)); + /* Process the routine's dimension clauses. */ + tree dims = build_oacc_routine_dims (data->clauses); replace_oacc_fn_attrib (fndecl, dims); - /* Also attach as a declare. */ + /* Add an "omp declare target" attribute. */ DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("omp declare target"), - clauses, DECL_ATTRIBUTES (fndecl)); + NULL_TREE, DECL_ATTRIBUTES (fndecl)); } /* OpenACC 2.0: diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index b66b7e1..c163dba 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1384,10 +1384,8 @@ cp_ensure_no_oacc_routine (cp_parser *parser) { if (parser->oacc_routine && !parser->oacc_routine->error_seen) { - tree clauses = parser->oacc_routine->clauses; - location_t loc = OMP_CLAUSE_LOCATION (TREE_PURPOSE (clauses)); - - error_at (loc, "%<#pragma acc routine%> not followed by a function " + error_at (parser->oacc_routine->loc, + "%<#pragma acc routine%> not followed by a function " "declaration or definition"); parser->oacc_routine = NULL; } @@ -3756,15 +3754,17 @@ cp_parser_new (void) /* No template parameters apply. */ parser->num_template_parameter_lists = 0; + /* Special parsing data structures. */ + parser->omp_declare_simd = NULL; + parser->cilk_simd_fn_info = NULL; + parser->oacc_routine = NULL; + /* Not declaring an implicit function template. */ parser->auto_is_implicit_function_template_parm_p = false; parser->fully_implicit_function_template_p = false; parser->implicit_template_parms = 0; parser->implicit_template_scope = 0; - /* Active OpenACC routine clauses. */ - parser->oacc_routine = NULL; - /* Allow constrained-type-specifiers. */ parser->prevent_constrained_type_specifiers = 0; @@ -19839,8 +19839,9 @@ parsing_nsdmi (void) Returns the type indicated by the type-id. - In addition to this, parse any queued up omp declare simd - clauses and Cilk Plus SIMD-enabled function's vector attributes. + In addition to this, parse any queued up #pragma omp declare simd + clauses, Cilk Plus SIMD-enabled functions' vector attributes, and + #pragma acc routine clauses. QUALS is either a bitmask of cv_qualifiers or -1 for a non-member function. */ @@ -23717,6 +23718,7 @@ cp_parser_cilk_simd_fn_vector_attrs (cp_parser *parser, cp_token *v_token) parser->cilk_simd_fn_info->error_seen = false; parser->cilk_simd_fn_info->fndecl_seen = false; parser->cilk_simd_fn_info->tokens = vNULL; + parser->cilk_simd_fn_info->clauses = NULL_TREE; } int paren_scope = 0; if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)) @@ -35718,6 +35720,9 @@ cp_parser_omp_declare_simd (cp_parser *parser, cp_token *pragma_tok, data.error_seen = false; data.fndecl_seen = false; data.tokens = vNULL; + data.clauses = NULL_TREE; + /* It is safe to take the address of a local variable; it will only be + used while this scope is live. */ parser->omp_declare_simd = &data; } while (cp_lexer_next_token_is_not (parser->lexer, CPP_PRAGMA_EOL) @@ -35835,7 +35840,6 @@ cp_parser_late_parsing_omp_declare_simd (cp_parser *parser, tree attrs) error ("%<#pragma omp declare simd%> not immediately followed by " "a single function declaration or definition"); data->error_seen = true; - return attrs; } if (data->error_seen) return attrs; @@ -36549,21 +36553,19 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, enum pragma_context context) { bool first_p = parser->oacc_routine == NULL; - location_t loc = pragma_tok->location; - cp_omp_declare_simd_data data; + cp_oacc_routine_data data; if (first_p) { data.error_seen = false; data.fndecl_seen = false; data.tokens = vNULL; data.clauses = NULL_TREE; + data.loc = pragma_tok->location; + /* It is safe to take the address of a local variable; it will only be + used while this scope is live. */ parser->oacc_routine = &data; } - tree decl = NULL_TREE; - /* Create a dummy claue, to record location. */ - tree c_head = build_omp_clause (pragma_tok->location, OMP_CLAUSE_SEQ); - if (context != pragma_external) { cp_parser_error (parser, "%<#pragma acc routine%> not at file scope"); @@ -36584,7 +36586,7 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, parser->oacc_routine->error_seen = true; cp_parser_require_pragma_eol (parser, pragma_tok); - error_at (OMP_CLAUSE_LOCATION (parser->oacc_routine->clauses), + error_at (parser->oacc_routine->loc, "%<#pragma acc routine%> not followed by a " "function declaration or definition"); @@ -36604,7 +36606,7 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, /*template_p=*/NULL, /*declarator_p=*/false, /*optional_p=*/false); - decl = cp_parser_lookup_name_simple (parser, id, token->location); + tree decl = cp_parser_lookup_name_simple (parser, id, token->location); if (id != error_mark_node && decl == error_mark_node) cp_parser_name_lookup_error (parser, id, decl, NLE_NULL, token->location); @@ -36619,20 +36621,17 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, /* Build a chain of clauses. */ parser->lexer->in_pragma = true; - tree clauses = NULL_TREE; - clauses = cp_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, - "#pragma acc routine", - cp_lexer_peek_token - (parser->lexer)); - - /* Force clauses to be non-null, by attaching context to it. */ - clauses = tree_cons (c_head, clauses, NULL_TREE); + data.clauses + = cp_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, + "#pragma acc routine", + cp_lexer_peek_token (parser->lexer)); if (decl && is_overloaded_fn (decl) && (TREE_CODE (decl) != FUNCTION_DECL || DECL_FUNCTION_TEMPLATE_P (decl))) { - error_at (loc, "%<#pragma acc routine%> names a set of overloads"); + error_at (data.loc, + "%<#pragma acc routine%> names a set of overloads"); parser->oacc_routine = NULL; return; } @@ -36641,7 +36640,8 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, namespaces? */ if (!DECL_NAMESPACE_SCOPE_P (decl)) { - error_at (loc, "%<#pragma acc routine%> does not refer to a " + error_at (data.loc, + "%<#pragma acc routine%> does not refer to a " "namespace scope function"); parser->oacc_routine = NULL; return; @@ -36649,14 +36649,12 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, if (!decl || TREE_CODE (decl) != FUNCTION_DECL) { - error_at (loc, + error_at (data.loc, "%<#pragma acc routine%> does not refer to a function"); parser->oacc_routine = NULL; return; } - data.clauses = clauses; - cp_finalize_oacc_routine (parser, decl, false); data.tokens.release (); parser->oacc_routine = NULL; @@ -36674,23 +36672,18 @@ cp_parser_oacc_routine (cp_parser *parser, cp_token *pragma_tok, = cp_token_cache_new (pragma_tok, cp_lexer_peek_token (parser->lexer)); parser->oacc_routine->tokens.safe_push (cp); - if (first_p) - parser->oacc_routine->clauses = c_head; - while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)) cp_parser_pragma (parser, context, NULL); if (first_p) { - /* Create an empty list of clauses. */ - parser->oacc_routine->clauses = tree_cons (c_head, NULL_TREE, - NULL_TREE); cp_parser_declaration (parser); if (parser->oacc_routine && !parser->oacc_routine->error_seen && !parser->oacc_routine->fndecl_seen) - error_at (loc, "%<#pragma acc routine%> not followed by a " + error_at (data.loc, + "%<#pragma acc routine%> not followed by a " "function declaration or definition"); data.tokens.release (); @@ -36706,19 +36699,15 @@ static tree cp_parser_late_parsing_oacc_routine (cp_parser *parser, tree attrs) { struct cp_token_cache *ce; - cp_omp_declare_simd_data *data = parser->oacc_routine; - tree cl, clauses = parser->oacc_routine->clauses; - location_t loc; + cp_oacc_routine_data *data = parser->oacc_routine; - loc = OMP_CLAUSE_LOCATION (TREE_PURPOSE(clauses)); - if ((!data->error_seen && data->fndecl_seen) || data->tokens.length () != 1) { - error_at (loc, "%<#pragma acc routine%> not followed by a " + error_at (data->loc, + "%<#pragma acc routine%> not followed by a " "function declaration or definition"); data->error_seen = true; - return attrs; } if (data->error_seen) return attrs; @@ -36730,15 +36719,11 @@ cp_parser_late_parsing_oacc_routine (cp_parser *parser, tree attrs) gcc_assert (cp_lexer_peek_token (parser->lexer)->type == CPP_PRAGMA); cp_token *pragma_tok = cp_lexer_consume_token (parser->lexer); - cl = cp_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, + parser->oacc_routine->clauses + = cp_parser_oacc_all_clauses (parser, OACC_ROUTINE_CLAUSE_MASK, "#pragma acc routine", pragma_tok); cp_parser_pop_lexer (parser); - tree c_head = build_omp_clause (loc, OMP_CLAUSE_SEQ); - - /* Force clauses to be non-null, by attaching context to it. */ - parser->oacc_routine->clauses = tree_cons (c_head, cl, NULL_TREE); - data->fndecl_seen = true; return attrs; } @@ -36751,9 +36736,6 @@ cp_finalize_oacc_routine (cp_parser *parser, tree fndecl, bool is_defn) { if (__builtin_expect (parser->oacc_routine != NULL, 0)) { - tree clauses = parser->oacc_routine->clauses; - location_t loc = OMP_CLAUSE_LOCATION (TREE_PURPOSE(clauses)); - if (parser->oacc_routine->error_seen) return; @@ -36771,31 +36753,35 @@ cp_finalize_oacc_routine (cp_parser *parser, tree fndecl, bool is_defn) if (!fndecl || TREE_CODE (fndecl) != FUNCTION_DECL) { - error_at (loc, + error_at (parser->oacc_routine->loc, "%<#pragma acc routine%> not followed by a function " "declaration or definition"); parser->oacc_routine = NULL; + return; } if (get_oacc_fn_attrib (fndecl)) { - error_at (loc, "%<#pragma acc routine%> already applied to %D", - fndecl); + error_at (parser->oacc_routine->loc, + "%<#pragma acc routine%> already applied to %D", fndecl); parser->oacc_routine = NULL; + return; } if (TREE_USED (fndecl) || (!is_defn && DECL_SAVED_TREE (fndecl))) { - error_at (loc, "%<#pragma acc routine%> must be applied before %s", + error_at (parser->oacc_routine->loc, + "%<#pragma acc routine%> must be applied before %s", TREE_USED (fndecl) ? "use" : "definition"); parser->oacc_routine = NULL; + return; } - /* Process for function attrib */ - tree dims = build_oacc_routine_dims (TREE_VALUE (clauses)); + /* Process the routine's dimension clauses. */ + tree dims = build_oacc_routine_dims (parser->oacc_routine->clauses); replace_oacc_fn_attrib (fndecl, dims); - /* Add an "omp target" attribute. */ + /* Add an "omp declare target" attribute. */ DECL_ATTRIBUTES (fndecl) = tree_cons (get_identifier ("omp declare target"), NULL_TREE, DECL_ATTRIBUTES (fndecl)); diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h index ccbace9..a777a84 100644 --- a/gcc/cp/parser.h +++ b/gcc/cp/parser.h @@ -199,7 +199,8 @@ struct GTY (()) cp_parser_context { }; -/* Control structure for #pragma omp declare simd parsing. */ +/* Helper data structure for parsing #pragma omp declare simd, and Cilk Plus + SIMD-enabled functions' vector attribute. */ struct cp_omp_declare_simd_data { bool error_seen; /* Set if error has been reported. */ bool fndecl_seen; /* Set if one fn decl/definition has been seen already. */ @@ -207,6 +208,10 @@ struct cp_omp_declare_simd_data { tree clauses; }; +/* Helper data structure for parsing #pragma acc routine. */ +struct cp_oacc_routine_data : cp_omp_declare_simd_data { + location_t loc; +}; /* The cp_parser structure represents the C++ parser. */ @@ -363,18 +368,16 @@ struct GTY(()) cp_parser { unsigned num_template_parameter_lists; /* When parsing #pragma omp declare simd, this is a pointer to a - data structure with everything needed for parsing the clauses. */ + helper data structure. */ cp_omp_declare_simd_data * GTY((skip)) omp_declare_simd; - /* When parsing the vector attribute in Cilk Plus SIMD-enabled function, - this is a pointer to data structure with everything needed for parsing - the clauses. The cp_omp_declare_simd_data struct will hold all the - necessary information, so creating another struct for this is not - necessary. */ + /* When parsing Cilk Plus SIMD-enabled functions' vector attributes, + this is a pointer to a helper data structure. */ cp_omp_declare_simd_data * GTY((skip)) cilk_simd_fn_info; - /* Parsing information for #pragma acc routine. */ - cp_omp_declare_simd_data * GTY((skip)) oacc_routine; + /* When parsing #pragma acc routine, this is a pointer to a helper data + structure. */ + cp_oacc_routine_data * GTY((skip)) oacc_routine; /* Nonzero if parsing a parameter list where 'auto' should trigger an implicit template parameter. */ -- 2.7.4 From 2c21a05b4241436d0a079ef49b46dc3269548a61 Mon Sep 17 00:00:00 2001 From: matz Date: Mon, 18 Apr 2016 20:36:27 +0000 Subject: [PATCH 05/16] * tree.h (TYPE_ALIGN, DECL_ALIGN): Return shifted amount. (SET_TYPE_ALIGN, SET_DECL_ALIGN): New. * tree-core.h (tree_type_common.align): Use bit-field. (tree_type_common.spare): New. (tree_decl_common.off_align): Make smaller. (tree_decl_common.align): Use bit-field. * expr.c (expand_expr_addr_expr_1): Use SET_TYPE_ALIGN. * omp-low.c (install_var_field): Use SET_DECL_ALIGN. (scan_sharing_clauses): Ditto. (finish_taskreg_scan): Use SET_DECL_ALIGN and SET_TYPE_ALIGN. (omp_finish_file): Ditto. * stor-layout.c (do_type_align): Use SET_DECL_ALIGN. (layout_decl): Ditto. (relayout_decl): Ditto. (finalize_record_size): Use SET_TYPE_ALIGN. (finalize_type_size): Ditto. (finish_builtin_struct): Ditto. (layout_type): Ditto. (initialize_sizetypes): Ditto. * targhooks.c (std_gimplify_va_arg_expr): Use SET_TYPE_ALIGN. * tree-nested.c (insert_field_into_struct): Use SET_TYPE_ALIGN. (lookup_field_for_decl): Use SET_DECL_ALIGN. (get_chain_field): Ditto. (get_trampoline_type): Ditto. (get_nl_goto_field): Ditto. * tree-streamer-in.c (unpack_ts_decl_common_value_fields): Use SET_DECL_ALIGN. (unpack_ts_type_common_value_fields): Use SET_TYPE_ALIGN. * gimple-expr.c (copy_var_decl): Use SET_DECL_ALIGN. * tree.c (make_node_stat): Use SET_DECL_ALIGN and SET_TYPE_ALIGN. (build_qualified_type): Use SET_TYPE_ALIGN. (build_aligned_type, build_range_type_1): Ditto. (build_atomic_base): Ditto. (build_common_tree_nodes): Ditto. * cfgexpand.c (align_local_variable): Use SET_DECL_ALIGN. (expand_one_stack_var_at): Ditto. * coverage.c (build_var): Use SET_DECL_ALIGN. * except.c (init_eh): Ditto. * function.c (assign_parm_setup_block): Ditto. * symtab.c (increase_alignment_1): Ditto. * tree-ssa-ccp.c (fold_builtin_alloca_with_align): Ditto. * tree-vect-stmts.c (ensure_base_align): Ditto. * varasm.c (align_variable): Ditto. (assemble_variable): Ditto. (build_constant_desc): Ditto. (output_constant_def_contents): Ditto. * config/arm/arm.c (arm_relayout_function): Use SET_DECL_ALIGN. * config/avr/avr.c (avr_adjust_type_node): Use SET_TYPE_ALIGN. * config/mips/mips.c (mips_std_gimplify_va_arg_expr): Ditto. * config/msp430/msp430.c (msp430_gimplify_va_arg_expr): Ditto. * config/spu/spu.c (spu_build_builtin_va_list): Use SET_DECL_ALIGN. ada/ * gcc-interface/decl.c (gnat_to_gnu_entity): Use SET_TYPE_ALIGN. (gnat_to_gnu_field): Ditto. (components_to_record): Ditto. (create_variant_part_from): Ditto. (copy_and_substitute_in_size): Ditto. (substitute_in_type): Ditto. * gcc-interface/utils.c (make_aligning_type): Use SET_TYPE_ALIGN. (make_packable_type): Ditto. (maybe_pad_type): Ditto. (finish_fat_pointer_type): Ditto. (finish_record_type): Ditto and use SET_DECL_ALIGN. (rest_of_record_type_compilation): Use SET_TYPE_ALIGN. (create_field_decl): Use SET_DECL_ALIGN. c-family/ * c-common.c (handle_aligned_attribute): Use SET_TYPE_ALIGN and SET_DECL_ALIGN. c/ * c-decl.c (merge_decls): Use SET_DECL_ALIGN and SET_TYPE_ALIGN. (grokdeclarator, parser_xref_tag, finish_enum): Use SET_TYPE_ALIGN. cp/ * class.c (build_vtable): Use SET_DECL_ALIGN and SET_TYPE_ALIGN. (layout_class_type): Ditto. (build_base_field): Use SET_DECL_ALIGN. (fixup_attribute_variants): Use SET_TYPE_ALIGN. * decl.c (duplicate_decls): Use SET_DECL_ALIGN. (record_unknown_type): Use SET_TYPE_ALIGN. (cxx_init_decl_processing): Ditto. (copy_type_enum): Ditto. (grokfndecl): Use SET_DECL_ALIGN. (copy_type_enum): Use SET_TYPE_ALIGN. * pt.c (instantiate_class_template_1): Use SET_TYPE_ALIGN. (tsubst): Ditto. * tree.c (cp_build_qualified_type_real): Use SET_TYPE_ALIGN. * lambda.c (maybe_add_lambda_conv_op): Use SET_DECL_ALIGN. * method.c (implicitly_declare_fn): Use SET_DECL_ALIGN. * rtti.c (emit_tinfo_decl): Ditto. fortran/ * trans-io.c (gfc_build_io_library_fndecls): Use SET_TYPE_ALIGN. * trans-common.c (build_common_decl): Use SET_DECL_ALIGN. * trans-types.c (gfc_add_field_to_struct): Use SET_DECL_ALIGN. go/ * go-gcc.cc (Gcc_backend::implicit_variable): Use SET_DECL_ALIGN. java/ * class.c (add_method_1): Use SET_DECL_ALIGN. (make_class_data): Ditto. (emit_register_classes_in_jcr_section): Ditto. * typeck.c (build_java_array_type): Ditto. objc/ * objc-act.c (objc_build_struct): Use SET_DECL_ALIGN. libcc1/ * plugin.cc (plugin_finish_record_or_union): Use SET_TYPE_ALIGN. upstream hash: 5d4b30ea56c1733a9149b59105b9645c115cc123 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@235172 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: Ia135e37556ac5bc0e2db4cc2a940d8d31e243ade --- gcc/ada/gcc-interface/decl.c | 52 ++++++++++++++++++++++--------------------- gcc/ada/gcc-interface/utils.c | 37 +++++++++++++++--------------- gcc/c-family/c-common.c | 4 ++-- gcc/c/c-decl.c | 12 +++++----- gcc/cfgexpand.c | 4 ++-- gcc/config/arm/arm.c | 4 ++-- gcc/config/avr/avr.c | 2 +- gcc/config/mips/mips.c | 2 +- gcc/config/msp430/msp430.c | 2 +- gcc/config/spu/spu.c | 4 ++-- gcc/coverage.c | 2 +- gcc/cp/class.c | 10 ++++----- gcc/cp/decl.c | 12 +++++----- gcc/cp/lambda.c | 2 +- gcc/cp/method.c | 2 +- gcc/cp/pt.c | 4 ++-- gcc/cp/rtti.c | 2 +- gcc/cp/tree.c | 2 +- gcc/except.c | 2 +- gcc/expr.c | 2 +- gcc/fortran/trans-common.c | 4 ++-- gcc/fortran/trans-io.c | 4 ++-- gcc/fortran/trans-types.c | 2 +- gcc/function.c | 2 +- gcc/gimple-expr.c | 2 +- gcc/go/go-gcc.cc | 2 +- gcc/java/class.c | 10 ++++----- gcc/java/typeck.c | 2 +- gcc/objc/objc-act.c | 2 +- gcc/omp-low.c | 24 ++++++++++---------- gcc/stor-layout.c | 44 ++++++++++++++++++------------------ gcc/symtab.c | 2 +- gcc/targhooks.c | 2 +- gcc/tree-core.h | 16 ++++++++----- gcc/tree-nested.c | 12 +++++----- gcc/tree-ssa-ccp.c | 2 +- gcc/tree-streamer-in.c | 8 +++---- gcc/tree-vect-stmts.c | 2 +- gcc/tree.c | 16 ++++++------- gcc/tree.h | 30 +++++++++++++++++-------- gcc/varasm.c | 12 +++++----- libcc1/plugin.cc | 4 ++-- 42 files changed, 194 insertions(+), 173 deletions(-) diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c index 4290e9b..fc06514 100644 --- a/gcc/ada/gcc-interface/decl.c +++ b/gcc/ada/gcc-interface/decl.c @@ -1896,8 +1896,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) This means that bit-packed arrays are given "ceil" alignment for their size by default, which may seem counter-intuitive but makes it possible to overlay them on modular types easily. */ - TYPE_ALIGN (gnu_type) - = align > 0 ? align : TYPE_ALIGN (gnu_field_type); + SET_TYPE_ALIGN (gnu_type, + align > 0 ? align : TYPE_ALIGN (gnu_field_type)); /* Propagate the reverse storage order flag to the record type so that the required byte swapping is performed when retrieving the @@ -1961,7 +1961,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) TYPE_SIZE (gnu_type) = TYPE_SIZE (gnu_field_type); TYPE_SIZE_UNIT (gnu_type) = TYPE_SIZE_UNIT (gnu_field_type); SET_TYPE_ADA_SIZE (gnu_type, TYPE_RM_SIZE (gnu_field_type)); - TYPE_ALIGN (gnu_type) = align; + SET_TYPE_ALIGN (gnu_type, align); relate_alias_sets (gnu_type, gnu_field_type, ALIAS_SET_COPY); /* Don't declare the field as addressable since we won't be taking @@ -2273,9 +2273,10 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) if (No (Packed_Array_Impl_Type (gnat_entity)) && Known_Alignment (gnat_entity)) { - TYPE_ALIGN (tem) - = validate_alignment (Alignment (gnat_entity), gnat_entity, - TYPE_ALIGN (tem)); + SET_TYPE_ALIGN (tem, + validate_alignment (Alignment (gnat_entity), + gnat_entity, + TYPE_ALIGN (tem))); if (Present (Alignment_Clause (gnat_entity))) TYPE_USER_ALIGN (tem) = 1; } @@ -2304,7 +2305,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) TYPE_POINTER_TO (gnu_type) = gnu_fat_type; TYPE_REFERENCE_TO (gnu_type) = gnu_fat_type; SET_TYPE_MODE (gnu_type, BLKmode); - TYPE_ALIGN (gnu_type) = TYPE_ALIGN (tem); + SET_TYPE_ALIGN (gnu_type, TYPE_ALIGN (tem)); /* If the maximum size doesn't overflow, use it. */ if (gnu_max_size @@ -3045,11 +3046,12 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) /* Always set the alignment on the record type here so that it can get the proper layout. */ if (has_align) - TYPE_ALIGN (gnu_type) - = validate_alignment (Alignment (gnat_entity), gnat_entity, 0); + SET_TYPE_ALIGN (gnu_type, + validate_alignment (Alignment (gnat_entity), + gnat_entity, 0)); else { - TYPE_ALIGN (gnu_type) = 0; + SET_TYPE_ALIGN (gnu_type, 0); /* If a type needs strict alignment, the minimum size will be the type size instead of the RM size (see validate_size). Cap the @@ -3148,7 +3150,7 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) be created with a component clause below, then we need to apply the same adjustment as in gnat_to_gnu_field. */ if (has_rep && TYPE_ALIGN (gnu_type) < TYPE_ALIGN (gnu_parent)) - TYPE_ALIGN (gnu_type) = TYPE_ALIGN (gnu_parent); + SET_TYPE_ALIGN (gnu_type, TYPE_ALIGN (gnu_parent)); /* Finally we fix up both kinds of twisted COMPONENT_REF we have initially built. The discriminants must reference the fields @@ -4575,8 +4577,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) /* Set a default alignment to speed up accesses. But we shouldn't increase the size of the structure too much, lest it doesn't fit in return registers anymore. */ - TYPE_ALIGN (gnu_return_type) - = get_mode_alignment (ptr_mode); + SET_TYPE_ALIGN (gnu_return_type, + get_mode_alignment (ptr_mode)); } gnu_field @@ -4623,8 +4625,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition) if (mode != BLKmode) { SET_TYPE_MODE (gnu_return_type, mode); - TYPE_ALIGN (gnu_return_type) - = GET_MODE_ALIGNMENT (mode); + SET_TYPE_ALIGN (gnu_return_type, + GET_MODE_ALIGNMENT (mode)); TYPE_SIZE (gnu_return_type) = bitsize_int (GET_MODE_BITSIZE (mode)); TYPE_SIZE_UNIT (gnu_return_type) @@ -6806,7 +6808,7 @@ gnat_to_gnu_field (Entity_Id gnat_field, tree gnu_record_type, int packed, const unsigned int type_align = TYPE_ALIGN (gnu_field_type); if (TYPE_ALIGN (gnu_record_type) < type_align) - TYPE_ALIGN (gnu_record_type) = type_align; + SET_TYPE_ALIGN (gnu_record_type, type_align); /* If the position is not a multiple of the alignment of the type, then error out and reset the position. */ @@ -7293,7 +7295,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, = make_node (unchecked_union ? UNION_TYPE : QUAL_UNION_TYPE); TYPE_NAME (gnu_union_type) = gnu_union_name; - TYPE_ALIGN (gnu_union_type) = 0; + SET_TYPE_ALIGN (gnu_union_type, 0); TYPE_PACKED (gnu_union_type) = TYPE_PACKED (gnu_record_type); TYPE_REVERSE_STORAGE_ORDER (gnu_union_type) = TYPE_REVERSE_STORAGE_ORDER (gnu_record_type); @@ -7346,7 +7348,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, /* Set the alignment of the inner type in case we need to make inner objects into bitfields, but then clear it out so the record actually gets only the alignment required. */ - TYPE_ALIGN (gnu_variant_type) = TYPE_ALIGN (gnu_record_type); + SET_TYPE_ALIGN (gnu_variant_type, TYPE_ALIGN (gnu_record_type)); TYPE_PACKED (gnu_variant_type) = TYPE_PACKED (gnu_record_type); TYPE_REVERSE_STORAGE_ORDER (gnu_variant_type) = TYPE_REVERSE_STORAGE_ORDER (gnu_record_type); @@ -7578,9 +7580,9 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, SET_DECL_OFFSET_ALIGN (gnu_field, BIGGEST_ALIGNMENT); DECL_FIELD_BIT_OFFSET (gnu_field) = bitsize_zero_node; if (field_is_aliased (gnu_field)) - TYPE_ALIGN (gnu_record_type) - = MAX (TYPE_ALIGN (gnu_record_type), - TYPE_ALIGN (TREE_TYPE (gnu_field))); + SET_TYPE_ALIGN (gnu_record_type, + MAX (TYPE_ALIGN (gnu_record_type), + TYPE_ALIGN (TREE_TYPE (gnu_field)))); MOVE_FROM_FIELD_LIST_TO (gnu_zero_list); continue; } @@ -7691,7 +7693,7 @@ components_to_record (tree gnu_record_type, Node_Id gnat_component_list, gnu_field_list = chainon (gnu_field_list, gnu_variant_part); if (cancel_alignment) - TYPE_ALIGN (gnu_record_type) = 0; + SET_TYPE_ALIGN (gnu_record_type, 0); TYPE_ARTIFICIAL (gnu_record_type) = artificial; @@ -8804,7 +8806,7 @@ create_variant_part_from (tree old_variant_part, SET_TYPE_ADA_SIZE (new_union_type, size_binop (MINUS_EXPR, TYPE_ADA_SIZE (record_type), first_bit)); - TYPE_ALIGN (new_union_type) = TYPE_ALIGN (old_union_type); + SET_TYPE_ALIGN (new_union_type, TYPE_ALIGN (old_union_type)); relate_alias_sets (new_union_type, old_union_type, ALIAS_SET_COPY); } else @@ -8901,7 +8903,7 @@ copy_and_substitute_in_size (tree new_type, tree old_type, TYPE_SIZE (new_type) = TYPE_SIZE (old_type); TYPE_SIZE_UNIT (new_type) = TYPE_SIZE_UNIT (old_type); SET_TYPE_ADA_SIZE (new_type, TYPE_ADA_SIZE (old_type)); - TYPE_ALIGN (new_type) = TYPE_ALIGN (old_type); + SET_TYPE_ALIGN (new_type, TYPE_ALIGN (old_type)); relate_alias_sets (new_type, old_type, ALIAS_SET_COPY); if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (new_type))) @@ -9044,7 +9046,7 @@ substitute_in_type (tree t, tree f, tree r) return t; nt = build_nonshared_array_type (component, domain); - TYPE_ALIGN (nt) = TYPE_ALIGN (t); + SET_TYPE_ALIGN (nt, TYPE_ALIGN (t)); TYPE_USER_ALIGN (nt) = TYPE_USER_ALIGN (t); SET_TYPE_MODE (nt, TYPE_MODE (t)); TYPE_SIZE (nt) = SUBSTITUTE_IN_EXPR (TYPE_SIZE (t), f, r); diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c index c47be7d..90277a7 100644 --- a/gcc/ada/gcc-interface/utils.c +++ b/gcc/ada/gcc-interface/utils.c @@ -910,7 +910,7 @@ make_aligning_type (tree type, unsigned int align, tree size, pos, 1, -1); TYPE_FIELDS (record_type) = field; - TYPE_ALIGN (record_type) = base_align; + SET_TYPE_ALIGN (record_type, base_align); TYPE_USER_ALIGN (record_type) = 1; TYPE_SIZE (record_type) @@ -969,7 +969,7 @@ make_packable_type (tree type, bool in_record) if (in_record && size <= MAX_FIXED_MODE_SIZE) { align = ceil_pow2 (size); - TYPE_ALIGN (new_type) = align; + SET_TYPE_ALIGN (new_type, align); new_size = (size + align - 1) & -align; } else @@ -989,7 +989,7 @@ make_packable_type (tree type, bool in_record) return type; align = new_size & -new_size; - TYPE_ALIGN (new_type) = MIN (TYPE_ALIGN (type), align); + SET_TYPE_ALIGN (new_type, MIN (TYPE_ALIGN (type), align)); } TYPE_USER_ALIGN (new_type) = 1; @@ -1301,7 +1301,7 @@ maybe_pad_type (tree type, tree size, unsigned int align, else if (Present (gnat_entity)) TYPE_NAME (record) = create_concat_name (gnat_entity, "PAD"); - TYPE_ALIGN (record) = align ? align : orig_align; + SET_TYPE_ALIGN (record, align ? align : orig_align); TYPE_SIZE (record) = size ? size : orig_size; TYPE_SIZE_UNIT (record) = convert (sizetype, @@ -1674,7 +1674,7 @@ finish_fat_pointer_type (tree record_type, tree field_list) { /* Make sure we can put it into a register. */ if (STRICT_ALIGNMENT) - TYPE_ALIGN (record_type) = MIN (BIGGEST_ALIGNMENT, 2 * POINTER_SIZE); + SET_TYPE_ALIGN (record_type, MIN (BIGGEST_ALIGNMENT, 2 * POINTER_SIZE)); /* Show what it really is. */ TYPE_FAT_POINTER_P (record_type) = 1; @@ -1721,7 +1721,8 @@ finish_record_type (tree record_type, tree field_list, int rep_level, that just means some initializations; otherwise, layout the record. */ if (rep_level > 0) { - TYPE_ALIGN (record_type) = MAX (BITS_PER_UNIT, TYPE_ALIGN (record_type)); + SET_TYPE_ALIGN (record_type, MAX (BITS_PER_UNIT, + TYPE_ALIGN (record_type))); if (!had_size_unit) TYPE_SIZE_UNIT (record_type) = size_zero_node; @@ -1799,7 +1800,7 @@ finish_record_type (tree record_type, tree field_list, int rep_level, maximum alignment, if any. */ if (TYPE_ALIGN (record_type) >= align) { - DECL_ALIGN (field) = MAX (DECL_ALIGN (field), align); + SET_DECL_ALIGN (field, MAX (DECL_ALIGN (field), align)); DECL_BIT_FIELD (field) = 0; } else if (!had_align @@ -1808,8 +1809,8 @@ finish_record_type (tree record_type, tree field_list, int rep_level, && (!TYPE_MAX_ALIGN (record_type) || TYPE_MAX_ALIGN (record_type) >= align)) { - TYPE_ALIGN (record_type) = align; - DECL_ALIGN (field) = MAX (DECL_ALIGN (field), align); + SET_TYPE_ALIGN (record_type, align); + SET_DECL_ALIGN (field, MAX (DECL_ALIGN (field), align)); DECL_BIT_FIELD (field) = 0; } } @@ -1832,8 +1833,8 @@ finish_record_type (tree record_type, tree field_list, int rep_level, /* A type must be as aligned as its most aligned field that is not a bit-field. But this is already enforced by layout_type. */ if (rep_level > 0 && !DECL_BIT_FIELD (field)) - TYPE_ALIGN (record_type) - = MAX (TYPE_ALIGN (record_type), DECL_ALIGN (field)); + SET_TYPE_ALIGN (record_type, + MAX (TYPE_ALIGN (record_type), DECL_ALIGN (field))); switch (code) { @@ -2004,7 +2005,7 @@ rest_of_record_type_compilation (tree record_type) = concat_name (orig_name, TREE_CODE (record_type) == QUAL_UNION_TYPE ? "XVU" : "XVE"); TYPE_NAME (new_record_type) = new_name; - TYPE_ALIGN (new_record_type) = BIGGEST_ALIGNMENT; + SET_TYPE_ALIGN (new_record_type, BIGGEST_ALIGNMENT); TYPE_STUB_DECL (new_record_type) = create_type_stub_decl (new_name, new_record_type); DECL_IGNORED_P (TYPE_STUB_DECL (new_record_type)) @@ -2096,7 +2097,7 @@ rest_of_record_type_compilation (tree record_type) if (align != 0 && TYPE_ALIGN (field_type) > align) { field_type = copy_node (field_type); - TYPE_ALIGN (field_type) = align; + SET_TYPE_ALIGN (field_type, align); } var = true; } @@ -2644,7 +2645,7 @@ create_field_decl (tree name, tree type, tree record_type, tree size, tree pos, || (!pos && AGGREGATE_TYPE_P (type) && aggregate_type_contains_array_p (type)))) - DECL_ALIGN (field_decl) = BITS_PER_UNIT; + SET_DECL_ALIGN (field_decl, BITS_PER_UNIT); /* If a size is specified, use it. Otherwise, if the record type is packed compute a size to use, which may differ from the object's natural size. @@ -2691,9 +2692,9 @@ create_field_decl (tree name, tree type, tree record_type, tree size, tree pos, { if (TYPE_ALIGN (record_type) != 0 && TYPE_ALIGN (record_type) < TYPE_ALIGN (type)) - DECL_ALIGN (field_decl) = TYPE_ALIGN (record_type); + SET_DECL_ALIGN (field_decl, TYPE_ALIGN (record_type)); else - DECL_ALIGN (field_decl) = TYPE_ALIGN (type); + SET_DECL_ALIGN (field_decl, TYPE_ALIGN (type)); } } @@ -2709,10 +2710,10 @@ create_field_decl (tree name, tree type, tree record_type, tree size, tree pos, : packed && TYPE_MODE (type) != BLKmode ? BITS_PER_UNIT : 0); if (bit_align > DECL_ALIGN (field_decl)) - DECL_ALIGN (field_decl) = bit_align; + SET_DECL_ALIGN (field_decl, bit_align); else if (!bit_align && TYPE_ALIGN (type) > DECL_ALIGN (field_decl)) { - DECL_ALIGN (field_decl) = TYPE_ALIGN (type); + SET_DECL_ALIGN (field_decl, TYPE_ALIGN (type)); DECL_USER_ALIGN (field_decl) = TYPE_USER_ALIGN (type); } } diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 7068034..2a0006c 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -7879,7 +7879,7 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, else *type = build_variant_type_copy (*type); - TYPE_ALIGN (*type) = (1U << i) * BITS_PER_UNIT; + SET_TYPE_ALIGN (*type, (1U << i) * BITS_PER_UNIT); TYPE_USER_ALIGN (*type) = 1; } else if (! VAR_OR_FUNCTION_DECL_P (decl) @@ -7913,7 +7913,7 @@ handle_aligned_attribute (tree *node, tree ARG_UNUSED (name), tree args, } else { - DECL_ALIGN (decl) = (1U << i) * BITS_PER_UNIT; + SET_DECL_ALIGN (decl, (1U << i) * BITS_PER_UNIT); DECL_USER_ALIGN (decl) = 1; } diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index e8bafed..5d50fc2 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -2369,7 +2369,7 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) if (TYPE_USER_ALIGN (tem)) { if (TYPE_ALIGN (tem) > TYPE_ALIGN (newtype)) - TYPE_ALIGN (newtype) = TYPE_ALIGN (tem); + SET_TYPE_ALIGN (newtype, TYPE_ALIGN (tem)); TYPE_USER_ALIGN (newtype) = true; } @@ -2410,7 +2410,7 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype) DECL_MODE (newdecl) = DECL_MODE (olddecl); if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) { - DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl); + SET_DECL_ALIGN (newdecl, DECL_ALIGN (olddecl)); DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl); } } @@ -6775,7 +6775,7 @@ grokdeclarator (const struct c_declarator *declarator, /* Apply _Alignas specifiers. */ if (alignas_align) { - DECL_ALIGN (decl) = alignas_align * BITS_PER_UNIT; + SET_DECL_ALIGN (decl, alignas_align * BITS_PER_UNIT); DECL_USER_ALIGN (decl) = 1; } @@ -7217,7 +7217,7 @@ parser_xref_tag (location_t loc, enum tree_code code, tree name) /* Give the type a default layout like unsigned int to avoid crashing if it does not get defined. */ SET_TYPE_MODE (ref, TYPE_MODE (unsigned_type_node)); - TYPE_ALIGN (ref) = TYPE_ALIGN (unsigned_type_node); + SET_TYPE_ALIGN (ref, TYPE_ALIGN (unsigned_type_node)); TYPE_USER_ALIGN (ref) = 0; TYPE_UNSIGNED (ref) = 1; TYPE_PRECISION (ref) = TYPE_PRECISION (unsigned_type_node); @@ -8113,7 +8113,7 @@ finish_enum (tree enumtype, tree values, tree attributes) TYPE_MIN_VALUE (enumtype) = TYPE_MIN_VALUE (tem); TYPE_MAX_VALUE (enumtype) = TYPE_MAX_VALUE (tem); TYPE_UNSIGNED (enumtype) = TYPE_UNSIGNED (tem); - TYPE_ALIGN (enumtype) = TYPE_ALIGN (tem); + SET_TYPE_ALIGN (enumtype, TYPE_ALIGN (tem)); TYPE_SIZE (enumtype) = 0; TYPE_PRECISION (enumtype) = TYPE_PRECISION (tem); @@ -8175,7 +8175,7 @@ finish_enum (tree enumtype, tree values, tree attributes) TYPE_SIZE_UNIT (tem) = TYPE_SIZE_UNIT (enumtype); SET_TYPE_MODE (tem, TYPE_MODE (enumtype)); TYPE_PRECISION (tem) = TYPE_PRECISION (enumtype); - TYPE_ALIGN (tem) = TYPE_ALIGN (enumtype); + SET_TYPE_ALIGN (tem, TYPE_ALIGN (enumtype)); TYPE_USER_ALIGN (tem) = TYPE_USER_ALIGN (enumtype); TYPE_UNSIGNED (tem) = TYPE_UNSIGNED (enumtype); TYPE_LANG_SPECIFIC (tem) = TYPE_LANG_SPECIFIC (enumtype); diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index b612293..21f21c9 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -369,7 +369,7 @@ align_local_variable (tree decl) else { align = LOCAL_DECL_ALIGNMENT (decl); - DECL_ALIGN (decl) = align; + SET_DECL_ALIGN (decl, align); } return align / BITS_PER_UNIT; } @@ -1018,7 +1018,7 @@ expand_one_stack_var_at (tree decl, rtx base, unsigned base_align, alignment here, but (at least) the i386 port does exactly this via the MINIMUM_ALIGNMENT hook. */ - DECL_ALIGN (decl) = align; + SET_DECL_ALIGN (decl, align); DECL_USER_ALIGN (decl) = 0; } diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c index b199529..181c304 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -30254,8 +30254,8 @@ arm_relayout_function (tree fndecl) if (!callee_tree) callee_tree = target_option_default_node; - DECL_ALIGN (fndecl) = - FUNCTION_BOUNDARY_P (TREE_TARGET_OPTION (callee_tree)->x_target_flags); + struct cl_target_option *opts = TREE_TARGET_OPTION (callee_tree); + SET_DECL_ALIGN (fndecl, FUNCTION_BOUNDARY_P (opts->x_target_flags)); } /* Inner function to process the attribute((target(...))), take an argument and diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c index 61ff515..5f661ee 100644 --- a/gcc/config/avr/avr.c +++ b/gcc/config/avr/avr.c @@ -908,7 +908,7 @@ avr_adjust_type_node (tree *node, machine_mode mode, int sat_p) TYPE_IBIT (*node) = GET_MODE_IBIT (mode); TYPE_FBIT (*node) = GET_MODE_FBIT (mode); TYPE_PRECISION (*node) = GET_MODE_BITSIZE (mode); - TYPE_ALIGN (*node) = 8; + SET_TYPE_ALIGN (*node, 8); SET_TYPE_MODE (*node, mode); layout_type (*node); diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 55cf52f..821cce8 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -6305,7 +6305,7 @@ mips_std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, if (boundary < TYPE_ALIGN (type)) { type = build_variant_type_copy (type); - TYPE_ALIGN (type) = boundary; + SET_TYPE_ALIGN (type, boundary); } /* Compute the rounded size of the type. */ diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c index 6f63116..2e2a02c 100644 --- a/gcc/config/msp430/msp430.c +++ b/gcc/config/msp430/msp430.c @@ -1461,7 +1461,7 @@ msp430_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, if (boundary < TYPE_ALIGN (type)) { type = build_variant_type_copy (type); - TYPE_ALIGN (type) = boundary; + SET_TYPE_ALIGN (type, boundary); } /* Compute the rounded size of the type. */ diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c index 401c295..c3757eb 100644 --- a/gcc/config/spu/spu.c +++ b/gcc/config/spu/spu.c @@ -3915,11 +3915,11 @@ spu_build_builtin_va_list (void) FIELD_DECL, get_identifier ("__skip"), ptr_type_node); DECL_FIELD_CONTEXT (f_args) = record; - DECL_ALIGN (f_args) = 128; + SET_DECL_ALIGN (f_args, 128); DECL_USER_ALIGN (f_args) = 1; DECL_FIELD_CONTEXT (f_skip) = record; - DECL_ALIGN (f_skip) = 128; + SET_DECL_ALIGN (f_skip, 128); DECL_USER_ALIGN (f_skip) = 1; TYPE_STUB_DECL (record) = type_decl; diff --git a/gcc/coverage.c b/gcc/coverage.c index b1fce7d..67cc908 100644 --- a/gcc/coverage.c +++ b/gcc/coverage.c @@ -751,7 +751,7 @@ build_var (tree fn_decl, tree type, int counter) TREE_STATIC (var) = 1; TREE_ADDRESSABLE (var) = 1; DECL_NONALIASED (var) = 1; - DECL_ALIGN (var) = TYPE_ALIGN (type); + SET_DECL_ALIGN (var, TYPE_ALIGN (type)); return var; } diff --git a/gcc/cp/class.c b/gcc/cp/class.c index ceff3ef..71f7eec 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -804,7 +804,7 @@ build_vtable (tree class_type, tree name, tree vtable_type) TREE_STATIC (decl) = 1; TREE_READONLY (decl) = 1; DECL_VIRTUAL_P (decl) = 1; - DECL_ALIGN (decl) = TARGET_VTABLE_ENTRY_ALIGN; + SET_DECL_ALIGN (decl, TARGET_VTABLE_ENTRY_ALIGN); DECL_USER_ALIGN (decl) = true; DECL_VTABLE_OR_VTT_P (decl) = 1; set_linkage_according_to_type (class_type, decl); @@ -2040,7 +2040,7 @@ fixup_attribute_variants (tree t) valign = MAX (valign, TYPE_ALIGN (variants)); else TYPE_USER_ALIGN (variants) = user_align; - TYPE_ALIGN (variants) = valign; + SET_TYPE_ALIGN (variants, valign); if (may_alias) fixup_may_alias (variants); } @@ -4490,7 +4490,7 @@ build_base_field (record_layout_info rli, tree binfo, { DECL_SIZE (decl) = CLASSTYPE_SIZE (basetype); DECL_SIZE_UNIT (decl) = CLASSTYPE_SIZE_UNIT (basetype); - DECL_ALIGN (decl) = CLASSTYPE_ALIGN (basetype); + SET_DECL_ALIGN (decl, CLASSTYPE_ALIGN (basetype)); DECL_USER_ALIGN (decl) = CLASSTYPE_USER_ALIGN (basetype); DECL_MODE (decl) = TYPE_MODE (basetype); DECL_FIELD_IS_BASE (decl) = 1; @@ -6409,7 +6409,7 @@ layout_class_type (tree t, tree *virtuals_p) } DECL_SIZE (field) = TYPE_SIZE (integer_type); - DECL_ALIGN (field) = TYPE_ALIGN (integer_type); + SET_DECL_ALIGN (field, TYPE_ALIGN (integer_type)); DECL_USER_ALIGN (field) = TYPE_USER_ALIGN (integer_type); layout_nonempty_base_or_field (rli, field, NULL_TREE, empty_base_offsets); @@ -6544,7 +6544,7 @@ layout_class_type (tree t, tree *virtuals_p) size_binop (MULT_EXPR, fold_convert (bitsizetype, eoc), bitsize_int (BITS_PER_UNIT))); - TYPE_ALIGN (base_t) = rli->record_align; + SET_TYPE_ALIGN (base_t, rli->record_align); TYPE_USER_ALIGN (base_t) = TYPE_USER_ALIGN (t); /* Copy the fields from T. */ diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 30a8c5a..95d7cf0 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -2066,7 +2066,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) if (TYPE_USER_ALIGN (tem)) { if (TYPE_ALIGN (tem) > TYPE_ALIGN (newtype)) - TYPE_ALIGN (newtype) = TYPE_ALIGN (tem); + SET_TYPE_ALIGN (newtype, TYPE_ALIGN (tem)); TYPE_USER_ALIGN (newtype) = true; } @@ -2498,7 +2498,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend) /* Likewise for DECL_ALIGN, DECL_USER_ALIGN and DECL_PACKED. */ if (DECL_ALIGN (olddecl) > DECL_ALIGN (newdecl)) { - DECL_ALIGN (newdecl) = DECL_ALIGN (olddecl); + SET_DECL_ALIGN (newdecl, DECL_ALIGN (olddecl)); DECL_USER_ALIGN (newdecl) |= DECL_USER_ALIGN (olddecl); } DECL_USER_ALIGN (olddecl) = DECL_USER_ALIGN (newdecl); @@ -3927,7 +3927,7 @@ record_unknown_type (tree type, const char* name) DECL_IGNORED_P (decl) = 1; TYPE_DECL_SUPPRESS_DEBUG (decl) = 1; TYPE_SIZE (type) = TYPE_SIZE (void_type_node); - TYPE_ALIGN (type) = 1; + SET_TYPE_ALIGN (type, 1); TYPE_USER_ALIGN (type) = 0; SET_TYPE_MODE (type, TYPE_MODE (void_type_node)); } @@ -4182,7 +4182,7 @@ cxx_init_decl_processing (void) TYPE_UNSIGNED (nullptr_type_node) = 1; TYPE_PRECISION (nullptr_type_node) = GET_MODE_BITSIZE (ptr_mode); if (abi_version_at_least (9)) - TYPE_ALIGN (nullptr_type_node) = GET_MODE_ALIGNMENT (ptr_mode); + SET_TYPE_ALIGN (nullptr_type_node, GET_MODE_ALIGNMENT (ptr_mode)); SET_TYPE_MODE (nullptr_type_node, ptr_mode); record_builtin_type (RID_MAX, "decltype(nullptr)", nullptr_type_node); nullptr_node = build_int_cst (nullptr_type_node, 0); @@ -7938,7 +7938,7 @@ grokfndecl (tree ctype, parms = parm; /* Allocate space to hold the vptr bit if needed. */ - DECL_ALIGN (decl) = MINIMUM_METHOD_BOUNDARY; + SET_DECL_ALIGN (decl, MINIMUM_METHOD_BOUNDARY); } DECL_ARGUMENTS (decl) = parms; for (t = parms; t; t = DECL_CHAIN (t)) @@ -13128,7 +13128,7 @@ copy_type_enum (tree dst, tree src) valign = MAX (valign, TYPE_ALIGN (t)); else TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (src); - TYPE_ALIGN (t) = valign; + SET_TYPE_ALIGN (t, valign); TYPE_UNSIGNED (t) = TYPE_UNSIGNED (src); } } diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c index 7a5220c..9fa2142 100644 --- a/gcc/cp/lambda.c +++ b/gcc/cp/lambda.c @@ -1011,7 +1011,7 @@ maybe_add_lambda_conv_op (tree type) tree convfn = build_lang_decl (FUNCTION_DECL, name, fntype); tree fn = convfn; DECL_SOURCE_LOCATION (fn) = DECL_SOURCE_LOCATION (callop); - DECL_ALIGN (fn) = MINIMUM_METHOD_BOUNDARY; + SET_DECL_ALIGN (fn, MINIMUM_METHOD_BOUNDARY); SET_OVERLOADED_OPERATOR_CODE (fn, TYPE_EXPR); grokclassfn (type, fn, NO_SPECIAL); set_linkage_according_to_type (type, fn); diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 6920fbb..547e672 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1867,7 +1867,7 @@ implicitly_declare_fn (special_function_kind kind, tree type, SET_OVERLOADED_OPERATOR_CODE (fn, NOP_EXPR); } - DECL_ALIGN (fn) = MINIMUM_METHOD_BOUNDARY; + SET_DECL_ALIGN (fn, MINIMUM_METHOD_BOUNDARY); /* Create the explicit arguments. */ if (rhs_parm_type) diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index a98a5dc..e6ea2e8 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -9880,7 +9880,7 @@ instantiate_class_template_1 (tree type) DECL_SOURCE_LOCATION (typedecl); TYPE_PACKED (type) = TYPE_PACKED (pattern); - TYPE_ALIGN (type) = TYPE_ALIGN (pattern); + SET_TYPE_ALIGN (type, TYPE_ALIGN (pattern)); TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (pattern); TYPE_FOR_JAVA (type) = TYPE_FOR_JAVA (pattern); /* For libjava's JArray */ if (ANON_AGGR_TYPE_P (pattern)) @@ -13471,7 +13471,7 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl) if (TYPE_USER_ALIGN (t)) { - TYPE_ALIGN (r) = TYPE_ALIGN (t); + SET_TYPE_ALIGN (r, TYPE_ALIGN (t)); TYPE_USER_ALIGN (r) = 1; } diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c index 244c34d..43d5f15 100644 --- a/gcc/cp/rtti.c +++ b/gcc/cp/rtti.c @@ -1603,7 +1603,7 @@ emit_tinfo_decl (tree decl) /* Avoid targets optionally bumping up the alignment to improve vector instruction accesses, tinfo are never accessed this way. */ #ifdef DATA_ABI_ALIGNMENT - DECL_ALIGN (decl) = DATA_ABI_ALIGNMENT (decl, TYPE_ALIGN (TREE_TYPE (decl))); + SET_DECL_ALIGN (decl, DATA_ABI_ALIGNMENT (decl, TYPE_ALIGN (TREE_TYPE (decl)))); DECL_USER_ALIGN (decl) = true; #endif return true; diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 5e8bb74..807ed82 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1075,7 +1075,7 @@ cp_build_qualified_type_real (tree type, { t = build_variant_type_copy (t); TYPE_NAME (t) = TYPE_NAME (type); - TYPE_ALIGN (t) = TYPE_ALIGN (type); + SET_TYPE_ALIGN (t, TYPE_ALIGN (type)); TYPE_USER_ALIGN (t) = TYPE_USER_ALIGN (type); } } diff --git a/gcc/except.c b/gcc/except.c index 2a1073f..cf1df8c 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -300,7 +300,7 @@ init_eh (void) #ifdef DONT_USE_BUILTIN_SETJMP /* We don't know what the alignment requirements of the runtime's jmp_buf has. Overestimate. */ - DECL_ALIGN (f_jbuf) = BIGGEST_ALIGNMENT; + SET_DECL_ALIGN (f_jbuf, BIGGEST_ALIGNMENT); DECL_USER_ALIGN (f_jbuf) = 1; #endif DECL_FIELD_CONTEXT (f_jbuf) = sjlj_fc_type_node; diff --git a/gcc/expr.c b/gcc/expr.c index 6260f5e..b25ba3a 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -7704,7 +7704,7 @@ expand_expr_addr_expr_1 (tree exp, rtx target, machine_mode tmode, { inner = copy_node (inner); TREE_TYPE (inner) = copy_node (TREE_TYPE (inner)); - TYPE_ALIGN (TREE_TYPE (inner)) = TYPE_ALIGN (TREE_TYPE (exp)); + SET_TYPE_ALIGN (TREE_TYPE (inner), TYPE_ALIGN (TREE_TYPE (exp))); TYPE_USER_ALIGN (TREE_TYPE (inner)) = 1; } result = expand_expr_addr_expr_1 (inner, subtarget, tmode, modifier, as); diff --git a/gcc/fortran/trans-common.c b/gcc/fortran/trans-common.c index e39551c..432c83c 100644 --- a/gcc/fortran/trans-common.c +++ b/gcc/fortran/trans-common.c @@ -436,7 +436,7 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init) TREE_STATIC (decl) = 1; DECL_IGNORED_P (decl) = 1; if (!com->is_bind_c) - DECL_ALIGN (decl) = BIGGEST_ALIGNMENT; + SET_DECL_ALIGN (decl, BIGGEST_ALIGNMENT); else { /* Do not set the alignment for bind(c) common blocks to @@ -447,7 +447,7 @@ build_common_decl (gfc_common_head *com, tree union_type, bool is_init) tree field = NULL_TREE; field = TYPE_FIELDS (TREE_TYPE (decl)); if (DECL_CHAIN (field) == NULL_TREE) - DECL_ALIGN (decl) = TYPE_ALIGN (TREE_TYPE (field)); + SET_DECL_ALIGN (decl, TYPE_ALIGN (TREE_TYPE (field))); } DECL_USER_ALIGN (decl) = 0; GFC_DECL_COMMON_OR_EQUIV (decl) = 1; diff --git a/gcc/fortran/trans-io.c b/gcc/fortran/trans-io.c index 125f45c..aefa96d 100644 --- a/gcc/fortran/trans-io.c +++ b/gcc/fortran/trans-io.c @@ -309,8 +309,8 @@ gfc_build_io_library_fndecls (void) alignment that is at least as large as the needed alignment for those types. See the st_parameter_dt structure in libgfortran/io/io.h for what really goes into this space. */ - TYPE_ALIGN (types[IOPARM_type_pad]) = MAX (TYPE_ALIGN (pchar_type_node), - TYPE_ALIGN (gfc_get_int_type (gfc_intio_kind))); + SET_TYPE_ALIGN (types[IOPARM_type_pad], MAX (TYPE_ALIGN (pchar_type_node), + TYPE_ALIGN (gfc_get_int_type (gfc_intio_kind)))); for (ptype = IOPARM_ptype_common; ptype < IOPARM_ptype_num; ptype++) gfc_build_st_parameter ((enum ioparam_type) ptype, types); diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c index 831c84f..442fe56 100644 --- a/gcc/fortran/trans-types.c +++ b/gcc/fortran/trans-types.c @@ -2279,7 +2279,7 @@ gfc_add_field_to_struct (tree context, tree name, tree type, tree **chain) tree decl = gfc_add_field_to_struct_1 (context, name, type, chain); DECL_INITIAL (decl) = 0; - DECL_ALIGN (decl) = 0; + SET_DECL_ALIGN (decl, 0); DECL_USER_ALIGN (decl) = 0; return decl; diff --git a/gcc/function.c b/gcc/function.c index 4f27912..b78d097 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -2925,7 +2925,7 @@ assign_parm_setup_block (struct assign_parm_data_all *all, size_stored = CEIL_ROUND (size, UNITS_PER_WORD); if (stack_parm == 0) { - DECL_ALIGN (parm) = MAX (DECL_ALIGN (parm), BITS_PER_WORD); + SET_DECL_ALIGN (parm, MAX (DECL_ALIGN (parm), BITS_PER_WORD)); stack_parm = assign_stack_local (BLKmode, size_stored, DECL_ALIGN (parm)); if (GET_MODE_SIZE (GET_MODE (entry_parm)) == size) diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c index 29e9c0a..ed012cc 100644 --- a/gcc/gimple-expr.c +++ b/gcc/gimple-expr.c @@ -377,7 +377,7 @@ copy_var_decl (tree var, tree name, tree type) DECL_ATTRIBUTES (copy) = DECL_ATTRIBUTES (var); if (DECL_USER_ALIGN (var)) { - DECL_ALIGN (copy) = DECL_ALIGN (var); + SET_DECL_ALIGN (copy, DECL_ALIGN (var)); DECL_USER_ALIGN (copy) = 1; } diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 2793bb6..1cb3242 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -2687,7 +2687,7 @@ Gcc_backend::implicit_variable(const std::string& name, Btype* type, } if (alignment != 0) { - DECL_ALIGN(decl) = alignment * BITS_PER_UNIT; + SET_DECL_ALIGN(decl, alignment * BITS_PER_UNIT); DECL_USER_ALIGN(decl) = 1; } diff --git a/gcc/java/class.c b/gcc/java/class.c index 1904987..b4708bc 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -773,7 +773,7 @@ add_method_1 (tree this_class, int access_flags, tree name, tree function_type) TYPE_METHODS (this_class) = fndecl; if (!(access_flags & ACC_STATIC)) - DECL_ALIGN (fndecl) = MINIMUM_METHOD_BOUNDARY; + SET_DECL_ALIGN (fndecl, MINIMUM_METHOD_BOUNDARY); /* Notice that this is a finalizer and update the class type accordingly. This is used to optimize instance allocation. */ @@ -2207,11 +2207,11 @@ make_class_data (tree type) FINISH_RECORD_CONSTRUCTOR (cons, v2, class_type_node); DECL_INITIAL (decl) = cons; - + /* Hash synchronization requires at least 64-bit alignment. */ if (flag_hash_synchronization && POINTER_SIZE < 64) - DECL_ALIGN (decl) = 64; - + SET_DECL_ALIGN (decl, 64); + if (flag_indirect_classes) { TREE_READONLY (decl) = 1; @@ -2791,7 +2791,7 @@ emit_register_classes_in_jcr_section (void) cdecl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier ("_Jv_JCR_SECTION_data"), class_array_type); - DECL_ALIGN (cdecl) = POINTER_SIZE; + SET_DECL_ALIGN (cdecl, POINTER_SIZE); DECL_USER_ALIGN (cdecl) = 1; DECL_INITIAL (cdecl) = build_constructor (class_array_type, init); TREE_CONSTANT (DECL_INITIAL (cdecl)) = 1; diff --git a/gcc/java/typeck.c b/gcc/java/typeck.c index 1214eae..d2e3db6 100644 --- a/gcc/java/typeck.c +++ b/gcc/java/typeck.c @@ -305,7 +305,7 @@ build_java_array_type (tree element_type, HOST_WIDE_INT length) FIELD_DECL, get_identifier ("data"), atype); DECL_CONTEXT (arfld) = t; DECL_CHAIN (fld) = arfld; - DECL_ALIGN (arfld) = TYPE_ALIGN (element_type); + SET_DECL_ALIGN (arfld, TYPE_ALIGN (element_type)); /* We could layout_class, but that loads java.lang.Object prematurely. * This is called by the parser, and it is a bad idea to do load_class diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index 8109507..4856457 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -2115,7 +2115,7 @@ objc_build_struct (tree klass, tree fields, tree super_name) = size_binop (FLOOR_DIV_EXPR, convert (sizetype, DECL_SIZE (base)), size_int (BITS_PER_UNIT)); DECL_ARTIFICIAL (base) = 1; - DECL_ALIGN (base) = 1; + SET_DECL_ALIGN (base, 1); DECL_FIELD_CONTEXT (base) = s; #ifdef OBJCPLUS DECL_FIELD_IS_BASE (base) = 1; diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 57a03df..024b57a 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -1452,12 +1452,12 @@ install_var_field (tree var, bool by_ref, int mask, omp_context *ctx, DECL_ABSTRACT_ORIGIN (field) = var; if (type == TREE_TYPE (var)) { - DECL_ALIGN (field) = DECL_ALIGN (var); + SET_DECL_ALIGN (field, DECL_ALIGN (var)); DECL_USER_ALIGN (field) = DECL_USER_ALIGN (var); TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (var); } else - DECL_ALIGN (field) = TYPE_ALIGN (type); + SET_DECL_ALIGN (field, TYPE_ALIGN (type)); if ((mask & 3) == 3) { @@ -1467,7 +1467,7 @@ install_var_field (tree var, bool by_ref, int mask, omp_context *ctx, sfield = build_decl (DECL_SOURCE_LOCATION (var), FIELD_DECL, DECL_NAME (var), type); DECL_ABSTRACT_ORIGIN (sfield) = var; - DECL_ALIGN (sfield) = DECL_ALIGN (field); + SET_DECL_ALIGN (sfield, DECL_ALIGN (field)); DECL_USER_ALIGN (sfield) = DECL_USER_ALIGN (field); TREE_THIS_VOLATILE (sfield) = TREE_THIS_VOLATILE (field); insert_field_into_struct (ctx->srecord_type, sfield); @@ -2160,7 +2160,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx, tree field = build_decl (OMP_CLAUSE_LOCATION (c), FIELD_DECL, NULL_TREE, ptr_type_node); - DECL_ALIGN (field) = TYPE_ALIGN (ptr_type_node); + SET_DECL_ALIGN (field, TYPE_ALIGN (ptr_type_node)); insert_field_into_struct (ctx->record_type, field); splay_tree_insert (ctx->field_map, (splay_tree_key) decl, (splay_tree_value) field); @@ -2805,18 +2805,18 @@ finish_taskreg_scan (omp_context *ctx) TREE_TYPE (field) = build_pointer_type (TREE_TYPE (decl)); TREE_THIS_VOLATILE (field) = 0; DECL_USER_ALIGN (field) = 0; - DECL_ALIGN (field) = TYPE_ALIGN (TREE_TYPE (field)); + SET_DECL_ALIGN (field, TYPE_ALIGN (TREE_TYPE (field))); if (TYPE_ALIGN (ctx->record_type) < DECL_ALIGN (field)) - TYPE_ALIGN (ctx->record_type) = DECL_ALIGN (field); + SET_TYPE_ALIGN (ctx->record_type, DECL_ALIGN (field)); if (ctx->srecord_type) { tree sfield = lookup_sfield (decl, ctx); TREE_TYPE (sfield) = TREE_TYPE (field); TREE_THIS_VOLATILE (sfield) = 0; DECL_USER_ALIGN (sfield) = 0; - DECL_ALIGN (sfield) = DECL_ALIGN (field); + SET_DECL_ALIGN (sfield, DECL_ALIGN (field)); if (TYPE_ALIGN (ctx->srecord_type) < DECL_ALIGN (sfield)) - TYPE_ALIGN (ctx->srecord_type) = DECL_ALIGN (sfield); + SET_TYPE_ALIGN (ctx->srecord_type, DECL_ALIGN (sfield)); } } } @@ -18500,8 +18500,8 @@ omp_finish_file (void) num_vars * 2); tree funcs_decl_type = build_array_type_nelts (pointer_sized_int_node, num_funcs); - TYPE_ALIGN (vars_decl_type) = TYPE_ALIGN (pointer_sized_int_node); - TYPE_ALIGN (funcs_decl_type) = TYPE_ALIGN (pointer_sized_int_node); + SET_TYPE_ALIGN (vars_decl_type, TYPE_ALIGN (pointer_sized_int_node)); + SET_TYPE_ALIGN (funcs_decl_type, TYPE_ALIGN (pointer_sized_int_node)); tree ctor_v = build_constructor (vars_decl_type, v_v); tree ctor_f = build_constructor (funcs_decl_type, v_f); TREE_CONSTANT (ctor_v) = TREE_CONSTANT (ctor_f) = 1; @@ -18517,8 +18517,8 @@ omp_finish_file (void) otherwise a joint table in a binary will contain padding between tables from multiple object files. */ DECL_USER_ALIGN (funcs_decl) = DECL_USER_ALIGN (vars_decl) = 1; - DECL_ALIGN (funcs_decl) = TYPE_ALIGN (funcs_decl_type); - DECL_ALIGN (vars_decl) = TYPE_ALIGN (vars_decl_type); + SET_DECL_ALIGN (funcs_decl, TYPE_ALIGN (funcs_decl_type)); + SET_DECL_ALIGN (vars_decl, TYPE_ALIGN (vars_decl_type)); DECL_INITIAL (funcs_decl) = ctor_f; DECL_INITIAL (vars_decl) = ctor_v; set_decl_section_name (funcs_decl, OFFLOAD_FUNC_TABLE_SECTION_NAME); diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index dd40ca0..8629984 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -565,7 +565,7 @@ do_type_align (tree type, tree decl) { if (TYPE_ALIGN (type) > DECL_ALIGN (decl)) { - DECL_ALIGN (decl) = TYPE_ALIGN (type); + SET_DECL_ALIGN (decl, TYPE_ALIGN (type)); if (TREE_CODE (decl) == FIELD_DECL) DECL_USER_ALIGN (decl) = TYPE_USER_ALIGN (type); } @@ -658,7 +658,7 @@ layout_decl (tree decl, unsigned int known_align) #ifdef EMPTY_FIELD_BOUNDARY if (EMPTY_FIELD_BOUNDARY > DECL_ALIGN (decl)) { - DECL_ALIGN (decl) = EMPTY_FIELD_BOUNDARY; + SET_DECL_ALIGN (decl, EMPTY_FIELD_BOUNDARY); DECL_USER_ALIGN (decl) = 0; } #endif @@ -680,7 +680,7 @@ layout_decl (tree decl, unsigned int known_align) && !(xalign > BITS_PER_UNIT && DECL_PACKED (decl)) && (known_align == 0 || known_align >= xalign)) { - DECL_ALIGN (decl) = MAX (xalign, DECL_ALIGN (decl)); + SET_DECL_ALIGN (decl, MAX (xalign, DECL_ALIGN (decl))); DECL_MODE (decl) = xmode; DECL_BIT_FIELD (decl) = 0; } @@ -705,7 +705,7 @@ layout_decl (tree decl, unsigned int known_align) DECL_USER_ALIGN, so we need to check old_user_align instead. */ if (packed_p && !old_user_align) - DECL_ALIGN (decl) = MIN (DECL_ALIGN (decl), BITS_PER_UNIT); + SET_DECL_ALIGN (decl, MIN (DECL_ALIGN (decl), BITS_PER_UNIT)); if (! packed_p && ! DECL_USER_ALIGN (decl)) { @@ -713,11 +713,11 @@ layout_decl (tree decl, unsigned int known_align) to a lower boundary than alignment of variables unless it was overridden by attribute aligned. */ #ifdef BIGGEST_FIELD_ALIGNMENT - DECL_ALIGN (decl) - = MIN (DECL_ALIGN (decl), (unsigned) BIGGEST_FIELD_ALIGNMENT); + SET_DECL_ALIGN (decl, MIN (DECL_ALIGN (decl), + (unsigned) BIGGEST_FIELD_ALIGNMENT)); #endif #ifdef ADJUST_FIELD_ALIGN - DECL_ALIGN (decl) = ADJUST_FIELD_ALIGN (decl, DECL_ALIGN (decl)); + SET_DECL_ALIGN (decl, ADJUST_FIELD_ALIGN (decl, DECL_ALIGN (decl))); #endif } @@ -727,7 +727,7 @@ layout_decl (tree decl, unsigned int known_align) mfa = maximum_field_alignment; /* Should this be controlled by DECL_USER_ALIGN, too? */ if (mfa != 0) - DECL_ALIGN (decl) = MIN (DECL_ALIGN (decl), mfa); + SET_DECL_ALIGN (decl, MIN (DECL_ALIGN (decl), mfa)); } /* Evaluate nonconstant size only once, either now or as soon as safe. */ @@ -777,7 +777,7 @@ relayout_decl (tree decl) DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0; DECL_MODE (decl) = VOIDmode; if (!DECL_USER_ALIGN (decl)) - DECL_ALIGN (decl) = 0; + SET_DECL_ALIGN (decl, 0); SET_DECL_RTL (decl, 0); layout_decl (decl, 0); @@ -1558,10 +1558,10 @@ finalize_record_size (record_layout_info rli) /* Determine the desired alignment. */ #ifdef ROUND_TYPE_ALIGN - TYPE_ALIGN (rli->t) = ROUND_TYPE_ALIGN (rli->t, TYPE_ALIGN (rli->t), - rli->record_align); + SET_TYPE_ALIGN (rli->t, ROUND_TYPE_ALIGN (rli->t, TYPE_ALIGN (rli->t), + rli->record_align)); #else - TYPE_ALIGN (rli->t) = MAX (TYPE_ALIGN (rli->t), rli->record_align); + SET_TYPE_ALIGN (rli->t, MAX (TYPE_ALIGN (rli->t), rli->record_align)); #endif /* Compute the size so far. Be sure to allow for extra bits in the @@ -1718,15 +1718,15 @@ finalize_type_size (tree type) alignment of one of the fields. */ if (mode_align >= TYPE_ALIGN (type)) { - TYPE_ALIGN (type) = mode_align; + SET_TYPE_ALIGN (type, mode_align); TYPE_USER_ALIGN (type) = 0; } } /* Do machine-dependent extra alignment. */ #ifdef ROUND_TYPE_ALIGN - TYPE_ALIGN (type) - = ROUND_TYPE_ALIGN (type, TYPE_ALIGN (type), BITS_PER_UNIT); + SET_TYPE_ALIGN (type, + ROUND_TYPE_ALIGN (type, TYPE_ALIGN (type), BITS_PER_UNIT)); #endif /* If we failed to find a simple way to calculate the unit size @@ -1779,7 +1779,7 @@ finalize_type_size (tree type) valign = MAX (valign, TYPE_ALIGN (variant)); else TYPE_USER_ALIGN (variant) = user_align; - TYPE_ALIGN (variant) = valign; + SET_TYPE_ALIGN (variant, valign); TYPE_PRECISION (variant) = precision; SET_TYPE_MODE (variant, mode); } @@ -2073,7 +2073,7 @@ finish_builtin_struct (tree type, const char *name, tree fields, if (align_type) { - TYPE_ALIGN (type) = TYPE_ALIGN (align_type); + SET_TYPE_ALIGN (type, TYPE_ALIGN (align_type)); TYPE_USER_ALIGN (type) = TYPE_USER_ALIGN (align_type); } @@ -2184,7 +2184,7 @@ layout_type (tree type) Instead, query a target hook, defaulting to natural alignment. This prevents ABI changes depending on whether or not native vector modes are supported. */ - TYPE_ALIGN (type) = targetm.vector_alignment (type); + SET_TYPE_ALIGN (type, targetm.vector_alignment (type)); /* However, if the underlying mode requires a bigger alignment than what the target hook provides, we cannot use the mode. For now, @@ -2196,7 +2196,7 @@ layout_type (tree type) case VOID_TYPE: /* This is an incomplete type and so doesn't have a size. */ - TYPE_ALIGN (type) = 1; + SET_TYPE_ALIGN (type, 1); TYPE_USER_ALIGN (type) = 0; SET_TYPE_MODE (type, VOIDmode); break; @@ -2315,7 +2315,7 @@ layout_type (tree type) #else align = MAX (align, BITS_PER_UNIT); #endif - TYPE_ALIGN (type) = align; + SET_TYPE_ALIGN (type, align); SET_TYPE_MODE (type, BLKmode); if (TYPE_SIZE (type) != 0 && ! targetm.member_type_forces_blk (type, VOIDmode) @@ -2587,13 +2587,13 @@ initialize_sizetypes (void) /* Now layout both types manually. */ SET_TYPE_MODE (sizetype, smallest_mode_for_size (precision, MODE_INT)); - TYPE_ALIGN (sizetype) = GET_MODE_ALIGNMENT (TYPE_MODE (sizetype)); + SET_TYPE_ALIGN (sizetype, GET_MODE_ALIGNMENT (TYPE_MODE (sizetype))); TYPE_SIZE (sizetype) = bitsize_int (precision); TYPE_SIZE_UNIT (sizetype) = size_int (GET_MODE_SIZE (TYPE_MODE (sizetype))); set_min_and_max_values_for_integral_type (sizetype, precision, UNSIGNED); SET_TYPE_MODE (bitsizetype, smallest_mode_for_size (bprecision, MODE_INT)); - TYPE_ALIGN (bitsizetype) = GET_MODE_ALIGNMENT (TYPE_MODE (bitsizetype)); + SET_TYPE_ALIGN (bitsizetype, GET_MODE_ALIGNMENT (TYPE_MODE (bitsizetype))); TYPE_SIZE (bitsizetype) = bitsize_int (bprecision); TYPE_SIZE_UNIT (bitsizetype) = size_int (GET_MODE_SIZE (TYPE_MODE (bitsizetype))); diff --git a/gcc/symtab.c b/gcc/symtab.c index 3d3cc4f..343b38d 100644 --- a/gcc/symtab.c +++ b/gcc/symtab.c @@ -2152,7 +2152,7 @@ increase_alignment_1 (symtab_node *n, void *v) if (DECL_ALIGN (n->decl) < align && n->can_increase_alignment_p ()) { - DECL_ALIGN (n->decl) = align; + SET_DECL_ALIGN (n->decl, align); DECL_USER_ALIGN (n->decl) = 1; } return false; diff --git a/gcc/targhooks.c b/gcc/targhooks.c index a342277..6b4601b 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -1856,7 +1856,7 @@ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, if (boundary < TYPE_ALIGN (type)) { type = build_variant_type_copy (type); - TYPE_ALIGN (type) = boundary; + SET_TYPE_ALIGN (type, boundary); } /* Compute the rounded size of the type. */ diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 41c1a9b..0d48ff5 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1441,7 +1441,13 @@ struct GTY(()) tree_type_common { unsigned lang_flag_5 : 1; unsigned lang_flag_6 : 1; - unsigned int align; + /* TYPE_ALIGN in log2; this has to be large enough to hold values + of the maximum of BIGGEST_ALIGNMENT and MAX_OFILE_ALIGNMENT, + the latter being usually the larger. For ELF it is 8<<28, + so we need to store the value 32 (not 31, as we need the zero + as well), hence six bits. */ + unsigned align : 6; + unsigned spare : 26; alias_set_type alias_set; tree pointer_to; tree reference_to; @@ -1542,12 +1548,12 @@ struct GTY(()) tree_decl_common { unsigned decl_nonshareable_flag : 1; /* DECL_OFFSET_ALIGN, used only for FIELD_DECLs. */ - unsigned int off_align : 8; - - /* 24 bits unused. */ + unsigned int off_align : 6; /* DECL_ALIGN. It should have the same size as TYPE_ALIGN. */ - unsigned int align; + unsigned int align : 6; + + /* 20 bits unused. */ /* UID for points-to sets, stable over copying from inlining. */ unsigned int pt_uid; diff --git a/gcc/tree-nested.c b/gcc/tree-nested.c index de49bf48..229a271 100644 --- a/gcc/tree-nested.c +++ b/gcc/tree-nested.c @@ -192,7 +192,7 @@ insert_field_into_struct (tree type, tree field) /* Set correct alignment for frame struct type. */ if (TYPE_ALIGN (type) < DECL_ALIGN (field)) - TYPE_ALIGN (type) = DECL_ALIGN (field); + SET_TYPE_ALIGN (type, DECL_ALIGN (field)); } /* Build or return the RECORD_TYPE that describes the frame state that is @@ -275,14 +275,14 @@ lookup_field_for_decl (struct nesting_info *info, tree decl, if (use_pointer_in_frame (decl)) { TREE_TYPE (field) = build_pointer_type (TREE_TYPE (decl)); - DECL_ALIGN (field) = TYPE_ALIGN (TREE_TYPE (field)); + SET_DECL_ALIGN (field, TYPE_ALIGN (TREE_TYPE (field))); DECL_NONADDRESSABLE_P (field) = 1; } else { TREE_TYPE (field) = TREE_TYPE (decl); DECL_SOURCE_LOCATION (field) = DECL_SOURCE_LOCATION (decl); - DECL_ALIGN (field) = DECL_ALIGN (decl); + SET_DECL_ALIGN (field, DECL_ALIGN (decl)); DECL_USER_ALIGN (field) = DECL_USER_ALIGN (decl); TREE_ADDRESSABLE (field) = TREE_ADDRESSABLE (decl); DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (decl); @@ -361,7 +361,7 @@ get_chain_field (struct nesting_info *info) field = make_node (FIELD_DECL); DECL_NAME (field) = get_identifier ("__chain"); TREE_TYPE (field) = type; - DECL_ALIGN (field) = TYPE_ALIGN (type); + SET_DECL_ALIGN (field, TYPE_ALIGN (type)); DECL_NONADDRESSABLE_P (field) = 1; insert_field_into_struct (get_frame_type (info), field); @@ -474,7 +474,7 @@ get_trampoline_type (struct nesting_info *info) t = build_array_type (char_type_node, t); t = build_decl (DECL_SOURCE_LOCATION (info->context), FIELD_DECL, get_identifier ("__data"), t); - DECL_ALIGN (t) = align; + SET_DECL_ALIGN (t, align); DECL_USER_ALIGN (t) = 1; trampoline_type = make_node (RECORD_TYPE); @@ -548,7 +548,7 @@ get_nl_goto_field (struct nesting_info *info) field = make_node (FIELD_DECL); DECL_NAME (field) = get_identifier ("__nl_goto_buf"); TREE_TYPE (field) = type; - DECL_ALIGN (field) = TYPE_ALIGN (type); + SET_DECL_ALIGN (field, TYPE_ALIGN (type)); TREE_ADDRESSABLE (field) = 1; insert_field_into_struct (get_frame_type (info), field); diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c index 89556e1..c198c16 100644 --- a/gcc/tree-ssa-ccp.c +++ b/gcc/tree-ssa-ccp.c @@ -2119,7 +2119,7 @@ fold_builtin_alloca_with_align (gimple *stmt) n_elem = size * 8 / BITS_PER_UNIT; array_type = build_array_type_nelts (elem_type, n_elem); var = create_tmp_var (array_type); - DECL_ALIGN (var) = TREE_INT_CST_LOW (gimple_call_arg (stmt, 1)); + SET_DECL_ALIGN (var, TREE_INT_CST_LOW (gimple_call_arg (stmt, 1))); { struct ptr_info_def *pi = SSA_NAME_PTR_INFO (lhs); if (pi != NULL && !pi->pt.anything) diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c index 91c72eb..2ad2f92 100644 --- a/gcc/tree-streamer-in.c +++ b/gcc/tree-streamer-in.c @@ -230,10 +230,10 @@ unpack_ts_decl_common_value_fields (struct bitpack_d *bp, tree expr) DECL_PRESERVE_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_EXTERNAL (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_GIMPLE_REG_P (expr) = (unsigned) bp_unpack_value (bp, 1); - DECL_ALIGN (expr) = (unsigned) bp_unpack_var_len_unsigned (bp); + SET_DECL_ALIGN (expr, (unsigned) bp_unpack_var_len_unsigned (bp)); #ifdef ACCEL_COMPILER if (DECL_ALIGN (expr) > targetm.absolute_biggest_alignment) - DECL_ALIGN (expr) = targetm.absolute_biggest_alignment; + SET_DECL_ALIGN (expr, targetm.absolute_biggest_alignment); #endif if (TREE_CODE (expr) == LABEL_DECL) { @@ -378,10 +378,10 @@ unpack_ts_type_common_value_fields (struct bitpack_d *bp, tree expr) else if (TREE_CODE (expr) == ARRAY_TYPE) TYPE_NONALIASED_COMPONENT (expr) = (unsigned) bp_unpack_value (bp, 1); TYPE_PRECISION (expr) = bp_unpack_var_len_unsigned (bp); - TYPE_ALIGN (expr) = bp_unpack_var_len_unsigned (bp); + SET_TYPE_ALIGN (expr, bp_unpack_var_len_unsigned (bp)); #ifdef ACCEL_COMPILER if (TYPE_ALIGN (expr) > targetm.absolute_biggest_alignment) - TYPE_ALIGN (expr) = targetm.absolute_biggest_alignment; + SET_TYPE_ALIGN (expr, targetm.absolute_biggest_alignment); #endif } diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c index 4839efb..e69c678 100644 --- a/gcc/tree-vect-stmts.c +++ b/gcc/tree-vect-stmts.c @@ -5149,7 +5149,7 @@ ensure_base_align (stmt_vec_info stmt_info, struct data_reference *dr) symtab_node::get (base_decl)->increase_alignment (TYPE_ALIGN (vectype)); else { - DECL_ALIGN (base_decl) = TYPE_ALIGN (vectype); + SET_DECL_ALIGN (base_decl, TYPE_ALIGN (vectype)); DECL_USER_ALIGN (base_decl) = 1; } DR_VECT_AUX (dr)->base_misaligned = false; diff --git a/gcc/tree.c b/gcc/tree.c index 8dbaadd..e0a48cc 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -1022,11 +1022,11 @@ make_node_stat (enum tree_code code MEM_STAT_DECL) { if (code == FUNCTION_DECL) { - DECL_ALIGN (t) = FUNCTION_BOUNDARY; + SET_DECL_ALIGN (t, FUNCTION_BOUNDARY); DECL_MODE (t) = FUNCTION_MODE; } else - DECL_ALIGN (t) = 1; + SET_DECL_ALIGN (t, 1); } DECL_SOURCE_LOCATION (t) = input_location; if (TREE_CODE (t) == DEBUG_EXPR_DECL) @@ -1043,7 +1043,7 @@ make_node_stat (enum tree_code code MEM_STAT_DECL) case tcc_type: TYPE_UID (t) = next_type_uid++; - TYPE_ALIGN (t) = BITS_PER_UNIT; + SET_TYPE_ALIGN (t, BITS_PER_UNIT); TYPE_USER_ALIGN (t) = 0; TYPE_MAIN_VARIANT (t) = t; TYPE_CANONICAL (t) = t; @@ -6643,7 +6643,7 @@ build_qualified_type (tree type, int type_quals) /* Ensure the alignment of this type is compatible with the required alignment of the atomic type. */ if (TYPE_ALIGN (atomic_type) > TYPE_ALIGN (t)) - TYPE_ALIGN (t) = TYPE_ALIGN (atomic_type); + SET_TYPE_ALIGN (t, TYPE_ALIGN (atomic_type)); } } @@ -6682,7 +6682,7 @@ build_aligned_type (tree type, unsigned int align) return t; t = build_variant_type_copy (type); - TYPE_ALIGN (t) = align; + SET_TYPE_ALIGN (t, align); return t; } @@ -8132,7 +8132,7 @@ build_range_type_1 (tree type, tree lowval, tree highval, bool shared) SET_TYPE_MODE (itype, TYPE_MODE (type)); TYPE_SIZE (itype) = TYPE_SIZE (type); TYPE_SIZE_UNIT (itype) = TYPE_SIZE_UNIT (type); - TYPE_ALIGN (itype) = TYPE_ALIGN (type); + SET_TYPE_ALIGN (itype, TYPE_ALIGN (type)); TYPE_USER_ALIGN (itype) = TYPE_USER_ALIGN (type); if (!shared) @@ -10043,7 +10043,7 @@ build_atomic_base (tree type, unsigned int align) set_type_quals (t, TYPE_QUAL_ATOMIC); if (align) - TYPE_ALIGN (t) = align; + SET_TYPE_ALIGN (t, align); return t; } @@ -10192,7 +10192,7 @@ build_common_tree_nodes (bool signed_char) /* We are not going to have real types in C with less than byte alignment, so we might as well not have any types that claim to have it. */ - TYPE_ALIGN (void_type_node) = BITS_PER_UNIT; + SET_TYPE_ALIGN (void_type_node, BITS_PER_UNIT); TYPE_USER_ALIGN (void_type_node) = 0; void_node = make_node (VOID_CST); diff --git a/gcc/tree.h b/gcc/tree.h index 1967097..5cbce77 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -915,10 +915,7 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, of this type is aligned at least to the alignment of the type, even if it doesn't appear that it is. We see this, for example, in object-oriented languages where a tag field may show this is an object of a more-aligned - variant of the more generic type. - - In an SSA_NAME node, nonzero if the SSA_NAME node is on the SSA_NAME - freelist. */ + variant of the more generic type. */ #define TYPE_ALIGN_OK(NODE) (TYPE_CHECK (NODE)->base.nothrow_flag) /* Used in classes in C++. */ @@ -1864,8 +1861,15 @@ extern machine_mode element_mode (const_tree t); #define TYPE_ATTRIBUTES(NODE) (TYPE_CHECK (NODE)->type_common.attributes) /* The alignment necessary for objects of this type. - The value is an int, measured in bits. */ -#define TYPE_ALIGN(NODE) (TYPE_CHECK (NODE)->type_common.align) + The value is an int, measured in bits and must be a power of two. + We support also an "alignement" of zero. */ +#define TYPE_ALIGN(NODE) \ + (TYPE_CHECK (NODE)->type_common.align \ + ? ((unsigned)1) << ((NODE)->type_common.align - 1) : 0) + +/* Specify that TYPE_ALIGN(NODE) is X. */ +#define SET_TYPE_ALIGN(NODE, X) \ + (TYPE_CHECK (NODE)->type_common.align = ffs_hwi (X)) /* 1 if the alignment for this type was requested by "aligned" attribute, 0 if it is the default for this type. */ @@ -2305,8 +2309,16 @@ extern machine_mode element_mode (const_tree t); #define DECL_SIZE(NODE) (DECL_COMMON_CHECK (NODE)->decl_common.size) /* Likewise for the size in bytes. */ #define DECL_SIZE_UNIT(NODE) (DECL_COMMON_CHECK (NODE)->decl_common.size_unit) -/* Holds the alignment required for the datum, in bits. */ -#define DECL_ALIGN(NODE) (DECL_COMMON_CHECK (NODE)->decl_common.align) +/* Returns the alignment required for the datum, in bits. It must + be a power of two, but an "alignment" of zero is supported + (e.g. as "uninitialized" sentinel). */ +#define DECL_ALIGN(NODE) \ + (DECL_COMMON_CHECK (NODE)->decl_common.align \ + ? ((unsigned)1) << ((NODE)->decl_common.align - 1) : 0) +/* Specify that DECL_ALIGN(NODE) is X. */ +#define SET_DECL_ALIGN(NODE, X) \ + (DECL_COMMON_CHECK (NODE)->decl_common.align = ffs_hwi (X)) + /* The alignment of NODE, in bytes. */ #define DECL_ALIGN_UNIT(NODE) (DECL_ALIGN (NODE) / BITS_PER_UNIT) /* Set if the alignment of this DECL has been set by the user, for @@ -2509,7 +2521,7 @@ extern void decl_value_expr_insert (tree, tree); #define DECL_OFFSET_ALIGN(NODE) \ (((unsigned HOST_WIDE_INT)1) << FIELD_DECL_CHECK (NODE)->decl_common.off_align) -/* Specify that DECL_ALIGN(NODE) is a multiple of X. */ +/* Specify that DECL_OFFSET_ALIGN(NODE) is X. */ #define SET_DECL_OFFSET_ALIGN(NODE, X) \ (FIELD_DECL_CHECK (NODE)->decl_common.off_align = ffs_hwi (X) - 1) diff --git a/gcc/varasm.c b/gcc/varasm.c index 9317273..d8bd985 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -1053,7 +1053,7 @@ align_variable (tree decl, bool dont_output_data) /* Reset the alignment in case we have made it tighter, so we can benefit from it in get_pointer_alignment. */ - DECL_ALIGN (decl) = align; + SET_DECL_ALIGN (decl, align); } /* Return DECL_ALIGN (decl), possibly increased for optimization purposes @@ -2187,8 +2187,8 @@ assemble_variable (tree decl, int top_level ATTRIBUTE_UNUSED, && asan_protect_global (decl)) { asan_protected = true; - DECL_ALIGN (decl) = MAX (DECL_ALIGN (decl), - ASAN_RED_ZONE_SIZE * BITS_PER_UNIT); + SET_DECL_ALIGN (decl, MAX (DECL_ALIGN (decl), + ASAN_RED_ZONE_SIZE * BITS_PER_UNIT)); } set_mem_align (decl_rtl, DECL_ALIGN (decl)); @@ -3249,7 +3249,7 @@ build_constant_desc (tree exp) architectures so use DATA_ALIGNMENT as well, except for strings. */ if (TREE_CODE (exp) == STRING_CST) { - DECL_ALIGN (decl) = CONSTANT_ALIGNMENT (exp, DECL_ALIGN (decl)); + SET_DECL_ALIGN (decl, CONSTANT_ALIGNMENT (exp, DECL_ALIGN (decl))); } else align_variable (decl, 0); @@ -3408,8 +3408,8 @@ output_constant_def_contents (rtx symbol) && asan_protect_global (exp)) { asan_protected = true; - DECL_ALIGN (decl) = MAX (DECL_ALIGN (decl), - ASAN_RED_ZONE_SIZE * BITS_PER_UNIT); + SET_DECL_ALIGN (decl, MAX (DECL_ALIGN (decl), + ASAN_RED_ZONE_SIZE * BITS_PER_UNIT)); } /* If the constant is part of an object block, make sure that the diff --git a/libcc1/plugin.cc b/libcc1/plugin.cc index 57fca7c..44d0d60 100644 --- a/libcc1/plugin.cc +++ b/libcc1/plugin.cc @@ -553,8 +553,8 @@ plugin_finish_record_or_union (cc1_plugin::connection *, { // FIXME there's no way to get this from DWARF, // or even, it seems, a particularly good way to deduce it. - TYPE_ALIGN (record_or_union_type) - = TYPE_PRECISION (pointer_sized_int_node); + SET_TYPE_ALIGN (record_or_union_type, + TYPE_PRECISION (pointer_sized_int_node)); TYPE_SIZE (record_or_union_type) = bitsize_int (size_in_bytes * BITS_PER_UNIT); -- 2.7.4 From 76ce3f74c08305e293e970dc282f84756f14af28 Mon Sep 17 00:00:00 2001 From: mpolacek Date: Fri, 12 Aug 2016 10:30:47 +0000 Subject: [PATCH 06/16] PR c/7652 gcc/ * alias.c (find_base_value): Adjust fall through comment. * cfgexpand.c (expand_debug_expr): Likewise. * combine.c (find_split_point): Likewise. (expand_compound_operation): Likewise. Add FALLTHRU. (make_compound_operation): Adjust fall through comment. (canon_reg_for_combine): Add FALLTHRU. (force_to_mode): Adjust fall through comment. (simplify_shift_const_1): Likewise. (simplify_comparison): Likewise. * config/aarch64/aarch64-builtins.c (aarch64_simd_expand_args): Add FALLTHRU. * config/aarch64/predicates.md: Likewise. * config/i386/i386.c (function_arg_advance_32): Likewise. (ix86_gimplify_va_arg): Likewise. (print_reg): Likewise. (ix86_print_operand): Likewise. (ix86_build_const_vector): Likewise. (ix86_expand_branch): Likewise. (ix86_sched_init_global): Adjust fall through comment. (ix86_expand_args_builtin): Add FALLTHRU. (ix86_expand_builtin): Likewise. (ix86_expand_vector_init_one_var): Likewise. * config/rs6000/rs6000.c (rs6000_emit_vector_compare_inner): Likewise. (rs6000_adjust_cost): Likewise. (insn_must_be_first_in_group): Likewise. * config/rs6000/rs6000.md: Likewise. Adjust fall through comment. * dbxout.c (dbxout_symbol): Adjust fall through comment. * df-scan.c (df_uses_record): Likewise. * dojump.c (do_jump): Add FALLTHRU. * dwarf2out.c (mem_loc_descriptor): Likewise. Adjust fall through comment. (resolve_args_picking_1): Adjust fall through comment. (loc_list_from_tree_1): Likewise. * expmed.c (make_tree): Likewise. * expr.c (expand_expr_real_2): Add FALLTHRU. (expand_expr_real_1): Likewise. Adjust fall through comment. * fold-const.c (const_binop): Adjust fall through comment. (fold_truth_not_expr): Likewise. (fold_cond_expr_with_comparison): Add FALLTHRU. (fold_binary_loc): Likewise. (contains_label_1): Adjust fall through comment. (multiple_of_p): Likewise. * gcov-tool.c (process_args): Add FALLTHRU. * genattrtab.c (check_attr_test): Likewise. (write_test_expr): Likewise. * genconfig.c (walk_insn_part): Likewise. * genpreds.c (validate_exp): Adjust fall through comment. (needs_variable): Likewise. * gensupport.c (get_alternatives_number): Add FALLTHRU. (subst_dup): Likewise. * gimple-pretty-print.c (dump_gimple_assign): Likewise. * gimplify.c (gimplify_addr_expr): Adjust fall through comment. (gimplify_scan_omp_clauses): Add FALLTHRU. (goa_stabilize_expr): Likewise. * graphite-isl-ast-to-gimple.c (substitute_ssa_name): Adjust fall through comment. * hsa-gen.c (get_address_from_value): Likewise. * ipa-icf.c (sem_function::hash_stmt): Likewise. * ira.c (ira_setup_alts): Add FALLTHRU. * lra-eliminations.c (lra_eliminate_regs_1): Adjust fall through comment. * lto-streamer-out.c (lto_output_tree_ref): Add FALLTHRU. * opts.c (common_handle_option): Likewise. * read-rtl.c (read_rtx_code): Likewise. * real.c (round_for_format): Likewise. * recog.c (asm_operand_ok): Likewise. * reginfo.c (reg_scan_mark_refs): Adjust fall through comment. * reload1.c (set_label_offsets): Likewise. (eliminate_regs_1): Likewise. (reload_reg_reaches_end_p): Likewise. * rtlanal.c (commutative_operand_precedence): Add FALLTHRU. (rtx_cost): Likewise. * sched-rgn.c (is_exception_free): Likewise. * simplify-rtx.c (simplify_rtx): Adjust fall through comment. * stor-layout.c (int_mode_for_mode): Likewise. * toplev.c (print_to_asm_out_file): Likewise. (print_to_stderr): Likewise. * tree-cfg.c (gimple_verify_flow_info): Likewise. * tree-chrec.c (chrec_fold_plus_1): Add FALLTHRU. (chrec_fold_multiply): Likewise. (evolution_function_is_invariant_rec_p): Likewise. (for_each_scev_op): Likewise. * tree-data-ref.c (siv_subscript_p): Likewise. (get_references_in_stmt): Likewise. * tree.c (find_placeholder_in_expr): Adjust fall through comment. (substitute_in_expr): Likewise. (type_cache_hasher::equal): Likewise. (walk_type_fields): Likewise. * var-tracking.c (adjust_mems): Add FALLTHRU. (set_dv_changed): Adjust fall through comment. * varasm.c (default_function_section): Add FALLTHRU. gcc/c-family/ * c-common.c (scalar_to_vector): Adjust fall through comment. * c-opts.c (c_common_handle_option): Likewise. * c-pragma.c (handle_pragma_pack): Add FALLTHRU. * c-pretty-print.c (c_pretty_printer::postfix_expression): Adjust fall through comment. * cilk.c (extract_free_variables): Add FALLTHRU. gcc/c/ * c-parser.c (c_parser_external_declaration): Add FALLTHRU. (c_parser_postfix_expression): Likewise. * c-typeck.c (build_unary_op): Adjust fall through comment. (c_mark_addressable): Likewise. gcc/cp/ * call.c (add_builtin_candidate): Add FALLTHRU. (build_integral_nontype_arg_conv): Adjust fall through comment. (build_new_op_1): Add FALLTHRU. (convert_like_real): Adjust fall through comment. * class.c (fixed_type_or_null): Likewise. * constexpr.c (cxx_eval_constant_expression): Likewise. (potential_constant_expression_1): Likewise. Add FALLTHRU. * cp-gimplify.c (cp_gimplify_expr): Adjust fall through comment. (cp_fold): Add FALLTHRU. * cvt.c (build_expr_type_conversion): Adjust fall through comment. * cxx-pretty-print.c (pp_cxx_unqualified_id): Add FALLTHRU. (pp_cxx_qualified_id): Likewise. (cxx_pretty_printer::constant): Adjust fall through comment. (cxx_pretty_printer::primary_expression): Add FALLTHRU. (pp_cxx_pm_expression): Adjust fall through comment. (cxx_pretty_printer::expression): Add FALLTHRU. (cxx_pretty_printer::declaration_specifiers): Reformat code. (pp_cxx_type_specifier_seq): Adjust fall through comment. (pp_cxx_ptr_operator): Likewise. Add FALLTHRU. * error.c (dump_type): Adjust fall through comment. (dump_decl): Likewise. * mangle.c (write_type): Likewise. * method.c (synthesized_method_walk): Add FALLTHRU. * name-lookup.c (arg_assoc_type): Likewise. * parser.c (cp_lexer_print_token): Adjust fall through comment. (cp_parser_primary_expression): Add FALLTHRU. (cp_parser_operator): Likewise. * pt.c (find_parameter_packs_r): Likewise. (tsubst_aggr_type): Adjust fall through comment. * semantics.c (finish_omp_clauses): Add FALLTHRU. * tree.c (lvalue_kind): Likewise. gcc/fortran/ * decl.c (match_attr_spec): Add FALLTHRU. * primary.c (match_arg_list_function): Likewise. * resolve.c (resolve_operator): Adjust fall through comment. (fixup_charlen): Add FALLTHRU. (resolve_allocate_expr): Adjust fall through comment. * trans-array.c (gfc_conv_ss_startstride): Add FALLTHRU. * trans-intrinsic.c (gfc_conv_intrinsic_len): Adjust fall through comment. gcc/java/ * expr.c (java_truthvalue_conversion): Adjust fall through comment. * jcf-io.c (verify_constant_pool): Likewise. * typeck.c (promote_type): Likewise. gcc/objc/ * objc-encoding.c (encode_type): Add FALLTHRU. libcpp/ * lex.c (search_line_fast): Add FALLTHRU. (_cpp_lex_direct): Likewise. (cpp_token_val_index): Adjust fall through comment. * macro.c (parse_params): Add FALLTHRU. * pch.c (count_defs): Adjust fall through comment. (write_defs): Likewise. libiberty/ * cp-demangle.c (d_print_mod): Add FALLTHRU. upstream hash: e3533433b8efa642ea08f2704b1dd7b7f741fbc3 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@239410 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: I4ebe40df8514b8ec4a6d5c701b2b672107fcc40c --- gcc/alias.c | 2 +- gcc/c-family/c-common.c | 2 +- gcc/c-family/c-opts.c | 2 +- gcc/c-family/c-pragma.c | 1 + gcc/c-family/c-pretty-print.c | 2 +- gcc/c-family/cilk.c | 1 + gcc/c/c-parser.c | 2 ++ gcc/c/c-typeck.c | 6 +++--- gcc/cfgexpand.c | 2 +- gcc/combine.c | 16 +++++++++------- gcc/config/aarch64/aarch64-builtins.c | 1 + gcc/config/aarch64/predicates.md | 2 ++ gcc/config/i386/i386.c | 17 ++++++++++++++++- gcc/config/rs6000/rs6000.c | 3 +++ gcc/config/rs6000/rs6000.md | 3 ++- gcc/cp/call.c | 9 +++++++-- gcc/cp/class.c | 2 +- gcc/cp/constexpr.c | 3 ++- gcc/cp/cp-gimplify.c | 5 ++++- gcc/cp/cvt.c | 2 +- gcc/cp/cxx-pretty-print.c | 17 ++++++++++++----- gcc/cp/error.c | 4 ++-- gcc/cp/mangle.c | 2 +- gcc/cp/method.c | 1 + gcc/cp/name-lookup.c | 1 + gcc/cp/parser.c | 4 +++- gcc/cp/pt.c | 3 ++- gcc/cp/semantics.c | 2 ++ gcc/cp/tree.c | 2 ++ gcc/dbxout.c | 2 +- gcc/df-scan.c | 2 +- gcc/dojump.c | 3 +++ gcc/dwarf2out.c | 7 ++++--- gcc/expmed.c | 2 +- gcc/expr.c | 11 ++++++----- gcc/fold-const.c | 11 +++++++---- gcc/fortran/decl.c | 1 + gcc/fortran/primary.c | 3 +++ gcc/fortran/resolve.c | 9 ++++++--- gcc/fortran/trans-array.c | 1 + gcc/fortran/trans-intrinsic.c | 2 +- gcc/gcov-tool.c | 2 ++ gcc/genattrtab.c | 2 ++ gcc/genconfig.c | 1 + gcc/genpreds.c | 8 ++++---- gcc/gensupport.c | 2 ++ gcc/gimple-pretty-print.c | 2 ++ gcc/gimplify.c | 4 +++- gcc/graphite-isl-ast-to-gimple.c | 2 +- gcc/hsa-gen.c | 2 +- gcc/ipa-icf.c | 2 +- gcc/ira.c | 1 + gcc/java/expr.c | 2 +- gcc/java/jcf-io.c | 2 +- gcc/java/typeck.c | 2 +- gcc/lra-eliminations.c | 4 ++-- gcc/lto-streamer-out.c | 1 + gcc/objc/objc-encoding.c | 1 + gcc/opts.c | 3 +++ gcc/read-rtl.c | 1 + gcc/real.c | 1 + gcc/recog.c | 1 + gcc/reginfo.c | 2 +- gcc/reload1.c | 10 +++++----- gcc/rtlanal.c | 3 ++- gcc/sched-rgn.c | 1 + gcc/simplify-rtx.c | 2 +- gcc/stor-layout.c | 2 +- gcc/toplev.c | 4 ++-- gcc/tree-cfg.c | 2 +- gcc/tree-chrec.c | 10 ++++++++++ gcc/tree-data-ref.c | 2 ++ gcc/tree.c | 8 ++++---- gcc/var-tracking.c | 4 +++- gcc/varasm.c | 1 + libcpp/lex.c | 4 +++- libcpp/macro.c | 1 + libcpp/pch.c | 4 ++-- libiberty/cp-demangle.c | 2 ++ 79 files changed, 196 insertions(+), 85 deletions(-) diff --git a/gcc/alias.c b/gcc/alias.c index c762894..f92b90a 100644 --- a/gcc/alias.c +++ b/gcc/alias.c @@ -1390,7 +1390,7 @@ find_base_value (rtx src) if (GET_CODE (src) != PLUS && GET_CODE (src) != MINUS) break; - /* ... fall through ... */ + /* fall through */ case PLUS: case MINUS: diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 2a0006c..3961e94 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -12595,7 +12595,7 @@ scalar_to_vector (location_t loc, enum tree_code code, tree op0, tree op1, case BIT_XOR_EXPR: case BIT_AND_EXPR: integer_only_op = true; - /* ... fall through ... */ + /* fall through */ case VEC_COND_EXPR: diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c index 434f35a..1ac017a 100644 --- a/gcc/c-family/c-opts.c +++ b/gcc/c-family/c-opts.c @@ -436,7 +436,7 @@ c_common_handle_option (size_t scode, const char *arg, int value, case OPT_ffreestanding: value = !value; - /* Fall through.... */ + /* Fall through. */ case OPT_fhosted: flag_hosted = value; flag_no_builtin = !value; diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index c73aa82..177a244 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -214,6 +214,7 @@ handle_pragma_pack (cpp_reader * ARG_UNUSED (dummy)) align = maximum_field_alignment; break; } + /* FALLTHRU */ default: GCC_BAD2 ("alignment must be a small power of two, not %d", align); } diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c index 6a23b0b..800cbac 100644 --- a/gcc/c-family/c-pretty-print.c +++ b/gcc/c-family/c-pretty-print.c @@ -1665,7 +1665,7 @@ c_pretty_printer::postfix_expression (tree e) id_expression (TREE_OPERAND (e, 0)); break; } - /* else fall through. */ + /* fall through. */ default: primary_expression (e); diff --git a/gcc/c-family/cilk.c b/gcc/c-family/cilk.c index 0b876b9..047a65f 100644 --- a/gcc/c-family/cilk.c +++ b/gcc/c-family/cilk.c @@ -1092,6 +1092,7 @@ extract_free_variables (tree t, struct wrapper_data *wd, case RESULT_DECL: if (wd->type != CILK_BLOCK_SPAWN) TREE_ADDRESSABLE (t) = 1; + /* FALLTHRU */ case VAR_DECL: case PARM_DECL: if (!is_global_var (t)) diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c index 99a2314..30d9d27 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1548,6 +1548,7 @@ c_parser_external_declaration (c_parser *parser) } /* Else fall through, and yield a syntax error trying to parse as a declaration or function definition. */ + /* FALLTHRU */ default: decl_or_fndef: /* A declaration or a function definition (or, in Objective-C, @@ -8138,6 +8139,7 @@ c_parser_postfix_expression (c_parser *parser) break; } /* Else fall through to report error. */ + /* FALLTHRU */ default: c_parser_error (parser, "expected expression"); expr.set_error (); diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c index 5793a4a..a4003cf 100644 --- a/gcc/c/c-typeck.c +++ b/gcc/c/c-typeck.c @@ -4463,7 +4463,7 @@ build_unary_op (location_t location, return error_mark_node; } - /* ... fall through ... */ + /* fall through */ case ARRAY_REF: if (TYPE_REVERSE_STORAGE_ORDER (TREE_TYPE (TREE_OPERAND (arg, 0)))) @@ -4665,10 +4665,10 @@ c_mark_addressable (tree exp) return false; } - /* drops in */ + /* FALLTHRU */ case FUNCTION_DECL: TREE_ADDRESSABLE (x) = 1; - /* drops out */ + /* FALLTHRU */ default: return true; } diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 21f21c9..20a0fc2 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -4207,7 +4207,7 @@ expand_debug_expr (tree exp) set_mem_attributes (op0, exp, 0); return op0; } - /* Fall through... */ + /* Fall through. */ case INTEGER_CST: case REAL_CST: diff --git a/gcc/combine.c b/gcc/combine.c index 75c6229..77c2c26 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -5135,7 +5135,7 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src) split = find_split_point (&XEXP (x, 2), insn, false); if (split) return split; - /* ... fall through ... */ + /* fall through */ case RTX_BIN_ARITH: case RTX_COMM_ARITH: case RTX_COMPARE: @@ -5143,7 +5143,7 @@ find_split_point (rtx *loc, rtx_insn *insn, bool set_src) split = find_split_point (&XEXP (x, 1), insn, false); if (split) return split; - /* ... fall through ... */ + /* fall through */ case RTX_UNARY: /* Some machines have (and (shift ...) ...) insns. If X is not an AND, but XEXP (X, 0) is, use it as our split point. */ @@ -6955,6 +6955,7 @@ expand_compound_operation (rtx x) { case ZERO_EXTEND: unsignedp = 1; + /* FALLTHRU */ case SIGN_EXTEND: /* We can't necessarily use a const_int for a multiword mode; it depends on implicitly extending the value. @@ -6997,7 +6998,7 @@ expand_compound_operation (rtx x) case ZERO_EXTRACT: unsignedp = 1; - /* ... fall through ... */ + /* fall through */ case SIGN_EXTRACT: /* If the operand is a CLOBBER, just return it. */ @@ -8013,7 +8014,7 @@ make_compound_operation (rtx x, enum rtx_code in_code) break; } - /* ... fall through ... */ + /* fall through */ case ASHIFTRT: lhs = XEXP (x, 0); @@ -8240,6 +8241,7 @@ canon_reg_for_combine (rtx x, rtx reg) if (op0 != XEXP (x, 0) || op1 != XEXP (x, 1) || op2 != XEXP (x, 2)) return simplify_gen_ternary (GET_CODE (x), GET_MODE (x), GET_MODE (op0), op0, op1, op2); + /* FALLTHRU */ case RTX_OBJ: if (REG_P (x)) @@ -8506,7 +8508,7 @@ force_to_mode (rtx x, machine_mode mode, unsigned HOST_WIDE_INT mask, mode, smask, next_select); } - /* ... fall through ... */ + /* fall through */ case MULT: /* Substituting into the operands of a widening MULT is not likely to @@ -10379,7 +10381,7 @@ simplify_shift_const_1 (enum rtx_code code, machine_mode result_mode, continue; } - /* ... fall through ... */ + /* fall through */ case LSHIFTRT: case ASHIFT: @@ -11707,7 +11709,7 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1) continue; } - /* ... fall through ... */ + /* fall through */ case SIGN_EXTRACT: tem = expand_compound_operation (op0); diff --git a/gcc/config/aarch64/aarch64-builtins.c b/gcc/config/aarch64/aarch64-builtins.c index 0b80c3d..b69294f 100644 --- a/gcc/config/aarch64/aarch64-builtins.c +++ b/gcc/config/aarch64/aarch64-builtins.c @@ -1039,6 +1039,7 @@ aarch64_simd_expand_args (rtx target, int icode, int have_retval, } /* Fall through - if the lane index isn't a constant then the next case will error. */ + /* FALLTHRU */ case SIMD_ARG_CONSTANT: constant_arg: if (!(*insn_data[icode].operand[opc].predicate) diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md index 8f2726d..ebda6d8 100644 --- a/gcc/config/aarch64/predicates.md +++ b/gcc/config/aarch64/predicates.md @@ -180,6 +180,7 @@ || GET_CODE (XEXP (op, 1)) != CONST_INT) return false; op = XEXP (op, 0); + /* FALLTHRU */ case SYMBOL_REF: return SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_INITIAL_EXEC; @@ -201,6 +202,7 @@ || GET_CODE (XEXP (op, 1)) != CONST_INT) return false; op = XEXP (op, 0); + /* FALLTHRU */ case SYMBOL_REF: return SYMBOL_REF_TLS_MODEL (op) == TLS_MODEL_LOCAL_EXEC; diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 6cb5dec..898c247 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -8735,6 +8735,7 @@ pass_in_reg: error_p = 1; if (cum->float_in_sse < 2) break; + /* FALLTHRU */ case SFmode: if (cum->float_in_sse == -1) error_p = 1; @@ -8997,6 +8998,7 @@ pass_in_reg: error_p = 1; if (cum->float_in_sse < 2) break; + /* FALLTHRU */ case SFmode: if (cum->float_in_sse == -1) error_p = 1; @@ -10392,6 +10394,7 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, container = NULL; break; } + /* FALLTHRU */ default: container = construct_container (nat_mode, TYPE_MODE (type), @@ -16609,6 +16612,7 @@ print_reg (rtx x, int code, FILE *file) case 4: if (LEGACY_INT_REGNO_P (regno)) putc (msize == 8 && TARGET_64BIT ? 'r' : 'e', file); + /* FALLTHRU */ case 16: case 12: case 2: @@ -17018,6 +17022,7 @@ ix86_print_operand (FILE *file, rtx x, int code) fputs ("eq_us", file); break; } + /* FALLTHRU */ case EQ: fputs ("eq", file); break; @@ -17027,6 +17032,7 @@ ix86_print_operand (FILE *file, rtx x, int code) fputs ("nge", file); break; } + /* FALLTHRU */ case LT: fputs ("lt", file); break; @@ -17036,6 +17042,7 @@ ix86_print_operand (FILE *file, rtx x, int code) fputs ("ngt", file); break; } + /* FALLTHRU */ case LE: fputs ("le", file); break; @@ -17048,6 +17055,7 @@ ix86_print_operand (FILE *file, rtx x, int code) fputs ("neq_oq", file); break; } + /* FALLTHRU */ case NE: fputs ("neq", file); break; @@ -17057,6 +17065,7 @@ ix86_print_operand (FILE *file, rtx x, int code) fputs ("ge", file); break; } + /* FALLTHRU */ case UNGE: fputs ("nlt", file); break; @@ -17066,6 +17075,7 @@ ix86_print_operand (FILE *file, rtx x, int code) fputs ("gt", file); break; } + /* FALLTHRU */ case UNGT: fputs ("nle", file); break; @@ -20854,6 +20864,7 @@ ix86_build_const_vector (machine_mode mode, bool vect, rtx value) case V4DImode: case V2DImode: gcc_assert (vect); + /* FALLTHRU */ case V16SFmode: case V8SFmode: case V4SFmode: @@ -21839,6 +21850,7 @@ ix86_expand_branch (enum rtx_code code, rtx op0, rtx op1, rtx label) op0 = force_reg (mode, gen_rtx_XOR (mode, op0, op1)); op1 = const0_rtx; } + /* FALLTHRU */ case TImode: /* Expand DImode branch into multiple compare+branch. */ { @@ -29131,7 +29143,7 @@ ix86_sched_init_global (FILE *, int, int) core2i7_ifetch_block_max_insns = 6; break; } - /* ... Fall through ... */ + /* Fall through. */ default: targetm.sched.dfa_post_advance_cycle = NULL; targetm.sched.first_cycle_multipass_init = NULL; @@ -39486,6 +39498,7 @@ ix86_expand_args_builtin (const struct builtin_description *d, error ("the next to last argument must be an 8-bit immediate"); break; } + /* FALLTHRU */ case 1: error ("the last argument must be an 8-bit immediate"); break; @@ -42189,6 +42202,7 @@ rdseed_step: if (!TARGET_SSE) /* Emit a normal call if SSE isn't available. */ return expand_call (exp, target, ignore); + /* FALLTHRU */ default: return ix86_expand_args_builtin (d, exp, target); } @@ -46295,6 +46309,7 @@ ix86_expand_vector_init_one_var (bool mmx_ok, machine_mode mode, /* Use ix86_expand_vector_set in 64bit mode only. */ if (!TARGET_64BIT) return false; + /* FALLTHRU */ case V4DFmode: case V8SFmode: case V8SImode: diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index b0b1b3a..cbf350b 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -22484,6 +22484,7 @@ rs6000_emit_vector_compare_inner (enum rtx_code code, rtx op0, rtx op1) case GE: if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT) return NULL_RTX; + /* FALLTHRU */ case EQ: case GT: @@ -30276,6 +30277,7 @@ rs6000_adjust_cost (rtx_insn *insn, rtx link, rtx_insn *dep_insn, int cost) } } /* Fall through, no cost for output dependency. */ + /* FALLTHRU */ case REG_DEP_ANTI: /* Anti dependency; DEP_INSN reads a register that INSN writes some @@ -31422,6 +31424,7 @@ insn_must_be_first_in_group (rtx_insn *insn) case PROCESSOR_POWER5: if (is_cracked_insn (insn)) return true; + /* FALLTHRU */ case PROCESSOR_POWER4: if (is_microcoded_insn (insn)) return true; diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md index a73c4a2..0a96f56 100644 --- a/gcc/config/rs6000/rs6000.md +++ b/gcc/config/rs6000/rs6000.md @@ -7923,6 +7923,7 @@ case 0: if (TARGET_STRING) return \"stswi %1,%P0,16\"; + /* FALLTHRU */ case 1: return \"#\"; case 2: @@ -7931,7 +7932,7 @@ if (TARGET_STRING && ! reg_overlap_mentioned_p (operands[0], operands[1])) return \"lswi %0,%P1,16\"; - /* ... fall through ... */ + /* fall through */ case 3: case 4: case 5: diff --git a/gcc/cp/call.c b/gcc/cp/call.c index cbc3ec6..71ce008 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -2402,6 +2402,7 @@ add_builtin_candidate (struct z_candidate **candidates, enum tree_code code, case PREDECREMENT_EXPR: if (TREE_CODE (type1) == BOOLEAN_TYPE) return; + /* FALLTHRU */ case POSTINCREMENT_EXPR: case PREINCREMENT_EXPR: if (ARITHMETIC_TYPE_P (type1) || TYPE_PTROB_P (type1)) @@ -2438,6 +2439,7 @@ add_builtin_candidate (struct z_candidate **candidates, enum tree_code code, case UNARY_PLUS_EXPR: /* unary + */ if (TYPE_PTR_P (type1)) break; + /* FALLTHRU */ case NEGATE_EXPR: if (ARITHMETIC_TYPE_P (type1)) break; @@ -2575,6 +2577,7 @@ add_builtin_candidate (struct z_candidate **candidates, enum tree_code code, case PLUS_EXPR: if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2)) break; + /* FALLTHRU */ case ARRAY_REF: if (INTEGRAL_OR_UNSCOPED_ENUMERATION_TYPE_P (type1) && TYPE_PTROB_P (type2)) { @@ -2655,6 +2658,7 @@ add_builtin_candidate (struct z_candidate **candidates, enum tree_code code, type2 = ptrdiff_type_node; break; } + /* FALLTHRU */ case MULT_EXPR: case TRUNC_DIV_EXPR: if (ARITHMETIC_TYPE_P (type1) && ARITHMETIC_TYPE_P (type2)) @@ -3941,7 +3945,7 @@ build_integral_nontype_arg_conv (tree type, tree expr, tsubst_flags_t complain) if (complain & tf_error) error_at (loc, "conversion from %qT to %qT not considered for " "non-type template argument", t, type); - /* and fall through. */ + /* fall through. */ default: conv = NULL; @@ -5436,6 +5440,7 @@ build_new_op_1 (location_t loc, enum tree_code code, int flags, tree arg1, case MODIFY_EXPR: if (code2 != NOP_EXPR) break; + /* FALLTHRU */ case COMPONENT_REF: case ARRAY_REF: memonly = true; @@ -6569,7 +6574,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum, if (! MAYBE_CLASS_TYPE_P (totype)) return expr; - /* Else fall through. */ + /* Fall through. */ case ck_base: if (convs->kind == ck_base && !convs->need_temporary_p) { diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 71f7eec..ae5250f 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -7562,7 +7562,7 @@ fixed_type_or_null (tree instance, int *nonnull, int *cdtorp) *nonnull = 1; return TREE_TYPE (TREE_TYPE (instance)); } - /* fall through... */ + /* fall through. */ case TARGET_EXPR: case PARM_DECL: case RESULT_DECL: diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index cff531e..dd31d56 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -5042,7 +5042,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, /* A destructor. */ if (TYPE_P (TREE_OPERAND (t, 0))) return true; - /* else fall through. */ + /* fall through. */ case REALPART_EXPR: case IMAGPART_EXPR: @@ -5117,6 +5117,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, } return false; } + /* FALLTHRU */ case INIT_EXPR: return RECUR (TREE_OPERAND (t, 1), rval); diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index d1b8f0b..216334a 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -630,7 +630,7 @@ cp_gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) cp_gimplify_init_expr (expr_p); if (TREE_CODE (*expr_p) != INIT_EXPR) return GS_OK; - /* Otherwise fall through. */ + /* Fall through. */ case MODIFY_EXPR: modify_expr_case: { @@ -1998,6 +1998,7 @@ cp_fold (tree x) case VIEW_CONVERT_EXPR: rval_ops = false; + /* FALLTHRU */ case CONVERT_EXPR: case NOP_EXPR: case NON_LVALUE_EXPR: @@ -2046,6 +2047,7 @@ cp_fold (tree x) case REALPART_EXPR: case IMAGPART_EXPR: rval_ops = false; + /* FALLTHRU */ case CONJ_EXPR: case FIX_TRUNC_EXPR: case FLOAT_EXPR: @@ -2098,6 +2100,7 @@ cp_fold (tree x) case COMPOUND_EXPR: case MODIFY_EXPR: rval_ops = false; + /* FALLTHRU */ case POINTER_PLUS_EXPR: case PLUS_EXPR: case MINUS_EXPR: diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c index 0d1048c..a0cd577 100644 --- a/gcc/cp/cvt.c +++ b/gcc/cp/cvt.c @@ -1548,7 +1548,7 @@ build_expr_type_conversion (int desires, tree expr, bool complain) case INTEGER_TYPE: if ((desires & WANT_NULL) && null_ptr_cst_p (expr)) return expr; - /* else fall through... */ + /* fall through. */ case BOOLEAN_TYPE: return (desires & WANT_INT) ? expr : NULL_TREE; diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c index cd5d606..f06fc84 100644 --- a/gcc/cp/cxx-pretty-print.c +++ b/gcc/cp/cxx-pretty-print.c @@ -153,6 +153,7 @@ pp_cxx_unqualified_id (cxx_pretty_printer *pp, tree t) case USING_DECL: case TEMPLATE_DECL: t = DECL_NAME (t); + /* FALLTHRU */ case IDENTIFIER_NODE: if (t == NULL) @@ -280,6 +281,7 @@ pp_cxx_qualified_id (cxx_pretty_printer *pp, tree t) functions and some function templates. */ case OVERLOAD: t = OVL_CURRENT (t); + /* FALLTHRU */ case FUNCTION_DECL: if (DECL_FUNCTION_MEMBER_P (t)) pp_cxx_nested_name_specifier (pp, DECL_CONTEXT (t)); @@ -331,7 +333,7 @@ cxx_pretty_printer::constant (tree t) pp_string (this, "nullptr"); break; } - /* else fall through. */ + /* fall through. */ default: c_pretty_printer::constant (t); @@ -417,6 +419,7 @@ cxx_pretty_printer::primary_expression (tree t) case BASELINK: t = BASELINK_FUNCTIONS (t); + /* FALLTHRU */ case VAR_DECL: case PARM_DECL: case FIELD_DECL: @@ -873,7 +876,7 @@ pp_cxx_pm_expression (cxx_pretty_printer *pp, tree t) pp_cxx_qualified_id (pp, t); break; } - /* Else fall through. */ + /* Fall through. */ case MEMBER_REF: case DOTSTAR_EXPR: pp_cxx_pm_expression (pp, TREE_OPERAND (t, 0)); @@ -1058,6 +1061,7 @@ cxx_pretty_printer::expression (tree t) case OVERLOAD: t = OVL_CURRENT (t); + /* FALLTHRU */ case VAR_DECL: case PARM_DECL: case FIELD_DECL: @@ -1268,7 +1272,9 @@ cxx_pretty_printer::declaration_specifiers (tree t) else if (DECL_NONSTATIC_MEMBER_FUNCTION_P (t)) declaration_specifiers (TREE_TYPE (TREE_TYPE (t))); else - default: + c_pretty_printer::declaration_specifiers (t); + break; + default: c_pretty_printer::declaration_specifiers (t); break; } @@ -1365,7 +1371,7 @@ pp_cxx_type_specifier_seq (cxx_pretty_printer *pp, tree t) pp_cxx_ptr_operator (pp, t); break; } - /* else fall through */ + /* fall through */ default: if (!(TREE_CODE (t) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (t))) @@ -1407,6 +1413,7 @@ pp_cxx_ptr_operator (cxx_pretty_printer *pp, tree t) pp_star (pp); break; } + /* FALLTHRU */ case OFFSET_TYPE: if (TYPE_PTRMEM_P (t)) { @@ -1417,7 +1424,7 @@ pp_cxx_ptr_operator (cxx_pretty_printer *pp, tree t) pp_cxx_cv_qualifier_seq (pp, t); break; } - /* else fall through. */ + /* fall through. */ default: pp_unsupported_tree (pp, t); diff --git a/gcc/cp/error.c b/gcc/cp/error.c index a852e71..b8fced2 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -450,7 +450,7 @@ dump_type (cxx_pretty_printer *pp, tree t, int flags) ? DECL_ORIGINAL_TYPE (t) : TREE_TYPE (t), flags); break; } - /* Else fall through. */ + /* Fall through. */ case TEMPLATE_DECL: case NAMESPACE_DECL: @@ -1064,7 +1064,7 @@ dump_decl (cxx_pretty_printer *pp, tree t, int flags) dump_type (pp, DECL_CONTEXT (t), flags); break; } - /* Else fall through. */ + /* Fall through. */ case FIELD_DECL: case PARM_DECL: dump_simple_decl (pp, t, TREE_TYPE (t), flags); diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c index 23fd4ef..f1ba032 100644 --- a/gcc/cp/mangle.c +++ b/gcc/cp/mangle.c @@ -2051,7 +2051,7 @@ write_type (tree type) ++is_builtin_type; break; } - /* else fall through. */ + /* fall through. */ case TEMPLATE_PARM_INDEX: write_template_param (type); break; diff --git a/gcc/cp/method.c b/gcc/cp/method.c index 547e672..2fd6cb1 100644 --- a/gcc/cp/method.c +++ b/gcc/cp/method.c @@ -1406,6 +1406,7 @@ synthesized_method_walk (tree ctype, special_function_kind sfk, bool const_p, case sfk_move_constructor: case sfk_move_assignment: move_p = true; + /* FALLTHRU */ case sfk_copy_constructor: case sfk_copy_assignment: copy_arg_p = true; diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c index a4a8af2..5e18a72 100644 --- a/gcc/cp/name-lookup.c +++ b/gcc/cp/name-lookup.c @@ -5557,6 +5557,7 @@ arg_assoc_type (struct arg_lookup *k, tree type) case RECORD_TYPE: if (TYPE_PTRMEMFUNC_P (type)) return arg_assoc_type (k, TYPE_PTRMEMFUNC_FN_TYPE (type)); + /* FALLTHRU */ case UNION_TYPE: return arg_assoc_class (k, type); case POINTER_TYPE: diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index c163dba..6ba9c11 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -1259,7 +1259,7 @@ cp_lexer_print_token (FILE * stream, cp_token *token) For example, `struct' is mapped to an INTEGER_CST. */ if (!identifier_p (token->u.value)) break; - /* else fall through */ + /* fall through */ case CPP_NAME: fputs (IDENTIFIER_POINTER (token->u.value), stream); break; @@ -5117,6 +5117,7 @@ cp_parser_primary_expression (cp_parser *parser, cp_parser_skip_to_end_of_block_or_statement (parser); return error_mark_node; } + /* FALLTHRU */ default: cp_parser_error (parser, "expected primary-expression"); return error_mark_node; @@ -14028,6 +14029,7 @@ cp_parser_operator (cp_parser* parser) case CPP_UTF8STRING: case CPP_UTF8STRING_USERDEF: utf8 = true; + /* FALLTHRU */ case CPP_STRING: case CPP_WSTRING: case CPP_STRING16: diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index e6ea2e8..9f595bb 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -3452,6 +3452,7 @@ find_parameter_packs_r (tree *tp, int *walk_subtrees, void* data) case TEMPLATE_TYPE_PARM: t = TYPE_MAIN_VARIANT (t); + /* FALLTHRU */ case TEMPLATE_TEMPLATE_PARM: /* If the placeholder appears in the decl-specifier-seq of a function parameter pack (14.6.3), or the type-specifier-seq of a type-id that @@ -11427,7 +11428,7 @@ tsubst_aggr_type (tree t, if (TYPE_PTRMEMFUNC_P (t)) return tsubst (TYPE_PTRMEMFUNC_FN_TYPE (t), args, complain, in_decl); - /* Else fall through. */ + /* Fall through. */ case ENUMERAL_TYPE: case UNION_TYPE: if (TYPE_TEMPLATE_INFO (t) && uses_template_parms (t)) diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index a44b820..2cb8d29 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -6174,11 +6174,13 @@ finish_omp_clauses (tree clauses, bool allow_fields, bool declare_simd) OMP_CLAUSE_OPERAND (c, 1) = t; } /* Check operand 0, the num argument. */ + /* FALLTHRU */ case OMP_CLAUSE_WORKER: case OMP_CLAUSE_VECTOR: if (OMP_CLAUSE_OPERAND (c, 0) == NULL_TREE) break; + /* FALLTHRU */ case OMP_CLAUSE_NUM_TASKS: case OMP_CLAUSE_NUM_TEAMS: diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 807ed82..88d8f5e 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -142,11 +142,13 @@ lvalue_kind (const_tree ref) lvalues. */ if (! TREE_STATIC (ref)) return clk_none; + /* FALLTHRU */ case VAR_DECL: if (TREE_READONLY (ref) && ! TREE_STATIC (ref) && DECL_LANG_SPECIFIC (ref) && DECL_IN_AGGR_P (ref)) return clk_none; + /* FALLTHRU */ case INDIRECT_REF: case ARROW_EXPR: case ARRAY_REF: diff --git a/gcc/dbxout.c b/gcc/dbxout.c index 25a03ef..510b2c7 100644 --- a/gcc/dbxout.c +++ b/gcc/dbxout.c @@ -2867,7 +2867,7 @@ dbxout_symbol (tree decl, int local ATTRIBUTE_UNUSED) disguised VAR_DECLs like Out parameters in Ada. */ gcc_assert (TREE_CODE (decl) == VAR_DECL); - /* ... fall through ... */ + /* fall through */ case RESULT_DECL: case VAR_DECL: diff --git a/gcc/df-scan.c b/gcc/df-scan.c index 98de844..621d78f 100644 --- a/gcc/df-scan.c +++ b/gcc/df-scan.c @@ -2875,7 +2875,7 @@ df_uses_record (struct df_collection_rec *collection_rec, df_uses_record (collection_rec, loc, ref_type, bb, insn_info, flags); return; } - /* ... Fall through ... */ + /* Fall through */ case REG: df_ref_record (DF_REF_REGULAR, collection_rec, diff --git a/gcc/dojump.c b/gcc/dojump.c index 6e0c01c..3a4f0e2 100644 --- a/gcc/dojump.c +++ b/gcc/dojump.c @@ -461,12 +461,14 @@ do_jump (tree exp, rtx_code_label *if_false_label, || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_REF || TREE_CODE (TREE_OPERAND (exp, 0)) == ARRAY_RANGE_REF) goto normal; + /* FALLTHRU */ case CONVERT_EXPR: /* If we are narrowing the operand, we have to do the compare in the narrower mode. */ if ((TYPE_PRECISION (TREE_TYPE (exp)) < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (exp, 0))))) goto normal; + /* FALLTHRU */ case NON_LVALUE_EXPR: case ABS_EXPR: case NEGATE_EXPR: @@ -610,6 +612,7 @@ do_jump (tree exp, rtx_code_label *if_false_label, goto normal; /* Boolean comparisons can be compiled as TRUTH_AND_EXPR. */ + /* FALLTHRU */ case TRUTH_AND_EXPR: /* High branch cost, expand as the bitwise AND of the conditions. diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c index 995ae7f..d66abf6 100644 --- a/gcc/dwarf2out.c +++ b/gcc/dwarf2out.c @@ -13342,6 +13342,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode, if (!subreg_lowpart_p (rtl)) break; inner = SUBREG_REG (rtl); + /* FALLTHRU */ case TRUNCATE: if (inner == NULL_RTX) inner = XEXP (rtl, 0); @@ -13682,7 +13683,7 @@ mem_loc_descriptor (rtx rtl, machine_mode mode, : -GET_MODE_UNIT_SIZE (mem_mode), mode)); - /* ... fall through ... */ + /* fall through */ case PLUS: plus: @@ -15608,7 +15609,7 @@ resolve_args_picking_1 (dw_loc_descr_ref loc, unsigned initial_frame_offset, if (!resolve_args_picking_1 (l->dw_loc_next, frame_offset_, dpi, visited)) return false; - /* Fall through... */ + /* Fall through. */ case DW_OP_skip: l = l->dw_loc_oprnd1.v.val_loc; @@ -16358,7 +16359,7 @@ loc_list_from_tree_1 (tree loc, int want_address, TREE_OPERAND (loc, 1), TREE_OPERAND (loc, 0)); } - /* ... fall through ... */ + /* fall through */ case COND_EXPR: { diff --git a/gcc/expmed.c b/gcc/expmed.c index 3f95a70..13fad52 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -5220,7 +5220,7 @@ make_tree (tree type, rtx x) t = SYMBOL_REF_DECL (x); if (t) return fold_convert (type, build_fold_addr_expr (t)); - /* else fall through. */ + /* fall through. */ default: t = build_decl (RTL_LOCATION (x), VAR_DECL, NULL_TREE, type); diff --git a/gcc/expr.c b/gcc/expr.c index b25ba3a..6342c0a 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -8272,6 +8272,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode, offset to have matching modes. */ else if (TYPE_PRECISION (sizetype) > TYPE_PRECISION (type)) treeop1 = fold_convert_loc (loc, type, treeop1); + /* FALLTHRU */ case PLUS_EXPR: /* If we are adding a constant, a VAR_DECL that is sp, fp, or ap, and @@ -9437,9 +9438,9 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, switch (TREE_CODE_LENGTH (code)) { default: - case 3: treeop2 = TREE_OPERAND (exp, 2); - case 2: treeop1 = TREE_OPERAND (exp, 1); - case 1: treeop0 = TREE_OPERAND (exp, 0); + case 3: treeop2 = TREE_OPERAND (exp, 2); /* FALLTHRU */ + case 2: treeop1 = TREE_OPERAND (exp, 1); /* FALLTHRU */ + case 1: treeop0 = TREE_OPERAND (exp, 0); /* FALLTHRU */ case 0: break; } ops.code = code; @@ -9611,7 +9612,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, && (TREE_STATIC (exp) || DECL_EXTERNAL (exp))) layout_decl (exp, 0); - /* ... fall through ... */ + /* fall through */ case FUNCTION_DECL: case RESULT_DECL: @@ -9820,7 +9821,7 @@ expand_expr_real_1 (tree exp, rtx target, machine_mode tmode, return original_target; } - /* ... fall through ... */ + /* fall through */ case STRING_CST: temp = expand_expr_constant (exp, 1, modifier); diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 23ee11f..28292a1 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -1305,7 +1305,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2) return do_mpc_arg2 (arg1, arg2, type, /* do_nonfinite= */ folding_initializer, mpc_div); - /* Fallthru ... */ + /* Fallthru. */ case TRUNC_DIV_EXPR: case CEIL_DIV_EXPR: case FLOOR_DIV_EXPR: @@ -3682,7 +3682,7 @@ fold_truth_not_expr (location_t loc, tree arg) if (TREE_CODE (TREE_TYPE (arg)) == BOOLEAN_TYPE) return build1_loc (loc, TRUTH_NOT_EXPR, type, arg); - /* ... fall through ... */ + /* fall through */ case FLOAT_EXPR: loc1 = expr_location_or (TREE_OPERAND (arg, 0), loc); @@ -5077,6 +5077,7 @@ fold_cond_expr_with_comparison (location_t loc, tree type, case UNLT_EXPR: if (flag_trapping_math) break; + /* FALLTHRU */ case LE_EXPR: case LT_EXPR: if (TYPE_UNSIGNED (TREE_TYPE (arg1))) @@ -10577,6 +10578,7 @@ fold_binary_loc (location_t loc, /* If first arg is constant zero, return it. */ if (integer_zerop (arg0)) return fold_convert_loc (loc, type, arg0); + /* FALLTHRU */ case TRUTH_AND_EXPR: /* If either arg is constant true, drop it. */ if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) @@ -10632,6 +10634,7 @@ fold_binary_loc (location_t loc, /* If first arg is constant true, return it. */ if (TREE_CODE (arg0) == INTEGER_CST && ! integer_zerop (arg0)) return fold_convert_loc (loc, type, arg0); + /* FALLTHRU */ case TRUTH_OR_EXPR: /* If either arg is constant zero, drop it. */ if (TREE_CODE (arg0) == INTEGER_CST && integer_zerop (arg0)) @@ -11476,7 +11479,7 @@ contains_label_1 (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) case GOTO_EXPR: *walk_subtrees = 0; - /* ... fall through ... */ + /* fall through */ default: return NULL_TREE; @@ -12859,7 +12862,7 @@ multiple_of_p (tree type, const_tree top, const_tree bottom) < TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (top, 0))))) return 0; - /* .. fall through ... */ + /* fall through */ case SAVE_EXPR: return multiple_of_p (type, TREE_OPERAND (top, 0), bottom); diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c index 37ba82b..c9abdcc 100644 --- a/gcc/fortran/decl.c +++ b/gcc/fortran/decl.c @@ -3929,6 +3929,7 @@ match_attr_spec (void) d = DECL_CODIMENSION; break; } + /* FALLTHRU */ case 'n': if (match_string_p ("tiguous")) { diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c index 009ae99..b796810 100644 --- a/gcc/fortran/primary.c +++ b/gcc/fortran/primary.c @@ -1690,18 +1690,21 @@ match_arg_list_function (gfc_actual_arglist *result) result->name = "%LOC"; break; } + /* FALLTHRU */ case 'r': if (strncmp (name, "ref", 3) == 0) { result->name = "%REF"; break; } + /* FALLTHRU */ case 'v': if (strncmp (name, "val", 3) == 0) { result->name = "%VAL"; break; } + /* FALLTHRU */ default: m = MATCH_ERROR; goto cleanup; diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c index 7cf2ca2..6b21c1c 100644 --- a/gcc/fortran/resolve.c +++ b/gcc/fortran/resolve.c @@ -3535,7 +3535,7 @@ resolve_operator (gfc_expr *e) if (!gfc_resolve_expr (e->value.op.op2)) return false; - /* Fall through... */ + /* Fall through. */ case INTRINSIC_NOT: case INTRINSIC_UPLUS: @@ -3653,7 +3653,7 @@ resolve_operator (gfc_expr *e) goto bad_op; } - /* Fall through... */ + /* Fall through. */ case INTRINSIC_EQ: case INTRINSIC_EQ_OS: @@ -5417,14 +5417,17 @@ fixup_charlen (gfc_expr *e) { case EXPR_OP: gfc_resolve_character_operator (e); + /* FALLTHRU */ case EXPR_ARRAY: if (e->expr_type == EXPR_ARRAY) gfc_resolve_character_array_constructor (e); + /* FALLTHRU */ case EXPR_SUBSTRING: if (!e->ts.u.cl && e->ref) gfc_resolve_substring_charlen (e); + /* FALLTHRU */ default: if (!e->ts.u.cl) @@ -7276,7 +7279,7 @@ resolve_allocate_expr (gfc_expr *e, gfc_code *code, bool *array_alloc_wo_spec) && ar->stride[i] == NULL) break; - /* Fall Through... */ + /* Fall through. */ case DIMEN_UNKNOWN: case DIMEN_VECTOR: diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 0882a3a..08c3233 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -4031,6 +4031,7 @@ done: continue; } + /* FALLTHRU */ case GFC_SS_CONSTRUCTOR: case GFC_SS_FUNCTION: for (n = 0; n < ss->dimen; n++) diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index fea26d1..7fbe101 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -5299,7 +5299,7 @@ gfc_conv_intrinsic_len (gfc_se * se, gfc_expr * expr) break; } - /* Otherwise fall through. */ + /* Fall through. */ default: /* Anybody stupid enough to do this deserves inefficient code. */ diff --git a/gcc/gcov-tool.c b/gcc/gcov-tool.c index f628b60..4cb071f 100644 --- a/gcc/gcov-tool.c +++ b/gcc/gcov-tool.c @@ -553,9 +553,11 @@ process_args (int argc, char **argv) case 'h': print_usage (false); /* Print_usage will exit. */ + /* FALLTHRU */ case 'v': print_version (); /* Print_version will exit. */ + /* FALLTHRU */ default: print_usage (true); /* Print_usage will exit. */ diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c index b64d8b9..1d4965e 100644 --- a/gcc/genattrtab.c +++ b/gcc/genattrtab.c @@ -888,6 +888,7 @@ check_attr_test (file_location loc, rtx exp, attr_desc *attr) ATTR_IND_SIMPLIFIED_P (exp) = 1; break; } + /* FALLTHRU */ default: fatal_at (loc, "invalid operator `%s' in definition of attribute" " `%s'", GET_RTX_NAME (GET_CODE (exp)), attr->name); @@ -3455,6 +3456,7 @@ write_test_expr (FILE *outf, rtx exp, unsigned int attrs_cached, int flags) case GE: case GT: case LE: case LT: comparison_operator = FLG_BITWISE; + /* FALLTHRU */ case PLUS: case MINUS: case MULT: case DIV: case MOD: case AND: case IOR: case XOR: diff --git a/gcc/genconfig.c b/gcc/genconfig.c index b6ca35a..2237e1f 100644 --- a/gcc/genconfig.c +++ b/gcc/genconfig.c @@ -83,6 +83,7 @@ walk_insn_part (rtx part, int recog_p, int non_pc_set_src) case MATCH_OP_DUP: case MATCH_PAR_DUP: ++dup_operands_seen_this_insn; + /* FALLTHRU */ case MATCH_SCRATCH: case MATCH_PARALLEL: case MATCH_OPERATOR: diff --git a/gcc/genpreds.c b/gcc/genpreds.c index ac09245..60b12bd 100644 --- a/gcc/genpreds.c +++ b/gcc/genpreds.c @@ -51,12 +51,12 @@ validate_exp (rtx exp, const char *name, file_location loc) case IF_THEN_ELSE: if (validate_exp (XEXP (exp, 2), name, loc)) return true; - /* else fall through */ + /* fall through */ case AND: case IOR: if (validate_exp (XEXP (exp, 1), name, loc)) return true; - /* else fall through */ + /* fall through */ case NOT: return validate_exp (XEXP (exp, 0), name, loc); @@ -174,12 +174,12 @@ needs_variable (rtx exp, const char *var) case IF_THEN_ELSE: if (needs_variable (XEXP (exp, 2), var)) return true; - /* else fall through */ + /* fall through */ case AND: case IOR: if (needs_variable (XEXP (exp, 1), var)) return true; - /* else fall through */ + /* fall through */ case NOT: return needs_variable (XEXP (exp, 0), var); diff --git a/gcc/gensupport.c b/gcc/gensupport.c index 8c5a1ab..d8ce711 100644 --- a/gcc/gensupport.c +++ b/gcc/gensupport.c @@ -1038,6 +1038,7 @@ get_alternatives_number (rtx pattern, int *n_alt, file_location loc) case 'V': if (XVEC (pattern, i) == NULL) break; + /* FALLTHRU */ case 'E': for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) @@ -2156,6 +2157,7 @@ subst_dup (rtx pattern, int n_alt, int n_subst_alt) case 'V': if (XVEC (pattern, i) == NULL) break; + /* FALLTHRU */ case 'E': if (code != MATCH_DUP && code != MATCH_OP_DUP) for (j = XVECLEN (pattern, i) - 1; j >= 0; --j) diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index e27214f..0353829 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -499,8 +499,10 @@ dump_gimple_assign (pretty_printer *buffer, gassign *gs, int spc, int flags) { case 4: arg3 = gimple_assign_rhs3 (gs); + /* FALLTHRU */ case 3: arg2 = gimple_assign_rhs2 (gs); + /* FALLTHRU */ case 2: arg1 = gimple_assign_rhs1 (gs); break; diff --git a/gcc/gimplify.c b/gcc/gimplify.c index a66b846..e183574 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -5155,7 +5155,7 @@ gimplify_addr_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) if (integer_zerop (TREE_OPERAND (op0, 1))) goto do_indirect_ref; - /* ... fall through ... */ + /* fall through */ default: /* If we see a call to a declared builtin or see its address @@ -9962,6 +9962,7 @@ goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr, case tcc_comparison: saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, lhs_addr, lhs_var); + /* FALLTHRU */ case tcc_unary: saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, lhs_addr, lhs_var); @@ -9976,6 +9977,7 @@ goa_stabilize_expr (tree *expr_p, gimple_seq *pre_p, tree lhs_addr, case TRUTH_XOR_EXPR: saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 1), pre_p, lhs_addr, lhs_var); + /* FALLTHRU */ case TRUTH_NOT_EXPR: saw_lhs |= goa_stabilize_expr (&TREE_OPERAND (expr, 0), pre_p, lhs_addr, lhs_var); diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c index fba6cfb..a2f5c7b 100644 --- a/gcc/graphite-isl-ast-to-gimple.c +++ b/gcc/graphite-isl-ast-to-gimple.c @@ -1484,7 +1484,7 @@ substitute_ssa_name (tree exp, tree f, tree r) if (exp == f) return r; - /* Fall through... */ + /* Fall through. */ case tcc_exceptional: case tcc_unary: diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c index cf7d434..0e840b4 100644 --- a/gcc/hsa-gen.c +++ b/gcc/hsa-gen.c @@ -4519,7 +4519,7 @@ get_address_from_value (tree val, hsa_bb *hbb) case INTEGER_CST: if (tree_fits_shwi_p (val)) return new hsa_op_address (NULL, NULL, tree_to_shwi (val)); - /* Otherwise fall-through */ + /* fall-through */ default: HSA_SORRY_ATV (EXPR_LOCATION (val), diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c index d143141..e05e181 100644 --- a/gcc/ipa-icf.c +++ b/gcc/ipa-icf.c @@ -1634,7 +1634,7 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate) add_type (TREE_TYPE (gimple_assign_lhs (stmt)), two); break; } - /* ... fall through ... */ + /* fall through */ case GIMPLE_CALL: case GIMPLE_ASM: case GIMPLE_COND: diff --git a/gcc/ira.c b/gcc/ira.c index 8ac153b..a0424b8 100644 --- a/gcc/ira.c +++ b/gcc/ira.c @@ -1832,6 +1832,7 @@ ira_setup_alts (rtx_insn *insn, HARD_REG_SET &alts) case '#': case ',': c = '\0'; + /* FALLTHRU */ case '\0': len = 0; break; diff --git a/gcc/java/expr.c b/gcc/java/expr.c index 2b856e5..ca58d28 100644 --- a/gcc/java/expr.c +++ b/gcc/java/expr.c @@ -191,7 +191,7 @@ java_truthvalue_conversion (tree expr) if (TYPE_PRECISION (TREE_TYPE (expr)) >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) return java_truthvalue_conversion (TREE_OPERAND (expr, 0)); - /* fall through to default */ + /* fall through */ default: return fold_build2 (NE_EXPR, boolean_type_node, diff --git a/gcc/java/jcf-io.c b/gcc/java/jcf-io.c index a560db7..cc8616b 100644 --- a/gcc/java/jcf-io.c +++ b/gcc/java/jcf-io.c @@ -471,7 +471,7 @@ verify_constant_pool (JCF *jcf) if (n <= 0 || n >= JPOOL_SIZE(jcf) || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) return i; - /* ... fall through ... */ + /* fall through */ case CONSTANT_Class: case CONSTANT_String: n = JPOOL_USHORT1 (jcf, i); diff --git a/gcc/java/typeck.c b/gcc/java/typeck.c index d2e3db6..61394a9 100644 --- a/gcc/java/typeck.c +++ b/gcc/java/typeck.c @@ -341,7 +341,7 @@ promote_type (tree type) return promoted_byte_type_node; return int_type_node; } - /* ... else fall through ... */ + /* fall through */ default: return type; } diff --git a/gcc/lra-eliminations.c b/gcc/lra-eliminations.c index 9ae5cfe..08cc390 100644 --- a/gcc/lra-eliminations.c +++ b/gcc/lra-eliminations.c @@ -484,7 +484,7 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode, return gen_rtx_MULT (Pmode, to, XEXP (x, 1)); } - /* ... fall through ... */ + /* fall through */ case CALL: case COMPARE: @@ -536,7 +536,7 @@ lra_eliminate_regs_1 (rtx_insn *insn, rtx x, machine_mode mem_mode, } } - /* ... fall through ... */ + /* fall through */ case INSN_LIST: case INT_LIST: diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index 6703d41..89184b8 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -231,6 +231,7 @@ lto_output_tree_ref (struct output_block *ob, tree expr) case VAR_DECL: case DEBUG_EXPR_DECL: gcc_assert (decl_function_context (expr) == NULL || TREE_STATIC (expr)); + /* FALLTHRU */ case PARM_DECL: streamer_write_record_start (ob, LTO_global_decl_ref); lto_output_var_decl_index (ob->decl_state, ob->main_stream, expr); diff --git a/gcc/objc/objc-encoding.c b/gcc/objc/objc-encoding.c index 41ac6a4..0a5f02a 100644 --- a/gcc/objc/objc-encoding.c +++ b/gcc/objc/objc-encoding.c @@ -622,6 +622,7 @@ encode_type (tree type, int curtype, int format) } /* Else, they are encoded exactly like the integer type that is used by the compiler to store them. */ + /* FALLTHRU */ case INTEGER_TYPE: { char c; diff --git a/gcc/opts.c b/gcc/opts.c index c36db60..a7ad5ed 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -1972,6 +1972,7 @@ common_handle_option (struct gcc_options *opts, opts->x_flag_profile_use = true; value = true; /* No break here - do -fprofile-use processing. */ + /* FALLTHRU */ case OPT_fprofile_use: enable_fdo_optimizations (opts, opts_set, value); if (!opts_set->x_flag_profile_reorder_functions) @@ -1988,6 +1989,7 @@ common_handle_option (struct gcc_options *opts, opts->x_flag_auto_profile = true; value = true; /* No break here - do -fauto-profile processing. */ + /* FALLTHRU */ case OPT_fauto_profile: enable_fdo_optimizations (opts, opts_set, value); if (!opts_set->x_flag_profile_correction) @@ -2001,6 +2003,7 @@ common_handle_option (struct gcc_options *opts, opts->x_profile_data_prefix = xstrdup (arg); value = true; /* No break here - do -fprofile-generate processing. */ + /* FALLTHRU */ case OPT_fprofile_generate: if (!opts_set->x_profile_arc_flag) opts->x_profile_arc_flag = value; diff --git a/gcc/read-rtl.c b/gcc/read-rtl.c index 79f42bf..7f49a5f 100644 --- a/gcc/read-rtl.c +++ b/gcc/read-rtl.c @@ -1173,6 +1173,7 @@ read_rtx_code (const char *code_name) break; } /* Now process the vector. */ + /* FALLTHRU */ case 'E': { diff --git a/gcc/real.c b/gcc/real.c index fbebbf0..abe9306 100644 --- a/gcc/real.c +++ b/gcc/real.c @@ -2667,6 +2667,7 @@ round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r) { underflow: get_zero (r, r->sign); + /* FALLTHRU */ case rvc_zero: if (!fmt->has_signed_zero) r->sign = 0; diff --git a/gcc/recog.c b/gcc/recog.c index 92b2aa3..e62362a 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -1771,6 +1771,7 @@ asm_operand_ok (rtx op, const char *constraint, const char **constraints) Match any memory and hope things are resolved after reload. */ incdec_ok = true; + /* FALLTHRU */ default: cn = lookup_constraint (constraint); switch (get_constraint_type (cn)) diff --git a/gcc/reginfo.c b/gcc/reginfo.c index ccf53bf..122d21c 100644 --- a/gcc/reginfo.c +++ b/gcc/reginfo.c @@ -1148,7 +1148,7 @@ reg_scan_mark_refs (rtx x, rtx_insn *insn) if (REG_P (dest) && !REG_ATTRS (dest)) set_reg_attrs_from_value (dest, SET_SRC (x)); - /* ... fall through ... */ + /* fall through */ default: { diff --git a/gcc/reload1.c b/gcc/reload1.c index c2800f8..5a1a4d4 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -2331,7 +2331,7 @@ set_label_offsets (rtx x, rtx_insn *insn, int initial_p) x = LABEL_REF_LABEL (x); - /* ... fall through ... */ + /* fall through */ case CODE_LABEL: /* If we know nothing about this label, set the desired offsets. Note @@ -2378,7 +2378,7 @@ set_label_offsets (rtx x, rtx_insn *insn, int initial_p) case JUMP_INSN: set_label_offsets (PATTERN (insn), insn, initial_p); - /* ... fall through ... */ + /* fall through */ case INSN: case CALL_INSN: @@ -2693,7 +2693,7 @@ eliminate_regs_1 (rtx x, machine_mode mem_mode, rtx insn, ep->previous_offset * INTVAL (XEXP (x, 1))); } - /* ... fall through ... */ + /* fall through */ case CALL: case COMPARE: @@ -2740,7 +2740,7 @@ eliminate_regs_1 (rtx x, machine_mode mem_mode, rtx insn, } } - /* ... fall through ... */ + /* fall through */ case INSN_LIST: case INT_LIST: @@ -5499,7 +5499,7 @@ reload_reg_reaches_end_p (unsigned int regno, int reloadnum) opnum = reload_n_operands; - /* ... fall through ... */ + /* fall through */ case RELOAD_FOR_OUTPUT: case RELOAD_FOR_OUTPUT_ADDRESS: diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 902b687..376691b 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -3427,6 +3427,7 @@ commutative_operand_precedence (rtx op) /* Then prefer NEG and NOT. */ if (code == NEG || code == NOT) return 1; + /* FALLTHRU */ default: return 0; @@ -4101,7 +4102,7 @@ rtx_cost (rtx x, machine_mode mode, enum rtx_code outer_code, factor = GET_MODE_SIZE (mode) / UNITS_PER_WORD; if (factor == 0) factor = 1; - /* Pass through. */ + /* FALLTHRU */ default: total = factor * COSTS_N_INSNS (1); } diff --git a/gcc/sched-rgn.c b/gcc/sched-rgn.c index fa662ff..af43b26 100644 --- a/gcc/sched-rgn.c +++ b/gcc/sched-rgn.c @@ -2052,6 +2052,7 @@ is_exception_free (rtx_insn *insn, int bb_src, int bb_trg) if (is_pfree (insn, bb_src, bb_trg)) return 1; /* Don't 'break' here: PFREE-candidate is also PRISKY-candidate. */ + /* FALLTHRU */ case PRISKY_CANDIDATE: if (!flag_schedule_speculative_load_dangerous || is_prisky (insn, bb_src, bb_trg)) diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index e0f0264..ed1bb7b 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -6256,7 +6256,7 @@ simplify_rtx (const_rtx x) if (swap_commutative_operands_p (XEXP (x, 0), XEXP (x, 1))) return simplify_gen_binary (code, mode, XEXP (x, 1), XEXP (x, 0)); - /* Fall through.... */ + /* Fall through. */ case RTX_BIN_ARITH: return simplify_binary_operation (code, mode, XEXP (x, 0), XEXP (x, 1)); diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index 8629984..821dd29 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -398,7 +398,7 @@ int_mode_for_mode (machine_mode mode) if (mode == BLKmode) break; - /* ... fall through ... */ + /* fall through */ case MODE_CC: default: diff --git a/gcc/toplev.c b/gcc/toplev.c index 827840b..39692c4 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -741,7 +741,7 @@ print_to_asm_out_file (print_switch_type type, const char * text) case SWITCH_TYPE_DESCRIPTIVE: if (ASM_COMMENT_START[0] == 0) prepend_sep = false; - /* Drop through. */ + /* FALLTHRU */ case SWITCH_TYPE_PASSED: case SWITCH_TYPE_ENABLED: if (prepend_sep) @@ -771,7 +771,7 @@ print_to_stderr (print_switch_type type, const char * text) case SWITCH_TYPE_PASSED: case SWITCH_TYPE_ENABLED: fputc (' ', stderr); - /* Drop through. */ + /* FALLTHRU */ case SWITCH_TYPE_DESCRIPTIVE: fputs (text, stderr); diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 483fbd9..3a736b9 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -5325,7 +5325,7 @@ gimple_verify_flow_info (void) case GIMPLE_CALL: if (!gimple_call_builtin_p (stmt, BUILT_IN_RETURN)) break; - /* ... fallthru ... */ + /* fallthru */ case GIMPLE_RETURN: if (!single_succ_p (bb) || (single_succ_edge (bb)->flags diff --git a/gcc/tree-chrec.c b/gcc/tree-chrec.c index 007243d..e74f96f 100644 --- a/gcc/tree-chrec.c +++ b/gcc/tree-chrec.c @@ -287,6 +287,7 @@ chrec_fold_plus_1 (enum tree_code code, tree type, CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; + /* FALLTHRU */ default: if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) @@ -304,6 +305,7 @@ chrec_fold_plus_1 (enum tree_code code, tree type, CASE_CONVERT: if (tree_contains_chrecs (op0, NULL)) return chrec_dont_know; + /* FALLTHRU */ default: switch (TREE_CODE (op1)) @@ -329,6 +331,7 @@ chrec_fold_plus_1 (enum tree_code code, tree type, CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; + /* FALLTHRU */ default: { @@ -423,6 +426,7 @@ chrec_fold_multiply (tree type, CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; + /* FALLTHRU */ default: if (integer_onep (op1)) @@ -439,6 +443,7 @@ chrec_fold_multiply (tree type, CASE_CONVERT: if (tree_contains_chrecs (op0, NULL)) return chrec_dont_know; + /* FALLTHRU */ default: if (integer_onep (op0)) @@ -461,6 +466,7 @@ chrec_fold_multiply (tree type, CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; + /* FALLTHRU */ default: if (integer_onep (op1)) @@ -1028,6 +1034,7 @@ evolution_function_is_invariant_rec_p (tree chrec, int loopnum) if (!evolution_function_is_invariant_rec_p (TREE_OPERAND (chrec, 1), loopnum)) return false; + /* FALLTHRU */ case 1: if (!evolution_function_is_invariant_rec_p (TREE_OPERAND (chrec, 0), @@ -1529,12 +1536,15 @@ for_each_scev_op (tree *scev, bool (*cbck) (tree *, void *), void *data) { case 3: for_each_scev_op (&TREE_OPERAND (*scev, 2), cbck, data); + /* FALLTHRU */ case 2: for_each_scev_op (&TREE_OPERAND (*scev, 1), cbck, data); + /* FALLTHRU */ case 1: for_each_scev_op (&TREE_OPERAND (*scev, 0), cbck, data); + /* FALLTHRU */ default: cbck (scev, data); diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c index 0bb01f1..db95bdd 100644 --- a/gcc/tree-data-ref.c +++ b/gcc/tree-data-ref.c @@ -1680,6 +1680,7 @@ siv_subscript_p (const_tree chrec_a, const_tree chrec_b) case POLYNOMIAL_CHREC: if (CHREC_VARIABLE (chrec_a) != CHREC_VARIABLE (chrec_b)) return false; + /* FALLTHRU */ default: return true; @@ -3882,6 +3883,7 @@ get_references_in_stmt (gimple *stmt, vec *references) if (gimple_call_lhs (stmt) == NULL_TREE) break; ref.is_read = true; + /* FALLTHRU */ case IFN_MASK_STORE: ptr = build_int_cst (TREE_TYPE (gimple_call_arg (stmt, 1)), 0); align = tree_to_shwi (gimple_call_arg (stmt, 1)); diff --git a/gcc/tree.c b/gcc/tree.c index e0a48cc..33f22ab 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -3730,7 +3730,7 @@ find_placeholder_in_expr (tree exp, vec *refs) break; } - /* Fall through... */ + /* Fall through. */ case tcc_exceptional: case tcc_unary: @@ -3819,7 +3819,7 @@ substitute_in_expr (tree exp, tree f, tree r) if (exp == f) return r; - /* Fall through... */ + /* Fall through. */ case tcc_exceptional: case tcc_unary: @@ -7039,7 +7039,7 @@ type_cache_hasher::equal (type_hash *a, type_hash *b) TYPE_VALUES (b->type)))) return 0; - /* ... fall through ... */ + /* fall through */ case INTEGER_TYPE: case REAL_TYPE: @@ -11457,7 +11457,7 @@ walk_type_fields (tree type, walk_tree_fn func, void *data, break; } - /* ... fall through ... */ + /* fall through */ case COMPLEX_TYPE: WALK_SUBTREE (TREE_TYPE (type)); diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c index 9f09d30..c3b24a1 100644 --- a/gcc/var-tracking.c +++ b/gcc/var-tracking.c @@ -1056,6 +1056,7 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data) ? GET_MODE_SIZE (amd->mem_mode) : -GET_MODE_SIZE (amd->mem_mode), GET_MODE (loc))); + /* FALLTHRU */ case POST_INC: case POST_DEC: if (addr == loc) @@ -1078,6 +1079,7 @@ adjust_mems (rtx loc, const_rtx old_rtx, void *data) return addr; case PRE_MODIFY: addr = XEXP (loc, 1); + /* FALLTHRU */ case POST_MODIFY: if (addr == loc) addr = XEXP (loc, 0); @@ -3152,7 +3154,7 @@ set_dv_changed (decl_or_value dv, bool newv) case ONEPART_DEXPR: if (newv) NO_LOC_P (DECL_RTL_KNOWN_SET (dv_as_decl (dv))) = false; - /* Fall through... */ + /* Fall through. */ default: DECL_CHANGED (dv_as_decl (dv)) = newv; diff --git a/gcc/varasm.c b/gcc/varasm.c index d8bd985..c709c8e 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -589,6 +589,7 @@ default_function_section (tree decl, enum node_frequency freq, these ELF section. */ if (!in_lto_p || !flag_profile_values) return get_named_text_section (decl, ".text.hot", NULL); + /* FALLTHRU */ default: return NULL; } diff --git a/libcpp/lex.c b/libcpp/lex.c index e5a0397..8508bd02a 100644 --- a/libcpp/lex.c +++ b/libcpp/lex.c @@ -610,6 +610,7 @@ search_line_fast (const uchar *s, const uchar *end ATTRIBUTE_UNUSED) if (l != 0) break; s += sizeof(unsigned long); + /* FALLTHRU */ case 2: l = u.l[i++]; if (l != 0) @@ -2717,6 +2718,7 @@ _cpp_lex_direct (cpp_reader *pfile) } buffer->cur++; } + /* FALLTHRU */ default: create_literal (pfile, result, buffer->cur - 1, 1, CPP_OTHER); @@ -3322,7 +3324,7 @@ cpp_token_val_index (const cpp_token *tok) return CPP_TOKEN_FLD_SOURCE; else if (tok->type == CPP_PRAGMA) return CPP_TOKEN_FLD_PRAGMA; - /* else fall through */ + /* fall through */ default: return CPP_TOKEN_FLD_NONE; } diff --git a/libcpp/macro.c b/libcpp/macro.c index c251553..1a817f3 100644 --- a/libcpp/macro.c +++ b/libcpp/macro.c @@ -2875,6 +2875,7 @@ parse_params (cpp_reader *pfile, cpp_macro *macro) return true; /* Fall through to pick up the error. */ + /* FALLTHRU */ case CPP_COMMA: if (!prev_ident) { diff --git a/libcpp/pch.c b/libcpp/pch.c index aa5ed6b..fb9696d 100644 --- a/libcpp/pch.c +++ b/libcpp/pch.c @@ -230,7 +230,7 @@ count_defs (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p) if (hn->flags & NODE_BUILTIN) return 1; - /* else fall through. */ + /* fall through. */ case NT_VOID: { @@ -269,7 +269,7 @@ write_defs (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *hn, void *ss_p) if (hn->flags & NODE_BUILTIN) return 1; - /* else fall through. */ + /* fall through. */ case NT_VOID: { diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index 78e5978..3aa06b6 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -5794,11 +5794,13 @@ d_print_mod (struct d_print_info *dpi, int options, case DEMANGLE_COMPONENT_REFERENCE_THIS: /* For the ref-qualifier, put a space before the &. */ d_append_char (dpi, ' '); + /* FALLTHRU */ case DEMANGLE_COMPONENT_REFERENCE: d_append_char (dpi, '&'); return; case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS: d_append_char (dpi, ' '); + /* FALLTHRU */ case DEMANGLE_COMPONENT_RVALUE_REFERENCE: d_append_string (dpi, "&&"); return; -- 2.7.4 From 6d1c5ce03b4989731c4579153742aab078160720 Mon Sep 17 00:00:00 2001 From: mpolacek Date: Mon, 26 Sep 2016 09:42:50 +0000 Subject: [PATCH 07/16] Implement -Wimplicit-fallthrough. With fixes for tizen linaro-gcc by Dmitriy Gonzha. Not fully implement implicit-fallthrough. Some tests are fail. Because of possible errors turned off from -Wextra and renamed to "-Wimplicit-fallthrough-disabled". Required for -fsanitize-address-use-after-scope Change-Id: I088b82dce350c017ecb3933c1cba3b2b01dde3f7 upstream hash: 3c77f69c50d3377491c917808fbfc4b9787acd6f git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@240485 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/Makefile.in | 5 + gcc/builtins.c | 5 +- gcc/c-family/c-common.c | 42 ++ gcc/c-family/c-common.h | 1 + gcc/c/c-decl.c | 2 +- gcc/c/c-parser.c | 97 +++- gcc/common.opt | 4 + gcc/config/rs6000/rs6000.c | 2 +- gcc/convert.c | 4 +- gcc/cp/constexpr.c | 2 + gcc/cp/constraint.cc | 3 +- gcc/cp/parser.c | 81 ++- gcc/cp/pt.c | 13 +- gcc/cp/semantics.c | 1 + gcc/cp/typeck.c | 4 +- gcc/doc/extend.texi | 62 ++- gcc/doc/invoke.texi | 89 ++++ gcc/final.c | 2 + gcc/fortran/arith.c | 2 +- gcc/fortran/frontend-passes.c | 3 +- gcc/fortran/parse.c | 2 +- gcc/fortran/primary.c | 1 + gcc/fortran/trans-array.c | 1 + gcc/fortran/trans-expr.c | 1 + gcc/genattrtab.c | 2 + gcc/genpreds.c | 2 +- gcc/gimple-ssa-strength-reduction.c | 2 +- gcc/gimple.h | 10 + gcc/gimplify.c | 454 ++++++++++++++++- gcc/godump.c | 1 + gcc/internal-fn.c | 9 + gcc/internal-fn.def | 3 + gcc/langhooks.c | 9 + gcc/langhooks.h | 3 +- gcc/reload1.c | 1 + gcc/resource.c | 2 + gcc/system.h | 6 + .../c-c++-common/Wimplicit-fallthrough-1.c | 38 ++ .../c-c++-common/Wimplicit-fallthrough-10.c | 239 +++++++++ .../c-c++-common/Wimplicit-fallthrough-11.c | 23 + .../c-c++-common/Wimplicit-fallthrough-12.c | 26 + .../c-c++-common/Wimplicit-fallthrough-13.c | 63 +++ .../c-c++-common/Wimplicit-fallthrough-14.c | 162 ++++++ .../c-c++-common/Wimplicit-fallthrough-15.c | 31 ++ .../c-c++-common/Wimplicit-fallthrough-16.c | 32 ++ .../c-c++-common/Wimplicit-fallthrough-17.c | 29 ++ .../c-c++-common/Wimplicit-fallthrough-18.c | 42 ++ .../c-c++-common/Wimplicit-fallthrough-19.c | 85 ++++ .../c-c++-common/Wimplicit-fallthrough-2.c | 223 +++++++++ .../c-c++-common/Wimplicit-fallthrough-20.c | 41 ++ .../c-c++-common/Wimplicit-fallthrough-21.c | 25 + .../c-c++-common/Wimplicit-fallthrough-3.c | 543 +++++++++++++++++++++ .../c-c++-common/Wimplicit-fallthrough-4.c | 250 ++++++++++ .../c-c++-common/Wimplicit-fallthrough-5.c | 109 +++++ .../c-c++-common/Wimplicit-fallthrough-6.c | 305 ++++++++++++ .../c-c++-common/Wimplicit-fallthrough-7.c | 124 +++++ .../c-c++-common/Wimplicit-fallthrough-8.c | 101 ++++ .../c-c++-common/Wimplicit-fallthrough-9.c | 26 + gcc/testsuite/c-c++-common/attr-fallthrough-1.c | 57 +++ gcc/testsuite/c-c++-common/attr-fallthrough-2.c | 54 ++ gcc/testsuite/g++.dg/cpp0x/fallthrough1.C | 57 +++ gcc/testsuite/g++.dg/cpp0x/fallthrough2.C | 21 + gcc/testsuite/g++.dg/cpp1z/fallthrough1.C | 20 + gcc/testsuite/g++.dg/warn/Wunused-label-1.C | 2 +- gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c | 22 + .../obj-c++.dg/Wimplicit-fallthrough-1.mm | 38 ++ gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m | 38 ++ gcc/tree-core.h | 3 + gcc/tree-ssa-loop-ivopts.c | 2 +- gcc/tree.h | 5 + gcc/varasm.c | 2 +- libcpp/include/cpplib.h | 4 +- libcpp/lex.c | 100 +++- libstdc++-v3/libsupc++/hash_bytes.cc | 2 + 74 files changed, 3832 insertions(+), 45 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c create mode 100644 gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c create mode 100644 gcc/testsuite/c-c++-common/attr-fallthrough-1.c create mode 100644 gcc/testsuite/c-c++-common/attr-fallthrough-2.c create mode 100644 gcc/testsuite/g++.dg/cpp0x/fallthrough1.C create mode 100644 gcc/testsuite/g++.dg/cpp0x/fallthrough2.C create mode 100644 gcc/testsuite/g++.dg/cpp1z/fallthrough1.C create mode 100644 gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c create mode 100644 gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm create mode 100644 gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m diff --git a/gcc/Makefile.in b/gcc/Makefile.in index ddb799f..2e8fa8a 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -217,6 +217,11 @@ libgcov-merge-tool.o-warn = -Wno-error gimple-match.o-warn = -Wno-unused generic-match.o-warn = -Wno-unused dfp.o-warn = -Wno-strict-aliasing +insn-attrtab.o-warn = -Wno-implicit-fallthrough +insn-dfatab.o-warn = -Wno-implicit-fallthrough +insn-latencytab.o-warn = -Wno-implicit-fallthrough +insn-output.o-warn = -Wno-implicit-fallthrough +insn-emit.o-warn = -Wno-implicit-fallthrough # All warnings have to be shut off in stage1 if the compiler used then # isn't gcc; configure determines that. WARN_CFLAGS will be either diff --git a/gcc/builtins.c b/gcc/builtins.c index 4ccd052..d32a1d1 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -2591,7 +2591,7 @@ expand_builtin_int_roundingfn_2 (tree exp, rtx target) { CASE_FLT_FN (BUILT_IN_IRINT): fallback_fn = BUILT_IN_LRINT; - /* FALLTHRU */ + gcc_fallthrough (); CASE_FLT_FN (BUILT_IN_LRINT): CASE_FLT_FN (BUILT_IN_LLRINT): builtin_optab = lrint_optab; @@ -2599,7 +2599,7 @@ expand_builtin_int_roundingfn_2 (tree exp, rtx target) CASE_FLT_FN (BUILT_IN_IROUND): fallback_fn = BUILT_IN_LROUND; - /* FALLTHRU */ + gcc_fallthrough (); CASE_FLT_FN (BUILT_IN_LROUND): CASE_FLT_FN (BUILT_IN_LLROUND): builtin_optab = lround_optab; @@ -5728,6 +5728,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, CASE_FLT_FN (BUILT_IN_ILOGB): if (! flag_unsafe_math_optimizations) break; + gcc_fallthrough (); CASE_FLT_FN (BUILT_IN_ISINF): CASE_FLT_FN (BUILT_IN_FINITE): case BUILT_IN_ISFINITE: diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 3961e94..4fd0016 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -396,6 +396,7 @@ static tree handle_designated_init_attribute (tree *, tree, tree, int, bool *); static tree handle_bnd_variable_size_attribute (tree *, tree, tree, int, bool *); static tree handle_bnd_legacy (tree *, tree, tree, int, bool *); static tree handle_bnd_instrument (tree *, tree, tree, int, bool *); +static tree handle_fallthrough_attribute (tree *, tree, tree, int, bool *); static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT); static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT); @@ -837,6 +838,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_bnd_legacy, false }, { "bnd_instrument", 0, 0, true, false, false, handle_bnd_instrument, false }, + { "fallthrough", 0, 0, false, false, false, + handle_fallthrough_attribute, false }, { NULL, 0, 0, false, false, false, NULL, false } }; @@ -9729,6 +9732,45 @@ handle_designated_init_attribute (tree *node, tree name, tree, int, return NULL_TREE; } + +/* Handle a "fallthrough" attribute; arguments as in struct + attribute_spec.handler. */ + +static tree +handle_fallthrough_attribute (tree *, tree name, tree, int, + bool *no_add_attrs) +{ + warning (OPT_Wattributes, "%qE attribute ignored", name); + *no_add_attrs = true; + return NULL_TREE; +} + +/* Check whether ATTR is a valid attribute fallthrough. */ + +bool +attribute_fallthrough_p (tree attr) +{ + tree t = lookup_attribute ("fallthrough", attr); + if (t == NULL_TREE) + return false; + /* This attribute shall appear at most once in each attribute-list. */ + if (lookup_attribute ("fallthrough", TREE_CHAIN (t))) + warning (OPT_Wattributes, "% attribute specified multiple " + "times"); + /* No attribute-argument-clause shall be present. */ + else if (TREE_VALUE (t) != NULL_TREE) + warning (OPT_Wattributes, "% attribute specified with " + "a parameter"); + /* Warn if other attributes are found. */ + for (t = attr; t != NULL_TREE; t = TREE_CHAIN (t)) + { + tree name = get_attribute_name (t); + if (!is_attribute_p ("fallthrough", name)) + warning (OPT_Wattributes, "%qE attribute ignored", name); + } + return true; +} + /* Check for valid arguments being passed to a function with FNTYPE. There are NARGS arguments in the array ARGARRAY. LOC should be used for diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index dd74d0d..a1694ff 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -790,6 +790,7 @@ extern void check_function_arguments_recurse (void (*) unsigned HOST_WIDE_INT); extern bool check_builtin_function_arguments (tree, int, tree *); extern void check_function_format (tree, int, tree *); +extern bool attribute_fallthrough_p (tree); extern tree handle_format_attribute (tree *, tree, tree, int, bool *); extern tree handle_format_arg_attribute (tree *, tree, tree, int, bool *); extern bool attribute_takes_identifier_p (const_tree); diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 5d50fc2..7f9d882 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -1326,7 +1326,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 30d9d27..728978a 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 { @@ -272,7 +274,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; @@ -1277,7 +1280,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, - 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, @@ -1581,6 +1585,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] ; @@ -1608,6 +1614,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 @@ -1642,7 +1650,8 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok, bool nested, bool start_attr_ok, tree *objc_foreach_object_declaration, vec 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; @@ -1704,6 +1713,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 @@ -1807,7 +1825,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, + "% attribute not followed by %<;%>"); + pending_xref_error (); prefix_attrs = specs->attrs; all_prefix_attrs = prefix_attrs; @@ -4797,12 +4818,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)) @@ -4919,6 +4942,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; @@ -4965,6 +4993,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, "% attribute " + "not followed by %<;%>"); + } + else if (attrs != NULL_TREE) + warning_at (loc, OPT_Wattributes, "only attribute %" + " can be applied to a null statement"); + } if (c_parser_next_tokens_start_declaration (parser)) { error_at (c_parser_peek_token (parser)->location, @@ -5018,6 +5073,9 @@ c_parser_label (c_parser *parser) jump-statement: goto * expression ; + expression-statement: + attributes ; + Objective-C: statement: @@ -5285,6 +5343,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, + "% attribute not followed " + "by %<;%>"); + } + else if (attrs != NULL_TREE) + warning_at (loc, OPT_Wattributes, "only attribute %" + " can be applied to a null statement"); + break; + } default: goto expr_stmt; } diff --git a/gcc/common.opt b/gcc/common.opt index 2b71763..b3498eb 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -601,6 +601,10 @@ Whsa Common Var(warn_hsa) Init(1) Warning Warn when a function cannot be expanded to HSAIL. +Wimplicit-fallthrough-disabled +Common Var(warn_implicit_fallthrough) Warning +Warn when a switch case falls through. + Winline Common Var(warn_inline) Warning Warn when an inlined function cannot be inlined. diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index cbf350b..0e029ae 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -5463,7 +5463,7 @@ rs6000_builtin_vectorized_libmass (combined_fn fn, tree type_out, CASE_CFN_HYPOT: CASE_CFN_POW: n_args = 2; - /* fall through */ + gcc_fallthrough (); CASE_CFN_ACOS: CASE_CFN_ACOSH: diff --git a/gcc/convert.c b/gcc/convert.c index 862287b..54b0a5d 100644 --- a/gcc/convert.c +++ b/gcc/convert.c @@ -164,6 +164,7 @@ convert_to_real_1 (tree type, tree expr, bool fold_p) -fmath-errno. */ if (flag_errno_math) break; + gcc_fallthrough (); CASE_MATHFN (ACOS) CASE_MATHFN (ACOSH) CASE_MATHFN (ASIN) @@ -184,6 +185,7 @@ convert_to_real_1 (tree type, tree expr, bool fold_p) /* The above functions are not safe to do this conversion. */ if (!flag_unsafe_math_optimizations) break; + gcc_fallthrough (); CASE_MATHFN (SQRT) CASE_MATHFN (FABS) CASE_MATHFN (LOGB) @@ -516,7 +518,7 @@ convert_to_integer_1 (tree type, tree expr, bool dofold) /* Only convert nearbyint* if we can ignore math exceptions. */ if (flag_trapping_math) break; - /* ... Fall through ... */ + gcc_fallthrough (); CASE_FLT_FN (BUILT_IN_RINT): /* Only convert in ISO C99 mode and with -fno-math-errno. */ if (!targetm.libc_has_function (function_c99_misc) || flag_errno_math) diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c index dd31d56..07fc90e 100644 --- a/gcc/cp/constexpr.c +++ b/gcc/cp/constexpr.c @@ -1313,6 +1313,7 @@ cxx_eval_call_expression (const constexpr_ctx *ctx, tree t, case IFN_UBSAN_NULL: case IFN_UBSAN_BOUNDS: case IFN_UBSAN_VPTR: + case IFN_FALLTHROUGH: return void_node; default: if (!ctx->quiet) @@ -4729,6 +4730,7 @@ potential_constant_expression_1 (tree t, bool want_rval, bool strict, case IFN_UBSAN_NULL: case IFN_UBSAN_BOUNDS: case IFN_UBSAN_VPTR: + case IFN_FALLTHROUGH: return true; case IFN_ISAN_CHECK_ADD: case IFN_ISAN_CHECK_SUB: diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 157f7dd..ddd935c 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -117,7 +117,8 @@ function_concept_check_p (tree t) { gcc_assert (TREE_CODE (t) == CALL_EXPR); tree fn = CALL_EXPR_FN (t); - if (TREE_CODE (fn) == TEMPLATE_ID_EXPR + if (fn != NULL_TREE + && TREE_CODE (fn) == TEMPLATE_ID_EXPR && TREE_CODE (TREE_OPERAND (fn, 0)) == OVERLOAD) { tree f1 = get_first_fn (fn); diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 6ba9c11..ce21352 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -10556,14 +10556,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, + "% 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, @@ -10599,6 +10616,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) { @@ -10630,7 +10651,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", @@ -10643,7 +10668,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; @@ -10651,6 +10680,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; } @@ -10699,6 +10730,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. */ @@ -10713,6 +10748,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, + "% 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::type t;" and the like. */ if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON) && !cp_parser_uncommitted_to_tentative_parse_p (parser)) @@ -12911,6 +12965,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: @@ -24010,7 +24065,7 @@ cp_parser_std_attribute (cp_parser *parser) 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, @@ -24018,6 +24073,15 @@ cp_parser_std_attribute (cp_parser *parser) " use %"); 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, + "% is a C++17 feature;" + " use %"); + 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)) @@ -24076,11 +24140,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 % 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 % can appear at most once " "in an attribute-list"); } } @@ -27168,6 +27232,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) @@ -27621,6 +27686,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) @@ -33263,6 +33329,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; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 9f595bb..faca6e3 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -16500,7 +16500,16 @@ tsubst_copy_and_build (tree t, tree ret; function = CALL_EXPR_FN (t); - /* When we parsed the expression, we determined whether or + if (function == NULL_TREE) + { + /* If you hit this assert, it means that you're trying to tsubst + an internal function with arguments. This isn't yet supported, + so you need to build another internal call with the tsubsted + arguments after the arguments have been tsubsted down below. */ + gcc_assert (call_expr_nargs (t) == 0); + RETURN (t); + } + /* When we parsed the expression, we determined whether or not Koenig lookup should be performed. */ koenig_p = KOENIG_LOOKUP_P (t); if (TREE_CODE (function) == SCOPE_REF) @@ -22708,7 +22717,7 @@ instantiation_dependent_scope_ref_p (tree t) bool value_dependent_expression_p (tree expression) { - if (!processing_template_decl) + if (!processing_template_decl || expression == NULL_TREE) return false; /* A name declared with a dependent type. */ diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c index 2cb8d29..342a8ce 100644 --- a/gcc/cp/semantics.c +++ b/gcc/cp/semantics.c @@ -8820,6 +8820,7 @@ finish_decltype_type (tree expr, bool id_expression_or_member_access_p, break; } /* Fall through for fields that aren't bitfields. */ + gcc_fallthrough (); case FUNCTION_DECL: case VAR_DECL: diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index fdaba65..669c03f 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -1304,6 +1304,7 @@ structural_comptypes (tree t1, tree t2, int strict) if (TYPE_REF_IS_RVALUE (t1) != TYPE_REF_IS_RVALUE (t2)) return false; /* fall through to checks for pointer types */ + gcc_fallthrough (); case POINTER_TYPE: if (TYPE_MODE (t1) != TYPE_MODE (t2) @@ -4243,6 +4244,7 @@ cp_build_binary_op (location_t location, } /* The pointer - int case is just like pointer + int; fall through. */ + gcc_fallthrough (); case PLUS_EXPR: if ((code0 == POINTER_TYPE || code1 == POINTER_TYPE) && (code0 == INTEGER_TYPE || code1 == INTEGER_TYPE)) @@ -7577,7 +7579,7 @@ cp_build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs, TREE_OPERAND (lhs, 1)), TREE_OPERAND (lhs, 0), TREE_OPERAND (lhs, 1)); - /* Fall through. */ + gcc_fallthrough (); /* Handle (a ? b : c) used as an "lvalue". */ case COND_EXPR: diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 04b9393..0c91d85 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -60,6 +60,7 @@ extensions, accepted by GCC in C90 mode and in C++. * Type Attributes:: Specifying attributes of types. * Label Attributes:: Specifying attributes on labels. * Enumerator Attributes:: Specifying attributes on enumerators. +* Statement Attributes:: Specifying attributes on statements. * Attribute Syntax:: Formal syntax for attributes. * Function Prototypes:: Prototype declarations and old-style definitions. * C++ Comments:: C++ comments are recognized. @@ -2229,6 +2230,7 @@ GCC also supports attributes on variable declarations (@pxref{Variable Attributes}), labels (@pxref{Label Attributes}), enumerators (@pxref{Enumerator Attributes}), +statements (@pxref{Statement Attributes}), and types (@pxref{Type Attributes}). There is some overlap between the purposes of attributes and pragmas @@ -5454,8 +5456,8 @@ attributes are currently defined generically for variables. Other attributes are defined for variables on particular target systems. Other attributes are available for functions (@pxref{Function Attributes}), labels (@pxref{Label Attributes}), -enumerators (@pxref{Enumerator Attributes}), and for types -(@pxref{Type Attributes}). +enumerators (@pxref{Enumerator Attributes}), statements +(@pxref{Statement Attributes}), and for types (@pxref{Type Attributes}). Other front ends might define more attributes (@pxref{C++ Extensions,,Extensions to the C++ Language}). @@ -6212,7 +6214,8 @@ attributes of types. Some type attributes apply only to @code{struct} and @code{union} types, while others can apply to any type defined via a @code{typedef} declaration. Other attributes are defined for functions (@pxref{Function Attributes}), labels (@pxref{Label -Attributes}), enumerators (@pxref{Enumerator Attributes}), and for +Attributes}), enumerators (@pxref{Enumerator Attributes}), +statements (@pxref{Statement Attributes}), and for variables (@pxref{Variable Attributes}). The @code{__attribute__} keyword is followed by an attribute specification @@ -6722,7 +6725,8 @@ GCC allows attributes to be set on C labels. @xref{Attribute Syntax}, for details of the exact syntax for using attributes. Other attributes are available for functions (@pxref{Function Attributes}), variables (@pxref{Variable Attributes}), enumerators (@pxref{Enumerator Attributes}), -and for types (@pxref{Type Attributes}). +statements (@pxref{Statement Attributes}), and for types +(@pxref{Type Attributes}). This example uses the @code{cold} label attribute to indicate the @code{ErrorHandling} branch is unlikely to be taken and that the @@ -6775,8 +6779,8 @@ with computed goto or @code{asm goto}. GCC allows attributes to be set on enumerators. @xref{Attribute Syntax}, for details of the exact syntax for using attributes. Other attributes are available for functions (@pxref{Function Attributes}), variables -(@pxref{Variable Attributes}), labels (@pxref{Label Attributes}), -and for types (@pxref{Type Attributes}). +(@pxref{Variable Attributes}), labels (@pxref{Label Attributes}), statements +(@pxref{Statement Attributes}), and for types (@pxref{Type Attributes}). This example uses the @code{deprecated} enumerator attribute to indicate the @code{oldval} enumerator is deprecated: @@ -6807,6 +6811,46 @@ do instead. Note that the warnings only occurs for uses. @end table +@node Statement Attributes +@section Statement Attributes +@cindex Statement Attributes + +GCC allows attributes to be set on null statements. @xref{Attribute Syntax}, +for details of the exact syntax for using attributes. Other attributes are +available for functions (@pxref{Function Attributes}), variables +(@pxref{Variable Attributes}), labels (@pxref{Label Attributes}), enumerators +(@pxref{Enumerator Attributes}), and for types (@pxref{Type Attributes}). + +This example uses the @code{fallthrough} statement attribute to indicate that +the @option{-Wimplicit-fallthrough} warning should not be emitted: + +@smallexample +switch (cond) + @{ + case 1: + bar (1); + __attribute__((fallthrough)); + case 2: + @dots{} + @} +@end smallexample + +@table @code +@item fallthrough +@cindex @code{fallthrough} statement attribute +The @code{fallthrough} attribute with a null statement serves as a +fallthrough statement. It hints to the compiler that a statement +that falls through to another case label, or user-defined label +in a switch statement is intentional and thus the +@option{-Wimplicit-fallthrough} warning must not trigger. The +fallthrough attribute may appear at most once in each attribute +list, and may not be mixed with other attributes. It can only +be used in a switch statement (the compiler will issue an error +otherwise), after a preceding statement and before a logically +succeeding case label, or user-defined label. + +@end table + @node Attribute Syntax @section Attribute Syntax @cindex attribute syntax @@ -6834,6 +6878,8 @@ and enumerated types. applying to labels. @xref{Enumerator Attributes}, for details of the semantics of attributes applying to enumerators. +@xref{Statement Attributes}, for details of the semantics of attributes +applying to statements. An @dfn{attribute specifier} is of the form @code{__attribute__ ((@var{attribute-list}))}. An @dfn{attribute list} @@ -6899,6 +6945,10 @@ present. The optional attribute in the enumerator appertains to the enumeration constant. It is not possible to place the attribute after the constant expression, if present. +@subsubheading Statement Attributes +In GNU C, an attribute specifier list may appear as part of a null +statement. The attribute goes before the semicolon. + @subsubheading Type Attributes An attribute specifier list may appear as part of a @code{struct}, diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 87da0ba..9d4f65d 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -268,6 +268,8 @@ Objective-C and Objective-C++ Dialects}. -Wformat-security -Wformat-signedness -Wformat-y2k -Wframe-address @gol -Wframe-larger-than=@var{len} -Wno-free-nonheap-object -Wjump-misses-init @gol -Wignored-qualifiers -Wignored-attributes -Wincompatible-pointer-types @gol +-Wimplicit -Wimplicit-fallthrough -Wimplicit-function-declaration @gol +-Wimplicit-int @gol -Wimplicit -Wimplicit-function-declaration -Wimplicit-int @gol -Winit-self -Winline -Wno-int-conversion @gol -Wno-int-to-pointer-cast -Winvalid-memory-model -Wno-invalid-offsetof @gol @@ -3877,6 +3879,93 @@ enabled by default and it is made into an error by Same as @option{-Wimplicit-int} and @option{-Wimplicit-function-declaration}. This warning is enabled by @option{-Wall}. +@item -Wimplicit-fallthrough +@opindex Wimplicit-fallthrough +@opindex Wno-implicit-fallthrough +Warn when a switch case falls through. For example: + +@smallexample +@group +switch (cond) + @{ + case 1: + a = 1; + break; + case 2: + a = 2; + case 3: + a = 3; + break; + @} +@end group +@end smallexample + +This warning does not warn when the last statement of a case cannot +fall through, e.g. when there is a return statement or a call to function +declared with the noreturn attribute. @option{-Wimplicit-fallthrough} +also takes into account control flow statements, such as ifs, and only +warns when appropriate. E.g.@: + +@smallexample +@group +switch (cond) + @{ + case 1: + if (i > 3) @{ + bar (5); + break; + @} else if (i < 1) @{ + bar (0); + @} else + return; + default: + @dots{} + @} +@end group +@end smallexample + +Since there are occasions where a switch case fall through is desirable, +GCC provides an attribute, @code{__attribute__ ((fallthrough))}, that is +to be used along with a null statement to suppress this warning that +would normally occur: + +@smallexample +@group +switch (cond) + @{ + case 1: + bar (0); + __attribute__ ((fallthrough)); + default: + @dots{} + @} +@end group +@end smallexample + +C++17 provides a standard way to suppress the @option{-Wimplicit-fallthrough} +warning using @code{[[fallthrough]];} instead of the GNU attribute. In C++11 +or C++14 users can use @code{[[gnu::fallthrough]];}, which is a GNU extension. +Instead of the these attributes, it is also possible to add a "falls through" +comment to silence the warning. GCC accepts a wide range of such comments, +for example all of "Falls through.", "fallthru", "FALLS-THROUGH" work. This +comment needs to consist of two words merely, optionally followed by periods +or whitespaces. + +@smallexample +@group +switch (cond) + @{ + case 1: + bar (0); + /* FALLTHRU */ + default: + @dots{} + @} +@end group +@end smallexample + +This warning is enabled by @option{-Wextra}. + @item -Wignored-qualifiers @r{(C and C++ only)} @opindex Wignored-qualifiers @opindex Wno-ignored-qualifiers diff --git a/gcc/final.c b/gcc/final.c index 55cf509..423550f 100644 --- a/gcc/final.c +++ b/gcc/final.c @@ -2096,9 +2096,11 @@ output_alternate_entry_point (FILE *file, rtx_insn *insn) case LABEL_WEAK_ENTRY: #ifdef ASM_WEAKEN_LABEL ASM_WEAKEN_LABEL (file, name); + gcc_fallthrough (); #endif case LABEL_GLOBAL_ENTRY: targetm.asm_out.globalize_label (file, name); + gcc_fallthrough (); case LABEL_STATIC_ENTRY: #ifdef ASM_OUTPUT_TYPE_DIRECTIVE ASM_OUTPUT_TYPE_DIRECTIVE (file, name, "function"); diff --git a/gcc/fortran/arith.c b/gcc/fortran/arith.c index e849f59..2781f10 100644 --- a/gcc/fortran/arith.c +++ b/gcc/fortran/arith.c @@ -1521,7 +1521,7 @@ eval_intrinsic (gfc_intrinsic_op op, break; } - /* Fall through */ + gcc_fallthrough (); /* Numeric binary */ case INTRINSIC_PLUS: case INTRINSIC_MINUS: diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c index d26a8ab..75800a7 100644 --- a/gcc/fortran/frontend-passes.c +++ b/gcc/fortran/frontend-passes.c @@ -1481,7 +1481,7 @@ optimize_op (gfc_expr *e) case INTRINSIC_LT: changed = optimize_comparison (e, op); - /* Fall through */ + gcc_fallthrough (); /* Look at array constructors. */ case INTRINSIC_PLUS: case INTRINSIC_MINUS: @@ -3354,6 +3354,7 @@ gfc_expr_walker (gfc_expr **e, walk_expr_fn_t exprfn, void *data) /* Fall through to the variable case in order to walk the reference. */ + gcc_fallthrough (); case EXPR_SUBSTRING: case EXPR_VARIABLE: diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c index 49da3d4..f8a51d2 100644 --- a/gcc/fortran/parse.c +++ b/gcc/fortran/parse.c @@ -1257,7 +1257,7 @@ next_fixed (void) return decode_oacc_directive (); } } - /* FALLTHROUGH */ + gcc_fallthrough (); /* Comments have already been skipped by the time we get here so don't bother checking for them. */ diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c index b796810..fccb6fd 100644 --- a/gcc/fortran/primary.c +++ b/gcc/fortran/primary.c @@ -3419,6 +3419,7 @@ match_variable (gfc_expr **result, int equiv_flag, int host_flag) break; /* Fall through to error */ + gcc_fallthrough (); default: gfc_error ("%qs at %C is not a variable", sym->name); diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 08c3233..3b51d9b 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -4021,6 +4021,7 @@ done: continue; } /* Otherwise fall through GFC_SS_FUNCTION. */ + gcc_fallthrough (); } case GFC_ISYM_LCOBOUND: case GFC_ISYM_UCOBOUND: diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 26cd439..e75f029 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -2131,6 +2131,7 @@ flatten_array_ctors_without_strlen (gfc_expr* e) } /* Otherwise, fall through to handle constructor elements. */ + gcc_fallthrough (); case EXPR_STRUCTURE: for (c = gfc_constructor_first (e->value.constructor); c; c = gfc_constructor_next (c)) diff --git a/gcc/genattrtab.c b/gcc/genattrtab.c index 1d4965e..f190196 100644 --- a/gcc/genattrtab.c +++ b/gcc/genattrtab.c @@ -1219,6 +1219,7 @@ make_canonical (file_location loc, struct attr_desc *attr, rtx exp) exp = newexp; /* Fall through to COND case since this is now a COND. */ + gcc_fallthrough (); case COND: { @@ -3602,6 +3603,7 @@ write_test_expr (FILE *outf, rtx exp, unsigned int attrs_cached, int flags) } /* Otherwise, fall through to normal unary operator. */ + gcc_fallthrough (); /* Unary operators. */ case ABS: case NEG: diff --git a/gcc/genpreds.c b/gcc/genpreds.c index 60b12bd..89a938b 100644 --- a/gcc/genpreds.c +++ b/gcc/genpreds.c @@ -74,7 +74,7 @@ validate_exp (rtx exp, const char *name, file_location loc) } } } - /* fall through */ + gcc_fallthrough (); /* These need no special checking. */ case MATCH_OPERAND: diff --git a/gcc/gimple-ssa-strength-reduction.c b/gcc/gimple-ssa-strength-reduction.c index cba6be5..266268e 100644 --- a/gcc/gimple-ssa-strength-reduction.c +++ b/gcc/gimple-ssa-strength-reduction.c @@ -1694,7 +1694,7 @@ find_candidates_dom_walker::before_dom_children (basic_block bb) case POINTER_PLUS_EXPR: case MINUS_EXPR: rhs2 = gimple_assign_rhs2 (gs); - /* Fall-through. */ + gcc_fallthrough (); CASE_CONVERT: case MODIFY_EXPR: diff --git a/gcc/gimple.h b/gcc/gimple.h index e0dfc3f..82eb6fd 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -2919,6 +2919,16 @@ gimple_call_internal_unique_p (const gimple *gs) return gimple_call_internal_unique_p (gc); } +/* Return true if GS is an internal function FN. */ + +static inline bool +gimple_call_internal_p (const gimple *gs, internal_fn fn) +{ + return (is_gimple_call (gs) + && gimple_call_internal_p (gs) + && gimple_call_internal_fn (gs) == fn); +} + /* If CTRL_ALTERING_P is true, mark GIMPLE_CALL S to be a stmt that could alter control flow. */ diff --git a/gcc/gimplify.c b/gcc/gimplify.c index e183574..590c65a 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -160,6 +160,7 @@ struct gimplify_ctx unsigned in_cleanup_point_expr : 1; unsigned keep_stack : 1; unsigned save_stack : 1; + unsigned in_switch_expr : 1; }; struct gimplify_omp_ctx @@ -1619,6 +1620,430 @@ maybe_warn_switch_unreachable (gimple_seq seq) } } + +/* A label entry that pairs label and a location. */ +struct label_entry +{ + tree label; + location_t loc; +}; + +/* Find LABEL in vector of label entries VEC. */ + +static struct label_entry * +find_label_entry (const auto_vec *vec, tree label) +{ + unsigned int i; + struct label_entry *l; + + FOR_EACH_VEC_ELT (*vec, i, l) + if (l->label == label) + return l; + return NULL; +} + +/* Return true if LABEL, a LABEL_DECL, represents a case label + in a vector of labels CASES. */ + +static bool +case_label_p (const vec *cases, tree label) +{ + unsigned int i; + tree l; + + FOR_EACH_VEC_ELT (*cases, i, l) + if (CASE_LABEL (l) == label) + return true; + return false; +} + +/* Find the last statement in a scope STMT. */ + +static gimple * +last_stmt_in_scope (gimple *stmt) +{ + if (!stmt) + return NULL; + + switch (gimple_code (stmt)) + { + case GIMPLE_BIND: + { + gbind *bind = as_a (stmt); + stmt = gimple_seq_last_stmt (gimple_bind_body (bind)); + return last_stmt_in_scope (stmt); + } + + case GIMPLE_TRY: + { + gtry *try_stmt = as_a (stmt); + stmt = gimple_seq_last_stmt (gimple_try_eval (try_stmt)); + gimple *last_eval = last_stmt_in_scope (stmt); + if (gimple_stmt_may_fallthru (last_eval) + && gimple_try_kind (try_stmt) == GIMPLE_TRY_FINALLY) + { + stmt = gimple_seq_last_stmt (gimple_try_cleanup (try_stmt)); + return last_stmt_in_scope (stmt); + } + else + return last_eval; + } + + default: + return stmt; + } +} + +/* Collect interesting labels in LABELS and return the statement preceding + another case label, or a user-defined label. */ + +static gimple * +collect_fallthrough_labels (gimple_stmt_iterator *gsi_p, + auto_vec *labels) +{ + gimple *prev = NULL; + + do + { + if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_BIND + || gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_TRY) + { + /* Nested scope. Only look at the last statement of + the innermost scope. */ + location_t bind_loc = gimple_location (gsi_stmt (*gsi_p)); + gimple *last = last_stmt_in_scope (gsi_stmt (*gsi_p)); + if (last) + { + prev = last; + /* It might be a label without a location. Use the + location of the scope then. */ + if (!gimple_has_location (prev)) + gimple_set_location (prev, bind_loc); + } + gsi_next (gsi_p); + continue; + } + + /* Ifs are tricky. */ + if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_COND) + { + gcond *cond_stmt = as_a (gsi_stmt (*gsi_p)); + tree false_lab = gimple_cond_false_label (cond_stmt); + location_t if_loc = gimple_location (cond_stmt); + + /* If we have e.g. + if (i > 1) goto ; else goto D; + we can't do much with the else-branch. */ + if (!DECL_ARTIFICIAL (false_lab)) + break; + + /* Go on until the false label, then one step back. */ + for (; !gsi_end_p (*gsi_p); gsi_next (gsi_p)) + { + gimple *stmt = gsi_stmt (*gsi_p); + if (gimple_code (stmt) == GIMPLE_LABEL + && gimple_label_label (as_a (stmt)) == false_lab) + break; + } + + /* Not found? Oops. */ + if (gsi_end_p (*gsi_p)) + break; + + struct label_entry l = { false_lab, if_loc }; + labels->safe_push (l); + + /* Go to the last statement of the then branch. */ + gsi_prev (gsi_p); + + /* if (i != 0) goto ; else goto ; + : + ; + goto ; + : + */ + if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_GOTO + && !gimple_has_location (gsi_stmt (*gsi_p))) + { + /* Look at the statement before, it might be + attribute fallthrough, in which case don't warn. */ + gsi_prev (gsi_p); + bool fallthru_before_dest + = gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_FALLTHROUGH); + gsi_next (gsi_p); + tree goto_dest = gimple_goto_dest (gsi_stmt (*gsi_p)); + if (!fallthru_before_dest) + { + struct label_entry l = { goto_dest, if_loc }; + labels->safe_push (l); + } + } + /* And move back. */ + gsi_next (gsi_p); + } + + /* Remember the last statement. Skip labels that are of no interest + to us. */ + if (gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL) + { + tree label = gimple_label_label (as_a (gsi_stmt (*gsi_p))); + if (find_label_entry (labels, label)) + prev = gsi_stmt (*gsi_p); + } + else + prev = gsi_stmt (*gsi_p); + gsi_next (gsi_p); + } + while (!gsi_end_p (*gsi_p) + /* Stop if we find a case or a user-defined label. */ + && (gimple_code (gsi_stmt (*gsi_p)) != GIMPLE_LABEL + || !gimple_has_location (gsi_stmt (*gsi_p)))); + + return prev; +} + +/* Return true if the switch fallthough warning should occur. LABEL is + the label statement that we're falling through to. */ + +static bool +should_warn_for_implicit_fallthrough (gimple_stmt_iterator *gsi_p, tree label) +{ + gimple_stmt_iterator gsi = *gsi_p; + + /* Don't warn for a non-case label followed by a statement: + case 0: + foo (); + label: + bar (); + as these are likely intentional. */ + if (!case_label_p (&gimplify_ctxp->case_labels, label)) + { + gsi_next (&gsi); + if (gsi_end_p (gsi) || gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL) + return false; + } + + /* Don't warn for terminated branches, i.e. when the subsequent case labels + immediately breaks. */ + gsi = *gsi_p; + + /* Skip all immediately following labels. */ + while (!gsi_end_p (gsi) && gimple_code (gsi_stmt (gsi)) == GIMPLE_LABEL) + gsi_next (&gsi); + + /* { ... something; default:; } */ + if (gsi_end_p (gsi) + /* { ... something; default: break; } or + { ... something; default: goto L; } */ + || gimple_code (gsi_stmt (gsi)) == GIMPLE_GOTO + /* { ... something; default: return; } */ + || gimple_code (gsi_stmt (gsi)) == GIMPLE_RETURN) + return false; + + return true; +} + +/* Callback for walk_gimple_seq. */ + +static tree +warn_implicit_fallthrough_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, + struct walk_stmt_info *) +{ + gimple *stmt = gsi_stmt (*gsi_p); + + *handled_ops_p = true; + switch (gimple_code (stmt)) + { + case GIMPLE_TRY: + case GIMPLE_BIND: + case GIMPLE_CATCH: + case GIMPLE_EH_FILTER: + case GIMPLE_TRANSACTION: + /* Walk the sub-statements. */ + *handled_ops_p = false; + break; + + /* Find a sequence of form: + + GIMPLE_LABEL + [...] + + GIMPLE_LABEL + + and possibly warn. */ + case GIMPLE_LABEL: + { + /* Found a label. Skip all immediately following labels. */ + while (!gsi_end_p (*gsi_p) + && gimple_code (gsi_stmt (*gsi_p)) == GIMPLE_LABEL) + gsi_next (gsi_p); + + /* There might be no more statements. */ + if (gsi_end_p (*gsi_p)) + return integer_zero_node; + + /* Vector of labels that fall through. */ + auto_vec labels; + gimple *prev = collect_fallthrough_labels (gsi_p, &labels); + + /* There might be no more statements. */ + if (gsi_end_p (*gsi_p)) + return integer_zero_node; + + gimple *next = gsi_stmt (*gsi_p); + tree label; + /* If what follows is a label, then we may have a fallthrough. */ + if (gimple_code (next) == GIMPLE_LABEL + && gimple_has_location (next) + && (label = gimple_label_label (as_a (next))) + && !FALLTHROUGH_LABEL_P (label) + && prev != NULL) + { + struct label_entry *l; + bool warned_p = false; + if (!should_warn_for_implicit_fallthrough (gsi_p, label)) + /* Quiet. */; + else if (gimple_code (prev) == GIMPLE_LABEL + && (label = gimple_label_label (as_a (prev))) + && (l = find_label_entry (&labels, label))) + warned_p = warning_at (l->loc, OPT_Wimplicit_fallthrough_disabled, + "this statement may fall through"); + else if (!gimple_call_internal_p (prev, IFN_FALLTHROUGH) + /* Try to be clever and don't warn when the statement + can't actually fall through. */ + && gimple_stmt_may_fallthru (prev) + && gimple_has_location (prev)) + warned_p = warning_at (gimple_location (prev), + OPT_Wimplicit_fallthrough_disabled, + "this statement may fall through"); + if (warned_p) + inform (gimple_location (next), "here"); + + /* Mark this label as processed so as to prevent multiple + warnings in nested switches. */ + FALLTHROUGH_LABEL_P (label) = true; + + /* So that next warn_implicit_fallthrough_r will start looking for + a new sequence starting with this label. */ + gsi_prev (gsi_p); + } + } + break; + default: + break; + } + return NULL_TREE; +} + +/* Warn when a switch case falls through. */ + +static void +maybe_warn_implicit_fallthrough (gimple_seq seq) +{ + if (!warn_implicit_fallthrough) + return; + + /* This warning is meant for C/C++/ObjC/ObjC++ only. */ + if (!(lang_GNU_C () + || lang_GNU_CXX () + || lang_GNU_OBJC ())) + return; + + struct walk_stmt_info wi; + memset (&wi, 0, sizeof (wi)); + walk_gimple_seq (seq, warn_implicit_fallthrough_r, NULL, &wi); +} + +/* Callback for walk_gimple_seq. */ + +static tree +expand_FALLTHROUGH_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, + struct walk_stmt_info *) +{ + gimple *stmt = gsi_stmt (*gsi_p); + + *handled_ops_p = true; + switch (gimple_code (stmt)) + { + case GIMPLE_TRY: + case GIMPLE_BIND: + case GIMPLE_CATCH: + case GIMPLE_EH_FILTER: + case GIMPLE_TRANSACTION: + /* Walk the sub-statements. */ + *handled_ops_p = false; + break; + case GIMPLE_CALL: + if (gimple_call_internal_p (stmt, IFN_FALLTHROUGH)) + { + gsi_remove (gsi_p, true); + if (gsi_end_p (*gsi_p)) + return integer_zero_node; + + bool found = false; + location_t loc = gimple_location (stmt); + + gimple_stmt_iterator gsi2 = *gsi_p; + stmt = gsi_stmt (gsi2); + if (gimple_code (stmt) == GIMPLE_GOTO && !gimple_has_location (stmt)) + { + /* Go on until the artificial label. */ + tree goto_dest = gimple_goto_dest (stmt); + for (; !gsi_end_p (gsi2); gsi_next (&gsi2)) + { + if (gimple_code (gsi_stmt (gsi2)) == GIMPLE_LABEL + && gimple_label_label (as_a (gsi_stmt (gsi2))) + == goto_dest) + break; + } + + /* Not found? Stop. */ + if (gsi_end_p (gsi2)) + break; + + /* Look one past it. */ + gsi_next (&gsi2); + } + + /* We're looking for a case label or default label here. */ + while (!gsi_end_p (gsi2)) + { + stmt = gsi_stmt (gsi2); + if (gimple_code (stmt) == GIMPLE_LABEL) + { + tree label = gimple_label_label (as_a (stmt)); + if (gimple_has_location (stmt) && DECL_ARTIFICIAL (label)) + { + found = true; + break; + } + } + else + /* Something other than a label. That's not expected. */ + break; + gsi_next (&gsi2); + } + if (!found) + warning_at (loc, 0, "attribute % not preceding " + "a case label or default label"); + } + break; + default: + break; + } + return NULL_TREE; +} + +/* Expand all FALLTHROUGH () calls in SEQ. */ + +static void +expand_FALLTHROUGH (gimple_seq *seq_p) +{ + struct walk_stmt_info wi; + memset (&wi, 0, sizeof (wi)); + walk_gimple_seq_mod (seq_p, expand_FALLTHROUGH_r, NULL, &wi); +} + /* Gimplify a SWITCH_EXPR, and collect the vector of labels it can branch to. */ @@ -1653,10 +2078,17 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) labels. Save all the things from the switch body to append after. */ saved_labels = gimplify_ctxp->case_labels; gimplify_ctxp->case_labels.create (8); + bool old_in_switch_expr = gimplify_ctxp->in_switch_expr; + gimplify_ctxp->in_switch_expr = true; gimplify_stmt (&SWITCH_BODY (switch_expr), &switch_body_seq); + gimplify_ctxp->in_switch_expr = old_in_switch_expr; maybe_warn_switch_unreachable (switch_body_seq); + maybe_warn_implicit_fallthrough (switch_body_seq); + /* Only do this for the outermost GIMPLE_SWITCH. */ + if (!gimplify_ctxp->in_switch_expr) + expand_FALLTHROUGH (&switch_body_seq); labels = gimplify_ctxp->case_labels; gimplify_ctxp->case_labels = saved_labels; @@ -1687,6 +2119,21 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) return GS_ALL_DONE; } +/* Gimplify the LABEL_EXPR pointed to by EXPR_P. */ + +static enum gimplify_status +gimplify_label_expr (tree *expr_p, gimple_seq *pre_p) +{ + gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p)) + == current_function_decl); + + glabel *label_stmt = gimple_build_label (LABEL_EXPR_LABEL (*expr_p)); + gimple_set_location (label_stmt, EXPR_LOCATION (*expr_p)); + gimplify_seq_add_stmt (pre_p, label_stmt); + + return GS_ALL_DONE; +} + /* Gimplify the CASE_LABEL_EXPR pointed to by EXPR_P. */ static enum gimplify_status @@ -1704,6 +2151,7 @@ gimplify_case_label_expr (tree *expr_p, gimple_seq *pre_p) break; label_stmt = gimple_build_label (CASE_LABEL (*expr_p)); + gimple_set_location (label_stmt, EXPR_LOCATION (*expr_p)); ctxp->case_labels.safe_push (*expr_p); gimplify_seq_add_stmt (pre_p, label_stmt); @@ -10704,11 +11152,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, break; case LABEL_EXPR: - ret = GS_ALL_DONE; - gcc_assert (decl_function_context (LABEL_EXPR_LABEL (*expr_p)) - == current_function_decl); - gimplify_seq_add_stmt (pre_p, - gimple_build_label (LABEL_EXPR_LABEL (*expr_p))); + ret = gimplify_label_expr (expr_p, pre_p); break; case CASE_LABEL_EXPR: diff --git a/gcc/godump.c b/gcc/godump.c index e3448a1..608542c 100644 --- a/gcc/godump.c +++ b/gcc/godump.c @@ -893,6 +893,7 @@ go_format_type (struct godump_container *container, tree type, case UNION_TYPE: is_union = true; /* Fall through to RECORD_TYPE case. */ + gcc_fallthrough (); case RECORD_TYPE: { unsigned int prev_field_end; diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index ab87b87..1fd7fa3 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -250,6 +250,15 @@ expand_TSAN_FUNC_EXIT (internal_fn, gcall *) gcc_unreachable (); } +/* This should get expanded in the lower pass. */ + +static void +expand_FALLTHROUGH (internal_fn, gcall *call) +{ + error_at (gimple_location (call), + "invalid use of attribute %"); +} + /* Helper function for expand_addsub_overflow. Return 1 if ARG interpreted as signed in its precision is known to be always positive or 2 if ARG is known to be always negative, or 3 if ARG may diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index c35c11e..0e9f83c 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -193,6 +193,9 @@ DEF_INTERNAL_FN (GOACC_REDUCTION, ECF_NOTHROW | ECF_LEAF, NULL) current target. */ DEF_INTERNAL_FN (SET_EDOM, ECF_LEAF | ECF_NOTHROW, NULL) +/* To implement [[fallthrough]]. */ +DEF_INTERNAL_FN (FALLTHROUGH, ECF_LEAF | ECF_NOTHROW, NULL) + #undef DEF_INTERNAL_INT_FN #undef DEF_INTERNAL_FLT_FN #undef DEF_INTERNAL_OPTAB_FN diff --git a/gcc/langhooks.c b/gcc/langhooks.c index 7c07175..917003a 100644 --- a/gcc/langhooks.c +++ b/gcc/langhooks.c @@ -714,3 +714,12 @@ lang_GNU_Fortran (void) { return strncmp (lang_hooks.name, "GNU Fortran", 11) == 0; } + +/* Returns true if the current lang_hooks represents the GNU Objective-C + frontend. */ + +bool +lang_GNU_OBJC (void) +{ + return strncmp (lang_hooks.name, "GNU Objective-C", 15) == 0; +} diff --git a/gcc/langhooks.h b/gcc/langhooks.h index bcfd389..70222d8 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -528,5 +528,6 @@ extern tree add_builtin_type (const char *name, tree type); extern bool lang_GNU_C (void); extern bool lang_GNU_CXX (void); extern bool lang_GNU_Fortran (void); - +extern bool lang_GNU_OBJC (void); + #endif /* GCC_LANG_HOOKS_H */ diff --git a/gcc/reload1.c b/gcc/reload1.c index 5a1a4d4..102161e 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -3033,6 +3033,7 @@ elimination_effects (rtx x, machine_mode mem_mode) break; /* Fall through to generic unary operation case. */ + gcc_fallthrough (); case STRICT_LOW_PART: case NEG: case NOT: case SIGN_EXTEND: case ZERO_EXTEND: diff --git a/gcc/resource.c b/gcc/resource.c index ae2f5d8..6e58b3b 100644 --- a/gcc/resource.c +++ b/gcc/resource.c @@ -364,6 +364,7 @@ mark_referenced_resources (rtx x, struct resources *res, } /* ... fall through to other INSN processing ... */ + gcc_fallthrough (); case INSN: case JUMP_INSN: @@ -674,6 +675,7 @@ mark_set_resources (rtx x, struct resources *res, int in_dest, } /* ... and also what its RTL says it modifies, if anything. */ + gcc_fallthrough (); case JUMP_INSN: case INSN: diff --git a/gcc/system.h b/gcc/system.h index 53db88b..61ccc41 100644 --- a/gcc/system.h +++ b/gcc/system.h @@ -746,6 +746,12 @@ extern void fancy_abort (const char *, int, const char *) ATTRIBUTE_NORETURN; #define gcc_unreachable() (fancy_abort (__FILE__, __LINE__, __FUNCTION__)) #endif +#if GCC_VERSION >= 7000 +# define gcc_fallthrough() __attribute__((fallthrough)) +#else +# define gcc_fallthrough() +#endif + #if GCC_VERSION >= 3001 #define STATIC_CONSTANT_P(X) (__builtin_constant_p (X) && (X)) #else diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c new file mode 100644 index 0000000..b45880f --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-1.c @@ -0,0 +1,38 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ +/* Test taken from + . */ + +extern void f (int); + +void +foo (int n) +{ + switch (n) + { + case 22: + case 33: + f (1); /* { dg-warning "statement may fall through" } */ + case 44: + f (2); + __attribute__((fallthrough)); + case 55: + if (n > 10) + { + f (3); + break; + } + else + { + f (4); + __attribute__((fallthrough)); + } + case 66: + f (5); + __attribute__((fallthrough)); /* { dg-warning "not preceding" } */ + f (6); /* { dg-warning "statement may fall through" } */ + case 77: + f (7); + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c new file mode 100644 index 0000000..99e44d9 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-10.c @@ -0,0 +1,239 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +extern void bar (int); + +void +f (int i) +{ + switch (i) + { + case 1: + if (i) + { + bar (0); + break; + } + else if (i > 10) + { + bar (1); + __attribute__((fallthrough)); + } + else + break; + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (2); + else if (i > 10) + { + bar (3); + __attribute__((fallthrough)); + } + else + break; + case 2: + bar (4); + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + break; + } + else if (i > 10) /* { dg-warning "statement may fall through" } */ + { + bar (1); + } + else + break; + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + break; + } + else if (i > 10) + { + bar (1); + break; + } + else + break; + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + break; + } + else if (i > 10) + { + bar (1); + break; + } + else + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + __attribute__((fallthrough)); + } + else if (i > 10) + { + bar (1); + break; + } + else + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + __attribute__((fallthrough)); + } + else if (i > 10) + { + bar (1); + __attribute__((fallthrough)); + } + else + break; + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + __attribute__((fallthrough)); + } + else if (i > 10) + { + bar (1); + __attribute__((fallthrough)); + } + else + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + __attribute__((fallthrough)); + } + else if (i > 10) /* { dg-warning "statement may fall through" } */ + { + bar (1); + bar (2); + } + else + __attribute__((fallthrough)); + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + { + bar (0); + } + else if (i > 10) + { + bar (1); + } + else + { + bar (1); + __attribute__((fallthrough)); + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + __attribute__((fallthrough)); + } + else if (i > 10) + { + bar (1); + break; + } + else + { + bar (1); + __attribute__((fallthrough)); + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i) + { + bar (0); + break; + } + else if (i > 10) /* { dg-warning "statement may fall through" } */ + { + bar (1); + } + else + { + bar (1); + __attribute__((fallthrough)); + } + case 2: + bar (99); + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c new file mode 100644 index 0000000..e8f47f5 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-11.c @@ -0,0 +1,23 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough -O2" } */ + +/* Prevent false positive with optimizations. */ + +extern void g (int); + +void +f (int i) +{ + switch (i) + { + case 1: + if (i > 10) + g (0); + else + goto L; + break; +L: + case 2:; + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c new file mode 100644 index 0000000..91a68ab --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-12.c @@ -0,0 +1,26 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough -O2" } */ + +/* Don't let optimizations preclude the warning. */ + +extern void bar (int); + +void +f (int i) +{ + switch (i) + { + case 1: + if (i > 1) + bar (1); + else + goto D; + break; + case 2: + bar (2); /* { dg-warning "statement may fall through" } */ + D: + default: + bar (33); + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c new file mode 100644 index 0000000..f3ec79f --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-13.c @@ -0,0 +1,63 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +/* As per , don't + warn for terminated branches (fall through to break / end of the switch). */ + +extern void bar (int); + +void +f (int i) +{ + switch (i) + { + case 1: + bar (1); + default: + return; + } + + switch (i) + { + case 1: + bar (1); + default: + goto X; + } +X: + + switch (i) + { + case 1: + bar (1); + default: + break; + } + + switch (i) + { + case 1: + bar (1); + case 2: + case 3: + default: + break; + } + + switch (i) + { + case 1: + bar (1); + default:; + } + + switch (i) + { + case 1: + bar (1); + case 2: + case 3: + default:; + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c new file mode 100644 index 0000000..b7c825b --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-14.c @@ -0,0 +1,162 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +/* Test various falls through comments. */ + +extern void bar (int); + +void +fn (int i) +{ + switch (i) + { + case -1: + bar (-1); + /*-fallthrough*/ + case 0: + bar (0); + /*@fallthrough@*/ + case 1: + bar (1); + /* FALL THRU */ + case 2: + bar (2); + /* FALLTHRU */ + case 3: + bar (3); + /* FALLS THRU */ + case 4: + bar (4); + /* FALL-THRU */ + case 5: + bar (5); + /* FALL THROUGH */ + case 6: + bar (6); + /* FALLTHROUGH */ + case 7: + bar (7); + /* FALLS THROUGH */ + case 8: + bar (8); + /* FALL-THROUGH */ + case 9: + bar (9); + /*FALLTHRU*/ + case 10: + bar (10); + /* FALLTHRU.*/ + case 11: + bar (11); + /* FALLTHROUGH. */ + case 12: + bar (12); + /* Fall thru */ + case 13: + bar (13); + /* Falls thru */ + case 14: + bar (14); + /* Fall-thru */ + case 15: + bar (15); + /* Fall Thru */ + case 16: + bar (16); + /* Falls Thru */ + case 17: + bar (17); + /* Fall-Thru */ + case 18: + bar (18); + /* Fall through */ + case 19: + bar (19); + /* Falls through */ + case 20: + bar (20); + /* Fall-through */ + case 21: + bar (21); + /* Fall Through */ + case 22: + bar (22); + /* Falls Through */ + case 23: + bar (23); + /* Fall-Through */ + case 24: + bar (24); + /* Falls through. */ + case 25: + bar (25); + /* Falls through. */ + case 26: + bar (26); + /* fall thru */ + case 27: + bar (27); + /* falls thru */ + case 28: + bar (28); + /* fall-thru */ + case 29: + bar (29); + /* fall thru */ + case 30: + bar (30); + /* falls thru */ + case 31: + bar (31); + /* fall-thru */ + case 32: + bar (32); + /* fall through */ + case 33: + bar (33); + /* falls through */ + case 34: + bar (34); + /* fall-through */ + default: + bar (99); + } + + switch (i) + { + case 0: + i++; + /*@fallthrough@*/ +L: + default: + bar (6); + } + + { + __label__ L2; + switch (i) + { + case 0: + i++; + /*@fallthrough@*/ +L2: + default: + bar (6); + } + } + + /* Don't generate false -Wswitch-unreachable warning. */ + switch (i) + { + /*FALLTHROUGH*/ + case 0: + i++; + } + + if (i) + { + /* fall through */ + L1:; + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c new file mode 100644 index 0000000..ee3e52d --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-15.c @@ -0,0 +1,31 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +/* Another nested switch. Check that we don't warn here. */ + +void +f (int i) +{ + int j = 0; + switch (i) + { + case 0: + case 1: + j = 10; + __attribute__((fallthrough)); + case 2: + j += 10; + break; + case 3: + switch (i) + { + case 5: + j += 2; + __attribute__((fallthrough)); + case 6: + j += 4; + break; + } + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c new file mode 100644 index 0000000..923f012 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-16.c @@ -0,0 +1,32 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +/* Another nested switch, and with an initialization on top. Check that + we do warn here. */ + +void +f (int i) +{ + switch (i) + { + case 1: + { + int t = 3; + switch (i) + { + case 3: + if (i > 5) + --i; + i += 10; /* { dg-warning "statement may fall through" } */ + case 4: + t /= 5; + break; + } + break; + } + case 2: + --i; + break; + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c new file mode 100644 index 0000000..23ff5f1 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-17.c @@ -0,0 +1,29 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +/* Another nested switch, and with an initialization on top. Check that + we do not warn here as the case 3 falls through to break. */ + +void +f (int i) +{ + switch (i) + { + case 1: + { + int t = 3; + switch (i) + { + case 3: + i += 10; + case 4: + break; + } + break; + } + case 2: + --i; + break; + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c new file mode 100644 index 0000000..2c8a3cb --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-18.c @@ -0,0 +1,42 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +/* Testing some loops. */ + +int f (void); + +int +g (int i) +{ + switch (i) + { + case 0: + for (;;) + { + if (f ()) /* { dg-warning "statement may fall through" "fall through" { xfail *-*-* } } */ + break; + } + case 1: + return 1; + } + return 0; +} + +int +h (int i) +{ + switch (i) + { + case 0: + do + { + if (f ()) /* { dg-warning "statement may fall through" } */ + break; + } + while (0); + case 1: + return 1; + } + return 0; +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c new file mode 100644 index 0000000..b7a3791 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-19.c @@ -0,0 +1,85 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +/* Testing non-case labels. */ + +int foo (int); + +void +f1 (int i) +{ + switch (i) + { + case 0: + foo (1); + L1: + foo (2); + } + + switch (i) + { + case 0: + foo (1); /* { dg-warning "statement may fall through" } */ + L2: + case 2: + foo (2); + } + + switch (i) + { + case 0: + foo (1); /* { dg-warning "statement may fall through" } */ + case 2: + L3: + foo (2); + } + + switch (i) + { + case 0: + foo (1); /* { dg-warning "statement may fall through" } */ + L4: + case 2: + L5: + foo (2); + } + + switch (i) + { + case 0: + switch (i) + { + case 1: + foo (2); + L6: + foo (3); + } + } + + switch (i) + { + case 0: + switch (i) + { + case 1: + foo (2); /* { dg-warning "statement may fall through" } */ + L7: + case 2: + foo (3); + } + } + + switch (i) + { + case 0: + switch (i) + { + case 1: + foo (2); /* { dg-warning "statement may fall through" } */ + case 2: + L8: + foo (3); + } + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c new file mode 100644 index 0000000..4dfb278 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-2.c @@ -0,0 +1,223 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +extern void bar (int); + +/* Test if without else. */ + +void +f (int i) +{ + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + goto L1; + case 2: +L1: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + goto L2; +L2: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L3; + break; + case 2: +L3: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L4; + break; +L4: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + if (i > 9) + bar (1); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + if (i > 9) + bar (1); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + { int a; } + { + if (i) /* { dg-warning "statement may fall through" } */ + if (i > 9) + bar (1); + } + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + bar (2); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + bar (2); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + if (i) + bar (2); + if (i) + bar (3); + bar (4); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + if (i) + bar (2); + if (i) /* { dg-warning "statement may fall through" } */ + bar (3); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + if (i) + bar (2); + if (i) + bar (3); + bar (4); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + if (i) + bar (2); + if (i) + bar (3); + break; + case 2: + __builtin_abort (); + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c new file mode 100644 index 0000000..d37a840 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-20.c @@ -0,0 +1,41 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +int +f (int i) +{ + switch (i) + { + case -1: + __attribute__((fallthrough)); + default: + __attribute__((fallthrough)); + case 1: + return 6; + case 2 ... 4: + __attribute__((fallthrough)); + case 5: + return 7; + } + return 0; +} + +int +g (int i) +{ + switch (i) + { + case -1: + __attribute__((used)); /* { dg-warning "ignored|only attribute" } */ + default: + __attribute__((used)); /* { dg-warning "ignored|only attribute" } */ + case 1: + return 6; + case 2 ... 4: + __attribute__((used)); /* { dg-warning "ignored|only attribute" } */ + case 5: + return 7; + } + return 0; +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c new file mode 100644 index 0000000..6092a90 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-21.c @@ -0,0 +1,25 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +int +f (int i) +{ + switch (i) + { + case 0: + i++; + __attribute__((fallthrough)); + lab1: + case 1: + i++; + __attribute__((fallthrough)); /* { dg-warning "not preceding" } */ + lab2: + --i; + break; + case 3: + i++; + break; + } + return 0; +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c new file mode 100644 index 0000000..fbb9712 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-3.c @@ -0,0 +1,543 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +extern void bar (int); + +/* Test if with else. */ + +void +f (int i) +{ + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + else + bar (2); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + bar (2); + bar (3); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + bar (2); + bar (3); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + else + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + return; + bar (3); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + return; + bar (3); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + { + bar (1); + bar (2); + bar (3); + bar (4); + } + else + { + bar (5); + bar (6); + bar (7); + bar (8); + } + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + bar (1); + bar (2); + bar (3); + bar (4); + } + else + { + bar (5); + bar (6); + bar (7); + bar (8); + } + bar (9); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + { + } + else + bar (2); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + else + { + } + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + { + } + else + { + } + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + return; + else + { + } + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + { + } + else + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L1; + else + bar (2); /* { dg-warning "statement may fall through" } */ + case 2: +L1: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L2; + else + bar (2); /* { dg-warning "statement may fall through" } */ +L2: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + else + goto L3; + case 2: +L3: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) /* { dg-warning "statement may fall through" } */ + bar (1); + else + goto L4; +L4: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L5; + else + goto L5; +L5: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + bar (2); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + bar (2); + bar (3); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + bar (2); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + bar (2); + bar (3); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + return; + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + return; + bar (3); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + return; + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + return; + bar (3); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + bar (1); + bar (2); + bar (3); + bar (4); + } + else + { + bar (5); + bar (6); + bar (7); + bar (8); + } + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + bar (1); + bar (2); + bar (3); + bar (4); + } + else + { + bar (5); + bar (6); + bar (7); + bar (8); + } + bar (9); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + } + else + bar (2); + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + { + } + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + } + else + { + } + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + return; + else + { + } + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + { + } + else + return; + break; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L6; + else + bar (2); + break; + case 2: +L6: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L7; + else + bar (2); + break; +L7: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + goto L8; + break; + case 2: +L8: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + bar (1); + else + goto L9; + break; +L9: + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i) + goto L10; + else + goto L10; + break; +L10: + case 2: + __builtin_abort (); + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c new file mode 100644 index 0000000..9a0aeb7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-4.c @@ -0,0 +1,250 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +extern void bar (int); + +/* Test if with more elses. */ + +void +f (int i) +{ + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + bar (2); + else if (i > 15) + bar (3); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + bar (2); + else if (i > 15) + bar (3); + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) /* { dg-warning "statement may fall through" } */ + bar (2); + else if (i > 15) + bar (3); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) /* { dg-warning "statement may fall through" } */ + bar (2); + else if (i > 15) + bar (3); + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + return; + else if (i > 15) + bar (3); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + return; + else if (i > 15) + bar (3); + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + bar (4); + else if (i > 15) + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + bar (4); + else if (i > 15) + return; + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) + return; + else if (i > 15) /* { dg-warning "statement may fall through" } */ + bar (3); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) + return; + else if (i > 15) /* { dg-warning "statement may fall through" } */ + bar (3); + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) /* { dg-warning "statement may fall through" } */ + bar (2); + else if (i > 15) + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) /* { dg-warning "statement may fall through" } */ + bar (2); + else if (i > 15) + return; + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + return; + else if (i > 15) + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) /* { dg-warning "statement may fall through" } */ + bar (1); + else if (i > 10) + return; + else if (i > 15) + return; + else + bar (4); + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) + return; + else if (i > 15) /* { dg-warning "statement may fall through" } */ + return; + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) + return; + else if (i > 15) + return; + else + bar (4); /* { dg-warning "statement may fall through" } */ + case 2: + __builtin_abort (); + } + + switch (i) + { + case 1: + if (i > 5) + return; + else if (i > 10) + return; + else if (i > 15) + return; + else + return; + case 2: + __builtin_abort (); + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c new file mode 100644 index 0000000..9317484 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-5.c @@ -0,0 +1,109 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +extern void bar (int); +extern void die (void) __attribute__((noreturn)); + +/* Test may_fallthru-ness. */ + +void +f (int i) +{ + switch (i) + { + case 1: + bar (0); + __attribute__((fallthrough)); + case 2:; + } + + switch (i) + { + case 1: + bar (0); + return; + case 2:; + } + + switch (i) + { + case 1: + bar (0); + break; + case 2:; + } + + switch (i) + { + case 1: + bar (0); + goto L1; +L1: + case 2:; + } + + switch (i) + { + case 1: + bar (0); + die (); + case 2:; + } + + switch (i) + { + case 1: + { + int i, j, k; + bar (0); + __attribute__((fallthrough)); + } + case 2:; + } + + switch (i) + { + case 1: + { + int i, j, k; + bar (0); + return; + } + case 2:; + } + + switch (i) + { + case 1: + { + int i, j, k; + bar (0); + break; + } + case 2:; + } + + switch (i) + { + case 1: + { + int i, j, k; + bar (0); + goto L2; + } +L2: + case 2:; + } + + switch (i) + { + case 1: + { + int i, j, k; + bar (0); + die (); + } + case 2:; + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c new file mode 100644 index 0000000..8364c1b --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-6.c @@ -0,0 +1,305 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +extern void bar (int); + +/* Test nested scopes. */ + +void +f (int i) +{ + switch (i) + { + case 1: + { + int j; + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 10; /* { dg-warning "statement may fall through" } */ + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int k = 9; + k++; + { + int j = 10; + j++; /* { dg-warning "statement may fall through" } */ + } + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int k = 9; + k++; + { + int j = 10; + j++; + { + bar (1); /* { dg-warning "statement may fall through" } */ + } + } + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + __attribute__((fallthrough)); + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + { + int k = j + 5; + bar (k); + __attribute__((fallthrough)); + } + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + return; + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + goto L1; + } +L1: + case 2: + bar (99); + } + + switch (i) + { + case 1: + { /* { dg-warning "statement may fall through" "" { target c } 120 } */ + int j = 0; + bar (j); + if (j == 8) + return; /* { dg-warning "statement may fall through" "" { target c++ } 124 } */ + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + return; + else + return; + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { /* { dg-warning "statement may fall through" "" { target c } 148 } */ + int j = 0; + bar (j); + if (j == 8) + bar (1); + else + return; /* { dg-warning "statement may fall through" "" { target c++ } 154 } */ + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + return; + else + bar (2); /* { dg-warning "statement may fall through" } */ + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { /* { dg-warning "statement may fall through" "" { target c } 178 } */ + int j = 0; + bar (j); + if (j == 8) + bar (1); + else + bar (2); /* { dg-warning "statement may fall through" "" { target c++ } 184 } */ + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + return; + } + break; + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + return; + else + return; + } + break; + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + bar (1); + else + return; + } + break; + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + return; + else + bar (2); + } + break; + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + bar (1); + else + bar (2); + } + break; + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 9; + while (1); + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { /* { dg-warning "statement may fall through" "" { target c } 282 } */ + int j = 9; + switch (j); /* { dg-warning "statement may fall through" "" { target c++ } 284 } */ + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + int j = 0; + bar (j); + if (j == 8) + bar (1); + else + bar (2); + __attribute__((fallthrough)); + } + case 2: + bar (99); + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c new file mode 100644 index 0000000..21a158c --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-7.c @@ -0,0 +1,124 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +extern void bar (int); +extern int bar2 (void); +extern int *map; +void +f (int i) +{ + switch (i) + { + case 1: + bar (0); /* { dg-warning "statement may fall through" } */ + static int i = 10; + case 2: + bar (99); + } + + switch (i) + { + case 1: + { /* { dg-warning "statement may fall through" "" { target c } 23 } */ + int a[i]; /* { dg-warning "statement may fall through" "" { target c++ } 24 } */ + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + for (int j = 0; j < 10; j++) /* { dg-warning "statement may fall through" "" { target c } 33 } */ + map[j] = j; /* { dg-warning "statement may fall through" "" { target c++ } 34 } */ + case 2: + bar (99); + } + + switch (i) + { + case 1: + do /* { dg-warning "statement may fall through" "" { target c++ } 42 } */ + bar (2); + while (--i); /* { dg-warning "statement may fall through" "" { target c } 44 } */ + case 2: + bar (99); + } + + switch (i) + { + case 1: + { + switch (i + 2) + case 4: + bar (1); /* { dg-warning "statement may fall through" } */ + case 5: + bar (5); + return; + } + case 2: + bar (99); + } + + switch (i) + { + case 1:; + case 2:; + } + + switch (i) + { + } + + switch (i) + { + case 1: + if (i & 1) /* { dg-warning "statement may fall through" } */ + { + bar (23); + break; + } + case 2: + bar (99); + } + + switch (i) + { + case 1: + if (i > 9) /* { dg-warning "statement may fall through" } */ + { + bar (9); + if (i == 10) + { + bar (10); + break; + } + } + case 2: + bar (99); + } + + int r; + switch (i) + { + case 1: + r = bar2 (); + if (r) /* { dg-warning "statement may fall through" } */ + break; + case 2: + bar (99); + } + + switch (i) + { + case 1: + r = bar2 (); + if (r) + return; + if (!i) /* { dg-warning "statement may fall through" } */ + return; + case 2: + bar (99); + } +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c new file mode 100644 index 0000000..0ed7928 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-8.c @@ -0,0 +1,101 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +extern void grace (int); + +int +fn1 (int i) +{ + switch (i) + case 1: + if (i == 5) + grace (0); + else + goto done; +done:; +} + +int +fn2 (int i) +{ + switch (i) + { + case 1: + if (i == 5) /* { dg-warning "statement may fall through" } */ + grace (0); + else + goto done; + case 2: + --i; + } +done:; +} + +int +fn3 (int i) +{ + switch (i) + { + case 1: + if (i == 5) + goto done; + else + goto done; + } +done:; +} + +int +fn4 (int i) +{ + switch (i) + { + case 1: + if (i == 5) + { + grace (1); + goto done; + } + else + goto done; + case 2:; + } +done:; +} + +int +fn5 (int i) +{ + switch (i) + { + case 1: + if (i == 5) + { + grace (1); + goto done; + } + else + grace (4); /* { dg-warning "statement may fall through" } */ + case 2: + grace (9); + } +done:; +} + +int +fn6 (int i) +{ + switch (i) + { + case 1: + if (i == 5) /* { dg-warning "statement may fall through" } */ + { + grace (1); + goto done; + } + case 2: + grace (8); + } +done:; +} diff --git a/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c new file mode 100644 index 0000000..394d699 --- /dev/null +++ b/gcc/testsuite/c-c++-common/Wimplicit-fallthrough-9.c @@ -0,0 +1,26 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ + +/* Test we don't remove FALLTHROUGH () too early. */ + +extern void h (int); + +void +g (int i) +{ + switch (i) + { + case 1: + { + switch (i) + { + case 3: + h (7); + __attribute__((fallthrough)); + case 4:; + } + } + case 2:; + } +} diff --git a/gcc/testsuite/c-c++-common/attr-fallthrough-1.c b/gcc/testsuite/c-c++-common/attr-fallthrough-1.c new file mode 100644 index 0000000..ecfd094 --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-fallthrough-1.c @@ -0,0 +1,57 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wall -Wextra -Wpedantic" } */ + +extern void bar (int); +void +fn (int i) +{ + __attribute__((fallthrough)) int j = 0; /* { dg-warning "ignored|attribute not followed" } */ + + if (j) + __attribute__((fallthrough)); /* { dg-error "invalid use" } */ + + __attribute__((fallthrough)); /* { dg-error "invalid use" } */ + switch (i) + { + __attribute__((fallthrough)); /* { dg-warning "statement will never" } */ + case 1: + i++; + __attribute__((fallthrough)); + case 2: + if (i) /* { dg-warning "statement may fall through" } */ + bar (2); + else + __attribute__((fallthrough)); + case 3: + if (i > 1) + __attribute__((fallthrough)); + else + return; + case 4: + if (i) + __attribute__((fallthrough)); /* { dg-warning "not preceding" } */ + __attribute__((fallthrough)); + case 5: + ; + __attribute__((fallthrough)); + case 6: + if (i) /* { dg-warning "statement may fall through" } */ + bar (6); + else + { + __attribute__((fallthrough)); + } + case 7: + if (i > 1) + { + __attribute__((fallthrough)); + } + else + bar (7); /* { dg-warning "statement may fall through" } */ + default: + --j; + } + + __attribute__((fallthrough)); /* { dg-error "invalid use" } */ +} diff --git a/gcc/testsuite/c-c++-common/attr-fallthrough-2.c b/gcc/testsuite/c-c++-common/attr-fallthrough-2.c new file mode 100644 index 0000000..959564b --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-fallthrough-2.c @@ -0,0 +1,54 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wall -Wextra -Wpedantic -Wno-unused -Wno-implicit-fallthrough" } */ + +extern void bar (int); +void +fn (int i) +{ + switch (i) + { + case 1: + bar (1); + __attribute__((used)); + /* { dg-warning "empty declaration" "" { target c } 13 } */ + /* { dg-warning "ignored" "" { target c++ } 13 } */ + case 2: + bar (1); + __attribute__((foo)); + /* { dg-warning "empty declaration" "" { target c } 18 } */ + /* { dg-warning "ignored" "" { target c++ } 18 } */ + case 3: + bar (1); + __attribute__((fallthrough)) /* { dg-warning "not followed" "" { target c } } */ + case 4: /* { dg-error "expected" } */ + bar (1); + __attribute__((fallthrough)) 1; + /* { dg-error "expected" "" { target c } 26 } */ + /* { dg-warning "not followed" "" { target *-*-* } 26 } */ + case 5: + bar (1); + __attribute__((fallthrough)) int i; /* { dg-warning "ignored|not followed" } */ + case 6: + bar (1); + __attribute__((fallthrough ("x"))); /* { dg-warning "specified with a parameter" } */ + case 7: + bar (1); + __attribute__((fallthrough, fallthrough)); /* { dg-warning "attribute specified multiple times" } */ + case 8: + bar (1); + __attribute__((fallthrough)); + case 9: + __attribute__((fallthrough)); + /* { dg-warning "not preceding" "" { target *-*-* } 42 } */ + bar (1); + case 10: + bar (1); + __attribute__((unused, fallthrough)); /* { dg-warning "attribute ignored" } */ + case 11: + bar (1); + __attribute__((fallthrough, unused)); /* { dg-warning "attribute ignored" } */ + default: + bar (99); + } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C b/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C new file mode 100644 index 0000000..523067e --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/fallthrough1.C @@ -0,0 +1,57 @@ +// PR c/7652 +// { dg-do compile { target c++11 } } +// { dg-options "-Wextra -Wall -Wpedantic" } + +extern void bar (int); +void +fn (int i) +{ + [[gnu::fallthrough]] int j = 0; // { dg-warning "attribute ignored" } + + if (j) + [[gnu::fallthrough]]; // { dg-error "invalid use" } + + [[gnu::fallthrough]]; // { dg-error "invalid use" } + switch (i) + { + [[gnu::fallthrough]]; // { dg-warning "statement will never" } + case 1: + i++; + [[gnu::fallthrough]]; + case 2: + if (i) // { dg-warning "statement may fall through" } + bar (2); + else + [[gnu::fallthrough]]; + case 3: + if (i > 1) + [[gnu::fallthrough]]; + else + return; + case 4: + if (i) + [[gnu::fallthrough]]; // { dg-warning "not preceding" } + [[gnu::fallthrough]]; + case 5: + ; + [[gnu::fallthrough]]; + case 6: + if (i) // { dg-warning "statement may fall through" } + bar (6); + else + { + [[gnu::fallthrough]]; + } + case 7: + if (i > 1) + { + [[gnu::fallthrough]]; + } + else + bar (7); // { dg-warning "statement may fall through" } + default: + --j; + } + + [[gnu::fallthrough]]; // { dg-error "invalid use" } +} diff --git a/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C b/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C new file mode 100644 index 0000000..b6964e1 --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp0x/fallthrough2.C @@ -0,0 +1,21 @@ +// PR c/7652 +// { dg-do compile { target c++11 } } +// { dg-options "-Wextra -Wall -Wpedantic" } + +extern void bar (int); + +void +f (int i) +{ + switch (i) + { + case 1: + bar (1); + [[fallthrough]]; // { dg-warning ".fallthrough. is a C\\+\\+17 feature" } + case 3: + bar (1); + [[gnu::fallthrough, gnu::fallthrough]]; // { dg-warning ".fallthrough. attribute specified multiple times" } + case 2: + bar (2); + } +} diff --git a/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C b/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C new file mode 100644 index 0000000..d15b1ea --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/fallthrough1.C @@ -0,0 +1,20 @@ +// PR c/7652 +// { dg-do compile } +// { dg-options "-std=c++1z -Wextra -Wall -Wpedantic" } + +// Check that we accept attribute [[fallthrough]]. + +extern void bar (int); + +void +f (int i) +{ + switch (i) + { + case 1: + bar (1); + [[fallthrough]]; + case 2: + bar (2); + } +} diff --git a/gcc/testsuite/g++.dg/warn/Wunused-label-1.C b/gcc/testsuite/g++.dg/warn/Wunused-label-1.C index 96f49b3..255a26e 100644 --- a/gcc/testsuite/g++.dg/warn/Wunused-label-1.C +++ b/gcc/testsuite/g++.dg/warn/Wunused-label-1.C @@ -21,7 +21,7 @@ void f3() { // The next line would be OK in C but is a syntax error in C++. - l2: __attribute__ ((unused)) f9(); // { dg-error "expected" } + l2: __attribute__ ((unused)) f9(); // { dg-warning "ignored" } // We still get an unused label warning--this is // optional and can be removed if it ever changes. // { dg-warning "not used" "expected" { target *-*-* } 24 } diff --git a/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c b/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c new file mode 100644 index 0000000..f8b54f5 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wimplicit-fallthrough-1.c @@ -0,0 +1,22 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough -Wdeclaration-after-statement" } */ + +/* Test we don't print bogus "mixed declarations and code" warning. */ + +int +f (int b) +{ + switch (b) + { + case 0: + b++; + __attribute__((fallthrough)); + case 1: + b--; + __attribute__((unused)) int a; /* { dg-warning "mixed declarations and code" } */ + case 2: + break; + } + return 99; +} diff --git a/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm b/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm new file mode 100644 index 0000000..b45880f --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/Wimplicit-fallthrough-1.mm @@ -0,0 +1,38 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ +/* Test taken from + . */ + +extern void f (int); + +void +foo (int n) +{ + switch (n) + { + case 22: + case 33: + f (1); /* { dg-warning "statement may fall through" } */ + case 44: + f (2); + __attribute__((fallthrough)); + case 55: + if (n > 10) + { + f (3); + break; + } + else + { + f (4); + __attribute__((fallthrough)); + } + case 66: + f (5); + __attribute__((fallthrough)); /* { dg-warning "not preceding" } */ + f (6); /* { dg-warning "statement may fall through" } */ + case 77: + f (7); + } +} diff --git a/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m b/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m new file mode 100644 index 0000000..b45880f --- /dev/null +++ b/gcc/testsuite/objc.dg/Wimplicit-fallthrough-1.m @@ -0,0 +1,38 @@ +/* PR c/7652 */ +/* { dg-do compile } */ +/* { dg-options "-Wimplicit-fallthrough" } */ +/* Test taken from + . */ + +extern void f (int); + +void +foo (int n) +{ + switch (n) + { + case 22: + case 33: + f (1); /* { dg-warning "statement may fall through" } */ + case 44: + f (2); + __attribute__((fallthrough)); + case 55: + if (n > 10) + { + f (3); + break; + } + else + { + f (4); + __attribute__((fallthrough)); + } + case 66: + f (5); + __attribute__((fallthrough)); /* { dg-warning "not preceding" } */ + f (6); /* { dg-warning "statement may fall through" } */ + case 77: + f (7); + } +} diff --git a/gcc/tree-core.h b/gcc/tree-core.h index 0d48ff5..f9ec151 100644 --- a/gcc/tree-core.h +++ b/gcc/tree-core.h @@ -1036,6 +1036,9 @@ struct GTY(()) tree_base { TRANSACTION_EXPR_RELAXED in TRANSACTION_EXPR + FALLTHROUGH_LABEL_P in + LABEL_DECL + private_flag: TREE_PRIVATE in diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index a016e9f..cab0041 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -1748,8 +1748,8 @@ find_deriving_biv_for_expr (struct ivopts_data *data, tree expr) iv = find_deriving_biv_for_expr (data, e2); if (iv) return iv; + gcc_fallthrough (); - /* Fallthru. */ CASE_CONVERT: /* Casts are simple. */ return find_deriving_biv_for_expr (data, e1); diff --git a/gcc/tree.h b/gcc/tree.h index 5cbce77..b6dd4cd 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -766,6 +766,11 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int, computed gotos. */ #define FORCED_LABEL(NODE) (LABEL_DECL_CHECK (NODE)->base.side_effects_flag) +/* Whether a case or a user-defined label is allowed to fall through to. + This is used to implement -Wimplicit-fallthrough. */ +#define FALLTHROUGH_LABEL_P(NODE) \ + (LABEL_DECL_CHECK (NODE)->base.public_flag) + /* Nonzero means this expression is volatile in the C sense: its address should be of type `volatile WHATEVER *'. In other words, the declared item is volatile qualified. diff --git a/gcc/varasm.c b/gcc/varasm.c index c709c8e..2c48b93 100644 --- a/gcc/varasm.c +++ b/gcc/varasm.c @@ -4166,7 +4166,7 @@ output_addressed_constants (tree exp) case POINTER_PLUS_EXPR: case MINUS_EXPR: output_addressed_constants (TREE_OPERAND (exp, 1)); - /* Fall through. */ + gcc_fallthrough (); CASE_CONVERT: case VIEW_CONVERT_EXPR: diff --git a/libcpp/include/cpplib.h b/libcpp/include/cpplib.h index 35b0375..49c9640 100644 --- a/libcpp/include/cpplib.h +++ b/libcpp/include/cpplib.h @@ -185,7 +185,8 @@ struct GTY(()) cpp_string { #define STRINGIFY_ARG (1 << 2) /* If macro argument to be stringified. */ #define PASTE_LEFT (1 << 3) /* If on LHS of a ## operator. */ #define NAMED_OP (1 << 4) /* C++ named operators. */ -#define NO_EXPAND (1 << 5) /* Do not macro-expand this token. */ +#define PREV_FALLTHROUGH (1 << 5) /* On a token preceeded by FALLTHROUGH + comment. */ #define BOL (1 << 6) /* Token at beginning of line. */ #define PURE_ZERO (1 << 7) /* Single 0 digit, used by the C++ frontend, set in c-lex.c. */ @@ -193,6 +194,7 @@ struct GTY(()) cpp_string { #define SP_PREV_WHITE (1 << 9) /* If whitespace before a ## operator, or before this token after a # operator. */ +#define NO_EXPAND (1 << 10) /* Do not macro-expand this token. */ /* Specify which field, if any, of the cpp_token union is used. */ diff --git a/libcpp/lex.c b/libcpp/lex.c index 8508bd02a..4d42f57 100644 --- a/libcpp/lex.c +++ b/libcpp/lex.c @@ -2032,6 +2032,94 @@ save_comment (cpp_reader *pfile, cpp_token *token, const unsigned char *from, store_comment (pfile, token); } +/* Returns true if comment at COMMENT_START is a recognized FALLTHROUGH + comment. */ + +static bool +fallthrough_comment_p (cpp_reader *pfile, const unsigned char *comment_start) +{ + const unsigned char *from = comment_start + 1; + /* Whole comment contents: + -fallthrough + @fallthrough@ + */ + if (*from == '-' || *from == '@') + { + size_t len = sizeof "fallthrough" - 1; + if ((size_t) (pfile->buffer->cur - from - 1) < len) + return false; + if (memcmp (from + 1, "fallthrough", len)) + return false; + if (*from == '@') + { + if (from[len + 1] != '@') + return false; + len++; + } + from += 1 + len; + } + /* Whole comment contents (regex): + [ \t]*FALL(S | |-)?THR(OUGH|U)\.?[ \t]* + [ \t]*Fall(s | |-)?[Tt]hr(ough|u)\.?[ \t]* + [ \t]*fall(s | |-)?thr(ough|u)\.?[ \t]* + */ + else + { + while (*from == ' ' || *from == '\t') + from++; + unsigned char f = *from; + if (f != 'F' && f != 'f') + return false; + if ((size_t) (pfile->buffer->cur - from) < sizeof "fallthrough") + return false; + bool all_upper = false; + if (f == 'F' && memcmp (from + 1, "ALL", sizeof "ALL" - 1) == 0) + all_upper = true; + else if (memcmp (from + 1, "all", sizeof "all" - 1)) + return false; + if (from[sizeof "fall" - 1] == (all_upper ? 'S' : 's') + && from[sizeof "falls" - 1] == ' ') + from += sizeof "falls " - 1; + else if (from[sizeof "fall" - 1] == ' ' + || from[sizeof "fall" - 1] == '-') + from += sizeof "fall " - 1; + else if (from[sizeof "fall" - 1] != (all_upper ? 'T' : 't')) + return false; + else + from += sizeof "fall" - 1; + if ((f == 'f' || *from != 'T') && (all_upper || *from != 't')) + return false; + if ((size_t) (pfile->buffer->cur - from) < sizeof "thru") + return false; + if (memcmp (from + 1, all_upper ? "HRU" : "hru", sizeof "hru" - 1)) + { + if ((size_t) (pfile->buffer->cur - from) < sizeof "through") + return false; + if (memcmp (from + 1, all_upper ? "HROUGH" : "hrough", + sizeof "hrough" - 1)) + return false; + from += sizeof "through" - 1; + } + else + from += sizeof "thru" - 1; + if (*from == '.') + from++; + while (*from == ' ' || *from == '\t') + from++; + } + /* C block comment. */ + if (*comment_start == '*') + { + if (*from != '*' || from[1] != '/') + return false; + } + /* C++ line comment. */ + else if (*from != '\n') + return false; + + return true; +} + /* Allocate COUNT tokens for RUN. */ void _cpp_init_tokenrun (tokenrun *run, unsigned int count) @@ -2310,7 +2398,7 @@ _cpp_lex_direct (cpp_reader *pfile) { cppchar_t c; cpp_buffer *buffer; - const unsigned char *comment_start; + const unsigned char *comment_start = NULL; cpp_token *result = pfile->cur_token++; fresh_line: @@ -2337,6 +2425,8 @@ _cpp_lex_direct (cpp_reader *pfile) } return result; } + if (buffer != pfile->buffer) + comment_start = NULL; if (!pfile->keep_tokens) { pfile->cur_run = &pfile->base_run; @@ -2443,6 +2533,11 @@ _cpp_lex_direct (cpp_reader *pfile) result->flags |= NAMED_OP; result->type = (enum cpp_ttype) result->val.node.node->directive_index; } + + /* Signal FALLTHROUGH comment followed by another token. */ + if (comment_start + && fallthrough_comment_p (pfile, comment_start)) + result->flags |= PREV_FALLTHROUGH; break; case '\'': @@ -2534,6 +2629,9 @@ _cpp_lex_direct (cpp_reader *pfile) goto update_tokens_line; } + if (fallthrough_comment_p (pfile, comment_start)) + result->flags |= PREV_FALLTHROUGH; + /* Save the comment as a token in its own right. */ save_comment (pfile, result, comment_start, c); break; diff --git a/libstdc++-v3/libsupc++/hash_bytes.cc b/libstdc++-v3/libsupc++/hash_bytes.cc index 2e5bbfa..1042de6 100644 --- a/libstdc++-v3/libsupc++/hash_bytes.cc +++ b/libstdc++-v3/libsupc++/hash_bytes.cc @@ -95,8 +95,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { case 3: hash ^= static_cast(buf[2]) << 16; + [[gnu::fallthrough]]; case 2: hash ^= static_cast(buf[1]) << 8; + [[gnu::fallthrough]]; case 1: hash ^= static_cast(buf[0]); hash *= m; -- 2.7.4 From d35bac6648c77b0686c3e6088d3f51ec677b9a6b Mon Sep 17 00:00:00 2001 From: marxin Date: Mon, 7 Nov 2016 10:23:38 +0000 Subject: [PATCH 08/16] Introduce -fsanitize-address-use-after-scope * c-warn.c (warn_for_unused_label): Save all labels used in goto or in &label. * asan.c (enum asan_check_flags): Move the enum to header file. (asan_init_shadow_ptr_types): Make type creation more generic. (shadow_mem_size): New function. (asan_emit_stack_protection): Use newly added ASAN_SHADOW_GRANULARITY. Rewritten stack unpoisoning code. (build_shadow_mem_access): Add new argument return_address. (instrument_derefs): Instrument local variables if use after scope sanitization is enabled. (asan_store_shadow_bytes): New function. (asan_expand_mark_ifn): Likewise. (asan_sanitize_stack_p): Moved from asan_sanitize_stack_p. * asan.h (enum asan_mark_flags): Moved here from asan.c (asan_protect_stack_decl): Protect all declaration that need to live in memory. (asan_sanitize_use_after_scope): New function. (asan_no_sanitize_address_p): Likewise. * cfgexpand.c (partition_stack_vars): Consider asan_sanitize_use_after_scope in condition. (expand_stack_vars): Likewise. * common.opt (-fsanitize-address-use-after-scope): New option. * doc/invoke.texi (use-after-scope-direct-emission-threshold): Explain the parameter. * flag-types.h (enum sanitize_code): Define SANITIZE_USE_AFTER_SCOPE. * gimplify.c (build_asan_poison_call_expr): New function. (asan_poison_variable): Likewise. (gimplify_bind_expr): Generate poisoning/unpoisoning for local variables that have address taken. (gimplify_decl_expr): Likewise. (gimplify_target_expr): Likewise for C++ temporaries. (sort_by_decl_uid): New function. (gimplify_expr): Unpoison all variables for a label we can jump from outside of a scope. (gimplify_switch_expr): Unpoison variables defined in the switch context. (gimplify_function_tree): Clear asan_poisoned_variables. (asan_poison_variables): New function. (warn_switch_unreachable_r): Handle IFN_ASAN_MARK. * internal-fn.c (expand_ASAN_MARK): New function. * internal-fn.def (ASAN_MARK): Declare. * opts.c (finish_options): Handle -fstack-reuse if -fsanitize-address-use-after-scope is enabled. (common_handle_option): Enable address sanitization if -fsanitize-address-use-after-scope is enabled. * params.def (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD): New parameter. * params.h: Likewise. * sancov.c (pass_sanopt::execute): Handle IFN_ASAN_MARK. * sanitizer.def: Define __asan_poison_stack_memory and __asan_unpoison_stack_memory functions. * asan.c (asan_mark_poison_p): New function. (transform_statements): Handle asan_mark_poison_p calls. * gimple.c (nonfreeing_call_p): Handle IFN_ASAN_MARK. With fixes for tizen linaro-gcc by Dmitriy Gonzha Change-Id: Ia39cbdfadac97f339dceb973872e15ee0d67ea19 upstream hash: 629b6abce95170a3ee8417479e82615fa1e4b67e git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@241896 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/asan.c | 302 +++++++++++++++++++++++++++++++++++++++--------- gcc/asan.h | 55 ++++++++- gcc/c-family/c-common.c | 8 ++ gcc/cfgexpand.c | 18 +-- gcc/common.opt | 3 + gcc/doc/invoke.texi | 15 ++- gcc/gimple.c | 3 + gcc/gimplify.c | 232 ++++++++++++++++++++++++++++++++++--- gcc/internal-fn.c | 9 ++ gcc/internal-fn.def | 1 + gcc/opts.c | 25 ++++ gcc/params.def | 6 + gcc/params.h | 2 + gcc/sanitizer.def | 4 + gcc/sanopt.c | 3 + 15 files changed, 596 insertions(+), 90 deletions(-) diff --git a/gcc/asan.c b/gcc/asan.c index 4806c3f..b09d1fc 100644 --- a/gcc/asan.c +++ b/gcc/asan.c @@ -243,6 +243,22 @@ static unsigned HOST_WIDE_INT asan_shadow_offset_value; static bool asan_shadow_offset_computed; static vec sanitized_sections; +/* Return true if STMT is ASAN_MARK poisoning internal function call. */ +static inline bool +asan_mark_poison_p (gimple *stmt) +{ + return (gimple_call_internal_p (stmt, IFN_ASAN_MARK) + && tree_to_uhwi (gimple_call_arg (stmt, 0)) == ASAN_MARK_CLOBBER); + +} + +/* Set of variable declarations that are going to be guarded by + use-after-scope sanitizer. */ + +static hash_set *asan_handled_variables = NULL; + +hash_set *asan_used_labels = NULL; + /* Sets shadow offset to value in string VAL. */ bool @@ -285,6 +301,14 @@ set_sanitized_sections (const char *sections) } } +bool +asan_sanitize_stack_p (void) +{ + return ((flag_sanitize & SANITIZE_ADDRESS) + && ASAN_STACK + && !asan_no_sanitize_address_p ()); +} + /* Checks whether section SEC should be sanitized. */ static bool @@ -313,22 +337,13 @@ asan_shadow_offset () alias_set_type asan_shadow_set = -1; -/* Pointer types to 1 resp. 2 byte integers in shadow memory. A separate +/* Pointer types to 1, 2 or 4 byte integers in shadow memory. A separate alias set is used for all shadow memory accesses. */ -static GTY(()) tree shadow_ptr_types[2]; +static GTY(()) tree shadow_ptr_types[3]; /* Decl for __asan_option_detect_stack_use_after_return. */ static GTY(()) tree asan_detect_stack_use_after_return; -/* Various flags for Asan builtins. */ -enum asan_check_flags -{ - ASAN_CHECK_STORE = 1 << 0, - ASAN_CHECK_SCALAR_ACCESS = 1 << 1, - ASAN_CHECK_NON_ZERO_LEN = 1 << 2, - ASAN_CHECK_LAST = 1 << 3 -}; - /* Hashtable support for memory references used by gimple statements. */ @@ -931,12 +946,16 @@ static void asan_init_shadow_ptr_types (void) { asan_shadow_set = new_alias_set (); - shadow_ptr_types[0] = build_distinct_type_copy (signed_char_type_node); - TYPE_ALIAS_SET (shadow_ptr_types[0]) = asan_shadow_set; - shadow_ptr_types[0] = build_pointer_type (shadow_ptr_types[0]); - shadow_ptr_types[1] = build_distinct_type_copy (short_integer_type_node); - TYPE_ALIAS_SET (shadow_ptr_types[1]) = asan_shadow_set; - shadow_ptr_types[1] = build_pointer_type (shadow_ptr_types[1]); + tree types[3] = { signed_char_type_node, short_integer_type_node, + integer_type_node }; + + for (unsigned i = 0; i < 3; i++) + { + shadow_ptr_types[i] = build_distinct_type_copy (types[i]); + TYPE_ALIAS_SET (shadow_ptr_types[i]) = asan_shadow_set; + shadow_ptr_types[i] = build_pointer_type (shadow_ptr_types[i]); + } + initialize_sanitizer_builtins (); } @@ -1020,6 +1039,15 @@ asan_function_start (void) current_function_funcdef_no); } +/* Return number of shadow bytes that are occupied by a local variable + of SIZE bytes. */ + +static unsigned HOST_WIDE_INT +shadow_mem_size (unsigned HOST_WIDE_INT size) +{ + return ROUND_UP (size, ASAN_SHADOW_GRANULARITY) / ASAN_SHADOW_GRANULARITY; +} + /* Insert code to protect stack vars. The prologue sequence should be emitted directly, epilogue sequence returned. BASE is the register holding the stack base, against which OFFSETS array offsets are relative to, OFFSETS @@ -1045,7 +1073,7 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb, HOST_WIDE_INT base_offset = offsets[length - 1]; HOST_WIDE_INT base_align_bias = 0, offset, prev_offset; HOST_WIDE_INT asan_frame_size = offsets[0] - base_offset; - HOST_WIDE_INT last_offset, last_size; + HOST_WIDE_INT last_offset; int l; unsigned char cur_shadow_byte = ASAN_STACK_MAGIC_LEFT; tree str_cst, decl, id; @@ -1203,10 +1231,10 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb, (aoff - prev_offset) >> ASAN_SHADOW_SHIFT); prev_offset = aoff; - for (i = 0; i < 4; i++, aoff += (1 << ASAN_SHADOW_SHIFT)) + for (i = 0; i < 4; i++, aoff += ASAN_SHADOW_GRANULARITY) if (aoff < offset) { - if (aoff < offset - (1 << ASAN_SHADOW_SHIFT) + 1) + if (aoff < offset - (HOST_WIDE_INT)ASAN_SHADOW_GRANULARITY + 1) shadow_bytes[i] = 0; else shadow_bytes[i] = offset - aoff; @@ -1280,35 +1308,66 @@ asan_emit_stack_protection (rtx base, rtx pbase, unsigned int alignb, if (STRICT_ALIGNMENT) set_mem_align (shadow_mem, (GET_MODE_ALIGNMENT (SImode))); - prev_offset = base_offset; + /* Unpoison shadow memory of a stack at the very end of a function. + As we're poisoning stack variables at the end of their scope, + shadow memory must be properly unpoisoned here. The easiest approach + would be to collect all variables that should not be unpoisoned and + we unpoison shadow memory of the whole stack except ranges + occupied by these variables. */ last_offset = base_offset; - last_size = 0; - for (l = length; l; l -= 2) + HOST_WIDE_INT current_offset = last_offset; + if (length) { - offset = base_offset + ((offsets[l - 1] - base_offset) - & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1)); - if (last_offset + last_size != offset) + HOST_WIDE_INT var_end_offset = 0; + HOST_WIDE_INT stack_start = offsets[length - 1]; + gcc_assert (last_offset == stack_start); + + for (int l = length - 2; l > 0; l -= 2) { - shadow_mem = adjust_address (shadow_mem, VOIDmode, - (last_offset - prev_offset) - >> ASAN_SHADOW_SHIFT); - prev_offset = last_offset; - asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT); - last_offset = offset; - last_size = 0; + HOST_WIDE_INT var_offset = offsets[l]; + current_offset = var_offset; + var_end_offset = offsets[l - 1]; + HOST_WIDE_INT rounded_size = ROUND_UP (var_end_offset - var_offset, + BITS_PER_UNIT); + + /* Should we unpoison the variable? */ + if (asan_handled_variables != NULL + && asan_handled_variables->contains (decl)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + const char *n = (DECL_NAME (decl) + ? IDENTIFIER_POINTER (DECL_NAME (decl)) + : ""); + fprintf (dump_file, "Unpoisoning shadow stack for variable: " + "%s (%" PRId64 "B)\n", n, + var_end_offset - var_offset); + } + + unsigned HOST_WIDE_INT s + = shadow_mem_size (current_offset - last_offset); + asan_clear_shadow (shadow_mem, s); + HOST_WIDE_INT shift + = shadow_mem_size (current_offset - last_offset + rounded_size); + shadow_mem = adjust_address (shadow_mem, VOIDmode, shift); + last_offset = var_offset + rounded_size; + current_offset = last_offset; + } + } - last_size += base_offset + ((offsets[l - 2] - base_offset) - & ~(ASAN_RED_ZONE_SIZE - HOST_WIDE_INT_1)) - - offset; - } - if (last_size) - { - shadow_mem = adjust_address (shadow_mem, VOIDmode, - (last_offset - prev_offset) - >> ASAN_SHADOW_SHIFT); - asan_clear_shadow (shadow_mem, last_size >> ASAN_SHADOW_SHIFT); + + /* Handle last redzone. */ + current_offset = offsets[0]; + asan_clear_shadow (shadow_mem, + shadow_mem_size (current_offset - last_offset)); } + /* Clean-up set with instrumented stack variables. */ + delete asan_handled_variables; + asan_handled_variables = NULL; + delete asan_used_labels; + asan_used_labels = NULL; + do_pending_stack_adjust (); if (lab) emit_label (lab); @@ -1598,12 +1657,14 @@ insert_if_then_before_iter (gcond *cond, gsi_insert_after (&cond_insert_point, cond, GSI_NEW_STMT); } -/* Build - (base_addr >> ASAN_SHADOW_SHIFT) + asan_shadow_offset (). */ +/* Build (base_addr >> ASAN_SHADOW_SHIFT) + asan_shadow_offset (). + If RETURN_ADDRESS is set to true, return memory location instread + of a value in the shadow memory. */ static tree build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location, - tree base_addr, tree shadow_ptr_type) + tree base_addr, tree shadow_ptr_type, + bool return_address = false) { tree t, uintptr_type = TREE_TYPE (base_addr); tree shadow_type = TREE_TYPE (shadow_ptr_type); @@ -1626,11 +1687,15 @@ build_shadow_mem_access (gimple_stmt_iterator *gsi, location_t location, gimple_set_location (g, location); gsi_insert_after (gsi, g, GSI_NEW_STMT); - t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g), - build_int_cst (shadow_ptr_type, 0)); - g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t); - gimple_set_location (g, location); - gsi_insert_after (gsi, g, GSI_NEW_STMT); + if (!return_address) + { + t = build2 (MEM_REF, shadow_type, gimple_assign_lhs (g), + build_int_cst (shadow_ptr_type, 0)); + g = gimple_build_assign (make_ssa_name (shadow_type), MEM_REF, t); + gimple_set_location (g, location); + gsi_insert_after (gsi, g, GSI_NEW_STMT); + } + return gimple_assign_lhs (g); } @@ -1834,7 +1899,9 @@ instrument_derefs (gimple_stmt_iterator *iter, tree t, { /* Automatic vars in the current function will be always accessible. */ - if (decl_function_context (inner) == current_function_decl) + if (decl_function_context (inner) == current_function_decl + && (!asan_sanitize_use_after_scope () + || !TREE_ADDRESSABLE (inner))) return; } /* Always instrument external vars, they might be dynamically @@ -2149,8 +2216,10 @@ transform_statements (void) If the current instruction is a function call that might free something, let's forget about the memory references that got instrumented. Otherwise we might - miss some instrumentation opportunities. */ - if (is_gimple_call (s) && !nonfreeing_call_p (s)) + miss some instrumentation opportunities. Do the same + for a ASAN_MARK poisoning internal function. */ + if (is_gimple_call (s) + && (!nonfreeing_call_p (s) || asan_mark_poison_p (s))) empty_mem_ref_hash_table (); gsi_next (&i); @@ -2588,6 +2657,131 @@ asan_finish_file (void) flag_sanitize |= SANITIZE_ADDRESS; } +/* Poison or unpoison (depending on IS_CLOBBER variable) shadow memory based + on SHADOW address. Newly added statements will be added to ITER with + given location LOC. We mark SIZE bytes in shadow memory, where + LAST_CHUNK_SIZE is greater than zero in situation where we are at the + end of a variable. */ + +static void +asan_store_shadow_bytes (gimple_stmt_iterator *iter, location_t loc, + tree shadow, + unsigned HOST_WIDE_INT base_addr_offset, + bool is_clobber, unsigned size, + unsigned last_chunk_size) +{ + tree shadow_ptr_type; + + switch (size) + { + case 1: + shadow_ptr_type = shadow_ptr_types[0]; + break; + case 2: + shadow_ptr_type = shadow_ptr_types[1]; + break; + case 4: + shadow_ptr_type = shadow_ptr_types[2]; + break; + default: + gcc_unreachable (); + } + + unsigned char c = (char) is_clobber ? ASAN_STACK_MAGIC_USE_AFTER_SCOPE : 0; + unsigned HOST_WIDE_INT val = 0; + for (unsigned i = 0; i < size; ++i) + { + unsigned char shadow_c = c; + if (i == size - 1 && last_chunk_size && !is_clobber) + shadow_c = last_chunk_size; + val |= (unsigned HOST_WIDE_INT) shadow_c << (BITS_PER_UNIT * i); + } + + /* Handle last chunk in unpoisoning. */ + tree magic = build_int_cst (TREE_TYPE (shadow_ptr_type), val); + + tree dest = build2 (MEM_REF, TREE_TYPE (shadow_ptr_type), shadow, + build_int_cst (shadow_ptr_type, base_addr_offset)); + + gimple *g = gimple_build_assign (dest, magic); + gimple_set_location (g, loc); + gsi_insert_after (iter, g, GSI_NEW_STMT); +} + +/* Expand the ASAN_MARK builtins. */ + +bool +asan_expand_mark_ifn (gimple_stmt_iterator *iter) +{ + gimple *g = gsi_stmt (*iter); + location_t loc = gimple_location (g); + HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0)); + gcc_assert (flags < ASAN_MARK_LAST); + bool is_clobber = (flags & ASAN_MARK_CLOBBER) != 0; + + tree base = gimple_call_arg (g, 1); + gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR); + tree decl = TREE_OPERAND (base, 0); + gcc_checking_assert (TREE_CODE (decl) == VAR_DECL); + if (asan_handled_variables == NULL) + asan_handled_variables = new hash_set (16); + asan_handled_variables->add (decl); + tree len = gimple_call_arg (g, 2); + + gcc_assert (tree_fits_shwi_p (len)); + unsigned HOST_WIDE_INT size_in_bytes = tree_to_shwi (len); + gcc_assert (size_in_bytes); + + g = gimple_build_assign (make_ssa_name (pointer_sized_int_node), + NOP_EXPR, base); + gimple_set_location (g, loc); + gsi_replace (iter, g, false); + tree base_addr = gimple_assign_lhs (g); + + /* Generate direct emission if size_in_bytes is small. */ + if (size_in_bytes <= ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD) + { + unsigned HOST_WIDE_INT shadow_size = shadow_mem_size (size_in_bytes); + + tree shadow = build_shadow_mem_access (iter, loc, base_addr, + shadow_ptr_types[0], true); + + for (unsigned HOST_WIDE_INT offset = 0; offset < shadow_size;) + { + unsigned size = 1; + if (shadow_size - offset >= 4) + size = 4; + else if (shadow_size - offset >= 2) + size = 2; + + unsigned HOST_WIDE_INT last_chunk_size = 0; + unsigned HOST_WIDE_INT s = (offset + size) * ASAN_SHADOW_GRANULARITY; + if (s > size_in_bytes) + last_chunk_size = ASAN_SHADOW_GRANULARITY - (s - size_in_bytes); + + asan_store_shadow_bytes (iter, loc, shadow, offset, is_clobber, + size, last_chunk_size); + offset += size; + } + } + else + { + g = gimple_build_assign (make_ssa_name (pointer_sized_int_node), + NOP_EXPR, len); + gimple_set_location (g, loc); + gsi_insert_before (iter, g, GSI_SAME_STMT); + tree sz_arg = gimple_assign_lhs (g); + + tree fun = builtin_decl_implicit (is_clobber ? BUILT_IN_ASAN_CLOBBER_N + : BUILT_IN_ASAN_UNCLOBBER_N); + g = gimple_build_call (fun, 2, base_addr, sz_arg); + gimple_set_location (g, loc); + gsi_insert_after (iter, g, GSI_NEW_STMT); + } + + return false; +} + /* Expand the ASAN_{LOAD,STORE} builtins. */ bool diff --git a/gcc/asan.h b/gcc/asan.h index 9182c60..214318e 100644 --- a/gcc/asan.h +++ b/gcc/asan.h @@ -29,6 +29,7 @@ extern bool asan_protect_global (tree, bool ignore_decl_rtl_set_p = false); extern void initialize_sanitizer_builtins (void); extern tree asan_dynamic_init_call (bool); extern bool asan_expand_check_ifn (gimple_stmt_iterator *, bool); +extern bool asan_expand_mark_ifn (gimple_stmt_iterator *); extern gimple_stmt_iterator create_cond_insert_point (gimple_stmt_iterator *, bool, bool, bool, basic_block *, basic_block *); @@ -36,9 +37,14 @@ extern gimple_stmt_iterator create_cond_insert_point /* Alias set for accessing the shadow memory. */ extern alias_set_type asan_shadow_set; +/* Hash set of labels that are either used in a goto, or their address + has been taken. */ +extern hash_set *asan_used_labels; + /* Shadow memory is found at (address >> ASAN_SHADOW_SHIFT) + asan_shadow_offset (). */ #define ASAN_SHADOW_SHIFT 3 +#define ASAN_SHADOW_GRANULARITY (1UL << ASAN_SHADOW_SHIFT) /* Red zone size, stack and global variables are padded by ASAN_RED_ZONE_SIZE up to 2 * ASAN_RED_ZONE_SIZE - 1 bytes. */ @@ -59,13 +65,22 @@ extern alias_set_type asan_shadow_set; #define ASAN_STACK_FRAME_MAGIC 0x41b58ab3 #define ASAN_STACK_RETIRED_MAGIC 0x45e0360e -/* Return true if DECL should be guarded on the stack. */ - -static inline bool -asan_protect_stack_decl (tree decl) +/* Various flags for Asan builtins. */ +enum asan_check_flags { - return DECL_P (decl) && !DECL_ARTIFICIAL (decl); -} + ASAN_CHECK_STORE = 1 << 0, + ASAN_CHECK_SCALAR_ACCESS = 1 << 1, + ASAN_CHECK_NON_ZERO_LEN = 1 << 2, + ASAN_CHECK_LAST = 1 << 3 +}; + +/* Flags for Asan check builtins. */ +enum asan_mark_flags +{ + ASAN_MARK_CLOBBER = 1 << 0, + ASAN_MARK_UNCLOBBER = 1 << 1, + ASAN_MARK_LAST = 1 << 2 +}; /* Return the size of padding needed to insert after a protected decl of SIZE. */ @@ -81,6 +96,8 @@ extern bool set_asan_shadow_offset (const char *); extern void set_sanitized_sections (const char *); +extern bool asan_sanitize_stack_p (void); + /* Return TRUE if builtin with given FCODE will be intercepted by libasan. */ @@ -109,4 +126,30 @@ asan_intercepted_p (enum built_in_function fcode) || fcode == BUILT_IN_STRSTR || fcode == BUILT_IN_STRNCPY; } + +/* Return TRUE if we should instrument for use-after-scope sanity checking. */ + +static inline bool +asan_sanitize_use_after_scope (void) +{ + return (flag_sanitize_address_use_after_scope && asan_sanitize_stack_p ()); +} + +static inline bool +asan_no_sanitize_address_p (void) +{ + return lookup_attribute ("no_sanitize_address", + DECL_ATTRIBUTES (current_function_decl)); +} + +/* Return true if DECL should be guarded on the stack. */ + +static inline bool +asan_protect_stack_decl (tree decl) +{ + return DECL_P (decl) + && (!DECL_ARTIFICIAL (decl) + || (asan_sanitize_use_after_scope () && TREE_ADDRESSABLE (decl))); +} + #endif /* TREE_ASAN */ diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 4fd0016..b2b36b5 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -46,6 +46,7 @@ along with GCC; see the file COPYING3. If not see #include "tree-iterator.h" #include "opts.h" #include "gimplify.h" +#include "asan.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ @@ -11838,6 +11839,13 @@ warn_for_unused_label (tree label) else warning (OPT_Wunused_label, "label %q+D declared but not defined", label); } + else if (asan_sanitize_use_after_scope ()) + { + if (asan_used_labels == NULL) + asan_used_labels = new hash_set (16); + + asan_used_labels->add (label); + } } /* Warn for division by zero according to the value of DIVISOR. LOC diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 20a0fc2..475e2f6 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -868,18 +868,6 @@ union_stack_vars (size_t a, size_t b) } } -/* Return true if the current function should have its stack frame - protected by address sanitizer. */ - -static inline bool -asan_sanitize_stack_p (void) -{ - return ((flag_sanitize & SANITIZE_ADDRESS) - && ASAN_STACK - && !lookup_attribute ("no_sanitize_address", - DECL_ATTRIBUTES (current_function_decl))); -} - /* A subroutine of expand_used_vars. Binpack the variables into partitions constrained by the interference graph. The overall algorithm used is as follows: @@ -941,7 +929,8 @@ partition_stack_vars (void) sizes, as the shorter vars wouldn't be adequately protected. Don't do that for "large" (unsupported) alignment objects, those aren't protected anyway. */ - if (asan_sanitize_stack_p () && isize != jsize + if ((asan_sanitize_stack_p ()) + && isize != jsize && ialign * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT) break; @@ -1132,7 +1121,8 @@ expand_stack_vars (bool (*pred) (size_t), struct stack_vars_data *data) if (alignb * BITS_PER_UNIT <= MAX_SUPPORTED_STACK_ALIGNMENT) { base = virtual_stack_vars_rtx; - if (asan_sanitize_stack_p () && pred) + if ((asan_sanitize_stack_p ()) + && pred) { HOST_WIDE_INT prev_offset = align_base (frame_offset, diff --git a/gcc/common.opt b/gcc/common.opt index b3498eb..aaaf467 100644 --- a/gcc/common.opt +++ b/gcc/common.opt @@ -965,6 +965,9 @@ fsanitize-recover Common Report This switch is deprecated; use -fsanitize-recover= instead. +fsanitize-address-use-after-scope +Common Driver Report Var(flag_sanitize_address_use_after_scope) Init(0) + fsanitize-undefined-trap-on-error Common Driver Report Var(flag_sanitize_undefined_trap_on_error) Init(0) Use trap instead of a library function for undefined behavior sanitization. diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 9d4f65d..39b7d58 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -9696,6 +9696,10 @@ is greater or equal to this number, use callbacks instead of inline checks. E.g. to disable inline code use @option{--param asan-instrumentation-with-call-threshold=0}. +@item use-after-scope-direct-emission-threshold +If size of a local variables in bytes is smaller of equal to this number, +direct instruction emission is utilized to poison and unpoison local variables. + @item chkp-max-ctor-size Static constructors generated by Pointer Bounds Checker may become very large and significantly increase compile time at optimization level @@ -9890,6 +9894,7 @@ To optimize the program based on the collected profile information, use Enable AddressSanitizer, a fast memory error detector. Memory access instructions are instrumented to detect out-of-bounds and use-after-free bugs. +The option enables @option{-fsanitize-address-use-after-scope}. See @uref{https://github.com/google/sanitizers/wiki/AddressSanitizer} for more details. The run-time behavior can be influenced using the @env{ASAN_OPTIONS} environment variable. When set to @code{help=1}, @@ -9900,6 +9905,7 @@ for a list of supported options. @item -fsanitize=kernel-address @opindex fsanitize=kernel-address Enable AddressSanitizer for Linux kernel. +The option enables @option{-fsanitize-address-use-after-scope}. See @uref{https://github.com/google/kasan/wiki} for more details. @item -fsanitize=thread @@ -10104,8 +10110,8 @@ Currently this feature only works for @option{-fsanitize=undefined} (and its sub except for @option{-fsanitize=unreachable} and @option{-fsanitize=return}), @option{-fsanitize=float-cast-overflow}, @option{-fsanitize=float-divide-by-zero}, @option{-fsanitize=kernel-address} and @option{-fsanitize=address}. -For these sanitizers error recovery is turned on by default, except @option{-fsanitize=address}, -for which this feature is experimental. +For these sanitizers error recovery is turned on by default, +except @option{-fsanitize=address}, for which this feature is experimental. @option{-fsanitize-recover=all} and @option{-fno-sanitize-recover=all} is also accepted, the former enables recovery for all sanitizers that support it, the latter disables recovery for all sanitizers that support it. @@ -10120,6 +10126,11 @@ Similarly @option{-fno-sanitize-recover} is equivalent to -fno-sanitize-recover=undefined,float-cast-overflow,float-divide-by-zero @end smallexample +@item -fsanitize-address-use-after-scope +@opindex fsanitize-address-use-after-scope +Enable sanitization of local variables to detect use-after-scope bugs. +The option sets @option{-fstack-reuse} to @samp{none}. + @item -fsanitize-undefined-trap-on-error @opindex fsanitize-undefined-trap-on-error The @option{-fsanitize-undefined-trap-on-error} option instructs the compiler to diff --git a/gcc/gimple.c b/gcc/gimple.c index 9200a8b..973bcd7 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -39,6 +39,7 @@ along with GCC; see the file COPYING3. If not see #include "gimplify.h" #include "target.h" #include "builtins.h" +#include "asan.h" /* All the tuples have their operand vector (if present) at the very bottom @@ -2624,6 +2625,8 @@ nonfreeing_call_p (gimple *call) { case IFN_ABNORMAL_DISPATCHER: return true; + case IFN_ASAN_MARK: + return tree_to_uhwi (gimple_call_arg (call, 0)) == ASAN_MARK_UNCLOBBER; default: if (gimple_call_flags (call) & ECF_LEAF) return true; diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 590c65a..5fdf0cd 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -59,6 +59,10 @@ along with GCC; see the file COPYING3. If not see #include "gimple-walk.h" #include "langhooks-def.h" /* FIXME: for lhd_set_decl_assembler_name */ #include "builtins.h" +#include "asan.h" + +/* Hash set of poisoned variables in a bind expr. */ +static hash_set *asan_poisoned_variables = NULL; enum gimplify_omp_var_data { @@ -151,6 +155,7 @@ struct gimplify_ctx tree return_temp; vec case_labels; + hash_set *live_switch_vars; /* The formal temporary table. Should this be persistent? */ hash_table *temp_htab; @@ -1081,6 +1086,121 @@ build_stack_save_restore (gcall **save, gcall **restore) 1, tmp_var); } +/* Generate IFN_ASAN_MARK call that poisons shadow of a for DECL variable. */ + +static tree +build_asan_poison_call_expr (tree decl) +{ + /* Do not poison variables that have size equal to zero. */ + tree unit_size = DECL_SIZE_UNIT (decl); + if (zerop (unit_size)) + return NULL_TREE; + + tree base = build_fold_addr_expr (decl); + + return build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_ASAN_MARK, + void_type_node, 3, + build_int_cst (integer_type_node, + ASAN_MARK_CLOBBER), + base, unit_size); +} + +/* Generate IFN_ASAN_MARK call that would poison or unpoison, depending + on POISON flag, shadow memory of a DECL variable. The call will be + put on location identified by IT iterator, where BEFORE flag drives + position where the stmt will be put. */ + +static void +asan_poison_variable (tree decl, bool poison, gimple_stmt_iterator *it, + bool before) +{ + /* When within an OMP context, do not emit ASAN_MARK internal fns. */ + if (gimplify_omp_ctxp) + return; + + tree unit_size = DECL_SIZE_UNIT (decl); + tree base = build_fold_addr_expr (decl); + + /* Do not poison variables that have size equal to zero. */ + if (zerop (unit_size)) + return; + + /* It's necessary to have all stack variables aligned to ASAN granularity + bytes. */ + if (DECL_ALIGN_UNIT (decl) <= ASAN_SHADOW_GRANULARITY) + SET_DECL_ALIGN (decl, BITS_PER_UNIT * ASAN_SHADOW_GRANULARITY); + + HOST_WIDE_INT flags = poison ? ASAN_MARK_CLOBBER : ASAN_MARK_UNCLOBBER; + + gimple *g + = gimple_build_call_internal (IFN_ASAN_MARK, 3, + build_int_cst (integer_type_node, flags), + base, unit_size); + + if (before) + gsi_insert_before (it, g, GSI_NEW_STMT); + else + gsi_insert_after (it, g, GSI_NEW_STMT); +} + +/* Generate IFN_ASAN_MARK internal call that depending on POISON flag + either poisons or unpoisons a DECL. Created statement is appended + to SEQ_P gimple sequence. */ + +static void +asan_poison_variable (tree decl, bool poison, gimple_seq *seq_p) +{ + gimple_stmt_iterator it = gsi_last (*seq_p); + bool before = false; + + if (gsi_end_p (it)) + before = true; + + asan_poison_variable (decl, poison, &it, before); +} + +/* Sort pair of VAR_DECLs A and B by DECL_UID. */ + +static int +sort_by_decl_uid (const void *a, const void *b) +{ + const tree *t1 = (const tree *)a; + const tree *t2 = (const tree *)b; + + int uid1 = DECL_UID (*t1); + int uid2 = DECL_UID (*t2); + + if (uid1 < uid2) + return -1; + else if (uid1 > uid2) + return 1; + else + return 0; +} + +/* Generate IFN_ASAN_MARK internal call for all VARIABLES + depending on POISON flag. Created statement is appended + to SEQ_P gimple sequence. */ + +static void +asan_poison_variables (hash_set *variables, bool poison, gimple_seq *seq_p) +{ + unsigned c = variables->elements (); + if (c == 0) + return; + + auto_vec sorted_variables (c); + + for (hash_set::iterator it = variables->begin (); + it != variables->end (); ++it) + sorted_variables.safe_push (*it); + + sorted_variables.qsort (sort_by_decl_uid); + + for (unsigned i = 0; i < sorted_variables.length (); i++) + asan_poison_variable (sorted_variables[i], poison, seq_p); +} + /* Gimplify a BIND_EXPR. Just voidify and recurse. */ static enum gimplify_status @@ -1221,6 +1341,17 @@ gimplify_bind_expr (tree *expr_p, gimple_seq *pre_p) } } } + + if (asan_poisoned_variables != NULL + && asan_poisoned_variables->contains (t)) + { + asan_poisoned_variables->remove (t); + asan_poison_variable (t, true, &cleanup); + } + + if (gimplify_ctxp->live_switch_vars != NULL + && gimplify_ctxp->live_switch_vars->contains (t)) + gimplify_ctxp->live_switch_vars->remove (t); } if (ret_clauses) @@ -1465,13 +1596,29 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p) if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)) { tree init = DECL_INITIAL (decl); + bool is_vla = false; if (TREE_CODE (DECL_SIZE_UNIT (decl)) != INTEGER_CST || (!TREE_STATIC (decl) && flag_stack_check == GENERIC_STACK_CHECK && compare_tree_int (DECL_SIZE_UNIT (decl), STACK_CHECK_MAX_VAR_SIZE) > 0)) - gimplify_vla_decl (decl, seq_p); + { + gimplify_vla_decl (decl, seq_p); + is_vla = true; + } + + if (asan_sanitize_use_after_scope () + && !asan_no_sanitize_address_p () + && !is_vla + && TREE_ADDRESSABLE (decl) + && !TREE_STATIC (decl)) + { + asan_poisoned_variables->add (decl); + asan_poison_variable (decl, false, seq_p); + if (gimplify_ctxp->live_switch_vars) + gimplify_ctxp->live_switch_vars->add (decl); + } /* Some front ends do not explicitly declare all anonymous artificial variables. We compensate here by declaring the @@ -1581,6 +1728,13 @@ warn_switch_unreachable_r (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, /* Walk the sub-statements. */ *handled_ops_p = false; break; + case GIMPLE_CALL: + if (gimple_call_internal_p (stmt, IFN_ASAN_MARK)) + { + *handled_ops_p = false; + break; + } + /* Fall through. */ default: /* Save the first "real" statement (not a decl/lexical scope/...). */ wi->info = stmt; @@ -1790,6 +1944,8 @@ collect_fallthrough_labels (gimple_stmt_iterator *gsi_p, if (find_label_entry (labels, label)) prev = gsi_stmt (*gsi_p); } + else if (gimple_call_internal_p (gsi_stmt (*gsi_p), IFN_ASAN_MARK)) + ; else prev = gsi_stmt (*gsi_p); gsi_next (gsi_p); @@ -2067,6 +2223,7 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) { vec labels; vec saved_labels; + hash_set *saved_live_switch_vars; tree default_case = NULL_TREE; gswitch *switch_stmt; @@ -2078,6 +2235,8 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) labels. Save all the things from the switch body to append after. */ saved_labels = gimplify_ctxp->case_labels; gimplify_ctxp->case_labels.create (8); + saved_live_switch_vars = gimplify_ctxp->live_switch_vars; + gimplify_ctxp->live_switch_vars = new hash_set (4); bool old_in_switch_expr = gimplify_ctxp->in_switch_expr; gimplify_ctxp->in_switch_expr = true; @@ -2092,6 +2251,9 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) labels = gimplify_ctxp->case_labels; gimplify_ctxp->case_labels = saved_labels; + gcc_assert (gimplify_ctxp->live_switch_vars->elements () == 0); + delete gimplify_ctxp->live_switch_vars; + gimplify_ctxp->live_switch_vars = saved_live_switch_vars; preprocess_case_label_vec_for_gimple (labels, index_type, &default_case); @@ -6122,6 +6284,9 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) tree init = TARGET_EXPR_INITIAL (targ); enum gimplify_status ret; + bool unpoison_empty_seq = false; + gimple_stmt_iterator unpoison_it; + if (init) { tree cleanup = NULL_TREE; @@ -6135,7 +6300,14 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) gimplify_vla_decl (temp, pre_p); } else - gimple_add_tmp_var (temp); + { + /* Save location where we need to place unpoisoning. It's possible + that a variable will be converted to needs_to_live_in_memory. */ + unpoison_it = gsi_last (*pre_p); + unpoison_empty_seq = gsi_end_p (unpoison_it); + + gimple_add_tmp_var (temp); + } /* If TARGET_EXPR_INITIAL is void, then the mere evaluation of the expression is supposed to initialize the slot. */ @@ -6171,20 +6343,34 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) /* Add a clobber for the temporary going out of scope, like gimplify_bind_expr. */ if (gimplify_ctxp->in_cleanup_point_expr - && needs_to_live_in_memory (temp) - && flag_stack_reuse == SR_ALL) + && needs_to_live_in_memory (temp)) { - tree clobber = build_constructor (TREE_TYPE (temp), - NULL); - TREE_THIS_VOLATILE (clobber) = true; - clobber = build2 (MODIFY_EXPR, TREE_TYPE (temp), temp, clobber); - if (cleanup) - cleanup = build2 (COMPOUND_EXPR, void_type_node, cleanup, - clobber); - else - cleanup = clobber; - } + if (flag_stack_reuse == SR_ALL) + { + tree clobber = build_constructor (TREE_TYPE (temp), + NULL); + TREE_THIS_VOLATILE (clobber) = true; + clobber = build2 (MODIFY_EXPR, TREE_TYPE (temp), temp, clobber); + if (cleanup) + cleanup = build2 (COMPOUND_EXPR, void_type_node, cleanup, + clobber); + else + cleanup = clobber; + } + if (asan_sanitize_use_after_scope ()) + { + tree asan_cleanup = build_asan_poison_call_expr (temp); + if (asan_cleanup) + { + if (unpoison_empty_seq) + unpoison_it = gsi_start (*pre_p); + asan_poison_variable (temp, false, &unpoison_it, + unpoison_empty_seq); + gimple_push_cleanup (temp, asan_cleanup, false, pre_p); + } + } + } if (cleanup) gimple_push_cleanup (temp, cleanup, false, pre_p); @@ -10738,6 +10924,7 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, location_t saved_location; enum gimplify_status ret; gimple_stmt_iterator pre_last_gsi, post_last_gsi; + tree label; save_expr = *expr_p; if (save_expr == NULL_TREE) @@ -11153,10 +11340,24 @@ gimplify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p, case LABEL_EXPR: ret = gimplify_label_expr (expr_p, pre_p); + label = LABEL_EXPR_LABEL (*expr_p); + gcc_assert (decl_function_context (label) == current_function_decl); + + /* If the label is used in a goto statement, or address of the label + is taken, we need to unpoison all variables that were seen so far. + Doing so would prevent us from reporting a false positives. */ + if (asan_sanitize_use_after_scope () + && asan_used_labels != NULL + && asan_used_labels->contains (label)) + asan_poison_variables (asan_poisoned_variables, false, pre_p); break; case CASE_LABEL_EXPR: ret = gimplify_case_label_expr (expr_p, pre_p); + + if (gimplify_ctxp->live_switch_vars) + asan_poison_variables (gimplify_ctxp->live_switch_vars, false, + pre_p); break; case RETURN_EXPR: @@ -12234,7 +12435,10 @@ gimplify_function_tree (tree fndecl) && !needs_to_live_in_memory (ret)) DECL_GIMPLE_REG_P (ret) = 1; + asan_poisoned_variables = new hash_set (); bind = gimplify_body (fndecl, true); + delete asan_poisoned_variables; + asan_poisoned_variables = NULL; /* The tree body of the function is no longer needed, replace it with the new GIMPLE body. */ diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 1fd7fa3..dd515a6 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -242,6 +242,15 @@ expand_ASAN_CHECK (internal_fn, gcall *) gcc_unreachable (); } +/* This should get expanded in the sanopt pass. */ + +static void +expand_ASAN_MARK (internal_fn, gcall *) +{ + gcc_unreachable (); +} + + /* This should get expanded in the tsan pass. */ static void diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 0e9f83c..1e97044 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -161,6 +161,7 @@ DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL) DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".R...") +DEF_INTERNAL_FN (ASAN_MARK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".R..") DEF_INTERNAL_FN (ADD_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) diff --git a/gcc/opts.c b/gcc/opts.c index a7ad5ed..1455a14 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -972,6 +972,25 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, opts->x_flag_aggressive_loop_optimizations = 0; opts->x_flag_strict_overflow = 0; } + + /* Enable -fsanitize-address-use-after-scope if address sanitizer is + enabled. */ + if (opts->x_flag_sanitize + && !opts_set->x_flag_sanitize_address_use_after_scope) + opts->x_flag_sanitize_address_use_after_scope = true; + + /* Force -fstack-reuse=none in case -fsanitize-address-use-after-scope + is enabled. */ + if (opts->x_flag_sanitize_address_use_after_scope) + { + if (opts->x_flag_stack_reuse != SR_NONE + && opts_set->x_flag_stack_reuse != SR_NONE) + error_at (loc, + "-fsanitize-address-use-after-scope requires " + "-fstack-reuse=none option"); + + opts->x_flag_stack_reuse = SR_NONE; + } } #define LEFT_COLUMN 27 @@ -1444,6 +1463,8 @@ const struct sanitizer_opts_s sanitizer_opts[] = #define SANITIZER_OPT(name, flags) { #name, flags, sizeof #name - 1 } SANITIZER_OPT (address, SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS), SANITIZER_OPT (kernel-address, SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS), + SANITIZER_OPT (address, (SANITIZE_ADDRESS | SANITIZE_USER_ADDRESS)), + SANITIZER_OPT (kernel-address, (SANITIZE_ADDRESS | SANITIZE_KERNEL_ADDRESS)), SANITIZER_OPT (thread, SANITIZE_THREAD), SANITIZER_OPT (leak, SANITIZE_LEAK), SANITIZER_OPT (shift, SANITIZE_SHIFT), @@ -1758,6 +1779,10 @@ common_handle_option (struct gcc_options *opts, /* Deferred. */ break; + case OPT_fsanitize_address_use_after_scope: + opts->x_flag_sanitize_address_use_after_scope = value; + break; + case OPT_fsanitize_recover: if (value) opts->x_flag_sanitize_recover diff --git a/gcc/params.def b/gcc/params.def index 9e05401..c1d2e7b 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -1138,6 +1138,12 @@ DEFPARAM (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD, "in function becomes greater or equal to this number.", 7000, 0, INT_MAX) +DEFPARAM (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD, + "use-after-scope-direct-emission-threshold", + "Use direct poisoning/unpoisoning intructions for variables " + "smaller or equal to this number.", + 256, 0, INT_MAX) + DEFPARAM (PARAM_UNINIT_CONTROL_DEP_ATTEMPTS, "uninit-control-dep-attempts", "Maximum number of nested calls to search for control dependencies " diff --git a/gcc/params.h b/gcc/params.h index 7221ab6..4017c85 100644 --- a/gcc/params.h +++ b/gcc/params.h @@ -243,5 +243,7 @@ extern void init_param_values (int *params); PARAM_VALUE (PARAM_ASAN_USE_AFTER_RETURN) #define ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD \ PARAM_VALUE (PARAM_ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD) +#define ASAN_PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD \ + ((unsigned) PARAM_VALUE (PARAM_USE_AFTER_SCOPE_DIRECT_EMISSION_THRESHOLD)) #endif /* ! GCC_PARAMS_H */ diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def index 7f0bf8c..8b44a2d 100644 --- a/gcc/sanitizer.def +++ b/gcc/sanitizer.def @@ -165,6 +165,10 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT, DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_AFTER_DYNAMIC_INIT, "__asan_after_dynamic_init", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_CLOBBER_N, "__asan_poison_stack_memory", + BT_FN_VOID_PTR_PTRMODE, 0) +DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNCLOBBER_N, "__asan_unpoison_stack_memory", + BT_FN_VOID_PTR_PTRMODE, 0) /* Efficiency Sanitizer */ DEF_SANITIZER_BUILTIN(BUILT_IN_ESAN_INIT, "__esan_init", diff --git a/gcc/sanopt.c b/gcc/sanopt.c index e864360..3931752 100644 --- a/gcc/sanopt.c +++ b/gcc/sanopt.c @@ -705,6 +705,9 @@ pass_sanopt::execute (function *fun) case IFN_ASAN_CHECK: no_next = asan_expand_check_ifn (&gsi, use_calls); break; + case IFN_ASAN_MARK: + no_next = asan_expand_mark_ifn (&gsi); + break; case IFN_ESAN_RECORD_ACCESS: no_next = esan_expand_record_access_ifn (&gsi); default: -- 2.7.4 From 17b4b3a6f4e25811c89f13b8327d788ce83cfb04 Mon Sep 17 00:00:00 2001 From: marxin Date: Mon, 7 Nov 2016 10:25:18 +0000 Subject: [PATCH 09/16] Introduce tests for -fsanitize-address-use-after-scope * c-c++-common/asan/force-inline-opt0-1.c: Disable -f-sanitize-address-use-after-scope. * c-c++-common/asan/inc.c: Change number of expected ASAN_CHECK internal fn calls. * g++.dg/asan/use-after-scope-1.C: New test. * g++.dg/asan/use-after-scope-2.C: Likewise. * g++.dg/asan/use-after-scope-3.C: Likewise. * g++.dg/asan/use-after-scope-types-1.C: Likewise. * g++.dg/asan/use-after-scope-types-2.C: Likewise. * g++.dg/asan/use-after-scope-types-3.C: Likewise. * g++.dg/asan/use-after-scope-types-4.C: Likewise. * g++.dg/asan/use-after-scope-types-5.C: Likewise. * g++.dg/asan/use-after-scope-types.h: Likewise. * gcc.dg/asan/use-after-scope-1.c: Likewise. * gcc.dg/asan/use-after-scope-2.c: Likewise. * gcc.dg/asan/use-after-scope-3.c: Likewise. * gcc.dg/asan/use-after-scope-4.c: Likewise. * gcc.dg/asan/use-after-scope-5.c: Likewise. * gcc.dg/asan/use-after-scope-6.c: Likewise. * gcc.dg/asan/use-after-scope-7.c: Likewise. * gcc.dg/asan/use-after-scope-8.c: Likewise. * gcc.dg/asan/use-after-scope-9.c: Likewise. * gcc.dg/asan/use-after-scope-switch-1.c: Likewise. * gcc.dg/asan/use-after-scope-switch-2.c: Likewise. * gcc.dg/asan/use-after-scope-switch-3.c: Likewise. * gcc.dg/asan/use-after-scope-goto-1.c: Likewise. * gcc.dg/asan/use-after-scope-goto-2.c: Likewise. upstream hash: ea86011c3ffb79f3a8ce8f1ffe0f89abfb8d7ace git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@241897 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: Ibab662fa2a192a856c195377cb08796bcad7112f --- .../c-c++-common/asan/force-inline-opt0-1.c | 1 + gcc/testsuite/c-c++-common/asan/inc.c | 3 +- gcc/testsuite/g++.dg/asan/use-after-scope-1.C | 21 ++++++++++ gcc/testsuite/g++.dg/asan/use-after-scope-2.C | 40 ++++++++++++++++++ gcc/testsuite/g++.dg/asan/use-after-scope-3.C | 22 ++++++++++ .../g++.dg/asan/use-after-scope-types-1.C | 17 ++++++++ .../g++.dg/asan/use-after-scope-types-2.C | 17 ++++++++ .../g++.dg/asan/use-after-scope-types-3.C | 17 ++++++++ .../g++.dg/asan/use-after-scope-types-4.C | 17 ++++++++ .../g++.dg/asan/use-after-scope-types-5.C | 17 ++++++++ gcc/testsuite/g++.dg/asan/use-after-scope-types.h | 30 ++++++++++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-1.c | 18 +++++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-2.c | 47 ++++++++++++++++++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-3.c | 20 +++++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-4.c | 16 ++++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-5.c | 27 +++++++++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-6.c | 15 +++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-7.c | 15 +++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-8.c | 14 +++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-9.c | 20 +++++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c | 47 ++++++++++++++++++++++ gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c | 25 ++++++++++++ .../gcc.dg/asan/use-after-scope-switch-1.c | 25 ++++++++++++ .../gcc.dg/asan/use-after-scope-switch-2.c | 33 +++++++++++++++ .../gcc.dg/asan/use-after-scope-switch-3.c | 36 +++++++++++++++++ 25 files changed, 559 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-1.C create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-2.C create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-3.C create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-types-1.C create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-types-2.C create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-types-3.C create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-types-5.C create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-types.h create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-1.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-2.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-3.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-4.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-5.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-6.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-7.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-8.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-9.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c diff --git a/gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c b/gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c index 0576155..2e156f7 100644 --- a/gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c +++ b/gcc/testsuite/c-c++-common/asan/force-inline-opt0-1.c @@ -2,6 +2,7 @@ (before and after inlining) */ /* { dg-do compile } */ +/* { dg-options "-fno-sanitize-address-use-after-scope" } */ /* { dg-final { scan-assembler-not "__asan_report_load" } } */ __attribute__((always_inline)) diff --git a/gcc/testsuite/c-c++-common/asan/inc.c b/gcc/testsuite/c-c++-common/asan/inc.c index 5abf373..98121d2 100644 --- a/gcc/testsuite/c-c++-common/asan/inc.c +++ b/gcc/testsuite/c-c++-common/asan/inc.c @@ -16,5 +16,6 @@ main () return 0; } -/* { dg-final { scan-tree-dump-times "ASAN_" 1 "asan0" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_" 4 "asan0" } } */ /* { dg-final { scan-tree-dump "ASAN_CHECK \\(.*, 4\\);" "asan0" } } */ +/* { dg-final { scan-tree-dump "ASAN_CHECK \\(.*, 8\\);" "asan0" } } */ diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-1.C b/gcc/testsuite/g++.dg/asan/use-after-scope-1.C new file mode 100644 index 0000000..fd875ad --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-1.C @@ -0,0 +1,21 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +#include + +int main() { + std::function function; + { + int v = 0; + function = [&v]() + { + return v; + }; + } + return function(); +} + + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size 4 at.*" } +// { dg-output ".*'v' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-2.C b/gcc/testsuite/g++.dg/asan/use-after-scope-2.C new file mode 100644 index 0000000..92a4bd1 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-2.C @@ -0,0 +1,40 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +#include + +struct Test +{ + Test () + { + my_value = 0; + } + + ~Test () + { + fprintf (stderr, "Value: %d\n", *my_value); + } + + void init (int *v) + { + my_value = v; + } + + int *my_value; +}; + +int main(int argc, char **argv) +{ + Test t; + + { + int x = argc; + t.init(&x); + } + + return 0; +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size 4 at.*" } +// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-3.C b/gcc/testsuite/g++.dg/asan/use-after-scope-3.C new file mode 100644 index 0000000..172f374 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-3.C @@ -0,0 +1,22 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +struct IntHolder { + int val; +}; + +const IntHolder *saved; + +void save(const IntHolder &holder) { + saved = &holder; +} + +int main(int argc, char *argv[]) { + save({10}); + int x = saved->val; // BOOM + return x; +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size 4 at.*" } +// { dg-output ".*'' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-1.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-1.C new file mode 100644 index 0000000..bedcfa4 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-1.C @@ -0,0 +1,17 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +#include "use-after-scope-types.h" + +int main() +{ + using Tests = void (*)(); + Tests t = &test; + t(); + + return 0; +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "WRITE of size " } +// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-2.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-2.C new file mode 100644 index 0000000..75a01d9 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-2.C @@ -0,0 +1,17 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +#include "use-after-scope-types.h" + +int main() +{ + using Tests = void (*)(); + Tests t = &test; + t(); + + return 0; +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "WRITE of size " } +// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-3.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-3.C new file mode 100644 index 0000000..3350c69 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-3.C @@ -0,0 +1,17 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +#include "use-after-scope-types.h" + +int main() +{ + using Tests = void (*)(); + Tests t = &test; + t(); + + return 0; +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "WRITE of size " } +// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C new file mode 100644 index 0000000..dd06e94 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C @@ -0,0 +1,17 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +#include "use-after-scope-types.h" + +int main() +{ + using Tests = void (*)(); + Tests t = &test>; + t(); + + return 0; +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size 8 at" } +// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-5.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-5.C new file mode 100644 index 0000000..42abc2a --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-5.C @@ -0,0 +1,17 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +#include "use-after-scope-types.h" + +int main() +{ + using Tests = void (*)(); + Tests t = &test; + t(); + + return 0; +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "WRITE of size " } +// { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types.h b/gcc/testsuite/g++.dg/asan/use-after-scope-types.h new file mode 100644 index 0000000..b96b02b --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types.h @@ -0,0 +1,30 @@ +#include +#include +#include + +template struct Ptr { + void Store(T *ptr) { t = ptr; } + + void Access() { *t = {}; } + + T *t; +}; + +template struct Ptr { + using Type = T[N]; + void Store(Type *ptr) { t = *ptr; } + + void Access() { *t = {}; } + + T *t; +}; + +template __attribute__((noinline)) void test() { + Ptr ptr; + { + T x; + ptr.Store(&x); + } + + ptr.Access(); +} diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-1.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-1.c new file mode 100644 index 0000000..bdbc97b --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-1.c @@ -0,0 +1,18 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +int +main (void) +{ + char *ptr; + { + char my_char[9]; + ptr = &my_char[0]; + } + + return *(ptr+8); +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size 1 at.*" } +// { dg-output ".*'my_char' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-2.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-2.c new file mode 100644 index 0000000..dedb734 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-2.c @@ -0,0 +1,47 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +int *bar (int *x, int *y) { return y; } + +int foo (void) +{ + char *p; + { + char a = 0; + p = &a; + } + + if (*p) + return 1; + else + return 0; +} + +int +main (void) +{ + char *ptr; + { + char my_char[9]; + ptr = &my_char[0]; + } + + int a[16]; + int *p, *q = a; + { + int b[16]; + p = bar (a, b); + } + bar (a, q); + { + int c[16]; + q = bar (a, c); + } + int v = *bar (a, q); + return v; +} + + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size 4 at.*" } +// { dg-output ".*'c' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-3.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-3.c new file mode 100644 index 0000000..9aeed51 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-3.c @@ -0,0 +1,20 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +int +main (void) +{ + char *ptr; + char *ptr2; + { + char my_char[9]; + ptr = &my_char[0]; + __builtin_memcpy (&ptr2, &ptr, sizeof (ptr2)); + } + + *(ptr2+9) = 'c'; +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "WRITE of size 1 at.*" } +// { dg-output ".*'my_char' <== Memory access at offset \[0-9\]* overflows this variable.*" } diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-4.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-4.c new file mode 100644 index 0000000..77d7052 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-4.c @@ -0,0 +1,16 @@ +// { dg-do run } + +int +__attribute__((no_sanitize_address)) +main (void) +{ + char *ptr; + char *ptr2; + { + char my_char[9]; + ptr = &my_char[0]; + __builtin_memcpy (&ptr2, &ptr, sizeof (ptr2)); + } + + *(ptr2+9) = 'c'; +} diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-5.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-5.c new file mode 100644 index 0000000..b53712d --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-5.c @@ -0,0 +1,27 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +int *ptr; + +__attribute__((always_inline)) +inline static void +foo(int v) +{ + int values[10]; + for (unsigned i = 0; i < 10; i++) + values[i] = v; + + ptr = &values[3]; +} + +int +main (int argc, char **argv) +{ + foo (argc); + + return *ptr; +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size 4 at.*" } +// { dg-output ".*'values' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-6.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-6.c new file mode 100644 index 0000000..bb13cec --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-6.c @@ -0,0 +1,15 @@ +// { dg-do run } +// { dg-additional-options "--param asan-stack=0" } + +int +main (void) +{ + char *ptr; + { + char my_char[9]; + ptr = &my_char[0]; + } + + *ptr = 'c'; + return 0; +} diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-7.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-7.c new file mode 100644 index 0000000..4115205 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-7.c @@ -0,0 +1,15 @@ +// { dg-do run } +// { dg-additional-options "-fno-sanitize-address-use-after-scope" } + +int +main (void) +{ + char *ptr; + { + char my_char[9]; + ptr = &my_char[0]; + } + + *ptr = 'c'; + return 0; +} diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-8.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-8.c new file mode 100644 index 0000000..b204206 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-8.c @@ -0,0 +1,14 @@ +// { dg-do compile } +// { dg-additional-options "-fdump-tree-asan0" } +/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */ + +int +fn1 () +{ + int x = 123; + register int a asm("rdi") = 123; + + return x * x; +} + +/* { dg-final { scan-tree-dump-not "ASAN_CHECK" "asan0" } } */ diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-9.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-9.c new file mode 100644 index 0000000..2e30def --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-9.c @@ -0,0 +1,20 @@ +// { dg-do run } +// { dg-shouldfail "asan" } + +int +main (int argc, char **argv) +{ + int *ptr = 0; + + { + int a; + ptr = &a; + *ptr = 12345; + } + + return *ptr; +} + +// { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } +// { dg-output "READ of size .*" } +// { dg-output ".*'a' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c new file mode 100644 index 0000000..c47a5e8 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c @@ -0,0 +1,47 @@ +// { dg-do run } +// { dg-additional-options "-fdump-tree-asan0" } +/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */ + +int main(int argc, char **argv) +{ + int a = 123; + int b = 123; + int c = 123; + int d = 123; + int e = 123; + int f = 123; + + if (argc == 0) + { + int *ptr; + int *ptr2; + int *ptr3; + int *ptr4; + int *ptr5; + int *ptr6; + label: + { + ptr = &a; + *ptr = 1; + ptr2 = &b; + *ptr2 = 1; + ptr3 = &c; + *ptr3 = 1; + ptr4 = &d; + *ptr4 = 1; + ptr5 = &e; + *ptr5 = 1; + ptr6 = &f; + *ptr6 = 1; + return 0; + } + } + else + goto label; + + return 0; +} + +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, 4\\);" 2 "asan0" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &c, 4\\);" 2 "asan0" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &e, 4\\);" 2 "asan0" } } */ diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c new file mode 100644 index 0000000..73ef4e0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c @@ -0,0 +1,25 @@ +// { dg-do run } +// { dg-additional-options "-fdump-tree-asan0" } +/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */ + +int main(int argc, char **argv) +{ + int a = 123; + + if (argc == 0) + { + int *ptr; + /* The label is not used in &label or goto label. Thus '&a' should be + marked just once. */ + label: + { + ptr = &a; + *ptr = 1; + return 0; + } + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, 4\\);" 1 "asan0" } } */ diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c new file mode 100644 index 0000000..a834268 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c @@ -0,0 +1,25 @@ +// { dg-do run } +// { dg-additional-options "-fdump-tree-gimple" } + +int +main (int argc, char **argv) +{ + int *ptr = 0; + + for (unsigned i = 0; i < 2; i++) + { + switch (argc) + { + int a; + default: + ptr = &a; + *ptr = 12345; + break; + } + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, \[0-9\]\\);" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &a, \[0-9\]\\);" 1 "gimple" } } */ diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c new file mode 100644 index 0000000..8aeca5a --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c @@ -0,0 +1,33 @@ +// { dg-do run } +// { dg-additional-options "-fdump-tree-gimple" } + +int +main (int argc, char **argv) +{ + int *ptr = 0; + int *ptr2 = 0; + int *ptr3 = 0; + + for (unsigned i = 0; i < 2; i++) + { + switch (argc) + { + case 1111:; + int a, b, c; + default: + ptr = &a; + ptr2 = &b; + ptr3 = &c; + break; + } + } + + return 0; +} + +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, \[0-9\]\\);" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &b, \[0-9\]\\);" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &c, \[0-9\]\\);" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &a, \[0-9\]\\);" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &b, \[0-9\]\\);" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &c, \[0-9\]\\);" 1 "gimple" } } */ diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c new file mode 100644 index 0000000..828cb7c --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c @@ -0,0 +1,36 @@ +// { dg-do run } +// { dg-additional-options "-fdump-tree-gimple" } + +int +main (int argc, char **argv) +{ + int *ptr = 0; + + for (unsigned i = 0; i < 2; i++) + { + switch (argc) + { + case 11111:; + int a; + ptr = &a; + break; + { + default: + ptr = &a; + *ptr = 12345; + case 222222: + my_label: + ptr = &a; + break; + } + } + } + + if (argc == 333333) + goto my_label; + + return 0; +} + +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, \[0-9\]\\);" 4 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &a, \[0-9\]\\);" 1 "gimple" } } */ -- 2.7.4 From a6210478a8afda7f649ca86044c903dd4f0f907b Mon Sep 17 00:00:00 2001 From: marxin Date: Tue, 8 Nov 2016 12:28:33 +0000 Subject: [PATCH 10/16] use-after-scope fallout PR testsuite/78242 * g++.dg/asan/use-after-scope-4.C: New test. * g++.dg/asan/use-after-scope-types-4.C: Update scanned pattern. * gcc.dg/asan/use-after-scope-8.c: Remove. PR testsuite/78242 * dbgcnt.def: Add new debug counter asan_use_after_scope. * gimplify.c (gimplify_decl_expr): Do not sanitize vars with a value expr. Do not add artificial variables to live_switch_vars. Use the debug counter. (gimplify_target_expr): Use the debug counter. * internal-fn.def: Remove ECF_TM_PURE from ASAN_MARK builtin. * sanitizer.def: Set ATTR_NOTHROW_LEAF_LIST to BUILT_IN_ASAN_CLOBBER_N and BUILT_IN_ASAN_UNCLOBBER_N. upstream hash: d71fcb4d6c78c38912a87df7e0aa09407b691f79 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@241961 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: I9e5609ee7f9015cfd0951ad8aedd1437d90dca9d --- gcc/dbgcnt.def | 1 + gcc/gimplify.c | 10 ++++-- gcc/internal-fn.def | 2 +- gcc/sanitizer.def | 4 +-- gcc/testsuite/g++.dg/asan/use-after-scope-4.C | 36 ++++++++++++++++++++++ .../g++.dg/asan/use-after-scope-types-4.C | 2 +- gcc/testsuite/gcc.dg/asan/use-after-scope-8.c | 14 --------- 7 files changed, 48 insertions(+), 21 deletions(-) create mode 100644 gcc/testsuite/g++.dg/asan/use-after-scope-4.C delete mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-8.c diff --git a/gcc/dbgcnt.def b/gcc/dbgcnt.def index 78ddcc2..0a45bac 100644 --- a/gcc/dbgcnt.def +++ b/gcc/dbgcnt.def @@ -141,6 +141,7 @@ echo ubound: $ub */ /* Debug counter definitions. */ +DEBUG_COUNTER (asan_use_after_scope) DEBUG_COUNTER (auto_inc_dec) DEBUG_COUNTER (ccp) DEBUG_COUNTER (cfg_cleanup) diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 5fdf0cd..afe6752 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see #include "langhooks-def.h" /* FIXME: for lhd_set_decl_assembler_name */ #include "builtins.h" #include "asan.h" +#include "dbgcnt.h" /* Hash set of poisoned variables in a bind expr. */ static hash_set *asan_poisoned_variables = NULL; @@ -1612,11 +1613,13 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p) && !asan_no_sanitize_address_p () && !is_vla && TREE_ADDRESSABLE (decl) - && !TREE_STATIC (decl)) + && !TREE_STATIC (decl) + && !DECL_HAS_VALUE_EXPR_P (decl) + && dbg_cnt (asan_use_after_scope)) { asan_poisoned_variables->add (decl); asan_poison_variable (decl, false, seq_p); - if (gimplify_ctxp->live_switch_vars) + if (!DECL_ARTIFICIAL (decl) && gimplify_ctxp->live_switch_vars) gimplify_ctxp->live_switch_vars->add (decl); } @@ -6357,7 +6360,8 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p) else cleanup = clobber; } - if (asan_sanitize_use_after_scope ()) + if (asan_sanitize_use_after_scope () + && dbg_cnt (asan_use_after_scope)) { tree asan_cleanup = build_asan_poison_call_expr (temp); if (asan_cleanup) diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index 1e97044..18c4555 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -161,7 +161,7 @@ DEF_INTERNAL_FN (UBSAN_OBJECT_SIZE, ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN, NULL) DEF_INTERNAL_FN (BUILTIN_EXPECT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (ASAN_CHECK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".R...") -DEF_INTERNAL_FN (ASAN_MARK, ECF_TM_PURE | ECF_LEAF | ECF_NOTHROW, ".R..") +DEF_INTERNAL_FN (ASAN_MARK, ECF_LEAF | ECF_NOTHROW, ".R..") DEF_INTERNAL_FN (ADD_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (SUB_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) DEF_INTERNAL_FN (MUL_OVERFLOW, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL) diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def index 8b44a2d..587ea00 100644 --- a/gcc/sanitizer.def +++ b/gcc/sanitizer.def @@ -166,9 +166,9 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_AFTER_DYNAMIC_INIT, "__asan_after_dynamic_init", BT_FN_VOID, ATTR_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_CLOBBER_N, "__asan_poison_stack_memory", - BT_FN_VOID_PTR_PTRMODE, 0) + BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST) DEF_SANITIZER_BUILTIN(BUILT_IN_ASAN_UNCLOBBER_N, "__asan_unpoison_stack_memory", - BT_FN_VOID_PTR_PTRMODE, 0) + BT_FN_VOID_PTR_PTRMODE, ATTR_NOTHROW_LEAF_LIST) /* Efficiency Sanitizer */ DEF_SANITIZER_BUILTIN(BUILT_IN_ESAN_INIT, "__esan_init", diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-4.C b/gcc/testsuite/g++.dg/asan/use-after-scope-4.C new file mode 100644 index 0000000..c3b6932 --- /dev/null +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-4.C @@ -0,0 +1,36 @@ +/* Caused ICE in in make_decl_rtl, at varasm.c:1311. */ +/* { dg-do compile } */ + +class A +{ +public: + A () : value (123) {} + int value; +}; + +template class B +{ +public: + template B (F p1) : mFunction (p1) { mFunction (); } + StoredFunction mFunction; +}; +template +void +NS_NewRunnableFunction (Function p1) +{ + (B (p1)); +} +class C +{ + void DispatchConnectionCloseEvent (A); + void AsyncCloseConnectionWithErrorMsg (const A &); +}; +void +C::AsyncCloseConnectionWithErrorMsg (const A &) +{ + { + A message; + NS_NewRunnableFunction ( + [this, message] { DispatchConnectionCloseEvent (message); }); + } +} diff --git a/gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C b/gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C index dd06e94..44f4d3b 100644 --- a/gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C +++ b/gcc/testsuite/g++.dg/asan/use-after-scope-types-4.C @@ -13,5 +13,5 @@ int main() } // { dg-output "ERROR: AddressSanitizer: stack-use-after-scope on address.*(\n|\r\n|\r)" } -// { dg-output "READ of size 8 at" } +// { dg-output "READ of size " } // { dg-output ".*'x' <== Memory access at offset \[0-9\]* is inside this variable.*" } diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-8.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-8.c deleted file mode 100644 index b204206..0000000 --- a/gcc/testsuite/gcc.dg/asan/use-after-scope-8.c +++ /dev/null @@ -1,14 +0,0 @@ -// { dg-do compile } -// { dg-additional-options "-fdump-tree-asan0" } -/* { dg-skip-if "" { *-*-* } { "*" } { "-O0" } } */ - -int -fn1 () -{ - int x = 123; - register int a asm("rdi") = 123; - - return x * x; -} - -/* { dg-final { scan-tree-dump-not "ASAN_CHECK" "asan0" } } */ -- 2.7.4 From 22b1fc78b9839b0cc408a55bec2a603253579819 Mon Sep 17 00:00:00 2001 From: marxin Date: Thu, 10 Nov 2016 11:21:03 +0000 Subject: [PATCH 11/16] Create live_switch_vars conditionally (PR sanitizer/78270) PR sanitizer/78270 * gcc.dg/asan/pr78270.c: New test. PR sanitizer/78270 * gimplify.c (gimplify_switch_expr): Create live_switch_vars only when SWITCH_BODY is a BIND_EXPR. upstream hash: 65dc25166f86f75a85141e56344f482d41f3b024 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@242036 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: I8bc4e10c86602e72321af171755f7c54e6bd164c --- gcc/gimplify.c | 20 +++++++++++++++----- gcc/testsuite/gcc.dg/asan/pr78270.c | 13 +++++++++++++ 2 files changed, 28 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/asan/pr78270.c diff --git a/gcc/gimplify.c b/gcc/gimplify.c index afe6752..c294390 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2226,7 +2226,7 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) { vec labels; vec saved_labels; - hash_set *saved_live_switch_vars; + hash_set *saved_live_switch_vars = NULL; tree default_case = NULL_TREE; gswitch *switch_stmt; @@ -2238,8 +2238,14 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) labels. Save all the things from the switch body to append after. */ saved_labels = gimplify_ctxp->case_labels; gimplify_ctxp->case_labels.create (8); - saved_live_switch_vars = gimplify_ctxp->live_switch_vars; - gimplify_ctxp->live_switch_vars = new hash_set (4); + + /* Do not create live_switch_vars if SWITCH_BODY is not a BIND_EXPR. */ + if (TREE_CODE (SWITCH_BODY (switch_expr)) == BIND_EXPR) + { + saved_live_switch_vars = gimplify_ctxp->live_switch_vars; + gimplify_ctxp->live_switch_vars = new hash_set (4); + } + bool old_in_switch_expr = gimplify_ctxp->in_switch_expr; gimplify_ctxp->in_switch_expr = true; @@ -2254,8 +2260,12 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) labels = gimplify_ctxp->case_labels; gimplify_ctxp->case_labels = saved_labels; - gcc_assert (gimplify_ctxp->live_switch_vars->elements () == 0); - delete gimplify_ctxp->live_switch_vars; + + if (gimplify_ctxp->live_switch_vars) + { + gcc_assert (gimplify_ctxp->live_switch_vars->elements () == 0); + delete gimplify_ctxp->live_switch_vars; + } gimplify_ctxp->live_switch_vars = saved_live_switch_vars; preprocess_case_label_vec_for_gimple (labels, index_type, diff --git a/gcc/testsuite/gcc.dg/asan/pr78270.c b/gcc/testsuite/gcc.dg/asan/pr78270.c new file mode 100644 index 0000000..55840b0 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/pr78270.c @@ -0,0 +1,13 @@ +// { dg-do compile } +// { dg-additional-options "-Wno-switch-unreachable" } + +typedef struct +{ +} bdaddr_t; + +int a; +void fn1 () +{ + switch (a) + &(bdaddr_t){}; +} -- 2.7.4 From 037f5c0adf25b4487ca4c0621f26fb6171b40f07 Mon Sep 17 00:00:00 2001 From: marxin Date: Wed, 16 Nov 2016 11:56:58 +0000 Subject: [PATCH 12/16] Fix PR sanitizer/78270 (part 2) PR sanitizer/78270 * gimplify.c (gimplify_switch_expr): Always save previous gimplify_ctxp->live_switch_vars. PR sanitizer/78270 * gcc.dg/asan/pr78270.c: Update comment style. * gcc.dg/asan/pr78270-2.c: New test. upstream hash: 904e262bdb88c2cf1eefeb4997c8d4ed2a888d55 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@242485 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: I760170bff746390269035dd2c10afff960d06445 --- gcc/gimplify.c | 8 ++++---- gcc/testsuite/gcc.dg/asan/pr78270-2.c | 18 ++++++++++++++++++ gcc/testsuite/gcc.dg/asan/pr78270.c | 5 +++-- 3 files changed, 25 insertions(+), 6 deletions(-) create mode 100644 gcc/testsuite/gcc.dg/asan/pr78270-2.c diff --git a/gcc/gimplify.c b/gcc/gimplify.c index c294390..673738c 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2240,11 +2240,11 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) gimplify_ctxp->case_labels.create (8); /* Do not create live_switch_vars if SWITCH_BODY is not a BIND_EXPR. */ + saved_live_switch_vars = gimplify_ctxp->live_switch_vars; if (TREE_CODE (SWITCH_BODY (switch_expr)) == BIND_EXPR) - { - saved_live_switch_vars = gimplify_ctxp->live_switch_vars; - gimplify_ctxp->live_switch_vars = new hash_set (4); - } + gimplify_ctxp->live_switch_vars = new hash_set (4); + else + gimplify_ctxp->live_switch_vars = NULL; bool old_in_switch_expr = gimplify_ctxp->in_switch_expr; gimplify_ctxp->in_switch_expr = true; diff --git a/gcc/testsuite/gcc.dg/asan/pr78270-2.c b/gcc/testsuite/gcc.dg/asan/pr78270-2.c new file mode 100644 index 0000000..72195b3 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/pr78270-2.c @@ -0,0 +1,18 @@ +/* PR sanitizer/78270 */ +/* { dg-do compile } */ +/* { dg-additional-options "-Wno-switch-unreachable" } */ + +int a; +void +fn1 () +{ + switch (a) + { + char b; + case 8: + &b; + switch (0) + ; + } +} + diff --git a/gcc/testsuite/gcc.dg/asan/pr78270.c b/gcc/testsuite/gcc.dg/asan/pr78270.c index 55840b0..5583ce4 100644 --- a/gcc/testsuite/gcc.dg/asan/pr78270.c +++ b/gcc/testsuite/gcc.dg/asan/pr78270.c @@ -1,5 +1,6 @@ -// { dg-do compile } -// { dg-additional-options "-Wno-switch-unreachable" } +/* PR sanitizer/78270 */ +/* { dg-do compile } */ +/* { dg-additional-options "-Wno-switch-unreachable" } */ typedef struct { -- 2.7.4 From e2cd7f1b65dcf4eae695360c87fd4dd6159d54ca Mon Sep 17 00:00:00 2001 From: mpolacek Date: Wed, 17 May 2017 09:59:20 +0000 Subject: [PATCH 13/16] PR sanitizer/80659 * c-decl.c (build_compound_literal): Set DECL_ARTIFICIAL and DECL_IGNORED_P even for non-static compound literals. * gcc.dg/asan/pr80659.c: New test. Change-Id: I7565aba65e49836947e0faf2eb5ea668b46a0d87 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@248143138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/c/ChangeLog | 6 ++++++ gcc/c/c-decl.c | 4 ++-- gcc/testsuite/ChangeLog | 6 ++++++ testsuite/gcc.dg/asan/pr80659.c | 13 +++++++++++++ 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 testsuite/gcc.dg/asan/pr80659.c diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog index 2b1f718..de88c93 100644 --- a/gcc/c/ChangeLog +++ b/gcc/c/ChangeLog @@ -1,3 +1,9 @@ +2017-05-17 Marek Polacek + + PR sanitizer/80659 + * c-decl.c (build_compound_literal): Set DECL_ARTIFICIAL and + DECL_IGNORED_P even for non-static compound literals. + 2016-12-21 Jakub Jelinek PR c/77767 diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c index 7f9d882..93c11cc 100644 --- a/gcc/c/c-decl.c +++ b/gcc/c/c-decl.c @@ -5091,6 +5091,8 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const) DECL_CONTEXT (decl) = current_function_decl; TREE_USED (decl) = 1; DECL_READ_P (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; TREE_TYPE (decl) = type; TREE_READONLY (decl) = (TYPE_READONLY (type) || (TREE_CODE (type) == ARRAY_TYPE @@ -5127,8 +5129,6 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const) set_compound_literal_name (decl); DECL_DEFER_OUTPUT (decl) = 1; DECL_COMDAT (decl) = 1; - DECL_ARTIFICIAL (decl) = 1; - DECL_IGNORED_P (decl) = 1; pushdecl (decl); rest_of_decl_compilation (decl, 1, 0); } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 0cfd70f..fcfdf84 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -19,6 +19,12 @@ PR sanitizer/81111 * g++.dg/ubsan/pr81111.C: New test. +2017-05-17 Marek Polacek + + PR sanitizer/80659 + * gcc.dg/asan/pr80659.c: New test. + + 2017-04-13 Denis Khalikov PR sanitizer/80414 diff --git a/testsuite/gcc.dg/asan/pr80659.c b/testsuite/gcc.dg/asan/pr80659.c new file mode 100644 index 0000000..0cbf2e4 --- /dev/null +++ b/testsuite/gcc.dg/asan/pr80659.c @@ -0,0 +1,13 @@ +/* PR sanitizer/80659 */ +/* { dg-do compile } */ + +void +foo (int a) +{ + switch (a) + { + case 0: + (int[3]) { }; + int h; + } +} -- 2.7.4 From 79a2757f5353263dec09ff9c7c624a624d27db68 Mon Sep 17 00:00:00 2001 From: marxin Date: Tue, 13 Dec 2016 09:14:47 +0000 Subject: [PATCH 14/16] Add pretty printer for ASAN_MARK and add a helper fn * asan.c (asan_mark_poison_p): Remove. (asan_mark_p): New function. (transform_statements): Use the function. (asan_expand_mark_ifn): Do not use masked enum. * asan.h (enum asan_mark_flags): Declare it via a macro. * gimple-pretty-print.c (dump_gimple_call_args): Dump first argument of ASAN_MARK. * gimplify.c (build_asan_poison_call_expr): Use new enum values. (asan_poison_variable): Likewise. * gcc.dg/asan/use-after-scope-goto-1.c: Update first argument of scanned pattern ASAN_MARK. * gcc.dg/asan/use-after-scope-goto-2.c: Likewise. * gcc.dg/asan/use-after-scope-switch-1.c: Likewise. * gcc.dg/asan/use-after-scope-switch-2.c: Likewise. * gcc.dg/asan/use-after-scope-switch-3.c: Likewise. Change-Id: Ife3e6037a03ec2b25a15d45bb301f43b750e6649 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@243597138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/asan.c | 28 ++++++------ gcc/asan.h | 11 +++-- gcc/gimple-pretty-print.c | 51 ++++++++++++++++++---- gcc/gimple.c | 2 +- gcc/gimplify.c | 4 +- gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c | 6 +-- gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c | 2 +- .../gcc.dg/asan/use-after-scope-switch-1.c | 4 +- .../gcc.dg/asan/use-after-scope-switch-2.c | 12 ++--- .../gcc.dg/asan/use-after-scope-switch-3.c | 4 +- 10 files changed, 80 insertions(+), 44 deletions(-) diff --git a/gcc/asan.c b/gcc/asan.c index b09d1fc..0f5419f 100644 --- a/gcc/asan.c +++ b/gcc/asan.c @@ -243,15 +243,6 @@ static unsigned HOST_WIDE_INT asan_shadow_offset_value; static bool asan_shadow_offset_computed; static vec sanitized_sections; -/* Return true if STMT is ASAN_MARK poisoning internal function call. */ -static inline bool -asan_mark_poison_p (gimple *stmt) -{ - return (gimple_call_internal_p (stmt, IFN_ASAN_MARK) - && tree_to_uhwi (gimple_call_arg (stmt, 0)) == ASAN_MARK_CLOBBER); - -} - /* Set of variable declarations that are going to be guarded by use-after-scope sanitizer. */ @@ -302,6 +293,13 @@ set_sanitized_sections (const char *sections) } bool +asan_mark_p (gimple *stmt, enum asan_mark_flags flag) +{ + return (gimple_call_internal_p (stmt, IFN_ASAN_MARK) + && tree_to_uhwi (gimple_call_arg (stmt, 0)) == flag); +} + +bool asan_sanitize_stack_p (void) { return ((flag_sanitize & SANITIZE_ADDRESS) @@ -2219,7 +2217,8 @@ transform_statements (void) miss some instrumentation opportunities. Do the same for a ASAN_MARK poisoning internal function. */ if (is_gimple_call (s) - && (!nonfreeing_call_p (s) || asan_mark_poison_p (s))) + && (!nonfreeing_call_p (s) + || asan_mark_p (s, ASAN_MARK_POISON))) empty_mem_ref_hash_table (); gsi_next (&i); @@ -2715,9 +2714,8 @@ asan_expand_mark_ifn (gimple_stmt_iterator *iter) { gimple *g = gsi_stmt (*iter); location_t loc = gimple_location (g); - HOST_WIDE_INT flags = tree_to_shwi (gimple_call_arg (g, 0)); - gcc_assert (flags < ASAN_MARK_LAST); - bool is_clobber = (flags & ASAN_MARK_CLOBBER) != 0; + HOST_WIDE_INT flag = tree_to_shwi (gimple_call_arg (g, 0)); + bool is_poison = ((asan_mark_flags)flag) == ASAN_MARK_POISON; tree base = gimple_call_arg (g, 1); gcc_checking_assert (TREE_CODE (base) == ADDR_EXPR); @@ -2759,7 +2757,7 @@ asan_expand_mark_ifn (gimple_stmt_iterator *iter) if (s > size_in_bytes) last_chunk_size = ASAN_SHADOW_GRANULARITY - (s - size_in_bytes); - asan_store_shadow_bytes (iter, loc, shadow, offset, is_clobber, + asan_store_shadow_bytes (iter, loc, shadow, offset, is_poison, size, last_chunk_size); offset += size; } @@ -2772,7 +2770,7 @@ asan_expand_mark_ifn (gimple_stmt_iterator *iter) gsi_insert_before (iter, g, GSI_SAME_STMT); tree sz_arg = gimple_assign_lhs (g); - tree fun = builtin_decl_implicit (is_clobber ? BUILT_IN_ASAN_CLOBBER_N + tree fun = builtin_decl_implicit (is_poison ? BUILT_IN_ASAN_CLOBBER_N : BUILT_IN_ASAN_UNCLOBBER_N); g = gimple_build_call (fun, 2, base_addr, sz_arg); gimple_set_location (g, loc); diff --git a/gcc/asan.h b/gcc/asan.h index 214318e..86b2955 100644 --- a/gcc/asan.h +++ b/gcc/asan.h @@ -75,13 +75,18 @@ enum asan_check_flags }; /* Flags for Asan check builtins. */ +#define IFN_ASAN_MARK_FLAGS DEF(POISON), DEF(UNPOISON) + enum asan_mark_flags { - ASAN_MARK_CLOBBER = 1 << 0, - ASAN_MARK_UNCLOBBER = 1 << 1, - ASAN_MARK_LAST = 1 << 2 +#define DEF(X) ASAN_MARK_##X + IFN_ASAN_MARK_FLAGS +#undef DEF }; +/* Return true if STMT is ASAN_MARK with FLAG as first argument. */ +extern bool asan_mark_p (gimple *stmt, enum asan_mark_flags flag); + /* Return the size of padding needed to insert after a protected decl of SIZE. */ diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c index 0353829..ed4c303 100644 --- a/gcc/gimple-pretty-print.c +++ b/gcc/gimple-pretty-print.c @@ -36,6 +36,7 @@ along with GCC; see the file COPYING3. If not see #include "dumpfile.h" /* for dump_flags */ #include "value-prof.h" #include "trans-mem.h" +#include "asan.h" #define INDENT(SPACE) \ do { int i; for (i = 0; i < SPACE; i++) pp_space (buffer); } while (0) @@ -581,22 +582,54 @@ dump_gimple_return (pretty_printer *buffer, greturn *gs, int spc, int flags) static void dump_gimple_call_args (pretty_printer *buffer, gcall *gs, int flags) { - size_t i; + size_t i = 0; - for (i = 0; i < gimple_call_num_args (gs); i++) + /* Pretty print first arg to certain internal fns. */ + if (gimple_call_internal_p (gs)) { - dump_generic_node (buffer, gimple_call_arg (gs, i), 0, flags, false); - if (i < gimple_call_num_args (gs) - 1) + const char *const *enums = NULL; + unsigned limit = 0; + + switch (gimple_call_internal_fn (gs)) + { + case IFN_ASAN_MARK: +#define DEF(X) #X + static const char *const asan_mark_args[] = {IFN_ASAN_MARK_FLAGS}; +#undef DEF + enums = asan_mark_args; + limit = ARRAY_SIZE (asan_mark_args); + break; + + default: + break; + } + if (limit) + { + tree arg0 = gimple_call_arg (gs, 0); + HOST_WIDE_INT v; + + if (TREE_CODE (arg0) == INTEGER_CST + && tree_fits_shwi_p (arg0) + && (v = tree_to_shwi (arg0)) >= 0 && v < limit) + { + i++; + pp_string (buffer, enums[v]); + } + } + } + + + for (; i < gimple_call_num_args (gs); i++) + { + if (i) pp_string (buffer, ", "); + dump_generic_node (buffer, gimple_call_arg (gs, i), 0, flags, false); } if (gimple_call_va_arg_pack_p (gs)) { - if (gimple_call_num_args (gs) > 0) - { - pp_comma (buffer); - pp_space (buffer); - } + if (i) + pp_string (buffer, ", "); pp_string (buffer, "__builtin_va_arg_pack ()"); } diff --git a/gcc/gimple.c b/gcc/gimple.c index 973bcd7..de8fa45 100644 --- a/gcc/gimple.c +++ b/gcc/gimple.c @@ -2626,7 +2626,7 @@ nonfreeing_call_p (gimple *call) case IFN_ABNORMAL_DISPATCHER: return true; case IFN_ASAN_MARK: - return tree_to_uhwi (gimple_call_arg (call, 0)) == ASAN_MARK_UNCLOBBER; + return tree_to_uhwi (gimple_call_arg (call, 0)) == ASAN_MARK_UNPOISON; default: if (gimple_call_flags (call) & ECF_LEAF) return true; diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 673738c..b8928d3 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -1102,7 +1102,7 @@ build_asan_poison_call_expr (tree decl) return build_call_expr_internal_loc (UNKNOWN_LOCATION, IFN_ASAN_MARK, void_type_node, 3, build_int_cst (integer_type_node, - ASAN_MARK_CLOBBER), + ASAN_MARK_POISON), base, unit_size); } @@ -1131,7 +1131,7 @@ asan_poison_variable (tree decl, bool poison, gimple_stmt_iterator *it, if (DECL_ALIGN_UNIT (decl) <= ASAN_SHADOW_GRANULARITY) SET_DECL_ALIGN (decl, BITS_PER_UNIT * ASAN_SHADOW_GRANULARITY); - HOST_WIDE_INT flags = poison ? ASAN_MARK_CLOBBER : ASAN_MARK_UNCLOBBER; + HOST_WIDE_INT flags = poison ? ASAN_MARK_POISON : ASAN_MARK_UNPOISON; gimple *g = gimple_build_call_internal (IFN_ASAN_MARK, 3, diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c index c47a5e8..c1538e4 100644 --- a/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-1.c @@ -42,6 +42,6 @@ int main(int argc, char **argv) return 0; } -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, 4\\);" 2 "asan0" } } */ -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &c, 4\\);" 2 "asan0" } } */ -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &e, 4\\);" 2 "asan0" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(UNPOISON, &a, 4\\);" 2 "asan0" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(UNPOISON, &c, 4\\);" 2 "asan0" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(UNPOISON, &e, 4\\);" 2 "asan0" } } */ diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c index 73ef4e0..7c39614 100644 --- a/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-goto-2.c @@ -22,4 +22,4 @@ int main(int argc, char **argv) return 0; } -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, 4\\);" 1 "asan0" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(UNPOISON, &a, 4\\);" 1 "asan0" } } */ diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c index a834268..d4d7539 100644 --- a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-1.c @@ -21,5 +21,5 @@ main (int argc, char **argv) return 0; } -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, \[0-9\]\\);" 2 "gimple" } } */ -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &a, \[0-9\]\\);" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(UNPOISON, &a, \[0-9\]\\);" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(POISON, &a, \[0-9\]\\);" 1 "gimple" } } */ diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c index 8aeca5a..5a5ea37 100644 --- a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-2.c @@ -25,9 +25,9 @@ main (int argc, char **argv) return 0; } -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, \[0-9\]\\);" 2 "gimple" } } */ -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &b, \[0-9\]\\);" 2 "gimple" } } */ -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &c, \[0-9\]\\);" 2 "gimple" } } */ -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &a, \[0-9\]\\);" 1 "gimple" } } */ -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &b, \[0-9\]\\);" 1 "gimple" } } */ -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &c, \[0-9\]\\);" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(UNPOISON, &a, \[0-9\]\\);" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(UNPOISON, &b, \[0-9\]\\);" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(UNPOISON, &c, \[0-9\]\\);" 2 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(POISON, &a, \[0-9\]\\);" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(POISON, &b, \[0-9\]\\);" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(POISON, &c, \[0-9\]\\);" 1 "gimple" } } */ diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c index 828cb7c..f361591 100644 --- a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-3.c @@ -32,5 +32,5 @@ main (int argc, char **argv) return 0; } -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(2, &a, \[0-9\]\\);" 4 "gimple" } } */ -/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(1, &a, \[0-9\]\\);" 1 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(UNPOISON, &a, \[0-9\]\\);" 4 "gimple" } } */ +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(POISON, &a, \[0-9\]\\);" 1 "gimple" } } */ -- 2.7.4 From 23387f866f6043803a0858019a309c34b4a5e231 Mon Sep 17 00:00:00 2001 From: marxin Date: Mon, 19 Jun 2017 13:27:48 +0000 Subject: [PATCH 15/16] Initialize live_switch_vars for SWITCH_BODY == STATEMENT_LIST (PR sanitizer/80879). 2017-06-19 Martin Liska PR sanitizer/80879 * gimplify.c (gimplify_switch_expr): Initialize live_switch_vars for SWITCH_BODY == STATEMENT_LIST. 2017-06-19 Martin Liska PR sanitizer/80879 * gcc.dg/asan/use-after-scope-switch-4.c: New test. upstream hash: dfbe80905a8674b4b1be4bf9181e824b37ffa33a git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@249368 138bc75d-0d04-0410-961f-82ee72b054a4 Change-Id: I64057623544d67381f52230ba75a9fa804eb6eb2 --- gcc/gimplify.c | 3 +- .../gcc.dg/asan/use-after-scope-switch-4.c | 35 ++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.dg/asan/use-after-scope-switch-4.c diff --git a/gcc/gimplify.c b/gcc/gimplify.c index b8928d3..bd48300 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -2241,7 +2241,8 @@ gimplify_switch_expr (tree *expr_p, gimple_seq *pre_p) /* Do not create live_switch_vars if SWITCH_BODY is not a BIND_EXPR. */ saved_live_switch_vars = gimplify_ctxp->live_switch_vars; - if (TREE_CODE (SWITCH_BODY (switch_expr)) == BIND_EXPR) + tree_code body_type = TREE_CODE (SWITCH_BODY (switch_expr)); + if (body_type == BIND_EXPR || body_type == STATEMENT_LIST) gimplify_ctxp->live_switch_vars = new hash_set (4); else gimplify_ctxp->live_switch_vars = NULL; diff --git a/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-4.c b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-4.c new file mode 100644 index 0000000..290a920 --- /dev/null +++ b/gcc/testsuite/gcc.dg/asan/use-after-scope-switch-4.c @@ -0,0 +1,35 @@ +// { dg-do run } +// { dg-additional-options "-fdump-tree-gimple" } + +int *ptr; + +struct a +{ + int c; +}; + +int main(int argc, char **argv) +{ + struct a e; + e.c = 2; + int x = 0; + + for (;;) + switch (e.c) + case 3: + { + int resxxx; + case 2: + ptr = &resxxx; + *ptr = 123; + + if (x) + return 0; + else + x = 1; + } + + return 1; +} + +/* { dg-final { scan-tree-dump-times "ASAN_MARK \\(UNPOISON, &resxxx, \[0-9\]\\);" 2 "gimple" } } */ -- 2.7.4 From 282842399f40d4063b5d61f62c2c4cd92c370df8 Mon Sep 17 00:00:00 2001 From: Denis Khalikov Date: Fri, 5 Oct 2018 11:57:28 +0300 Subject: [PATCH 16/16] [Sanitizers] Disable use-after-scope by default. So, until the patch "Speed up use-after-scope (v2): rewrite into SSA" is not implemented, we set use-after-scope disabled by default. Change-Id: Ia84ce0652ce68bc7c269d72a2a4613cb0806bcf4 --- gcc/opts.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/gcc/opts.c b/gcc/opts.c index 1455a14..b159d1e 100644 --- a/gcc/opts.c +++ b/gcc/opts.c @@ -973,12 +973,6 @@ finish_options (struct gcc_options *opts, struct gcc_options *opts_set, opts->x_flag_strict_overflow = 0; } - /* Enable -fsanitize-address-use-after-scope if address sanitizer is - enabled. */ - if (opts->x_flag_sanitize - && !opts_set->x_flag_sanitize_address_use_after_scope) - opts->x_flag_sanitize_address_use_after_scope = true; - /* Force -fstack-reuse=none in case -fsanitize-address-use-after-scope is enabled. */ if (opts->x_flag_sanitize_address_use_after_scope) -- 2.7.4