aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2017-11-28 22:24:32 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2017-11-28 22:24:32 +0100
commit1a2e970832f6076e76adc06b42c106bdb568a86c (patch)
treedc1f654cba4d0bcd4a20572243e7a1178be93750 /gcc/cp/decl.c
parent058f0b9e5f073da9d1d98a91e482cbdead1561ee (diff)
downloadgcc-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.c57
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;