This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
statement-expression error recovery
- To: gcc-patches at gcc dot gnu dot org, Gavin Romig-Koch <gavin at cygnus dot com>
- Subject: statement-expression error recovery
- From: Richard Henderson <rth at cygnus dot com>
- Date: Sat, 28 Aug 1999 15:19:28 -0700
This fixes a segv in gcc.c-torture/compile/990801-2.c when compiled
with optimization.
The crash is because flow, in building the CFG, finds a label in no
basic block and dereferences NULL. It turns out that the label never
made it into the initial rtl for the function. This is because
expand_end_stmt_expr was never called, leaving an open sequence with
the label therein. The sequence gets discarded at the beginning of
rest_of_compilation.
This does add a new shift-reduce error. I believe the new error to be
inconsequential, but my yacc debugging skills are nothing to write home
about, so I may have found the wrong error. It didn't help that the
list at the beginning of c-parse.in of expected errors hasn't been kept
up to date.
r~
* c-parse.in (compstmt_primary_start): New, broken out of first
part of compstmt handling in primary.
(primary): Use it. Add an error clause.
(compstmt_nostart): Renamed from compstmt; remove all
initial invocations of compstmt_start.
(compstmt): New.
Index: c-parse.in
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/c-parse.in,v
retrieving revision 1.16.2.2
diff -c -p -d -r1.16.2.2 c-parse.in
*** c-parse.in 1999/08/25 23:30:20 1.16.2.2
--- c-parse.in 1999/08/28 22:04:14
*************** ifobjc
*** 31,60 ****
%expect 66
end ifobjc
ifc
! %expect 51
!
! /* These are the 23 conflicts you should get in parse.output;
! the state numbers may vary if minor changes in the grammar are made.
!
! State 42 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.)
! State 44 contains 1 shift/reduce conflict. (Two ways to recover from error.)
! State 103 contains 1 shift/reduce conflict. (Two ways to recover from error.)
! State 110 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.)
! State 111 contains 1 shift/reduce conflict. (Two ways to recover from error.)
! State 115 contains 1 shift/reduce conflict. (Two ways to recover from error.)
! State 132 contains 1 shift/reduce conflict. (See comment at component_decl.)
! State 180 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTE.)
! State 194 contains 2 shift/reduce conflict. (Four ways to parse this.)
! State 202 contains 1 shift/reduce conflict. (Two ways to recover from error.)
! State 214 contains 1 shift/reduce conflict. (Two ways to recover from error.)
! State 220 contains 1 shift/reduce conflict. (Two ways to recover from error.)
! State 304 contains 2 shift/reduce conflicts. (Four ways to parse this.)
! State 335 contains 2 shift/reduce conflicts. (Four ways to parse this.)
! State 347 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTES.)
! State 352 contains 1 shift/reduce conflict. (Two ways to parse ATTRIBUTES.)
! State 383 contains 2 shift/reduce conflicts. (Four ways to parse this.)
! State 434 contains 2 shift/reduce conflicts. (Four ways to parse this.) */
!
end ifc
%{
--- 31,37 ----
%expect 66
end ifobjc
ifc
! %expect 52
end ifc
%{
*************** end ifc
*** 191,197 ****
%type <ttype> maybe_attribute attributes attribute attribute_list attrib
%type <ttype> any_word
! %type <ttype> compstmt
%type <ttype> declarator
%type <ttype> notype_declarator after_type_declarator
--- 168,174 ----
%type <ttype> maybe_attribute attributes attribute attribute_list attrib
%type <ttype> any_word
! %type <ttype> compstmt compstmt_nostart compstmt_primary_start
%type <ttype> declarator
%type <ttype> notype_declarator after_type_declarator
*************** end ifobjc
*** 806,848 ****
$$ = $2; }
| '(' error ')'
{ $$ = error_mark_node; }
! | '('
! { if (current_function_decl == 0)
! {
! error ("braced-group within expression allowed only inside a function");
! YYERROR;
! }
! /* 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 ();
! push_iterator_stack ();
! push_label_level ();
! $<ttype>$ = expand_start_stmt_expr (); }
! compstmt ')'
{ tree rtl_exp;
if (pedantic)
pedwarn ("ANSI C forbids braced-groups within expressions");
pop_iterator_stack ();
pop_label_level ();
! rtl_exp = expand_end_stmt_expr ($<ttype>2);
/* The statements have side effects, so the group does. */
TREE_SIDE_EFFECTS (rtl_exp) = 1;
! if (TREE_CODE ($3) == BLOCK)
{
/* Make a BIND_EXPR for the BLOCK already made. */
$$ = build (BIND_EXPR, TREE_TYPE (rtl_exp),
! NULL_TREE, rtl_exp, $3);
/* Remove the block from the tree at this point.
It gets put back at the proper place
when the BIND_EXPR is expanded. */
! delete_block ($3);
}
else
! $$ = $3;
}
| primary '(' exprlist ')' %prec '.'
{ $$ = build_function_call ($1, $3); }
| primary '[' expr ']' %prec '.'
--- 783,820 ----
$$ = $2; }
| '(' error ')'
{ $$ = error_mark_node; }
! | compstmt_primary_start compstmt_nostart ')'
{ tree rtl_exp;
if (pedantic)
pedwarn ("ANSI C forbids braced-groups within expressions");
pop_iterator_stack ();
pop_label_level ();
! rtl_exp = expand_end_stmt_expr ($1);
/* The statements have side effects, so the group does. */
TREE_SIDE_EFFECTS (rtl_exp) = 1;
! if (TREE_CODE ($2) == BLOCK)
{
/* Make a BIND_EXPR for the BLOCK already made. */
$$ = build (BIND_EXPR, TREE_TYPE (rtl_exp),
! NULL_TREE, rtl_exp, $2);
/* Remove the block from the tree at this point.
It gets put back at the proper place
when the BIND_EXPR is expanded. */
! delete_block ($2);
}
else
! $$ = $2;
}
+ | compstmt_primary_start error ')'
+ {
+ /* Make sure we call expand_end_stmt_expr. Otherwise
+ we are likely to lose sequences and crash later. */
+ pop_iterator_stack ();
+ pop_label_level ();
+ expand_end_stmt_expr ($1);
+ $$ = error_mark_node;
+ }
| primary '(' exprlist ')' %prec '.'
{ $$ = build_function_call ($1, $3); }
| primary '[' expr ']' %prec '.'
*************** compstmt_or_error:
*** 1795,1803 ****
compstmt_start: '{' { compstmt_count++; }
! compstmt: compstmt_start '}'
{ $$ = convert (void_type_node, integer_zero_node); }
! | compstmt_start pushlevel maybe_label_decls decls xstmts '}'
{ emit_line_note (input_filename, lineno);
expand_end_bindings (getdecls (), 1, 0);
$$ = poplevel (1, 1, 0);
--- 1767,1775 ----
compstmt_start: '{' { compstmt_count++; }
! compstmt_nostart: '}'
{ $$ = convert (void_type_node, integer_zero_node); }
! | pushlevel maybe_label_decls decls xstmts '}'
{ emit_line_note (input_filename, lineno);
expand_end_bindings (getdecls (), 1, 0);
$$ = poplevel (1, 1, 0);
*************** compstmt: compstmt_start '}'
*** 1805,1811 ****
pop_momentary_nofree ();
else
pop_momentary (); }
! | compstmt_start pushlevel maybe_label_decls error '}'
{ emit_line_note (input_filename, lineno);
expand_end_bindings (getdecls (), kept_level_p (), 0);
$$ = poplevel (kept_level_p (), 0, 0);
--- 1777,1783 ----
pop_momentary_nofree ();
else
pop_momentary (); }
! | pushlevel maybe_label_decls error '}'
{ emit_line_note (input_filename, lineno);
expand_end_bindings (getdecls (), kept_level_p (), 0);
$$ = poplevel (kept_level_p (), 0, 0);
*************** compstmt: compstmt_start '}'
*** 1813,1819 ****
pop_momentary_nofree ();
else
pop_momentary (); }
! | compstmt_start pushlevel maybe_label_decls stmts '}'
{ emit_line_note (input_filename, lineno);
expand_end_bindings (getdecls (), kept_level_p (), 0);
$$ = poplevel (kept_level_p (), 0, 0);
--- 1785,1791 ----
pop_momentary_nofree ();
else
pop_momentary (); }
! | pushlevel maybe_label_decls stmts '}'
{ emit_line_note (input_filename, lineno);
expand_end_bindings (getdecls (), kept_level_p (), 0);
$$ = poplevel (kept_level_p (), 0, 0);
*************** compstmt: compstmt_start '}'
*** 1821,1826 ****
--- 1793,1820 ----
pop_momentary_nofree ();
else
pop_momentary (); }
+ ;
+
+ compstmt_primary_start:
+ '(' '{'
+ { if (current_function_decl == 0)
+ {
+ error ("braced-group within expression allowed only inside a function");
+ YYERROR;
+ }
+ /* 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 ();
+ push_iterator_stack ();
+ push_label_level ();
+ $$ = expand_start_stmt_expr ();
+ compstmt_count++;
+ }
+
+ compstmt: compstmt_start compstmt_nostart
+ { $$ = $2; }
;
/* Value is number of statements counted as of the closeparen. */