diff options
| author | jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-03-30 19:56:39 +0000 |
|---|---|---|
| committer | jsm28 <jsm28@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-03-30 19:56:39 +0000 |
| commit | f08c7a57f79b981e68df4f7d1cfa244297849c4a (patch) | |
| tree | 975e92e4bf871faf584ef0740e176cafc5997392 /gcc/c-typeck.c | |
| parent | 494fc9d0f43f28049e7334c2f16183a700da3882 (diff) | |
| download | ppe42-gcc-f08c7a57f79b981e68df4f7d1cfa244297849c4a.tar.gz ppe42-gcc-f08c7a57f79b981e68df4f7d1cfa244297849c4a.zip | |
PR c/772
PR c/17913
* c-tree.h (C_DECL_UNJUMPABLE_STMT_EXPR,
C_DECL_UNDEFINABLE_STMT_EXPR, struct c_label_list, struct
c_label_context, label_context_stack): New.
* c-decl.c (define_label): Check for jumps into statement
expressions. Add label to list of defined labels.
(start_function): Push context on label_context_stack.
(finish_function): Pop context from label_context_stack.
* c-typeck.c (label_context_stack): New.
(c_finish_goto_label): Check for jumps into statement
expressions. Add label to list of jumped to labels.
(struct c_switch): Add blocked_stmt_expr.
(c_start_case): Initialize it.
(do_case): Check it.
(c_finish_case): Verify !blocked_stmt_expr.
(c_begin_stmt_expr): Push context on label_context_stack.
Increment blocked_stmt_expr. Mark labels jumped to from outside
as undefinable.
(c_finish_stmt_expr): December blocked_stmt_expr. Mark labels
defined in the statement expression and no longer jumpable to.
Mark labels jumped to from just outside the statement expression
as again definable. Pop context from label_context_stack.
* doc/extend.texi (Statement Exprs): Update.
objc:
* objc-act.c (objc_start_function): Push context on
label_context_stack.
testsuite:
* gcc.dg/stmt-expr-label-1.c, gcc.dg/stmt-expr-label-2.c,
gcc.dg/stmt-expr-label-3.c : New tests.
* gcc.c-torture/execute/medce-2.c: Remove.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@97273 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/c-typeck.c')
| -rw-r--r-- | gcc/c-typeck.c | 84 |
1 files changed, 83 insertions, 1 deletions
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c index 9ddafe10c5d..d6ffc87cf39 100644 --- a/gcc/c-typeck.c +++ b/gcc/c-typeck.c @@ -64,6 +64,8 @@ int in_sizeof; /* The level of nesting inside "typeof". */ int in_typeof; +struct c_label_context *label_context_stack; + /* Nonzero if we've already printed a "missing braces around initializer" message within this initializer. */ static int missing_braces_mentioned; @@ -6478,6 +6480,23 @@ c_finish_goto_label (tree label) if (!decl) return NULL_TREE; + if (C_DECL_UNJUMPABLE_STMT_EXPR (decl)) + { + error ("jump into statement expression"); + return NULL_TREE; + } + + if (!C_DECL_UNDEFINABLE_STMT_EXPR (decl)) + { + /* No jump from outside this statement expression context, so + record that there is a jump from within this context. */ + struct c_label_list *nlist; + nlist = XOBNEW (&parser_obstack, struct c_label_list); + nlist->next = label_context_stack->labels_used; + nlist->label = decl; + label_context_stack->labels_used = nlist; + } + TREE_USED (decl) = 1; return add_stmt (build1 (GOTO_EXPR, void_type_node, decl)); } @@ -6604,6 +6623,11 @@ struct c_switch { of the GNU case range extension. */ splay_tree cases; + /* Number of nested statement expressions within this switch + statement; if nonzero, case and default labels may not + appear. */ + unsigned int blocked_stmt_expr; + /* The next node on the stack. */ struct c_switch *next; }; @@ -6658,6 +6682,7 @@ c_start_case (tree exp) cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type); cs->orig_type = orig_type; cs->cases = splay_tree_new (case_compare, NULL, NULL); + cs->blocked_stmt_expr = 0; cs->next = c_switch_stack; c_switch_stack = cs; @@ -6671,7 +6696,7 @@ do_case (tree low_value, tree high_value) { tree label = NULL_TREE; - if (c_switch_stack) + if (c_switch_stack && !c_switch_stack->blocked_stmt_expr) { label = c_add_case_label (c_switch_stack->cases, SWITCH_STMT_COND (c_switch_stack->switch_stmt), @@ -6680,6 +6705,15 @@ do_case (tree low_value, tree high_value) if (label == error_mark_node) label = NULL_TREE; } + else if (c_switch_stack && c_switch_stack->blocked_stmt_expr) + { + if (low_value) + error ("case label in statement expression not containing " + "enclosing switch statement"); + else + error ("%<default%> label in statement expression not containing " + "enclosing switch statement"); + } else if (low_value) error ("case label not within a switch statement"); else @@ -6697,6 +6731,8 @@ c_finish_case (tree body) SWITCH_STMT_BODY (cs->switch_stmt) = body; + gcc_assert (!cs->blocked_stmt_expr); + /* Emit warnings as needed. */ c_do_switch_warnings (cs->cases, cs->switch_stmt); @@ -6963,12 +6999,30 @@ tree c_begin_stmt_expr (void) { tree ret; + struct c_label_context *nstack; + struct c_label_list *glist; /* We must force a BLOCK for this level so that, if it is not expanded later, there is a way to turn off the entire subtree of blocks that are contained in it. */ keep_next_level (); ret = c_begin_compound_stmt (true); + if (c_switch_stack) + { + c_switch_stack->blocked_stmt_expr++; + gcc_assert (c_switch_stack->blocked_stmt_expr != 0); + } + for (glist = label_context_stack->labels_used; + glist != NULL; + glist = glist->next) + { + C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 1; + } + nstack = XOBNEW (&parser_obstack, struct c_label_context); + nstack->labels_def = NULL; + nstack->labels_used = NULL; + nstack->next = label_context_stack; + label_context_stack = nstack; /* Mark the current statement list as belonging to a statement list. */ STATEMENT_LIST_STMT_EXPR (ret) = 1; @@ -6981,8 +7035,36 @@ c_finish_stmt_expr (tree body) { tree last, type, tmp, val; tree *last_p; + struct c_label_list *dlist, *glist, *glist_prev = NULL; body = c_end_compound_stmt (body, true); + if (c_switch_stack) + { + gcc_assert (c_switch_stack->blocked_stmt_expr != 0); + c_switch_stack->blocked_stmt_expr--; + } + /* It is no longer possible to jump to labels defined within this + statement expression. */ + for (dlist = label_context_stack->labels_def; + dlist != NULL; + dlist = dlist->next) + { + C_DECL_UNJUMPABLE_STMT_EXPR (dlist->label) = 1; + } + /* It is again possible to define labels with a goto just outside + this statement expression. */ + for (glist = label_context_stack->next->labels_used; + glist != NULL; + glist = glist->next) + { + C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 0; + glist_prev = glist; + } + if (glist_prev != NULL) + glist_prev->next = label_context_stack->labels_used; + else + label_context_stack->next->labels_used = label_context_stack->labels_used; + label_context_stack = label_context_stack->next; /* Locate the last statement in BODY. See c_end_compound_stmt about always returning a BIND_EXPR. */ |

