Commit fbc315db by Ian Lance Taylor Committed by Ian Lance Taylor

c-common.def: Move FOR_STMT...

./	* c-common.def: Move FOR_STMT, WHILE_STMT, DO_STMT, BREAK_STMT,
	CONTINUE_STMT, and SWITCH_STMT to cp/cp-tree.def.
	* c-common.h (WHILE_COND, WHILE_BODY): Move to cp/cp-tree.h.
	(DO_COND, DO_BODY): Likewise.
	(FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY): Likewise.
	(SWITCH_STMT_COND, SWITCH_STMT_BODY, SWITCH_STMT_TYPE): Likewise.
	(c_common_stmt_codes): Remove FOR_STMT, WHILE_STMT, DO_STMT,
	BREAK_STMT, CONTINUE_STMT, and SWITCH_STMT.
	(build_continue_stmt, build_break_stmt): Don't declare.
	(c_do_switch_warnings): Update declaration.
	* c-gimplify.c (enum bc_t): Remove.
	(struct c_gimplify_ctx, ctxp): Remove.
	(push_context, pop_context): Remove static functions.
	(c_genericize): Don't call push_context or pop_context.
	(begin_bc_block, finish_bc_block): Remove static functions.
	(build_bc_goto): Likewise.
	(gimplify_c_loop): Likewise.
	(gimplify_for_stmt, gimplify_while_stmt): Likewise.
	(gimplify_do_stmt, gimplify_switch_stmt): Likewise.
	(c_gimplify_expr): Remove handling of FOR_STMT, WHILE_STMT,
	DO_STMT, SWITCH_STMT, CONTINUE_STMT, BREAK_STMT.
	* c-common.c (c_do_switch_warnings): Rename from
	c_do_switch_warnings_1.
	(c_do_switch_warnings) [old version]: Remove.
	(c_do_switch_expr_warnings): Remove.
	* c-typeck.c (c_finish_case): Call new c_do_switch_warnings
	function instead of c_do_switch_expr_warnings.
	* c-dump.c (c_dump_tree): Remove handling of BREAK_STMT,
	CONTINUE_STMT, DO_STMT, FOR_STMT, SWITCH_STMT, and WHILE_STMT.
	* c-pretty-print.c (pp_c_statement): Likewise.
	* c-semantics.c (build_break_stmt, build_continue_stmt): Remove.
cp/
	* cp-tree.def: Define FOR_STMT, WHILE_STMT, DO_STMT, BREAK_STMT,
	CONTINUE_STMT, SWITCH_STMT.
	* cp-tree.h (cp_stmt_codes): Add FOR_STMT, WHILE_STMT, DO_STMT,
	BREAK_STMT, CONTINUE_STMT, SWITCH_STMT.
	(WHILE_COND, WHILE_BODY): Define.
	(DO_COND, DO_BODY): Define.
	(FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY): Define.
	(SWITCH_STMT_COND, SWITCH_STMT_BODY, SWITCH_STMT_TYPE): Define.
	* cp-gimplify.c (enum bc_t): Define.
	(struct cp_gimplify_ctx, ctxp): Define.
	(push_context, pop_context): New static functions.
	(begin_bc_block, finish_bc_block): New static functions.
	(build_bc_goto): New static function.
	(gimplify_cp_loop, gimplify_for_stmt): New static functions.
	(gimplify_while_stmt, gimplify_do_stmt): Likewise.
	(gimplify_switch_stmt): Likewise.
	(cp_gimplify_expr): Handle FOR_STMT, WHILE_STMT, DO_STMT,
	SWITCH_STMT, CONTINUE_STMT, BREAK_STMT.
	(cp_genericize): Call push_context and pop_context.
	* semantics.c (finish_break_stmt): Just call build_stmt
	(BREAK_STMT) rather than build_break_stmt.
	(finish_continue_stmt): Corresponding change.
	* decl.c (pop_switch): Update call to c_do_switch_warnings for new
	parameters.
	* cxx-pretty-print.c (pp_cxx_statement): Handle SWITCH_STMT,
	WHILE_STMT, DO_STMT, FOR_STMT, BREAK_STMT, CONTINUE_STMT.
	* dump.c (cp_dump_tree): Likewise.

From-SVN: r97885
parent 0bca51f0
2005-04-08 Ian Lance Taylor <ian@airs.com>
* c-common.def: Move FOR_STMT, WHILE_STMT, DO_STMT, BREAK_STMT,
CONTINUE_STMT, and SWITCH_STMT to cp/cp-tree.def.
* c-common.h (WHILE_COND, WHILE_BODY): Move to cp/cp-tree.h.
(DO_COND, DO_BODY): Likewise.
(FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY): Likewise.
(SWITCH_STMT_COND, SWITCH_STMT_BODY, SWITCH_STMT_TYPE): Likewise.
(c_common_stmt_codes): Remove FOR_STMT, WHILE_STMT, DO_STMT,
BREAK_STMT, CONTINUE_STMT, and SWITCH_STMT.
(build_continue_stmt, build_break_stmt): Don't declare.
(c_do_switch_warnings): Update declaration.
* c-gimplify.c (enum bc_t): Remove.
(struct c_gimplify_ctx, ctxp): Remove.
(push_context, pop_context): Remove static functions.
(c_genericize): Don't call push_context or pop_context.
(begin_bc_block, finish_bc_block): Remove static functions.
(build_bc_goto): Likewise.
(gimplify_c_loop): Likewise.
(gimplify_for_stmt, gimplify_while_stmt): Likewise.
(gimplify_do_stmt, gimplify_switch_stmt): Likewise.
(c_gimplify_expr): Remove handling of FOR_STMT, WHILE_STMT,
DO_STMT, SWITCH_STMT, CONTINUE_STMT, BREAK_STMT.
* c-common.c (c_do_switch_warnings): Rename from
c_do_switch_warnings_1.
(c_do_switch_warnings) [old version]: Remove.
(c_do_switch_expr_warnings): Remove.
* c-typeck.c (c_finish_case): Call new c_do_switch_warnings
function instead of c_do_switch_expr_warnings.
* c-dump.c (c_dump_tree): Remove handling of BREAK_STMT,
CONTINUE_STMT, DO_STMT, FOR_STMT, SWITCH_STMT, and WHILE_STMT.
* c-pretty-print.c (pp_c_statement): Likewise.
* c-semantics.c (build_break_stmt, build_continue_stmt): Remove.
2005-04-08 Diego Novillo <dnovillo@redhat.com>
Merge from tree-cleanup-branch: VRP, store CCP, store
......
......@@ -3708,10 +3708,15 @@ match_case_to_enum (splay_tree_node node, void *data)
return 0;
}
/* Common code for -Wswitch*. */
/* Handle -Wswitch*. Called from the front end after parsing the
switch construct. */
/* ??? Should probably be somewhere generic, since other languages
besides C and C++ would want this. At the moment, however, C/C++
are the only tree-ssa languages that support enumerations at all,
so the point is moot. */
static void
c_do_switch_warnings_1 (splay_tree cases, location_t switch_location,
void
c_do_switch_warnings (splay_tree cases, location_t switch_location,
tree type, tree cond)
{
splay_tree_node default_node;
......@@ -3773,45 +3778,6 @@ c_do_switch_warnings_1 (splay_tree cases, location_t switch_location,
}
}
/* Handle -Wswitch* for a SWITCH_STMT. Called from the front end
after parsing the switch construct. */
/* ??? Should probably be somewhere generic, since other languages besides
C and C++ would want this. We'd want to agree on the data structure,
however, which is a problem. Alternately, we operate on gimplified
switch_exprs, which I don't especially like. At the moment, however,
C/C++ are the only tree-ssa languages that support enumerations at all,
so the point is moot. */
void
c_do_switch_warnings (splay_tree cases, tree switch_stmt)
{
location_t switch_location;
if (EXPR_HAS_LOCATION (switch_stmt))
switch_location = EXPR_LOCATION (switch_stmt);
else
switch_location = input_location;
c_do_switch_warnings_1 (cases, switch_location,
SWITCH_STMT_TYPE (switch_stmt),
SWITCH_STMT_COND (switch_stmt));
}
/* Like c_do_switch_warnings, but takes a SWITCH_EXPR rather than a
SWITCH_STMT. */
void
c_do_switch_expr_warnings (splay_tree cases, tree switch_expr)
{
location_t switch_location;
if (EXPR_HAS_LOCATION (switch_expr))
switch_location = EXPR_LOCATION (switch_expr);
else
switch_location = input_location;
c_do_switch_warnings_1 (cases, switch_location, TREE_TYPE (switch_expr),
SWITCH_COND (switch_expr));
}
/* Finish an expression taking the address of LABEL (an
IDENTIFIER_NODE). Returns an expression for the address. */
......
......@@ -33,28 +33,6 @@ DEFTREECODE (ALIGNOF_EXPR, "alignof_expr", tcc_unary, 1)
obtain the expression. */
DEFTREECODE (EXPR_STMT, "expr_stmt", tcc_expression, 1)
/* Used to represent a `for' statement. The operands are
FOR_INIT_STMT, FOR_COND, FOR_EXPR, and FOR_BODY, respectively. */
DEFTREECODE (FOR_STMT, "for_stmt", tcc_expression, 4)
/* Used to represent a 'while' statement. The operands are WHILE_COND
and WHILE_BODY, respectively. */
DEFTREECODE (WHILE_STMT, "while_stmt", tcc_expression, 2)
/* Used to represent a 'do' statement. The operands are DO_BODY and
DO_COND, respectively. */
DEFTREECODE (DO_STMT, "do_stmt", tcc_expression, 2)
/* Used to represent a 'break' statement. */
DEFTREECODE (BREAK_STMT, "break_stmt", tcc_expression, 0)
/* Used to represent a 'continue' statement. */
DEFTREECODE (CONTINUE_STMT, "continue_stmt", tcc_expression, 0)
/* Used to represent a 'switch' statement. The operands are
SWITCH_STMT_COND, SWITCH_STMT_BODY and SWITCH_STMT_TYPE, respectively. */
DEFTREECODE (SWITCH_STMT, "switch_stmt", tcc_expression, 3)
/* A STMT_EXPR represents a statement-expression. The
STMT_EXPR_STMT is the statement given by the expression. */
DEFTREECODE (STMT_EXPR, "stmt_expr", tcc_expression, 1)
......
......@@ -709,32 +709,10 @@ extern void finish_file (void);
#define STATEMENT_LIST_HAS_LABEL(NODE) \
TREE_LANG_FLAG_3 (STATEMENT_LIST_CHECK (NODE))
/* WHILE_STMT accessors. These give access to the condition of the
while statement and the body of the while statement, respectively. */
#define WHILE_COND(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 0)
#define WHILE_BODY(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 1)
/* DO_STMT accessors. These give access to the condition of the do
statement and the body of the do statement, respectively. */
#define DO_COND(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 0)
#define DO_BODY(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 1)
/* EXPR_STMT accessor. This gives the expression associated with an
expression statement. */
#define EXPR_STMT_EXPR(NODE) TREE_OPERAND (EXPR_STMT_CHECK (NODE), 0)
/* FOR_STMT accessors. These give access to the init statement,
condition, update expression, and body of the for statement,
respectively. */
#define FOR_INIT_STMT(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 0)
#define FOR_COND(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 1)
#define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2)
#define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3)
#define SWITCH_STMT_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0)
#define SWITCH_STMT_BODY(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1)
#define SWITCH_STMT_TYPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2)
/* STMT_EXPR accessor. */
#define STMT_EXPR_STMT(NODE) TREE_OPERAND (STMT_EXPR_CHECK (NODE), 0)
......@@ -759,9 +737,7 @@ enum c_tree_code {
#undef DEFTREECODE
#define c_common_stmt_codes \
EXPR_STMT, FOR_STMT, \
WHILE_STMT, DO_STMT, \
BREAK_STMT, CONTINUE_STMT, SWITCH_STMT
EXPR_STMT
/* TRUE if a code represents a statement. The front end init
langhook should take care of initialization of this array. */
......@@ -796,8 +772,6 @@ extern void emit_local_var (tree);
extern tree do_case (tree, tree);
extern tree build_stmt (enum tree_code, ...);
extern tree build_case_label (tree, tree, tree);
extern tree build_continue_stmt (void);
extern tree build_break_stmt (void);
/* These functions must be defined by each front-end which implements
a variant of the C language. They are used in c-common.c. */
......@@ -820,8 +794,7 @@ extern int case_compare (splay_tree_key, splay_tree_key);
extern tree c_add_case_label (splay_tree, tree, tree, tree, tree);
extern void c_do_switch_warnings (splay_tree, tree);
extern void c_do_switch_expr_warnings (splay_tree, tree);
extern void c_do_switch_warnings (splay_tree, location_t, tree, tree);
extern tree build_function_call (tree, tree);
......
......@@ -54,42 +54,11 @@ c_dump_tree (void *dump_info, tree t)
dump_string (di, "bitfield");
break;
case BREAK_STMT:
case CONTINUE_STMT:
dump_stmt (di, t);
break;
case DO_STMT:
dump_stmt (di, t);
dump_child ("body", DO_BODY (t));
dump_child ("cond", DO_COND (t));
break;
case EXPR_STMT:
dump_stmt (di, t);
dump_child ("expr", EXPR_STMT_EXPR (t));
break;
case FOR_STMT:
dump_stmt (di, t);
dump_child ("init", FOR_INIT_STMT (t));
dump_child ("cond", FOR_COND (t));
dump_child ("expr", FOR_EXPR (t));
dump_child ("body", FOR_BODY (t));
break;
case SWITCH_STMT:
dump_stmt (di, t);
dump_child ("cond", SWITCH_STMT_COND (t));
dump_child ("body", SWITCH_STMT_BODY (t));
break;
case WHILE_STMT:
dump_stmt (di, t);
dump_child ("cond", WHILE_COND (t));
dump_child ("body", WHILE_BODY (t));
break;
case STMT_EXPR:
dump_child ("stmt", STMT_EXPR_STMT (t));
break;
......
......@@ -70,34 +70,6 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
walk back up, we check that they fit our constraints, and copy them
into temporaries if not. */
/* Local declarations. */
enum bc_t { bc_break = 0, bc_continue = 1 };
static struct c_gimplify_ctx
{
/* For handling break and continue. */
tree current_bc_label;
tree bc_id[2];
} *ctxp;
static void
push_context (void)
{
gcc_assert (!ctxp);
ctxp = (struct c_gimplify_ctx *) xcalloc (1, sizeof (struct c_gimplify_ctx));
ctxp->bc_id[bc_continue] = get_identifier ("continue");
ctxp->bc_id[bc_break] = get_identifier ("break");
}
static void
pop_context (void)
{
gcc_assert (ctxp && !ctxp->current_bc_label);
free (ctxp);
ctxp = NULL;
}
/* Gimplification of statement trees. */
/* Convert the tree representation of FNDECL from C frontend trees to
......@@ -132,9 +104,7 @@ c_genericize (tree fndecl)
}
/* Go ahead and gimplify for now. */
push_context ();
gimplify_function_tree (fndecl);
pop_context ();
/* Dump the genericized tree IR. */
dump_function (TDI_generic, fndecl);
......@@ -248,225 +218,6 @@ gimplify_expr_stmt (tree *stmt_p)
return GS_OK;
}
/* Begin a scope which can be exited by a break or continue statement. BC
indicates which.
Just creates a label and pushes it into the current context. */
static tree
begin_bc_block (enum bc_t bc)
{
tree label = create_artificial_label ();
DECL_NAME (label) = ctxp->bc_id[bc];
TREE_CHAIN (label) = ctxp->current_bc_label;
ctxp->current_bc_label = label;
return label;
}
/* Finish a scope which can be exited by a break or continue statement.
LABEL was returned from the most recent call to begin_bc_block. BODY is
an expression for the contents of the scope.
If we saw a break (or continue) in the scope, append a LABEL_EXPR to
body. Otherwise, just forget the label. */
static tree
finish_bc_block (tree label, tree body)
{
gcc_assert (label == ctxp->current_bc_label);
if (TREE_USED (label))
{
tree t, sl = NULL;
/* Clear the name so flow can delete the label. */
DECL_NAME (label) = NULL_TREE;
t = build1 (LABEL_EXPR, void_type_node, label);
append_to_statement_list (body, &sl);
append_to_statement_list (t, &sl);
body = sl;
}
ctxp->current_bc_label = TREE_CHAIN (label);
TREE_CHAIN (label) = NULL_TREE;
return body;
}
/* Build a GOTO_EXPR to represent a break or continue statement. BC
indicates which. */
static tree
build_bc_goto (enum bc_t bc)
{
tree label;
tree target_name = ctxp->bc_id[bc];
/* Look for the appropriate type of label. */
for (label = ctxp->current_bc_label;
label;
label = TREE_CHAIN (label))
if (DECL_NAME (label) == target_name)
break;
if (label == NULL_TREE)
{
if (bc == bc_break)
error ("break statement not within loop or switch");
else
error ("continue statement not within loop or switch");
return NULL_TREE;
}
/* Mark the label used for finish_bc_block. */
TREE_USED (label) = 1;
return build1 (GOTO_EXPR, void_type_node, label);
}
/* Build a generic representation of one of the C loop forms. COND is the
loop condition or NULL_TREE. BODY is the (possibly compound) statement
controlled by the loop. INCR is the increment expression of a for-loop,
or NULL_TREE. COND_IS_FIRST indicates whether the condition is
evaluated before the loop body as in while and for loops, or after the
loop body as in do-while loops. */
static tree
gimplify_c_loop (tree cond, tree body, tree incr, bool cond_is_first)
{
tree top, entry, exit, cont_block, break_block, stmt_list, t;
location_t stmt_locus;
stmt_locus = input_location;
stmt_list = NULL_TREE;
entry = NULL_TREE;
break_block = begin_bc_block (bc_break);
cont_block = begin_bc_block (bc_continue);
/* If condition is zero don't generate a loop construct. */
if (cond && integer_zerop (cond))
{
top = NULL_TREE;
exit = NULL_TREE;
if (cond_is_first)
{
t = build_bc_goto (bc_break);
append_to_statement_list (t, &stmt_list);
}
}
else
{
/* If we use a LOOP_EXPR here, we have to feed the whole thing
back through the main gimplifier to lower it. Given that we
have to gimplify the loop body NOW so that we can resolve
break/continue stmts, seems easier to just expand to gotos. */
top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
/* If we have an exit condition, then we build an IF with gotos either
out of the loop, or to the top of it. If there's no exit condition,
then we just build a jump back to the top. */
exit = build_and_jump (&LABEL_EXPR_LABEL (top));
if (cond && !integer_nonzerop (cond))
{
t = build_bc_goto (bc_break);
exit = build3 (COND_EXPR, void_type_node, cond, exit, t);
exit = fold (exit);
gimplify_stmt (&exit);
if (cond_is_first)
{
if (incr)
{
entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
t = build_and_jump (&LABEL_EXPR_LABEL (entry));
}
else
t = build_bc_goto (bc_continue);
append_to_statement_list (t, &stmt_list);
}
}
}
gimplify_stmt (&body);
gimplify_stmt (&incr);
body = finish_bc_block (cont_block, body);
append_to_statement_list (top, &stmt_list);
append_to_statement_list (body, &stmt_list);
append_to_statement_list (incr, &stmt_list);
append_to_statement_list (entry, &stmt_list);
append_to_statement_list (exit, &stmt_list);
annotate_all_with_locus (&stmt_list, stmt_locus);
return finish_bc_block (break_block, stmt_list);
}
/* Gimplify a FOR_STMT node. Move the stuff in the for-init-stmt into the
prequeue and hand off to gimplify_c_loop. */
static enum gimplify_status
gimplify_for_stmt (tree *stmt_p, tree *pre_p)
{
tree stmt = *stmt_p;
if (FOR_INIT_STMT (stmt))
gimplify_and_add (FOR_INIT_STMT (stmt), pre_p);
*stmt_p = gimplify_c_loop (FOR_COND (stmt), FOR_BODY (stmt),
FOR_EXPR (stmt), 1);
return GS_ALL_DONE;
}
/* Gimplify a WHILE_STMT node. */
static enum gimplify_status
gimplify_while_stmt (tree *stmt_p)
{
tree stmt = *stmt_p;
*stmt_p = gimplify_c_loop (WHILE_COND (stmt), WHILE_BODY (stmt),
NULL_TREE, 1);
return GS_ALL_DONE;
}
/* Gimplify a DO_STMT node. */
static enum gimplify_status
gimplify_do_stmt (tree *stmt_p)
{
tree stmt = *stmt_p;
*stmt_p = gimplify_c_loop (DO_COND (stmt), DO_BODY (stmt),
NULL_TREE, 0);
return GS_ALL_DONE;
}
/* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR. */
static enum gimplify_status
gimplify_switch_stmt (tree *stmt_p)
{
tree stmt = *stmt_p;
tree break_block, body;
location_t stmt_locus = input_location;
break_block = begin_bc_block (bc_break);
body = SWITCH_STMT_BODY (stmt);
if (!body)
body = build_empty_stmt ();
*stmt_p = build3 (SWITCH_EXPR, SWITCH_STMT_TYPE (stmt),
SWITCH_STMT_COND (stmt), body, NULL_TREE);
SET_EXPR_LOCATION (*stmt_p, stmt_locus);
gimplify_stmt (stmt_p);
*stmt_p = finish_bc_block (break_block, *stmt_p);
return GS_ALL_DONE;
}
/* Gimplification of expression trees. */
/* Gimplify a C99 compound literal expression. This just means adding the
......@@ -515,29 +266,9 @@ c_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED)
case COMPOUND_LITERAL_EXPR:
return gimplify_compound_literal_expr (expr_p, pre_p);
case FOR_STMT:
return gimplify_for_stmt (expr_p, pre_p);
case WHILE_STMT:
return gimplify_while_stmt (expr_p);
case DO_STMT:
return gimplify_do_stmt (expr_p);
case SWITCH_STMT:
return gimplify_switch_stmt (expr_p);
case EXPR_STMT:
return gimplify_expr_stmt (expr_p);
case CONTINUE_STMT:
*expr_p = build_bc_goto (bc_continue);
return GS_ALL_DONE;
case BREAK_STMT:
*expr_p = build_bc_goto (bc_break);
return GS_ALL_DONE;
default:
return GS_UNHANDLED;
}
......
......@@ -1965,84 +1965,6 @@ pp_c_statement (c_pretty_printer *pp, tree stmt)
pp_needs_newline (pp) = true;
break;
case SWITCH_STMT:
pp_c_identifier (pp, "switch");
pp_space (pp);
pp_c_left_paren (pp);
pp_expression (pp, SWITCH_COND (stmt));
pp_c_right_paren (pp);
pp_indentation (pp) += 3;
pp_needs_newline (pp) = true;
pp_statement (pp, SWITCH_BODY (stmt));
pp_newline_and_indent (pp, -3);
break;
/* iteration-statement:
while ( expression ) statement
do statement while ( expression ) ;
for ( expression(opt) ; expression(opt) ; expression(opt) ) statement
for ( declaration expression(opt) ; expression(opt) ) statement */
case WHILE_STMT:
pp_c_identifier (pp, "while");
pp_space (pp);
pp_c_left_paren (pp);
pp_expression (pp, WHILE_COND (stmt));
pp_c_right_paren (pp);
pp_newline_and_indent (pp, 3);
pp_statement (pp, WHILE_BODY (stmt));
pp_indentation (pp) -= 3;
pp_needs_newline (pp) = true;
break;
case DO_STMT:
pp_c_identifier (pp, "do");
pp_newline_and_indent (pp, 3);
pp_statement (pp, DO_BODY (stmt));
pp_newline_and_indent (pp, -3);
pp_c_identifier (pp, "while");
pp_space (pp);
pp_c_left_paren (pp);
pp_expression (pp, DO_COND (stmt));
pp_c_right_paren (pp);
pp_c_semicolon (pp);
pp_needs_newline (pp) = true;
break;
case FOR_STMT:
pp_c_identifier (pp, "for");
pp_space (pp);
pp_c_left_paren (pp);
if (FOR_INIT_STMT (stmt))
pp_statement (pp, FOR_INIT_STMT (stmt));
else
pp_c_semicolon (pp);
pp_needs_newline (pp) = false;
pp_c_whitespace (pp);
if (FOR_COND (stmt))
pp_expression (pp, FOR_COND (stmt));
pp_c_semicolon (pp);
pp_needs_newline (pp) = false;
pp_c_whitespace (pp);
if (FOR_EXPR (stmt))
pp_expression (pp, FOR_EXPR (stmt));
pp_c_right_paren (pp);
pp_newline_and_indent (pp, 3);
pp_statement (pp, FOR_BODY (stmt));
pp_indentation (pp) -= 3;
pp_needs_newline (pp) = true;
break;
/* jump-statement:
goto identifier;
continue ;
return expression(opt) ; */
case BREAK_STMT:
case CONTINUE_STMT:
pp_identifier (pp, code == BREAK_STMT ? "break" : "continue");
pp_c_semicolon (pp);
pp_needs_newline (pp) = true;
break;
default:
dump_generic_node (pp_base (pp), stmt, pp_indentation (pp), 0, true);
break;
......
......@@ -193,22 +193,6 @@ emit_local_var (tree decl)
}
}
/* Build a break statement node and return it. */
tree
build_break_stmt (void)
{
return (build_stmt (BREAK_STMT));
}
/* Build a continue statement node and return it. */
tree
build_continue_stmt (void)
{
return (build_stmt (CONTINUE_STMT));
}
/* Create a CASE_LABEL_EXPR tree node and return it. */
tree
......
......@@ -6728,13 +6728,20 @@ void
c_finish_case (tree body)
{
struct c_switch *cs = c_switch_stack;
location_t switch_location;
SWITCH_BODY (cs->switch_expr) = body;
gcc_assert (!cs->blocked_stmt_expr);
/* Emit warnings as needed. */
c_do_switch_expr_warnings (cs->cases, cs->switch_expr);
if (EXPR_HAS_LOCATION (cs->switch_expr))
switch_location = EXPR_LOCATION (cs->switch_expr);
else
switch_location = input_location;
c_do_switch_warnings (cs->cases, switch_location,
TREE_TYPE (cs->switch_expr),
SWITCH_COND (cs->switch_expr));
/* Pop the stack. */
c_switch_stack = cs->next;
......
2005-04-08 Ian Lance Taylor <ian@airs.com>
* cp-tree.def: Define FOR_STMT, WHILE_STMT, DO_STMT, BREAK_STMT,
CONTINUE_STMT, SWITCH_STMT.
* cp-tree.h (cp_stmt_codes): Add FOR_STMT, WHILE_STMT, DO_STMT,
BREAK_STMT, CONTINUE_STMT, SWITCH_STMT.
(WHILE_COND, WHILE_BODY): Define.
(DO_COND, DO_BODY): Define.
(FOR_INIT_STMT, FOR_COND, FOR_EXPR, FOR_BODY): Define.
(SWITCH_STMT_COND, SWITCH_STMT_BODY, SWITCH_STMT_TYPE): Define.
* cp-gimplify.c (enum bc_t): Define.
(struct cp_gimplify_ctx, ctxp): Define.
(push_context, pop_context): New static functions.
(begin_bc_block, finish_bc_block): New static functions.
(build_bc_goto): New static function.
(gimplify_cp_loop, gimplify_for_stmt): New static functions.
(gimplify_while_stmt, gimplify_do_stmt): Likewise.
(gimplify_switch_stmt): Likewise.
(cp_gimplify_expr): Handle FOR_STMT, WHILE_STMT, DO_STMT,
SWITCH_STMT, CONTINUE_STMT, BREAK_STMT.
(cp_genericize): Call push_context and pop_context.
* semantics.c (finish_break_stmt): Just call build_stmt
(BREAK_STMT) rather than build_break_stmt.
(finish_continue_stmt): Corresponding change.
* decl.c (pop_switch): Update call to c_do_switch_warnings for new
parameters.
* cxx-pretty-print.c (pp_cxx_statement): Handle SWITCH_STMT,
WHILE_STMT, DO_STMT, FOR_STMT, BREAK_STMT, CONTINUE_STMT.
* dump.c (cp_dump_tree): Likewise.
2005-04-08 Mark Mitchell <mark@codesourcery.com>
PR c++/20905
......
/* C++-specific tree lowering bits; see also c-gimplify.c and tree-gimple.c.
Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc.
Copyright (C) 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Contributed by Jason Merrill <jason@redhat.com>
This file is part of GCC.
......@@ -32,6 +32,100 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA
#include "hashtab.h"
#include "pointer-set.h"
/* Local declarations. */
enum bc_t { bc_break = 0, bc_continue = 1 };
static struct cp_gimplify_ctx
{
/* Stack of labels which are targets for "break" or "continue",
linked through TREE_CHAIN. */
tree current_label[2];
} *ctxp;
static void
push_context (void)
{
gcc_assert (!ctxp);
ctxp = ((struct cp_gimplify_ctx *)
xcalloc (1, sizeof (struct cp_gimplify_ctx)));
}
static void
pop_context (void)
{
gcc_assert (ctxp
&& !ctxp->current_label[0]
&& !ctxp->current_label[1]);
free (ctxp);
ctxp = NULL;
}
/* Begin a scope which can be exited by a break or continue statement. BC
indicates which.
Just creates a label and pushes it into the current context. */
static tree
begin_bc_block (enum bc_t bc)
{
tree label = create_artificial_label ();
TREE_CHAIN (label) = ctxp->current_label[bc];
ctxp->current_label[bc] = label;
return label;
}
/* Finish a scope which can be exited by a break or continue statement.
LABEL was returned from the most recent call to begin_bc_block. BODY is
an expression for the contents of the scope.
If we saw a break (or continue) in the scope, append a LABEL_EXPR to
body. Otherwise, just forget the label. */
static tree
finish_bc_block (enum bc_t bc, tree label, tree body)
{
gcc_assert (label == ctxp->current_label[bc]);
if (TREE_USED (label))
{
tree t, sl = NULL;
t = build1 (LABEL_EXPR, void_type_node, label);
append_to_statement_list (body, &sl);
append_to_statement_list (t, &sl);
body = sl;
}
ctxp->current_label[bc] = TREE_CHAIN (label);
TREE_CHAIN (label) = NULL_TREE;
return body;
}
/* Build a GOTO_EXPR to represent a break or continue statement. BC
indicates which. */
static tree
build_bc_goto (enum bc_t bc)
{
tree label = ctxp->current_label[bc];
if (label == NULL_TREE)
{
if (bc == bc_break)
error ("break statement not within loop or switch");
else
error ("continue statement not within loop or switch");
return NULL_TREE;
}
/* Mark the label used for finish_bc_block. */
TREE_USED (label) = 1;
return build1 (GOTO_EXPR, void_type_node, label);
}
/* Genericize a TRY_BLOCK. */
static void
......@@ -106,6 +200,144 @@ gimplify_if_stmt (tree *stmt_p)
*stmt_p = stmt;
}
/* Build a generic representation of one of the C loop forms. COND is the
loop condition or NULL_TREE. BODY is the (possibly compound) statement
controlled by the loop. INCR is the increment expression of a for-loop,
or NULL_TREE. COND_IS_FIRST indicates whether the condition is
evaluated before the loop body as in while and for loops, or after the
loop body as in do-while loops. */
static tree
gimplify_cp_loop (tree cond, tree body, tree incr, bool cond_is_first)
{
tree top, entry, exit, cont_block, break_block, stmt_list, t;
location_t stmt_locus;
stmt_locus = input_location;
stmt_list = NULL_TREE;
entry = NULL_TREE;
break_block = begin_bc_block (bc_break);
cont_block = begin_bc_block (bc_continue);
/* If condition is zero don't generate a loop construct. */
if (cond && integer_zerop (cond))
{
top = NULL_TREE;
exit = NULL_TREE;
if (cond_is_first)
{
t = build_bc_goto (bc_break);
append_to_statement_list (t, &stmt_list);
}
}
else
{
/* If we use a LOOP_EXPR here, we have to feed the whole thing
back through the main gimplifier to lower it. Given that we
have to gimplify the loop body NOW so that we can resolve
break/continue stmts, seems easier to just expand to gotos. */
top = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
/* If we have an exit condition, then we build an IF with gotos either
out of the loop, or to the top of it. If there's no exit condition,
then we just build a jump back to the top. */
exit = build_and_jump (&LABEL_EXPR_LABEL (top));
if (cond && !integer_nonzerop (cond))
{
t = build_bc_goto (bc_break);
exit = build3 (COND_EXPR, void_type_node, cond, exit, t);
exit = fold (exit);
gimplify_stmt (&exit);
if (cond_is_first)
{
if (incr)
{
entry = build1 (LABEL_EXPR, void_type_node, NULL_TREE);
t = build_and_jump (&LABEL_EXPR_LABEL (entry));
}
else
t = build_bc_goto (bc_continue);
append_to_statement_list (t, &stmt_list);
}
}
}
gimplify_stmt (&body);
gimplify_stmt (&incr);
body = finish_bc_block (bc_continue, cont_block, body);
append_to_statement_list (top, &stmt_list);
append_to_statement_list (body, &stmt_list);
append_to_statement_list (incr, &stmt_list);
append_to_statement_list (entry, &stmt_list);
append_to_statement_list (exit, &stmt_list);
annotate_all_with_locus (&stmt_list, stmt_locus);
return finish_bc_block (bc_break, break_block, stmt_list);
}
/* Gimplify a FOR_STMT node. Move the stuff in the for-init-stmt into the
prequeue and hand off to gimplify_cp_loop. */
static void
gimplify_for_stmt (tree *stmt_p, tree *pre_p)
{
tree stmt = *stmt_p;
if (FOR_INIT_STMT (stmt))
gimplify_and_add (FOR_INIT_STMT (stmt), pre_p);
*stmt_p = gimplify_cp_loop (FOR_COND (stmt), FOR_BODY (stmt),
FOR_EXPR (stmt), 1);
}
/* Gimplify a WHILE_STMT node. */
static void
gimplify_while_stmt (tree *stmt_p)
{
tree stmt = *stmt_p;
*stmt_p = gimplify_cp_loop (WHILE_COND (stmt), WHILE_BODY (stmt),
NULL_TREE, 1);
}
/* Gimplify a DO_STMT node. */
static void
gimplify_do_stmt (tree *stmt_p)
{
tree stmt = *stmt_p;
*stmt_p = gimplify_cp_loop (DO_COND (stmt), DO_BODY (stmt),
NULL_TREE, 0);
}
/* Genericize a SWITCH_STMT by turning it into a SWITCH_EXPR. */
static void
gimplify_switch_stmt (tree *stmt_p)
{
tree stmt = *stmt_p;
tree break_block, body;
location_t stmt_locus = input_location;
break_block = begin_bc_block (bc_break);
body = SWITCH_STMT_BODY (stmt);
if (!body)
body = build_empty_stmt ();
*stmt_p = build3 (SWITCH_EXPR, SWITCH_STMT_TYPE (stmt),
SWITCH_STMT_COND (stmt), body, NULL_TREE);
SET_EXPR_LOCATION (*stmt_p, stmt_locus);
gimplify_stmt (stmt_p);
*stmt_p = finish_bc_block (bc_break, break_block, *stmt_p);
}
/* Gimplify initialization from an AGGR_INIT_EXPR. */
static void
......@@ -254,6 +486,36 @@ cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p)
ret = GS_OK;
break;
case FOR_STMT:
gimplify_for_stmt (expr_p, pre_p);
ret = GS_ALL_DONE;
break;
case WHILE_STMT:
gimplify_while_stmt (expr_p);
ret = GS_ALL_DONE;
break;
case DO_STMT:
gimplify_do_stmt (expr_p);
ret = GS_ALL_DONE;
break;
case SWITCH_STMT:
gimplify_switch_stmt (expr_p);
ret = GS_ALL_DONE;
break;
case CONTINUE_STMT:
*expr_p = build_bc_goto (bc_continue);
ret = GS_ALL_DONE;
break;
case BREAK_STMT:
*expr_p = build_bc_goto (bc_break);
ret = GS_ALL_DONE;
break;
default:
ret = c_gimplify_expr (expr_p, pre_p, post_p);
break;
......@@ -369,5 +631,7 @@ cp_genericize (tree fndecl)
pointer_set_destroy (p_set);
/* Do everything else. */
push_context ();
c_genericize (fndecl);
pop_context ();
}
......@@ -2,7 +2,7 @@
additional tree codes used in the GNU C++ compiler (see tree.def
for the standard codes).
Copyright (C) 1987, 1988, 1990, 1993, 1997, 1998, 2003, 2004, 2005,
1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
Hacked by Michael Tiemann (tiemann@cygnus.com)
This file is part of GCC.
......@@ -283,6 +283,28 @@ DEFTREECODE (CLEANUP_STMT, "cleanup_stmt", tcc_expression, 3)
and COND_EXPR for the benefit of templates. */
DEFTREECODE (IF_STMT, "if_stmt", tcc_expression, 3)
/* Used to represent a `for' statement. The operands are
FOR_INIT_STMT, FOR_COND, FOR_EXPR, and FOR_BODY, respectively. */
DEFTREECODE (FOR_STMT, "for_stmt", tcc_expression, 4)
/* Used to represent a 'while' statement. The operands are WHILE_COND
and WHILE_BODY, respectively. */
DEFTREECODE (WHILE_STMT, "while_stmt", tcc_expression, 2)
/* Used to represent a 'do' statement. The operands are DO_BODY and
DO_COND, respectively. */
DEFTREECODE (DO_STMT, "do_stmt", tcc_expression, 2)
/* Used to represent a 'break' statement. */
DEFTREECODE (BREAK_STMT, "break_stmt", tcc_expression, 0)
/* Used to represent a 'continue' statement. */
DEFTREECODE (CONTINUE_STMT, "continue_stmt", tcc_expression, 0)
/* Used to represent a 'switch' statement. The operands are
SWITCH_STMT_COND, SWITCH_STMT_BODY and SWITCH_STMT_TYPE, respectively. */
DEFTREECODE (SWITCH_STMT, "switch_stmt", tcc_expression, 3)
DEFTREECODE (TAG_DEFN, "tag_defn", tcc_expression, 0)
/* Template instantiation level node.
......
......@@ -845,8 +845,9 @@ enum cplus_tree_code {
#define cp_stmt_codes \
CTOR_INITIALIZER, TRY_BLOCK, HANDLER, \
EH_SPEC_BLOCK, USING_STMT, TAG_DEFN, \
IF_STMT, CLEANUP_STMT
IF_STMT, CLEANUP_STMT, FOR_STMT, \
WHILE_STMT, DO_STMT, BREAK_STMT, \
CONTINUE_STMT, SWITCH_STMT
enum languages { lang_c, lang_cplusplus, lang_java };
/* Macros to make error reporting functions' lives easier. */
......@@ -2948,6 +2949,28 @@ struct lang_decl GTY(())
#define THEN_CLAUSE(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 1)
#define ELSE_CLAUSE(NODE) TREE_OPERAND (IF_STMT_CHECK (NODE), 2)
/* WHILE_STMT accessors. These give access to the condition of the
while statement and the body of the while statement, respectively. */
#define WHILE_COND(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 0)
#define WHILE_BODY(NODE) TREE_OPERAND (WHILE_STMT_CHECK (NODE), 1)
/* DO_STMT accessors. These give access to the condition of the do
statement and the body of the do statement, respectively. */
#define DO_COND(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 0)
#define DO_BODY(NODE) TREE_OPERAND (DO_STMT_CHECK (NODE), 1)
/* FOR_STMT accessors. These give access to the init statement,
condition, update expression, and body of the for statement,
respectively. */
#define FOR_INIT_STMT(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 0)
#define FOR_COND(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 1)
#define FOR_EXPR(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 2)
#define FOR_BODY(NODE) TREE_OPERAND (FOR_STMT_CHECK (NODE), 3)
#define SWITCH_STMT_COND(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 0)
#define SWITCH_STMT_BODY(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 1)
#define SWITCH_STMT_TYPE(NODE) TREE_OPERAND (SWITCH_STMT_CHECK (NODE), 2)
/* An enumeration of the kind of tags that C++ accepts. */
enum tag_types {
none_type = 0, /* Not a tag type. */
......
......@@ -1551,6 +1551,84 @@ pp_cxx_statement (cxx_pretty_printer *pp, tree t)
}
break;
case SWITCH_STMT:
pp_cxx_identifier (pp, "switch");
pp_space (pp);
pp_cxx_left_paren (pp);
pp_expression (pp, SWITCH_STMT_COND (t));
pp_cxx_right_paren (pp);
pp_indentation (pp) += 3;
pp_needs_newline (pp) = true;
pp_statement (pp, SWITCH_STMT_BODY (t));
pp_newline_and_indent (pp, -3);
break;
/* iteration-statement:
while ( expression ) statement
do statement while ( expression ) ;
for ( expression(opt) ; expression(opt) ; expression(opt) ) statement
for ( declaration expression(opt) ; expression(opt) ) statement */
case WHILE_STMT:
pp_cxx_identifier (pp, "while");
pp_space (pp);
pp_cxx_left_paren (pp);
pp_expression (pp, WHILE_COND (t));
pp_cxx_right_paren (pp);
pp_newline_and_indent (pp, 3);
pp_statement (pp, WHILE_BODY (t));
pp_indentation (pp) -= 3;
pp_needs_newline (pp) = true;
break;
case DO_STMT:
pp_cxx_identifier (pp, "do");
pp_newline_and_indent (pp, 3);
pp_statement (pp, DO_BODY (t));
pp_newline_and_indent (pp, -3);
pp_cxx_identifier (pp, "while");
pp_space (pp);
pp_cxx_left_paren (pp);
pp_expression (pp, DO_COND (t));
pp_cxx_right_paren (pp);
pp_cxx_semicolon (pp);
pp_needs_newline (pp) = true;
break;
case FOR_STMT:
pp_cxx_identifier (pp, "for");
pp_space (pp);
pp_cxx_left_paren (pp);
if (FOR_INIT_STMT (t))
pp_statement (pp, FOR_INIT_STMT (t));
else
pp_cxx_semicolon (pp);
pp_needs_newline (pp) = false;
pp_cxx_whitespace (pp);
if (FOR_COND (t))
pp_expression (pp, FOR_COND (t));
pp_cxx_semicolon (pp);
pp_needs_newline (pp) = false;
pp_cxx_whitespace (pp);
if (FOR_EXPR (t))
pp_expression (pp, FOR_EXPR (t));
pp_cxx_right_paren (pp);
pp_newline_and_indent (pp, 3);
pp_statement (pp, FOR_BODY (t));
pp_indentation (pp) -= 3;
pp_needs_newline (pp) = true;
break;
/* jump-statement:
goto identifier;
continue ;
return expression(opt) ; */
case BREAK_STMT:
case CONTINUE_STMT:
pp_identifier (pp, TREE_CODE (t) == BREAK_STMT ? "break" : "continue");
pp_cxx_semicolon (pp);
pp_needs_newline (pp) = true;
break;
case CLEANUP_STMT:
pp_cxx_identifier (pp, "try");
pp_newline_and_indent (pp, 2);
......
......@@ -2369,9 +2369,16 @@ void
pop_switch (void)
{
struct cp_switch *cs = switch_stack;
location_t switch_location;
/* Emit warnings as needed. */
c_do_switch_warnings (cs->cases, cs->switch_stmt);
if (EXPR_HAS_LOCATION (cs->switch_stmt))
switch_location = EXPR_LOCATION (cs->switch_stmt);
else
switch_location = input_location;
c_do_switch_warnings (cs->cases, switch_location,
SWITCH_STMT_TYPE (cs->switch_stmt),
SWITCH_STMT_COND (cs->switch_stmt));
splay_tree_delete (cs->cases);
switch_stack = switch_stack->next;
......
/* Tree-dumping functionality for intermediate representation.
Copyright (C) 1999, 2000, 2001, 2002, 2004 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
Free Software Foundation, Inc.
Written by Mark Mitchell <mark@codesourcery.com>
This file is part of GCC.
......@@ -423,6 +424,37 @@ cp_dump_tree (void* dump_info, tree t)
dump_child ("else", ELSE_CLAUSE (t));
break;
case BREAK_STMT:
case CONTINUE_STMT:
dump_stmt (di, t);
break;
case DO_STMT:
dump_stmt (di, t);
dump_child ("body", DO_BODY (t));
dump_child ("cond", DO_COND (t));
break;
case FOR_STMT:
dump_stmt (di, t);
dump_child ("init", FOR_INIT_STMT (t));
dump_child ("cond", FOR_COND (t));
dump_child ("expr", FOR_EXPR (t));
dump_child ("body", FOR_BODY (t));
break;
case SWITCH_STMT:
dump_stmt (di, t);
dump_child ("cond", SWITCH_STMT_COND (t));
dump_child ("body", SWITCH_STMT_BODY (t));
break;
case WHILE_STMT:
dump_stmt (di, t);
dump_child ("cond", WHILE_COND (t));
dump_child ("body", WHILE_BODY (t));
break;
default:
break;
}
......
......@@ -834,7 +834,7 @@ finish_for_stmt (tree for_stmt)
tree
finish_break_stmt (void)
{
return add_stmt (build_break_stmt ());
return add_stmt (build_stmt (BREAK_STMT));
}
/* Finish a continue-statement. */
......@@ -842,7 +842,7 @@ finish_break_stmt (void)
tree
finish_continue_stmt (void)
{
return add_stmt (build_continue_stmt ());
return add_stmt (build_stmt (CONTINUE_STMT));
}
/* Begin a switch-statement. Returns a new SWITCH_STMT if
......
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