diff options
author | Jakub Jelinek <jakub@redhat.com> | 2017-11-28 22:24:32 +0100 |
---|---|---|
committer | Jakub Jelinek <jakub@gcc.gnu.org> | 2017-11-28 22:24:32 +0100 |
commit | 1a2e970832f6076e76adc06b42c106bdb568a86c (patch) | |
tree | dc1f654cba4d0bcd4a20572243e7a1178be93750 /gcc/cp/decl.c | |
parent | 058f0b9e5f073da9d1d98a91e482cbdead1561ee (diff) | |
download | gcc-1a2e970832f6076e76adc06b42c106bdb568a86c.zip gcc-1a2e970832f6076e76adc06b42c106bdb568a86c.tar.gz gcc-1a2e970832f6076e76adc06b42c106bdb568a86c.tar.bz2 |
re PR sanitizer/81275 (-fsanitize=thread produce incorrect -Wreturn-type warning)
PR sanitizer/81275
* cp-tree.h (SWITCH_STMT_ALL_CASES_P): Define.
(SWITCH_STMT_NO_BREAK_P): Define.
(note_break_stmt, note_iteration_stmt_body_start,
note_iteration_stmt_body_end): Declare.
* decl.c (struct cp_switch): Add has_default_p, break_stmt_seen_p
and in_loop_body_p fields.
(push_switch): Clear them.
(pop_switch): Set SWITCH_STMT_CANNOT_FALLTHRU_P if has_default_p
and !break_stmt_seen_p. Assert in_loop_body_p is false.
(note_break_stmt, note_iteration_stmt_body_start,
note_iteration_stmt_body_end): New functions.
(finish_case_label): Set has_default_p when both low and high
are NULL_TREE.
* parser.c (cp_parser_iteration_statement): Use
note_iteration_stmt_body_start and note_iteration_stmt_body_end
around parsing iteration body.
* pt.c (tsubst_expr): Likewise.
* cp-objcp-common.c (cxx_block_may_fallthru): Return false for
SWITCH_STMT which contains no BREAK_STMTs, contains a default:
CASE_LABEL_EXPR and where SWITCH_STMT_BODY isn't empty and
can't fallthru.
* semantics.c (finish_break_stmt): Call note_break_stmt.
* cp-gimplify.c (genericize_switch_stmt): Copy SWITCH_STMT_ALL_CASES_P
bit to SWITCH_ALL_CASES_P. Assert that if SWITCH_STMT_NO_BREAK_P then
the break label is not TREE_USED.
* g++.dg/warn/pr81275-1.C: New test.
* g++.dg/warn/pr81275-2.C: New test.
* g++.dg/warn/pr81275-3.C: New test.
* c-c++-common/tsan/pr81275.c: Skip for C++ and -O2.
From-SVN: r255218
Diffstat (limited to 'gcc/cp/decl.c')
-rw-r--r-- | gcc/cp/decl.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 9f557b8..7085d5a 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -3426,6 +3426,13 @@ struct cp_switch /* Remember whether there was a case value that is outside the range of the original type of the controlling expression. */ bool outside_range_p; + /* Remember whether a default: case label has been seen. */ + bool has_default_p; + /* Remember whether a BREAK_STMT has been seen in this SWITCH_STMT. */ + bool break_stmt_seen_p; + /* Set if inside of {FOR,DO,WHILE}_BODY nested inside of a switch, + where BREAK_STMT doesn't belong to the SWITCH_STMT. */ + bool in_loop_body_p; }; /* A stack of the currently active switch statements. The innermost @@ -3448,6 +3455,9 @@ push_switch (tree switch_stmt) p->switch_stmt = switch_stmt; p->cases = splay_tree_new (case_compare, NULL, NULL); p->outside_range_p = false; + p->has_default_p = false; + p->break_stmt_seen_p = false; + p->in_loop_body_p = false; switch_stack = p; } @@ -3468,11 +3478,55 @@ pop_switch (void) SWITCH_STMT_COND (cs->switch_stmt), bool_cond_p, cs->outside_range_p); + /* For the benefit of block_may_fallthru remember if the switch body + case labels cover all possible values and if there are break; stmts. */ + if (cs->has_default_p + || (!processing_template_decl + && c_switch_covers_all_cases_p (cs->cases, + SWITCH_STMT_TYPE (cs->switch_stmt)))) + SWITCH_STMT_ALL_CASES_P (cs->switch_stmt) = 1; + if (!cs->break_stmt_seen_p) + SWITCH_STMT_NO_BREAK_P (cs->switch_stmt) = 1; + gcc_assert (!cs->in_loop_body_p); splay_tree_delete (cs->cases); switch_stack = switch_stack->next; free (cs); } +/* Note that a BREAK_STMT is about to be added. If it is inside of + a SWITCH_STMT and not inside of a loop body inside of it, note + in switch_stack we've seen a BREAK_STMT. */ + +void +note_break_stmt (void) +{ + if (switch_stack && !switch_stack->in_loop_body_p) + switch_stack->break_stmt_seen_p = true; +} + +/* Note the start of processing of an iteration statement's body. + The note_break_stmt function will do nothing while processing it. + Return a flag that should be passed to note_iteration_stmt_body_end. */ + +bool +note_iteration_stmt_body_start (void) +{ + if (!switch_stack) + return false; + bool ret = switch_stack->in_loop_body_p; + switch_stack->in_loop_body_p = true; + return ret; +} + +/* Note the end of processing of an iteration statement's body. */ + +void +note_iteration_stmt_body_end (bool prev) +{ + if (switch_stack) + switch_stack->in_loop_body_p = prev; +} + /* Convert a case constant VALUE in a switch to the type TYPE of the switch condition. Note that if TYPE and VALUE are already integral we don't really do the conversion because the language-independent @@ -3507,6 +3561,9 @@ finish_case_label (location_t loc, tree low_value, tree high_value) cp_binding_level *p; tree type; + if (low_value == NULL_TREE && high_value == NULL_TREE) + switch_stack->has_default_p = true; + if (processing_template_decl) { tree label; |