aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-typeck.c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2005-04-20 17:41:48 +0100
committerJoseph Myers <jsm28@gcc.gnu.org>2005-04-20 17:41:48 +0100
commit187230a795716fc0d98cb066402fe9d71639996c (patch)
treee2e44d98a3c2439eda0265c0bce9ef5990fc410d /gcc/c-typeck.c
parent2a9254314b416c9d6e8eccf600a54ed829a48147 (diff)
downloadgcc-187230a795716fc0d98cb066402fe9d71639996c.zip
gcc-187230a795716fc0d98cb066402fe9d71639996c.tar.gz
gcc-187230a795716fc0d98cb066402fe9d71639996c.tar.bz2
re PR c/12913 (Jumps into variable length array scope not rejected)
PR c/12913 * c-tree.h (struct c_label_list): Update comment. (struct c_label_context): Rename to struct c_label_context_se. (label_context_stack): Rename to label_context_stack_se. (C_DECL_UNJUMPABLE_VM, C_DECL_UNDEFINABLE_VM, struct c_label_context_vm, label_context_stack_vm, c_begin_vm_scope, c_end_vm_scope): New. (C_DECL_DECLARED_BUILTIN, C_DECL_USED): Use FUNCTION_DECL_CHECK. * c-decl.c (pop_scope): Call c_end_vm_scope. (pushdecl): Call c_begin_vm_scope for variably modified declarations. (define_label): Check for jumping into scope of identifier with variably modified type. Push label on stack for those defined at current context of identifiers with variably modified type. (start_function): Create stack level for context of identifiers with variably modified type. (finish_function): Pop stack level for context of identifiers with variably modified type. * c-typeck.c (label_context_stack): Rename to label_context_stack_se. (label_context_stack_vm, c_begin_vm_scope, c_end_vm_scope): New. (c_finish_goto_label): Check for jumping into scope of identifier with variably modified type. Push label on stack for those jumped to from current context of identifiers with variably modified type. (struct c_switch): Add blocked_vm. (c_start_case): Initialize blocked_vm. (do_case): Check blocked_vm. (c_finish_case): Add comment. (c_begin_stmt_expr, c_finish_stmt_expr): Update for renamed variable label_context_stack. objc: * objc-act.c (objc_start_function): Create stack level for context of identifiers with variably modified type. testsuite: * gcc.dg/c99-vla-jump-1.c, gcc.dg/c99-vla-jump-2.c, gcc.dg/c99-vla-jump-3.c, gcc.dg/c99-vla-jump-4.c, gcc.dg/c99-vla-jump-5.c: New tests. From-SVN: r98464
Diffstat (limited to 'gcc/c-typeck.c')
-rw-r--r--gcc/c-typeck.c136
1 files changed, 122 insertions, 14 deletions
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index a39d703..3f7699f 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -64,7 +64,8 @@ int in_sizeof;
/* The level of nesting inside "typeof". */
int in_typeof;
-struct c_label_context *label_context_stack;
+struct c_label_context_se *label_context_stack_se;
+struct c_label_context_vm *label_context_stack_vm;
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
@@ -6495,15 +6496,33 @@ c_finish_goto_label (tree label)
return NULL_TREE;
}
+ if (C_DECL_UNJUMPABLE_VM (decl))
+ {
+ error ("jump into scope of identifier with variably modified type");
+ 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->next = label_context_stack_se->labels_used;
+ nlist->label = decl;
+ label_context_stack_se->labels_used = nlist;
+ }
+
+ if (!C_DECL_UNDEFINABLE_VM (decl))
+ {
+ /* No jump from outside this context context of identifiers with
+ variably modified type, 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_vm->labels_used;
nlist->label = decl;
- label_context_stack->labels_used = nlist;
+ label_context_stack_vm->labels_used = nlist;
}
TREE_USED (decl) = 1;
@@ -6637,6 +6656,11 @@ struct c_switch {
appear. */
unsigned int blocked_stmt_expr;
+ /* Scope of outermost declarations of identifiers with variably
+ modified type within this switch statement; if nonzero, case and
+ default labels may not appear. */
+ unsigned int blocked_vm;
+
/* The next node on the stack. */
struct c_switch *next;
};
@@ -6692,6 +6716,7 @@ c_start_case (tree exp)
cs->orig_type = orig_type;
cs->cases = splay_tree_new (case_compare, NULL, NULL);
cs->blocked_stmt_expr = 0;
+ cs->blocked_vm = 0;
cs->next = c_switch_stack;
c_switch_stack = cs;
@@ -6705,7 +6730,8 @@ do_case (tree low_value, tree high_value)
{
tree label = NULL_TREE;
- if (c_switch_stack && !c_switch_stack->blocked_stmt_expr)
+ if (c_switch_stack && !c_switch_stack->blocked_stmt_expr
+ && !c_switch_stack->blocked_vm)
{
label = c_add_case_label (c_switch_stack->cases,
SWITCH_COND (c_switch_stack->switch_expr),
@@ -6723,6 +6749,15 @@ do_case (tree low_value, tree high_value)
error ("%<default%> label in statement expression not containing "
"enclosing switch statement");
}
+ else if (c_switch_stack && c_switch_stack->blocked_vm)
+ {
+ if (low_value)
+ error ("case label in scope of identifier with variably modified "
+ "type not containing enclosing switch statement");
+ else
+ error ("%<default%> label in scope of identifier with variably "
+ "modified type not containing enclosing switch statement");
+ }
else if (low_value)
error ("case label not within a switch statement");
else
@@ -6741,6 +6776,9 @@ c_finish_case (tree body)
SWITCH_BODY (cs->switch_expr) = body;
+ /* We must not be within a statement expression nested in the switch
+ at this point; we might, however, be within the scope of an
+ identifier with variably modified type nested in the switch. */
gcc_assert (!cs->blocked_stmt_expr);
/* Emit warnings as needed. */
@@ -7015,7 +7053,7 @@ tree
c_begin_stmt_expr (void)
{
tree ret;
- struct c_label_context *nstack;
+ struct c_label_context_se *nstack;
struct c_label_list *glist;
/* We must force a BLOCK for this level so that, if it is not expanded
@@ -7028,17 +7066,17 @@ c_begin_stmt_expr (void)
c_switch_stack->blocked_stmt_expr++;
gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
}
- for (glist = label_context_stack->labels_used;
+ for (glist = label_context_stack_se->labels_used;
glist != NULL;
glist = glist->next)
{
C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 1;
}
- nstack = XOBNEW (&parser_obstack, struct c_label_context);
+ nstack = XOBNEW (&parser_obstack, struct c_label_context_se);
nstack->labels_def = NULL;
nstack->labels_used = NULL;
- nstack->next = label_context_stack;
- label_context_stack = nstack;
+ nstack->next = label_context_stack_se;
+ label_context_stack_se = nstack;
/* Mark the current statement list as belonging to a statement list. */
STATEMENT_LIST_STMT_EXPR (ret) = 1;
@@ -7061,7 +7099,7 @@ c_finish_stmt_expr (tree body)
}
/* It is no longer possible to jump to labels defined within this
statement expression. */
- for (dlist = label_context_stack->labels_def;
+ for (dlist = label_context_stack_se->labels_def;
dlist != NULL;
dlist = dlist->next)
{
@@ -7069,7 +7107,7 @@ c_finish_stmt_expr (tree body)
}
/* It is again possible to define labels with a goto just outside
this statement expression. */
- for (glist = label_context_stack->next->labels_used;
+ for (glist = label_context_stack_se->next->labels_used;
glist != NULL;
glist = glist->next)
{
@@ -7077,10 +7115,11 @@ c_finish_stmt_expr (tree body)
glist_prev = glist;
}
if (glist_prev != NULL)
- glist_prev->next = label_context_stack->labels_used;
+ glist_prev->next = label_context_stack_se->labels_used;
else
- label_context_stack->next->labels_used = label_context_stack->labels_used;
- label_context_stack = label_context_stack->next;
+ label_context_stack_se->next->labels_used
+ = label_context_stack_se->labels_used;
+ label_context_stack_se = label_context_stack_se->next;
/* Locate the last statement in BODY. See c_end_compound_stmt
about always returning a BIND_EXPR. */
@@ -7151,6 +7190,75 @@ c_finish_stmt_expr (tree body)
return build4 (TARGET_EXPR, type, tmp, body, NULL_TREE, NULL_TREE);
}
+
+/* Begin the scope of an identifier of variably modified type, scope
+ number SCOPE. Jumping from outside this scope to inside it is not
+ permitted. */
+
+void
+c_begin_vm_scope (unsigned int scope)
+{
+ struct c_label_context_vm *nstack;
+ struct c_label_list *glist;
+
+ gcc_assert (scope > 0);
+ if (c_switch_stack && !c_switch_stack->blocked_vm)
+ c_switch_stack->blocked_vm = scope;
+ for (glist = label_context_stack_vm->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_VM (glist->label) = 1;
+ }
+ nstack = XOBNEW (&parser_obstack, struct c_label_context_vm);
+ nstack->labels_def = NULL;
+ nstack->labels_used = NULL;
+ nstack->scope = scope;
+ nstack->next = label_context_stack_vm;
+ label_context_stack_vm = nstack;
+}
+
+/* End a scope which may contain identifiers of variably modified
+ type, scope number SCOPE. */
+
+void
+c_end_vm_scope (unsigned int scope)
+{
+ if (label_context_stack_vm == NULL)
+ return;
+ if (c_switch_stack && c_switch_stack->blocked_vm == scope)
+ c_switch_stack->blocked_vm = 0;
+ /* We may have a number of nested scopes of identifiers with
+ variably modified type, all at this depth. Pop each in turn. */
+ while (label_context_stack_vm->scope == scope)
+ {
+ struct c_label_list *dlist, *glist, *glist_prev = NULL;
+
+ /* It is no longer possible to jump to labels defined within this
+ scope. */
+ for (dlist = label_context_stack_vm->labels_def;
+ dlist != NULL;
+ dlist = dlist->next)
+ {
+ C_DECL_UNJUMPABLE_VM (dlist->label) = 1;
+ }
+ /* It is again possible to define labels with a goto just outside
+ this scope. */
+ for (glist = label_context_stack_vm->next->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_VM (glist->label) = 0;
+ glist_prev = glist;
+ }
+ if (glist_prev != NULL)
+ glist_prev->next = label_context_stack_vm->labels_used;
+ else
+ label_context_stack_vm->next->labels_used
+ = label_context_stack_vm->labels_used;
+ label_context_stack_vm = label_context_stack_vm->next;
+ }
+}
/* Begin and end compound statements. This is as simple as pushing
and popping new statement lists from the tree. */