aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl.c
diff options
context:
space:
mode:
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;