re PR c/13014 (if shortcut misses required diagnostics)

2003-11-24  Eric Christopher  <echristo@redhat.com>

	PR C/13014
	* c-decl.c (c_in_iteration_stmt, c_in_case_stmt): New.
	(start_function): Use.
	(c_push_function_context): Ditto.
	(c-pop_function_context): Ditto.
        (language_function): Move...
	* c-tree.h: ... here. Add x_in_iteration_stmt, and
	x_in_case_stmt.
	* c-parse.in (do_stmt_start, select_or_iter_stmt, stmt): Use
	c_in_iteration_stmt, c_in_case_stmt for parser state. Move
	check for valid break or continue statment here...
	* c-semantics.c (genrtl_break_stmt, genrtl_continue_stmt): From
	here. Change original errors to abort.

From-SVN: r73887
This commit is contained in:
Eric Christopher 2003-11-24 20:12:06 +00:00
parent 8273c02d61
commit e13e48e707
5 changed files with 118 additions and 67 deletions

View File

@ -1,3 +1,19 @@
2003-11-24 Eric Christopher <echristo@redhat.com>
PR C/13014
* c-decl.c (c_in_iteration_stmt, c_in_case_stmt): New.
(start_function): Use.
(c_push_function_context): Ditto.
(c-pop_function_context): Ditto.
(language_function): Move...
* c-tree.h: ... here. Add x_in_iteration_stmt, and
x_in_case_stmt.
* c-parse.in (do_stmt_start, select_or_iter_stmt, stmt): Use
c_in_iteration_stmt, c_in_case_stmt for parser state. Move
check for valid break or continue statment here...
* c-semantics.c (genrtl_break_stmt, genrtl_continue_stmt): From
here. Change original errors to abort.
2003-11-24 Jan Hubicka <jh@suse.cz> 2003-11-24 Jan Hubicka <jh@suse.cz>
* fold-const.c (fold): Do not return early when optimizing COMPONENT_REF * fold-const.c (fold): Do not return early when optimizing COMPONENT_REF
@ -204,7 +220,7 @@
* calls.c (expand_call): Allocate new temp in pass1. * calls.c (expand_call): Allocate new temp in pass1.
(store_one_arg): If PARALLEL, calculate excess using mode size of (store_one_arg): If PARALLEL, calculate excess using mode size of
rtvec elt. rtvec elt.
* expr.c (emit_push_insn): If PARALLEL, calculate offset using * expr.c (emit_push_insn): If PARALLEL, calculate offset using
mode size of rtvec elt. mode size of rtvec elt.
* function.c (assign_parms): Use parm in register, if available. * function.c (assign_parms): Use parm in register, if available.

View File

@ -126,6 +126,10 @@ static GTY(()) struct stmt_tree_s c_stmt_tree;
static GTY(()) tree c_scope_stmt_stack; static GTY(()) tree c_scope_stmt_stack;
/* State saving variables. */
int c_in_iteration_stmt;
int c_in_case_stmt;
/* A list of external DECLs that appeared at block scope when there was /* A list of external DECLs that appeared at block scope when there was
some other global meaning for that identifier. */ some other global meaning for that identifier. */
static GTY(()) tree truly_local_externals; static GTY(()) tree truly_local_externals;
@ -425,13 +429,13 @@ void
objc_mark_locals_volatile (void *enclosing_blk) objc_mark_locals_volatile (void *enclosing_blk)
{ {
struct c_scope *scope; struct c_scope *scope;
for (scope = current_scope; for (scope = current_scope;
scope && scope != enclosing_blk; scope && scope != enclosing_blk;
scope = scope->outer) scope = scope->outer)
{ {
tree decl; tree decl;
for (decl = scope->names; decl; decl = TREE_CHAIN (decl)) for (decl = scope->names; decl; decl = TREE_CHAIN (decl))
{ {
DECL_REGISTER (decl) = 0; DECL_REGISTER (decl) = 0;
@ -440,9 +444,9 @@ objc_mark_locals_volatile (void *enclosing_blk)
/* Do not climb up past the current function. */ /* Do not climb up past the current function. */
if (scope->function_body) if (scope->function_body)
break; break;
} }
} }
/* Nonzero if we are currently in the global scope. */ /* Nonzero if we are currently in the global scope. */
int int
@ -1677,7 +1681,7 @@ pushdecl (tree x)
DECL_CONTEXT (x) = current_file_decl; DECL_CONTEXT (x) = current_file_decl;
else else
DECL_CONTEXT (x) = current_function_decl; DECL_CONTEXT (x) = current_function_decl;
if (name) if (name)
{ {
tree old; tree old;
@ -1718,7 +1722,7 @@ pushdecl (tree x)
tree ext = any_external_decl (name); tree ext = any_external_decl (name);
if (ext) if (ext)
{ {
if (duplicate_decls (x, ext, scope != global_scope, if (duplicate_decls (x, ext, scope != global_scope,
false)) false))
x = copy_node (ext); x = copy_node (ext);
} }
@ -2250,7 +2254,7 @@ c_init_decl_processing (void)
tree endlink; tree endlink;
tree ptr_ftype_void, ptr_ftype_ptr; tree ptr_ftype_void, ptr_ftype_ptr;
location_t save_loc = input_location; location_t save_loc = input_location;
/* Adds some ggc roots, and reserved words for c-parse.in. */ /* Adds some ggc roots, and reserved words for c-parse.in. */
c_parse_init (); c_parse_init ();
@ -4637,7 +4641,7 @@ get_parm_info (int void_at_end)
default: abort (); default: abort ();
} }
if (TREE_PURPOSE (decl)) if (TREE_PURPOSE (decl))
/* The first %s will be one of 'struct', 'union', or 'enum'. */ /* The first %s will be one of 'struct', 'union', or 'enum'. */
warning ("\"%s %s\" declared inside parameter list", warning ("\"%s %s\" declared inside parameter list",
keyword, IDENTIFIER_POINTER (TREE_PURPOSE (decl))); keyword, IDENTIFIER_POINTER (TREE_PURPOSE (decl)));
@ -5088,23 +5092,23 @@ finish_struct (tree t, tree fieldlist, tree attributes)
tree *field_array; tree *field_array;
struct lang_type *space; struct lang_type *space;
struct sorted_fields_type *space2; struct sorted_fields_type *space2;
len += list_length (x); len += list_length (x);
/* Use the same allocation policy here that make_node uses, to /* Use the same allocation policy here that make_node uses, to
ensure that this lives as long as the rest of the struct decl. ensure that this lives as long as the rest of the struct decl.
All decls in an inline function need to be saved. */ All decls in an inline function need to be saved. */
space = ggc_alloc (sizeof (struct lang_type)); space = ggc_alloc (sizeof (struct lang_type));
space2 = ggc_alloc (sizeof (struct sorted_fields_type) + len * sizeof (tree)); space2 = ggc_alloc (sizeof (struct sorted_fields_type) + len * sizeof (tree));
len = 0; len = 0;
space->s = space2; space->s = space2;
field_array = &space2->elts[0]; field_array = &space2->elts[0];
for (x = fieldlist; x; x = TREE_CHAIN (x)) for (x = fieldlist; x; x = TREE_CHAIN (x))
{ {
field_array[len++] = x; field_array[len++] = x;
/* If there is anonymous struct or union, break out of the loop. */ /* If there is anonymous struct or union, break out of the loop. */
if (DECL_NAME (x) == NULL) if (DECL_NAME (x) == NULL)
break; break;
@ -5119,7 +5123,7 @@ finish_struct (tree t, tree fieldlist, tree attributes)
} }
} }
} }
for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x)) for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
{ {
TYPE_FIELDS (x) = TYPE_FIELDS (t); TYPE_FIELDS (x) = TYPE_FIELDS (t);
@ -5438,6 +5442,8 @@ start_function (tree declspecs, tree declarator, tree attributes)
current_function_returns_abnormally = 0; current_function_returns_abnormally = 0;
warn_about_return_type = 0; warn_about_return_type = 0;
current_extern_inline = 0; current_extern_inline = 0;
c_in_iteration_stmt = 0;
c_in_case_stmt = 0;
/* Don't expand any sizes in the return type of the function. */ /* Don't expand any sizes in the return type of the function. */
immediate_size_expand = 0; immediate_size_expand = 0;
@ -6251,20 +6257,6 @@ check_for_loop_decls (void)
} }
} }
/* Save and restore the variables in this file and elsewhere
that keep track of the progress of compilation of the current function.
Used for nested functions. */
struct language_function GTY(())
{
struct c_language_function base;
int returns_value;
int returns_null;
int returns_abnormally;
int warn_about_return_type;
int extern_inline;
};
/* Save and reinitialize the variables /* Save and reinitialize the variables
used during compilation of a C function. */ used during compilation of a C function. */
@ -6277,6 +6269,8 @@ c_push_function_context (struct function *f)
p->base.x_stmt_tree = c_stmt_tree; p->base.x_stmt_tree = c_stmt_tree;
p->base.x_scope_stmt_stack = c_scope_stmt_stack; p->base.x_scope_stmt_stack = c_scope_stmt_stack;
p->x_in_iteration_stmt = c_in_iteration_stmt;
p->x_in_case_stmt = c_in_case_stmt;
p->returns_value = current_function_returns_value; p->returns_value = current_function_returns_value;
p->returns_null = current_function_returns_null; p->returns_null = current_function_returns_null;
p->returns_abnormally = current_function_returns_abnormally; p->returns_abnormally = current_function_returns_abnormally;
@ -6303,6 +6297,8 @@ c_pop_function_context (struct function *f)
c_stmt_tree = p->base.x_stmt_tree; c_stmt_tree = p->base.x_stmt_tree;
c_scope_stmt_stack = p->base.x_scope_stmt_stack; c_scope_stmt_stack = p->base.x_scope_stmt_stack;
c_in_iteration_stmt = p->x_in_iteration_stmt;
c_in_case_stmt = p->x_in_case_stmt;
current_function_returns_value = p->returns_value; current_function_returns_value = p->returns_value;
current_function_returns_null = p->returns_null; current_function_returns_null = p->returns_null;
current_function_returns_abnormally = p->returns_abnormally; current_function_returns_abnormally = p->returns_abnormally;
@ -6510,7 +6506,7 @@ merge_translation_unit_decls (void)
tree decl; tree decl;
htab_t link_hash_table; htab_t link_hash_table;
tree block; tree block;
/* Create the BLOCK that poplevel would have created, but don't /* Create the BLOCK that poplevel would have created, but don't
actually call poplevel since that's expensive. */ actually call poplevel since that's expensive. */
block = make_node (BLOCK); block = make_node (BLOCK);
@ -6551,7 +6547,7 @@ merge_translation_unit_decls (void)
DECL_EXTERNAL (decl) = 1; DECL_EXTERNAL (decl) = 1;
else if (DECL_COMMON (old_decl) || DECL_ONE_ONLY (old_decl)) else if (DECL_COMMON (old_decl) || DECL_ONE_ONLY (old_decl))
DECL_EXTERNAL (old_decl) = 1; DECL_EXTERNAL (old_decl) = 1;
if (DECL_EXTERNAL (decl)) if (DECL_EXTERNAL (decl))
{ {
DECL_INITIAL (decl) = NULL_TREE; DECL_INITIAL (decl) = NULL_TREE;
@ -6585,10 +6581,10 @@ merge_translation_unit_decls (void)
{ {
tree global_decl; tree global_decl;
global_decl = htab_find (link_hash_table, decl); global_decl = htab_find (link_hash_table, decl);
if (! global_decl) if (! global_decl)
continue; continue;
/* Print any appropriate error messages, and partially merge /* Print any appropriate error messages, and partially merge
the decls. */ the decls. */
(void) duplicate_decls (decl, global_decl, true, true); (void) duplicate_decls (decl, global_decl, true, true);
@ -6603,7 +6599,7 @@ void
c_write_global_declarations(void) c_write_global_declarations(void)
{ {
tree link; tree link;
for (link = current_file_decl; link; link = TREE_CHAIN (link)) for (link = current_file_decl; link; link = TREE_CHAIN (link))
{ {
tree globals = BLOCK_VARS (DECL_INITIAL (link)); tree globals = BLOCK_VARS (DECL_INITIAL (link));
@ -6611,16 +6607,16 @@ c_write_global_declarations(void)
tree *vec = xmalloc (sizeof (tree) * len); tree *vec = xmalloc (sizeof (tree) * len);
int i; int i;
tree decl; tree decl;
/* Process the decls in the order they were written. */ /* Process the decls in the order they were written. */
for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl)) for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl))
vec[i] = decl; vec[i] = decl;
wrapup_global_declarations (vec, len); wrapup_global_declarations (vec, len);
check_global_declarations (vec, len); check_global_declarations (vec, len);
/* Clean up. */ /* Clean up. */
free (vec); free (vec);
} }
@ -6633,7 +6629,7 @@ c_reset_state (void)
{ {
tree link; tree link;
tree file_scope_decl; tree file_scope_decl;
/* Pop the global scope. */ /* Pop the global scope. */
if (current_scope != global_scope) if (current_scope != global_scope)
current_scope = global_scope; current_scope = global_scope;

View File

@ -257,6 +257,9 @@ do { \
static int stmt_count; static int stmt_count;
static int compstmt_count; static int compstmt_count;
extern int c_in_iteration_stmt;
extern int c_in_case_stmt;
/* Input location of the end of the body of last simple_if; /* Input location of the end of the body of last simple_if;
used by the stmt-rule immediately after simple_if returns. */ used by the stmt-rule immediately after simple_if returns. */
static location_t if_stmt_locus; static location_t if_stmt_locus;
@ -2053,12 +2056,12 @@ pushlevel: /* empty */
; ;
poplevel: /* empty */ poplevel: /* empty */
{ {
@@ifobjc @@ifobjc
if (c_dialect_objc ()) if (c_dialect_objc ())
objc_clear_super_receiver (); objc_clear_super_receiver ();
@@end_ifobjc @@end_ifobjc
$$ = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0); $$ = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
} }
; ;
@ -2202,6 +2205,7 @@ do_stmt_start:
DO DO
{ stmt_count++; { stmt_count++;
compstmt_count++; compstmt_count++;
c_in_iteration_stmt++;
$<ttype>$ $<ttype>$
= add_stmt (build_stmt (DO_STMT, NULL_TREE, = add_stmt (build_stmt (DO_STMT, NULL_TREE,
NULL_TREE)); NULL_TREE));
@ -2212,7 +2216,8 @@ do_stmt_start:
DO_COND ($<ttype>$) = error_mark_node; } DO_COND ($<ttype>$) = error_mark_node; }
c99_block_lineno_labeled_stmt WHILE c99_block_lineno_labeled_stmt WHILE
{ $$ = $<ttype>2; { $$ = $<ttype>2;
RECHAIN_STMTS ($$, DO_BODY ($$)); } RECHAIN_STMTS ($$, DO_BODY ($$));
c_in_iteration_stmt--; }
; ;
/* The forced readahead in here is because we might be at the end of a /* The forced readahead in here is because we might be at the end of a
@ -2295,12 +2300,14 @@ select_or_iter_stmt:
{ stmt_count++; { stmt_count++;
$<ttype>$ = c_begin_while_stmt (); } $<ttype>$ = c_begin_while_stmt (); }
'(' expr ')' '(' expr ')'
{ $4 = c_common_truthvalue_conversion ($4); { c_in_iteration_stmt++;
$4 = c_common_truthvalue_conversion ($4);
c_finish_while_stmt_cond c_finish_while_stmt_cond
(c_common_truthvalue_conversion ($4), $<ttype>2); (c_common_truthvalue_conversion ($4), $<ttype>2);
$<ttype>$ = add_stmt ($<ttype>2); } $<ttype>$ = add_stmt ($<ttype>2); }
c99_block_lineno_labeled_stmt c99_block_lineno_labeled_stmt
{ RECHAIN_STMTS ($<ttype>6, WHILE_BODY ($<ttype>6)); } { c_in_iteration_stmt--;
RECHAIN_STMTS ($<ttype>6, WHILE_BODY ($<ttype>6)); }
| do_stmt_start | do_stmt_start
'(' expr ')' ';' '(' expr ')' ';'
{ DO_COND ($1) = c_common_truthvalue_conversion ($3); } { DO_COND ($1) = c_common_truthvalue_conversion ($3); }
@ -2318,14 +2325,18 @@ select_or_iter_stmt:
FOR_COND ($<ttype>2) FOR_COND ($<ttype>2)
= c_common_truthvalue_conversion ($6); } = c_common_truthvalue_conversion ($6); }
xexpr ')' xexpr ')'
{ FOR_EXPR ($<ttype>2) = $9; } { c_in_iteration_stmt++;
FOR_EXPR ($<ttype>2) = $9; }
c99_block_lineno_labeled_stmt c99_block_lineno_labeled_stmt
{ RECHAIN_STMTS ($<ttype>2, FOR_BODY ($<ttype>2)); } { RECHAIN_STMTS ($<ttype>2, FOR_BODY ($<ttype>2));
c_in_iteration_stmt--;}
| SWITCH '(' expr ')' | SWITCH '(' expr ')'
{ stmt_count++; { stmt_count++;
$<ttype>$ = c_start_case ($3); } $<ttype>$ = c_start_case ($3);
c_in_case_stmt++; }
c99_block_lineno_labeled_stmt c99_block_lineno_labeled_stmt
{ c_finish_case (); } { c_finish_case ();
c_in_case_stmt--; }
; ;
for_init_stmt: for_init_stmt:
@ -2348,9 +2359,21 @@ stmt:
$$ = NULL_TREE; } $$ = NULL_TREE; }
| BREAK ';' | BREAK ';'
{ stmt_count++; { stmt_count++;
if (!(c_in_iteration_stmt || c_in_case_stmt))
{
error ("break statement not within loop or switch");
$$ = NULL_TREE;
}
else
$$ = add_stmt (build_break_stmt ()); } $$ = add_stmt (build_break_stmt ()); }
| CONTINUE ';' | CONTINUE ';'
{ stmt_count++; { stmt_count++;
if (!c_in_iteration_stmt)
{
error ("continue statement not within a loop");
$$ = NULL_TREE;
}
else
$$ = add_stmt (build_continue_stmt ()); } $$ = add_stmt (build_continue_stmt ()); }
| RETURN ';' | RETURN ';'
{ stmt_count++; { stmt_count++;
@ -2397,18 +2420,18 @@ stmt:
{ $$ = NULL_TREE; } { $$ = NULL_TREE; }
@@ifobjc @@ifobjc
| AT_THROW expr ';' | AT_THROW expr ';'
{ stmt_count++; { stmt_count++;
$$ = objc_build_throw_stmt ($2); $$ = objc_build_throw_stmt ($2);
} }
| AT_THROW ';' | AT_THROW ';'
{ stmt_count++; { stmt_count++;
$$ = objc_build_throw_stmt (NULL_TREE); $$ = objc_build_throw_stmt (NULL_TREE);
} }
| objc_try_catch_stmt | objc_try_catch_stmt
{ objc_build_finally_prologue (); } { objc_build_finally_prologue (); }
objc_finally_block objc_finally_block
{ $$ = objc_build_try_catch_finally_stmt ($1, $3); } { $$ = objc_build_try_catch_finally_stmt ($1, $3); }
| AT_SYNCHRONIZED '(' expr ')' | AT_SYNCHRONIZED '(' expr ')'
{ objc_build_synchronized_prologue ($3); } { objc_build_synchronized_prologue ($3); }
compstmt compstmt
{ $$ = objc_build_synchronized_epilogue (); } { $$ = objc_build_synchronized_epilogue (); }
@ -2425,18 +2448,18 @@ objc_try_catch_stmt:
objc_try_stmt: objc_try_stmt:
AT_TRY AT_TRY
{ objc_build_try_prologue (); } { objc_build_try_prologue (); }
compstmt compstmt
; ;
objc_catch_list: objc_catch_list:
objc_catch_list objc_catch_block objc_catch_list objc_catch_block
| objc_catch_block | objc_catch_block
; ;
objc_catch_block: objc_catch_block:
AT_CATCH '(' parm ')' AT_CATCH '(' parm ')'
{ objc_build_catch_stmt ($3); } { objc_build_catch_stmt ($3); }
compstmt compstmt
{ stmt_count++; } { stmt_count++; }
@ -3689,7 +3712,7 @@ _yylex (void)
case CPP_STRING: case CPP_STRING:
case CPP_WSTRING: case CPP_WSTRING:
return STRING; return STRING;
case CPP_OBJC_STRING: case CPP_OBJC_STRING:
return OBJC_STRING; return OBJC_STRING;

View File

@ -592,7 +592,7 @@ genrtl_break_stmt (void)
{ {
emit_line_note (input_location); emit_line_note (input_location);
if ( ! expand_exit_something ()) if ( ! expand_exit_something ())
error ("break statement not within loop or switch"); abort ();
} }
/* Build a continue statement node and return it. */ /* Build a continue statement node and return it. */
@ -610,7 +610,7 @@ genrtl_continue_stmt (void)
{ {
emit_line_note (input_location); emit_line_note (input_location);
if (! expand_continue_loop (0)) if (! expand_continue_loop (0))
error ("continue statement not within a loop"); abort ();
} }
/* Generate the RTL for T, which is a SCOPE_STMT. */ /* Generate the RTL for T, which is a SCOPE_STMT. */

View File

@ -44,12 +44,12 @@ struct lang_identifier GTY(())
/* The resulting tree type. */ /* The resulting tree type. */
union lang_tree_node union lang_tree_node
GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"), GTY((desc ("TREE_CODE (&%h.generic) == IDENTIFIER_NODE"),
chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE ? (union lang_tree_node *)TYPE_NEXT_VARIANT (&%h.generic) : (union lang_tree_node *)TREE_CHAIN (&%h.generic)"))) chain_next ("TREE_CODE (&%h.generic) == INTEGER_TYPE ? (union lang_tree_node *)TYPE_NEXT_VARIANT (&%h.generic) : (union lang_tree_node *)TREE_CHAIN (&%h.generic)")))
{ {
union tree_node GTY ((tag ("0"), union tree_node GTY ((tag ("0"),
desc ("tree_node_structure (&%h)"))) desc ("tree_node_structure (&%h)")))
generic; generic;
struct lang_identifier GTY ((tag ("1"))) identifier; struct lang_identifier GTY ((tag ("1"))) identifier;
}; };
@ -106,7 +106,7 @@ struct lang_decl GTY(())
/* In a RECORD_TYPE, a sorted array of the fields of the type. */ /* In a RECORD_TYPE, a sorted array of the fields of the type. */
struct lang_type GTY(()) struct lang_type GTY(())
{ {
struct sorted_fields_type * GTY ((reorder ("resort_sorted_fields"))) s; struct sorted_fields_type * GTY ((reorder ("resort_sorted_fields"))) s;
}; };
/* Record whether a type or decl was written with nonconstant size. /* Record whether a type or decl was written with nonconstant size.
@ -152,6 +152,22 @@ struct lang_type GTY(())
#define KEEP_YES 1 #define KEEP_YES 1
#define KEEP_MAYBE 2 #define KEEP_MAYBE 2
/* Save and restore the variables in this file and elsewhere
that keep track of the progress of compilation of the current function.
Used for nested functions. */
struct language_function GTY(())
{
struct c_language_function base;
int returns_value;
int returns_null;
int returns_abnormally;
int warn_about_return_type;
int extern_inline;
int x_in_iteration_stmt;
int x_in_case_stmt;
};
/* in c-parse.in */ /* in c-parse.in */
extern void c_parse_init (void); extern void c_parse_init (void);