Commit 187230a7 by Joseph Myers Committed by Joseph Myers

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
parent 2a925431
2005-04-20 Joseph S. Myers <joseph@codesourcery.com>
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.
2005-04-20 Kazu Hirata <kazu@cs.umass.edu>
* tree-ssa-phiopt.c (tree_ssa_phi_opt): Update calls to
......
......@@ -673,6 +673,8 @@ pop_scope (void)
bool functionbody = scope->function_body;
bool keep = functionbody || scope->keep || scope->bindings;
c_end_vm_scope (scope->depth);
/* If appropriate, create a BLOCK to record the decls for the life
of this function. */
block = 0;
......@@ -1983,6 +1985,12 @@ pushdecl (tree x)
|| DECL_INITIAL (x) || !DECL_EXTERNAL (x)))
DECL_CONTEXT (x) = current_function_decl;
/* If this is of variably modified type, prevent jumping into its
scope. */
if ((TREE_CODE (x) == VAR_DECL || TREE_CODE (x) == TYPE_DECL)
&& variably_modified_type_p (TREE_TYPE (x), NULL_TREE))
c_begin_vm_scope (scope->depth);
/* Anonymous decls are just inserted in the scope. */
if (!name)
{
......@@ -2439,7 +2447,7 @@ define_label (location_t location, tree name)
if there is a containing function with a declared label with
the same name. */
tree label = I_LABEL_DECL (name);
struct c_label_list *nlist;
struct c_label_list *nlist_se, *nlist_vm;
if (label
&& ((DECL_CONTEXT (label) == current_function_decl
......@@ -2458,6 +2466,9 @@ define_label (location_t location, tree name)
definition. */
if (C_DECL_UNDEFINABLE_STMT_EXPR (label))
error ("%Jjump into statement expression", label);
if (C_DECL_UNDEFINABLE_VM (label))
error ("%Jjump into scope of identifier with variably modified type",
label);
DECL_SOURCE_LOCATION (label) = location;
}
else
......@@ -2474,10 +2485,15 @@ define_label (location_t location, tree name)
warning ("%Htraditional C lacks a separate namespace for labels, "
"identifier %qE conflicts", &location, name);
nlist = XOBNEW (&parser_obstack, struct c_label_list);
nlist->next = label_context_stack->labels_def;
nlist->label = label;
label_context_stack->labels_def = nlist;
nlist_se = XOBNEW (&parser_obstack, struct c_label_list);
nlist_se->next = label_context_stack_se->labels_def;
nlist_se->label = label;
label_context_stack_se->labels_def = nlist_se;
nlist_vm = XOBNEW (&parser_obstack, struct c_label_list);
nlist_vm->next = label_context_stack_vm->labels_def;
nlist_vm->label = label;
label_context_stack_vm->labels_def = nlist_vm;
/* Mark label as having been defined. */
DECL_INITIAL (label) = error_mark_node;
......@@ -5637,7 +5653,8 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
{
tree decl1, old_decl;
tree restype, resdecl;
struct c_label_context *nstack;
struct c_label_context_se *nstack_se;
struct c_label_context_vm *nstack_vm;
current_function_returns_value = 0; /* Assume, until we see it does. */
current_function_returns_null = 0;
......@@ -5646,11 +5663,18 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,
current_extern_inline = 0;
c_switch_stack = NULL;
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;
nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se);
nstack_se->labels_def = NULL;
nstack_se->labels_used = NULL;
nstack_se->next = label_context_stack_se;
label_context_stack_se = nstack_se;
nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm);
nstack_vm->labels_def = NULL;
nstack_vm->labels_used = NULL;
nstack_vm->scope = 0;
nstack_vm->next = label_context_stack_vm;
label_context_stack_vm = nstack_vm;
/* Indicate no valid break/continue context by setting these variables
to some non-null, non-label value. We'll notice and emit the proper
......@@ -6233,7 +6257,8 @@ finish_function (void)
{
tree fndecl = current_function_decl;
label_context_stack = label_context_stack->next;
label_context_stack_se = label_context_stack_se->next;
label_context_stack_vm = label_context_stack_vm->next;
if (TREE_CODE (fndecl) == FUNCTION_DECL
&& targetm.calls.promote_prototypes (TREE_TYPE (fndecl)))
......
......@@ -86,7 +86,8 @@ struct lang_type GTY(())
/* For FUNCTION_DECLs, evaluates true if the decl is built-in but has
been declared. */
#define C_DECL_DECLARED_BUILTIN(EXP) DECL_LANG_FLAG_3 (EXP)
#define C_DECL_DECLARED_BUILTIN(EXP) \
DECL_LANG_FLAG_3 (FUNCTION_DECL_CHECK (EXP))
/* Record whether a decl was declared register. This is strictly a
front-end flag, whereas DECL_REGISTER is used for code generation;
......@@ -97,7 +98,7 @@ struct lang_type GTY(())
unevaluated operand of sizeof / typeof / alignof. This is only
used for functions declared static but not defined, though outside
sizeof and typeof it is set for other function decls as well. */
#define C_DECL_USED(EXP) DECL_LANG_FLAG_5 (EXP)
#define C_DECL_USED(EXP) DECL_LANG_FLAG_5 (FUNCTION_DECL_CHECK (EXP))
/* Record whether a label was defined in a statement expression which
has finished and so can no longer be jumped to. */
......@@ -110,6 +111,18 @@ struct lang_type GTY(())
#define C_DECL_UNDEFINABLE_STMT_EXPR(EXP) \
DECL_LANG_FLAG_7 (LABEL_DECL_CHECK (EXP))
/* Record whether a label was defined in the scope of an identifier
with variably modified type which has finished and so can no longer
be jumped to. */
#define C_DECL_UNJUMPABLE_VM(EXP) \
DECL_LANG_FLAG_3 (LABEL_DECL_CHECK (EXP))
/* Record whether a label was the subject of a goto from outside the
current level of scopes of identifiers with variably modified type
and so cannot be defined right now. */
#define C_DECL_UNDEFINABLE_VM(EXP) \
DECL_LANG_FLAG_5 (LABEL_DECL_CHECK (EXP))
/* Nonzero for a decl which either doesn't exist or isn't a prototype.
N.B. Could be simplified if all built-in decls had complete prototypes
(but this is presently difficult because some of them need FILE*). */
......@@ -354,8 +367,8 @@ struct language_function GTY(())
int extern_inline;
};
/* Save lists of labels used or defined in particular statement
expression contexts. Allocated on the parser obstack. */
/* Save lists of labels used or defined in particular contexts.
Allocated on the parser obstack. */
struct c_label_list
{
......@@ -365,14 +378,32 @@ struct c_label_list
struct c_label_list *next;
};
struct c_label_context
/* Statement expression context. */
struct c_label_context_se
{
/* The labels defined at this level of nesting. */
struct c_label_list *labels_def;
/* The labels used at this level of nesting. */
struct c_label_list *labels_used;
/* The next outermost context. */
struct c_label_context_se *next;
};
/* Context of variably modified declarations. */
struct c_label_context_vm
{
/* The labels defined at this level of nesting. */
struct c_label_list *labels_def;
/* The labels used at this level of nesting. */
struct c_label_list *labels_used;
/* The scope of this context. Multiple contexts may be at the same
numbered scope, since each variably modified declaration starts a
new context. */
unsigned scope;
/* The next outermost context. */
struct c_label_context *next;
struct c_label_context_vm *next;
};
......@@ -477,7 +508,8 @@ extern int in_sizeof;
extern int in_typeof;
extern struct c_switch *c_switch_stack;
extern struct c_label_context *label_context_stack;
extern struct c_label_context_se *label_context_stack_se;
extern struct c_label_context_vm *label_context_stack_vm;
extern tree require_complete_type (tree);
extern int same_translation_unit_p (tree, tree);
......@@ -532,6 +564,8 @@ extern tree c_finish_return (tree);
extern tree c_finish_bc_stmt (tree *, bool);
extern tree c_finish_goto_label (tree);
extern tree c_finish_goto_ptr (tree);
extern void c_begin_vm_scope (unsigned int);
extern void c_end_vm_scope (unsigned int);
/* Set to 0 at beginning of a function definition, set to 1 if
a return statement that specifies a return value is seen. */
......
......@@ -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. */
......
2005-04-20 Joseph S. Myers <joseph@codesourcery.com>
PR c/12913
* objc-act.c (objc_start_function): Create stack level for context
of identifiers with variably modified type.
2005-03-30 Joseph S. Myers <joseph@codesourcery.com>
PR c/772
......
......@@ -7666,12 +7666,19 @@ objc_start_function (tree name, tree type, tree attrs,
cplus_decl_attributes (&fndecl, attrs, 0);
start_preparsed_function (fndecl, attrs, /*flags=*/SF_DEFAULT);
#else
struct c_label_context *nstack;
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;
struct c_label_context_se *nstack_se;
struct c_label_context_vm *nstack_vm;
nstack_se = XOBNEW (&parser_obstack, struct c_label_context_se);
nstack_se->labels_def = NULL;
nstack_se->labels_used = NULL;
nstack_se->next = label_context_stack_se;
label_context_stack_se = nstack_se;
nstack_vm = XOBNEW (&parser_obstack, struct c_label_context_vm);
nstack_vm->labels_def = NULL;
nstack_vm->labels_used = NULL;
nstack_vm->scope = 0;
nstack_vm->next = label_context_stack_vm;
label_context_stack_vm = nstack_vm;
decl_attributes (&fndecl, attrs, 0);
announce_function (fndecl);
DECL_INITIAL (fndecl) = error_mark_node;
......
2005-04-20 Joseph S. Myers <joseph@codesourcery.com>
PR c/12913
* 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.
2005-04-19 Richard Henderson <rth@redhat.com>
* lib/target-supports.exp (check_effective_target_vect_int_mult):
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
/* Test for labels and VM declarations: bug 12913.
switch statements must not jump into the scope of VM declarations.
c99-vla-jump-1.c tests with just that label and goto, VLAs.
c99-vla-jump-2.c tests with many other labels and gotos, VLAs.
c99-vla-jump-3.c tests with just that label and goto, VM.
c99-vla-jump-4.c tests with many other labels and gotos, VM.
c99-vla-jump-5.c tests with switch statements. */
/* Origin: Joseph Myers <joseph@codesourcery.com> */
/* { dg-do compile } */
/* { dg-options "-std=iso9899:1999 -pedantic-errors" } */
void
f (int a, int b)
{
switch (a) {
int v[b];
case 2: /* { dg-error "error: case label in scope of identifier with variably modified type not containing enclosing switch statement" } */
default: /* { dg-error "error: 'default' label in scope of identifier with variably modified type not containing enclosing switch statement" } */
switch (a)
{
case 4:
{ int z[b]; }
default:
;
int w[b];
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment