This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: Fix dce1.C
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 12 Nov 2003 11:59:13 -0800
- Subject: C++ PATCH: Fix dce1.C
- Reply-to: mark at codesourcery dot com
This test case:
void foo(void)
{
if (0)
break; /* { dg-error "" } */
if (1)
;
else
continue; /* { dg-error "" } */
}
was not generating error messages because the AST->RTL converters
never saw the invalid break/continue statements.
Of course, the fact that the AST->RTL converters are responsible for
generating error messages on this code is a design bug. (They should
never generate errors, period, but that's one of my well-known rants.)
These errors should be issued early, when the statements are first
seen. Furthermore, we should try to avoid creating invalid tree
structure; that just gives us opportunities to crash later.
So, I put the checks into the parser where they belong.
(Unfortunately, I could not eliminate them from the AST->RTL
converters without changing the C parser, which I did not want to do.)
Tested on i686-pc-linux-gnu, applied on the mainline.
--
Mark Mitchell
CodeSourcery, LLC
mark@codesourcery.com
2003-11-12 Mark Mitchell <mark@codesourcery.com>
* decl.c (finish_case_label): Do not check that we are within a
switch statement here.
* parser.c (struct cp_parser): Add in_iteration_statement_p and
in_switch_statement_p.
(cp_parser_new): Initialize them.
(cp_parser_labeled_statement): Check validity of case labels
here.
(cp_parser_selection_statement): Set in_switch_statement_p.
(cp_parser_iteration_statement): Set in_iteration_statement_p.
(cp_parser_jump_statement): Check validity of break/continue
statements here.
Index: decl.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/decl.c,v
retrieving revision 1.1152
diff -c -5 -p -r1.1152 decl.c
*** decl.c 12 Nov 2003 18:15:01 -0000 1.1152
--- decl.c 12 Nov 2003 19:55:26 -0000
*************** tree
*** 2431,2452 ****
finish_case_label (tree low_value, tree high_value)
{
tree cond, r;
register struct cp_binding_level *p;
- if (! switch_stack)
- {
- if (high_value)
- error ("case label not within a switch statement");
- else if (low_value)
- error ("case label `%E' not within a switch statement",
- low_value);
- else
- error ("`default' label not within a switch statement");
- return NULL_TREE;
- }
-
if (processing_template_decl)
{
tree label;
/* For templates, just add the case label; we'll do semantic
--- 2431,2440 ----
Index: parser.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/parser.c,v
retrieving revision 1.119
diff -c -5 -p -r1.119 parser.c
*** parser.c 11 Nov 2003 22:27:31 -0000 1.119
--- parser.c 12 Nov 2003 19:55:27 -0000
*************** typedef struct cp_parser GTY(())
*** 1228,1237 ****
--- 1228,1245 ----
/* TRUE if we are presently parsing a declarator, after the
direct-declarator. */
bool in_declarator_p;
+ /* TRUE if we are presently parsing the body of an
+ iteration-statement. */
+ bool in_iteration_statement_p;
+
+ /* TRUE if we are presently parsing the body of a switch
+ statement. */
+ bool in_switch_statement_p;
+
/* If non-NULL, then we are parsing a construct where new type
definitions are not permitted. The string stored here will be
issued as an error message if a type is defined. */
const char *type_definition_forbidden_message;
*************** cp_parser_new (void)
*** 2116,2125 ****
--- 2124,2139 ----
parser->in_unbraced_linkage_specification_p = false;
/* We are not processing a declarator. */
parser->in_declarator_p = false;
+ /* We are not in an iteration statement. */
+ parser->in_iteration_statement_p = false;
+
+ /* We are not in a switch statement. */
+ parser->in_switch_statement_p = false;
+
/* The unparsed function queue is empty. */
parser->unparsed_functions_queues = build_tree_list (NULL_TREE, NULL_TREE);
/* There are no classes being defined. */
parser->num_classes_being_defined = 0;
*************** cp_parser_statement (cp_parser* parser,
*** 5226,5236 ****
static tree
cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p)
{
cp_token *token;
! tree statement = NULL_TREE;
/* The next token should be an identifier. */
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_NAME
&& token->type != CPP_KEYWORD)
--- 5240,5250 ----
static tree
cp_parser_labeled_statement (cp_parser* parser, bool in_statement_expr_p)
{
cp_token *token;
! tree statement = error_mark_node;
/* The next token should be an identifier. */
token = cp_lexer_peek_token (parser->lexer);
if (token->type != CPP_NAME
&& token->type != CPP_KEYWORD)
*************** cp_parser_labeled_statement (cp_parser*
*** 5249,5268 ****
cp_lexer_consume_token (parser->lexer);
/* Parse the constant-expression. */
expr = cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
NULL);
! /* Create the label. */
! statement = finish_case_label (expr, NULL_TREE);
}
break;
case RID_DEFAULT:
/* Consume the `default' token. */
cp_lexer_consume_token (parser->lexer);
! /* Create the label. */
! statement = finish_case_label (NULL_TREE, NULL_TREE);
break;
default:
/* Anything else must be an ordinary label. */
statement = finish_label_stmt (cp_parser_identifier (parser));
--- 5263,5286 ----
cp_lexer_consume_token (parser->lexer);
/* Parse the constant-expression. */
expr = cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
NULL);
! if (!parser->in_switch_statement_p)
! error ("case label `%E' not within a switch statement", expr);
! else
! statement = finish_case_label (expr, NULL_TREE);
}
break;
case RID_DEFAULT:
/* Consume the `default' token. */
cp_lexer_consume_token (parser->lexer);
! if (!parser->in_switch_statement_p)
! error ("case label not within a switch statement");
! else
! statement = finish_case_label (NULL_TREE, NULL_TREE);
break;
default:
/* Anything else must be an ordinary label. */
statement = finish_label_stmt (cp_parser_identifier (parser));
*************** cp_parser_selection_statement (cp_parser
*** 5441,5456 ****
--- 5459,5478 ----
finish_if_stmt ();
}
else
{
tree body;
+ bool in_switch_statement_p;
/* Add the condition. */
finish_switch_cond (condition, statement);
/* Parse the body of the switch-statement. */
+ in_switch_statement_p = parser->in_switch_statement_p;
+ parser->in_switch_statement_p = true;
body = cp_parser_implicitly_scoped_statement (parser);
+ parser->in_switch_statement_p = in_switch_statement_p;
/* Now we're all done with the switch-statement. */
finish_switch_stmt (statement);
}
*************** static tree
*** 5562,5577 ****
--- 5584,5605 ----
cp_parser_iteration_statement (cp_parser* parser)
{
cp_token *token;
enum rid keyword;
tree statement;
+ bool in_iteration_statement_p;
+
/* Peek at the next token. */
token = cp_parser_require (parser, CPP_KEYWORD, "iteration-statement");
if (!token)
return error_mark_node;
+ /* Remember whether or not we are already within an iteration
+ statement. */
+ in_iteration_statement_p = parser->in_iteration_statement_p;
+
/* See what kind of keyword it is. */
keyword = token->keyword;
switch (keyword)
{
case RID_WHILE:
*************** cp_parser_iteration_statement (cp_parser
*** 5586,5596 ****
--- 5614,5626 ----
condition = cp_parser_condition (parser);
finish_while_stmt_cond (condition, statement);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'");
/* Parse the dependent statement. */
+ parser->in_iteration_statement_p = true;
cp_parser_already_scoped_statement (parser);
+ parser->in_iteration_statement_p = in_iteration_statement_p;
/* We're done with the while-statement. */
finish_while_stmt (statement);
}
break;
*************** cp_parser_iteration_statement (cp_parser
*** 5599,5609 ****
--- 5629,5641 ----
tree expression;
/* Begin the do-statement. */
statement = begin_do_stmt ();
/* Parse the body of the do-statement. */
+ parser->in_iteration_statement_p = true;
cp_parser_implicitly_scoped_statement (parser);
+ parser->in_iteration_statement_p = in_iteration_statement_p;
finish_do_body (statement);
/* Look for the `while' keyword. */
cp_parser_require_keyword (parser, RID_WHILE, "`while'");
/* Look for the `('. */
cp_parser_require (parser, CPP_OPEN_PAREN, "`('");
*************** cp_parser_iteration_statement (cp_parser
*** 5644,5654 ****
--- 5676,5688 ----
finish_for_expr (expression, statement);
/* Look for the `)'. */
cp_parser_require (parser, CPP_CLOSE_PAREN, "`;'");
/* Parse the body of the for-statement. */
+ parser->in_iteration_statement_p = true;
cp_parser_already_scoped_statement (parser);
+ parser->in_iteration_statement_p = in_iteration_statement_p;
/* We're done with the for-statement. */
finish_for_stmt (statement);
}
break;
*************** cp_parser_jump_statement (cp_parser* par
*** 5725,5740 ****
/* See what kind of keyword it is. */
keyword = token->keyword;
switch (keyword)
{
case RID_BREAK:
! statement = finish_break_stmt ();
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
break;
case RID_CONTINUE:
! statement = finish_continue_stmt ();
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
break;
case RID_RETURN:
{
--- 5759,5787 ----
/* See what kind of keyword it is. */
keyword = token->keyword;
switch (keyword)
{
case RID_BREAK:
! if (!parser->in_switch_statement_p
! && !parser->in_iteration_statement_p)
! {
! error ("break statement not within loop or switch");
! statement = error_mark_node;
! }
! else
! statement = finish_break_stmt ();
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
break;
case RID_CONTINUE:
! if (!parser->in_iteration_statement_p)
! {
! error ("continue statement not within a loop");
! statement = error_mark_node;
! }
! else
! statement = finish_continue_stmt ();
cp_parser_require (parser, CPP_SEMICOLON, "`;'");
break;
case RID_RETURN:
{