c-common.h (add_stmt): Change prototype.

* c-common.h (add_stmt): Change prototype.
	(RECHAIN_STMTS): New macro.
	(CASE_LABEL_DECL): Likewise.
	(genrtl_case_label): Change prototype.
	(c_expand_start_case): Remove prototype.
	(build_case_label): Change prototype.
	(decl_constant_value): Declare.
	* c-common.c (check_case_value): Handle C++'s extensions to C
	semantics.
	* c-commnon.def (CASE_LABEL): Add room for the CASE_LABEL_DECL
	field.
	* c-parse.in (stmt): Adjust handling of return statements and case
	laels.
	* c-semantics.c (add_stmt): Return the new statement.
	(genrtl_return_stmt): Take the RETURN_STMT as input, not the
	returned expression.  Directly generate RTL, rather than calling
	c_expand_return.
	(genrtl_switch_stmt): Don't call c_expand_start_case.
	(build_case_label): Take the LABEL_DECL as input, too.
	(genrtl_case_label): Just call add_case_node.
	(expand_stmt): Adjust calls to genrtl_return_stmt and
	genrtl_case_label.
	* c-tree.h (c_expand_start_case): Declare.
	* c-typeck.c (decl_constant_value): Give it external linkage.
	(c_expand_return): Don't call expand_return or expand_null_return;
	use genrtl_return_stmt instead.
	* stmt.c (struct nesting): Remove num_ranges field.
	(add_case_node): Give it external linkage.
	(expand_start_case): Don't set num_ranges.
	(expand_start_case_dummy): Don't clear it.
	(pushcase): Rely on add_case_node to handle `default' labels.
	(add_case_node): Handle `default' labels.
	* tree.c (tree_int_cst_compare): New function.
	* tree.h (tree_int_cst_compare): Declare.
	(add_case_node): Likewise.

	* cp-tree.h (push_switch): Change prototype.
	(check_cp_case_value): Remove declaration.
	(decl_constant_value): Likewise.
	* decl.c (struct cp_switch): Add switch_stmt and cases.
	(case_compare): New function.
	(push_switch): Set switch_stmt.  Initialize cases.
	(pop_switch): Clean up cases.
	(define_case_label): Rename to ...
	(finish_case_label): ... this.  Do semantic analysis for case
	labels here.
	(start_function): Correct comment.
	* decl2.c (check_cp_case_value): Remove.
	* expr.c (do_case): Remove.
	* pt.c (tsubst_expr): Adjust call to finish_case_label.
	* semantics.c (genrtl_do_poplevel): Remove declaration.
	(RECHAIN_STMTS): Remove.
	(finish_break_stmt): Use build_break_stmt.
	(finish_continue_stmt): Use build_continue_stmt.
	(finish_switch_cond): Adjust condition here, rater than in
	c_expand_start_case.
	(finish_case_label): Remove.
	* typeck.c (c_expand_return): Remove.
	(c_expand_start_case): Likewise.

From-SVN: r36305
This commit is contained in:
Mark Mitchell 2000-09-10 21:34:41 +00:00 committed by Mark Mitchell
parent 2c9f4db73a
commit 56cb97339b
19 changed files with 387 additions and 277 deletions

View File

@ -1,3 +1,41 @@
2000-09-10 Mark Mitchell <mark@codesourcery.com>
* c-common.h (add_stmt): Change prototype.
(RECHAIN_STMTS): New macro.
(CASE_LABEL_DECL): Likewise.
(genrtl_case_label): Change prototype.
(c_expand_start_case): Remove prototype.
(build_case_label): Change prototype.
(decl_constant_value): Declare.
* c-common.c (check_case_value): Handle C++'s extensions to C
semantics.
* c-commnon.def (CASE_LABEL): Add room for the CASE_LABEL_DECL
field.
* c-parse.in (stmt): Adjust handling of return statements and case
laels.
* c-semantics.c (add_stmt): Return the new statement.
(genrtl_return_stmt): Take the RETURN_STMT as input, not the
returned expression. Directly generate RTL, rather than calling
c_expand_return.
(genrtl_switch_stmt): Don't call c_expand_start_case.
(build_case_label): Take the LABEL_DECL as input, too.
(genrtl_case_label): Just call add_case_node.
(expand_stmt): Adjust calls to genrtl_return_stmt and
genrtl_case_label.
* c-tree.h (c_expand_start_case): Declare.
* c-typeck.c (decl_constant_value): Give it external linkage.
(c_expand_return): Don't call expand_return or expand_null_return;
use genrtl_return_stmt instead.
* stmt.c (struct nesting): Remove num_ranges field.
(add_case_node): Give it external linkage.
(expand_start_case): Don't set num_ranges.
(expand_start_case_dummy): Don't clear it.
(pushcase): Rely on add_case_node to handle `default' labels.
(add_case_node): Handle `default' labels.
* tree.c (tree_int_cst_compare): New function.
* tree.h (tree_int_cst_compare): Declare.
(add_case_node): Likewise.
2000-09-10 Richard Henderson <rth@cygnus.com>
* c-parse.in: Revert last change.

View File

@ -2678,6 +2678,18 @@ check_case_value (value)
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
STRIP_TYPE_NOPS (value);
/* In C++, the following is allowed:
const int i = 3;
switch (...) { case i: ... }
So, we try to reduce the VALUE to a constant that way. */
if (c_language == clk_cplusplus)
{
value = decl_constant_value (value);
STRIP_TYPE_NOPS (value);
value = fold (value);
}
if (TREE_CODE (value) != INTEGER_CST
&& value != error_mark_node)

View File

@ -95,8 +95,8 @@ DEFTREECODE (SCOPE_STMT, "scope_stmt", 'e', 1)
/* Used to represent a CASE_LABEL. The operands are CASE_LOW and
CASE_HIGH, respectively. If CASE_LOW is NULL_TREE, the label is a
'default' label. If CASE_HIGH is NULL_TREE, the label is a normal case
label. */
DEFTREECODE (CASE_LABEL, "case_label", 'e', 2)
label. The CASE_LABEL_DECL is a LABEL_DECL for this node. */
DEFTREECODE (CASE_LABEL, "case_label", 'e', 3)
/* A STMT_EXPR represents a statement-expression. The
STMT_EXPR_STMT is the statement given by the expression. */

View File

@ -256,7 +256,7 @@ typedef tree (*walk_tree_fn) PARAMS ((tree *,
extern stmt_tree current_stmt_tree PARAMS ((void));
extern void begin_stmt_tree PARAMS ((tree *));
extern void add_stmt PARAMS ((tree));
extern tree add_stmt PARAMS ((tree));
extern void finish_stmt_tree PARAMS ((tree *));
extern int statement_code_p PARAMS ((enum tree_code));
@ -268,6 +268,18 @@ extern void prep_stmt PARAMS ((tree));
extern void (*lang_expand_stmt) PARAMS ((tree));
extern void expand_stmt PARAMS ((tree));
/* LAST_TREE contains the last statement parsed. These are chained
together through the TREE_CHAIN field, but often need to be
re-organized since the parse is performed bottom-up. This macro
makes LAST_TREE the indicated SUBSTMT of STMT. */
#define RECHAIN_STMTS(stmt, substmt) \
do { \
substmt = TREE_CHAIN (stmt); \
TREE_CHAIN (stmt) = NULL_TREE; \
last_tree = stmt; \
} while (0)
/* The variant of the C language being processed. Each C language
front-end defines this variable. */
@ -457,6 +469,7 @@ extern tree simple_type_promotes_to PARAMS ((tree));
of a case label, respectively. */
#define CASE_LOW(NODE) TREE_OPERAND (CASE_LABEL_CHECK (NODE), 0)
#define CASE_HIGH(NODE) TREE_OPERAND (CASE_LABEL_CHECK (NODE), 1)
#define CASE_LABEL_DECL(NODE) TREE_OPERAND (CASE_LABEL_CHECK (NODE), 2)
/* GOTO_STMT accessor. This gives access to the label associated with
a goto statement. */
@ -570,7 +583,7 @@ extern void genrtl_break_stmt PARAMS ((void));
extern void genrtl_continue_stmt PARAMS ((void));
extern void genrtl_scope_stmt PARAMS ((tree));
extern void genrtl_switch_stmt PARAMS ((tree));
extern void genrtl_case_label PARAMS ((tree, tree));
extern void genrtl_case_label PARAMS ((tree));
extern void genrtl_compound_stmt PARAMS ((tree));
extern void genrtl_asm_stmt PARAMS ((tree, tree,
tree, tree,
@ -589,10 +602,9 @@ extern void emit_local_var PARAMS ((tree));
extern void make_rtl_for_local_static PARAMS ((tree));
extern tree expand_cond PARAMS ((tree));
extern void c_expand_return PARAMS ((tree));
extern tree c_expand_start_case PARAMS ((tree));
extern void do_case PARAMS ((tree, tree));
extern tree build_stmt PARAMS ((enum tree_code, ...));
extern tree build_case_label PARAMS ((tree, tree));
extern tree build_case_label PARAMS ((tree, tree, tree));
extern tree build_continue_stmt PARAMS ((void));
extern tree build_break_stmt PARAMS ((void));
extern tree build_return_stmt PARAMS ((tree));
@ -620,6 +632,8 @@ extern tree common_type PARAMS ((tree, tree));
extern tree expand_tree_builtin PARAMS ((tree, tree, tree));
extern tree decl_constant_value PARAMS ((tree));
/* Hook currently used only by the C++ front end to reset internal state
after entering or leaving a header file. */
extern void extract_interface_info PARAMS ((void));

View File

@ -1879,13 +1879,11 @@ stmt:
stmt_count++;
genrtl_continue_stmt (); }
| RETURN ';'
{ tree return_stmt = build_return_stmt (NULL_TREE);
stmt_count++;
genrtl_return_stmt (RETURN_EXPR(return_stmt)); }
{ stmt_count++;
c_expand_return (NULL_TREE); }
| RETURN expr ';'
{ tree return_stmt = build_return_stmt ($2);
stmt_count++;
genrtl_return_stmt (RETURN_EXPR(return_stmt)); }
{ stmt_count++;
c_expand_return ($2); }
| ASM_KEYWORD maybe_type_qual '(' expr ')' ';'
{ stmt_count++;
emit_line_note ($<filename>-1, $<lineno>0);
@ -1943,20 +1941,14 @@ stmt:
also at the end of a compound statement. */
label: CASE expr_no_commas ':'
{ tree case_label_tree = build_case_label ($2, NULL_TREE);
stmt_count++;
genrtl_case_label(CASE_LOW(case_label_tree), CASE_HIGH(case_label_tree));
}
{ stmt_count++;
do_case ($2, NULL_TREE); }
| CASE expr_no_commas ELLIPSIS expr_no_commas ':'
{ tree case_label_tree = build_case_label ($2, $4);
stmt_count++;
genrtl_case_label(CASE_LOW(case_label_tree), CASE_HIGH(case_label_tree));
}
{ stmt_count++;
do_case ($2, $4); }
| DEFAULT ':'
{ tree case_label_tree = build_case_label (NULL_TREE, NULL_TREE);
stmt_count++;
genrtl_case_label(CASE_LOW(case_label_tree), CASE_HIGH(case_label_tree));
}
{ stmt_count++;
do_case (NULL_TREE, NULL_TREE); }
| identifier save_filename save_lineno ':' maybe_attribute
{ tree label = define_label ($2, $3, $1);
stmt_count++;

View File

@ -58,7 +58,7 @@ begin_stmt_tree (t)
/* T is a statement. Add it to the statement-tree. */
void
tree
add_stmt (t)
tree t;
{
@ -68,6 +68,7 @@ add_stmt (t)
/* When we expand a statement-tree, we must know whether or not the
statements are full-expresions. We record that fact here. */
STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
return t;
}
/* Remove declarations of internal variables that are not used from a
@ -434,14 +435,23 @@ build_return_stmt (expr)
return (build_stmt (RETURN_STMT, expr));
}
/* Generate the RTL for EXPR, which is a RETURN_STMT. */
/* Generate the RTL for STMT, which is a RETURN_STMT. */
void
genrtl_return_stmt (expr)
tree expr;
genrtl_return_stmt (stmt)
tree stmt;
{
tree expr = RETURN_EXPR (stmt);
emit_line_note (input_filename, lineno);
c_expand_return (expr);
if (!expr)
expand_null_return ();
else
{
expand_start_target_temps ();
expand_return (expr);
expand_end_target_temps ();
}
}
/* Generate the RTL for T, which is a FOR_STMT. */
@ -547,40 +557,38 @@ genrtl_switch_stmt (t)
genrtl_do_pushlevel ();
cond = expand_cond (SWITCH_COND (t));
if (cond != error_mark_node)
{
emit_line_note (input_filename, lineno);
c_expand_start_case (cond);
}
else
if (cond == error_mark_node)
/* The code is in error, but we don't want expand_end_case to
crash. */
c_expand_start_case (boolean_false_node);
cond = boolean_false_node;
emit_line_note (input_filename, lineno);
expand_start_case (1, cond, TREE_TYPE (cond), "switch statement");
expand_stmt (SWITCH_BODY (t));
expand_end_case (cond);
}
/* Create a CASE_LABEL tree node and return it. */
tree
build_case_label (low_value, high_value)
build_case_label (low_value, high_value, label_decl)
tree low_value;
tree high_value;
tree label_decl;
{
return build_stmt (CASE_LABEL, low_value, high_value);
return build_stmt (CASE_LABEL, low_value, high_value, label_decl);
}
/* Generate the RTL for a CASE_LABEL. */
void
genrtl_case_label (low_value, high_value)
tree low_value;
tree high_value;
genrtl_case_label (case_label)
tree case_label;
{
do_case (low_value, high_value);
tree duplicate;
add_case_node (CASE_LOW (case_label), CASE_HIGH (case_label),
CASE_LABEL_DECL (case_label), &duplicate);
}
/* Generate the RTL for T, which is a COMPOUND_STMT. */
@ -677,7 +685,7 @@ expand_stmt (t)
switch (TREE_CODE (t))
{
case RETURN_STMT:
genrtl_return_stmt (RETURN_EXPR (t));
genrtl_return_stmt (t);
break;
case EXPR_STMT:
@ -721,7 +729,7 @@ expand_stmt (t)
break;
case CASE_LABEL:
genrtl_case_label (CASE_LOW (t), CASE_HIGH (t));
genrtl_case_label (t);
break;
case LABEL_STMT:

View File

@ -268,6 +268,7 @@ extern void set_init_label PARAMS ((tree));
extern void process_init_element PARAMS ((tree));
extern void pedwarn_c99 PARAMS ((const char *, ...))
ATTRIBUTE_PRINTF_1;
extern tree c_expand_start_case PARAMS ((tree));
/* Set to 0 at beginning of a function definition, set to 1 if
a return statement that specifies a return value is seen. */

View File

@ -54,7 +54,6 @@ static tree qualify_type PARAMS ((tree, tree));
static int comp_target_types PARAMS ((tree, tree));
static int function_types_compatible_p PARAMS ((tree, tree));
static int type_lists_compatible_p PARAMS ((tree, tree));
static tree decl_constant_value PARAMS ((tree));
static tree lookup_field PARAMS ((tree, tree, tree *));
static tree convert_arguments PARAMS ((tree, tree, tree, tree));
static tree pointer_int_sum PARAMS ((enum tree_code, tree, tree));
@ -838,7 +837,7 @@ c_alignof_expr (expr)
/* Return either DECL or its known constant value (if it has one). */
static tree
tree
decl_constant_value (decl)
tree decl;
{
@ -6629,14 +6628,12 @@ c_expand_return (retval)
if ((warn_return_type || flag_isoc99)
&& valtype != 0 && TREE_CODE (valtype) != VOID_TYPE)
pedwarn_c99 ("`return' with no value, in function returning non-void");
expand_null_return ();
}
else if (valtype == 0 || TREE_CODE (valtype) == VOID_TYPE)
{
current_function_returns_null = 1;
if (pedantic || TREE_CODE (TREE_TYPE (retval)) != VOID_TYPE)
pedwarn ("`return' with a value, in function returning void");
expand_return (retval);
}
else
{
@ -6701,11 +6698,11 @@ c_expand_return (retval)
break;
}
t = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
TREE_SIDE_EFFECTS (t) = 1;
expand_return (t);
retval = build (MODIFY_EXPR, TREE_TYPE (res), res, t);
current_function_returns_value = 1;
}
genrtl_return_stmt (build_return_stmt (retval));
}
/* Start a C switch statement, testing expression EXP.

View File

@ -1,3 +1,29 @@
2000-09-09 Mark Mitchell <mark@codesourcery.com>
* cp-tree.h (push_switch): Change prototype.
(check_cp_case_value): Remove declaration.
(decl_constant_value): Likewise.
* decl.c (struct cp_switch): Add switch_stmt and cases.
(case_compare): New function.
(push_switch): Set switch_stmt. Initialize cases.
(pop_switch): Clean up cases.
(define_case_label): Rename to ...
(finish_case_label): ... this. Do semantic analysis for case
labels here.
(start_function): Correct comment.
* decl2.c (check_cp_case_value): Remove.
* expr.c (do_case): Remove.
* pt.c (tsubst_expr): Adjust call to finish_case_label.
* semantics.c (genrtl_do_poplevel): Remove declaration.
(RECHAIN_STMTS): Remove.
(finish_break_stmt): Use build_break_stmt.
(finish_continue_stmt): Use build_continue_stmt.
(finish_switch_cond): Adjust condition here, rater than in
c_expand_start_case.
(finish_case_label): Remove.
* typeck.c (c_expand_return): Remove.
(c_expand_start_case): Likewise.
2000-09-07 Gabriel Dos Reis <gdr@codesourcery.com>
* ir.texi: Document type nodes.

View File

@ -3829,7 +3829,7 @@ extern void pop_nested_namespace PARAMS ((tree));
extern void maybe_push_to_top_level PARAMS ((int));
extern void push_to_top_level PARAMS ((void));
extern void pop_from_top_level PARAMS ((void));
extern void push_switch PARAMS ((void));
extern void push_switch PARAMS ((tree));
extern void pop_switch PARAMS ((void));
extern tree identifier_type_value PARAMS ((tree));
extern void set_identifier_type_value PARAMS ((tree, tree));
@ -3990,7 +3990,6 @@ extern tree reparse_absdcl_as_casts PARAMS ((tree, tree));
extern tree build_expr_from_tree PARAMS ((tree));
extern tree reparse_decl_as_expr PARAMS ((tree, tree));
extern tree finish_decl_parsing PARAMS ((tree));
extern tree check_cp_case_value PARAMS ((tree));
extern void set_decl_namespace PARAMS ((tree, tree, int));
extern tree current_decl_namespace PARAMS ((void));
extern void push_decl_namespace PARAMS ((tree));
@ -4075,7 +4074,6 @@ extern tree get_type_value PARAMS ((tree));
extern tree build_member_call PARAMS ((tree, tree, tree));
extern tree build_offset_ref PARAMS ((tree, tree));
extern tree resolve_offset_ref PARAMS ((tree));
extern tree decl_constant_value PARAMS ((tree));
extern tree build_new PARAMS ((tree, tree, tree, int));
extern tree build_vec_init PARAMS ((tree, tree, tree, tree, int));
extern tree build_x_delete PARAMS ((tree, int, tree));

View File

@ -187,6 +187,7 @@ static tree check_special_function_return_type
PARAMS ((special_function_kind, tree, tree, tree));
static tree push_cp_library_fn PARAMS ((enum tree_code, tree));
static tree build_cp_library_fn PARAMS ((tree, enum tree_code, tree));
static int case_compare PARAMS ((splay_tree_key, splay_tree_key));
#if defined (DEBUG_CP_BINDING_LEVELS)
static void indent PARAMS ((void));
@ -5176,17 +5177,52 @@ struct cp_switch
{
struct binding_level *level;
struct cp_switch *next;
/* The SWITCH_STMT being built. */
tree switch_stmt;
/* A splay-tree mapping the low element of a case range to the high
element, or NULL_TREE if there is no high element. Used to
determine whether or not a new case label duplicates an old case
label. We need a tree, rather than simply a hash table, because
of the GNU case range extension. */
splay_tree cases;
};
/* A stack of the currently active switch statements. The innermost
switch statement is on the top of the stack. There is no need to
mark the stack for garbage collection because it is only active
during the processing of the body of a function, and we never
collect at that point. */
static struct cp_switch *switch_stack;
static int
case_compare (k1, k2)
splay_tree_key k1;
splay_tree_key k2;
{
/* Consider a NULL key (such as arises with a `default' label) to be
smaller than anything else. */
if (!k1)
return k2 ? -1 : 0;
else if (!k2)
return k1 ? 1 : 0;
return tree_int_cst_compare ((tree) k1, (tree) k2);
}
/* Called right after a switch-statement condition is parsed.
SWITCH_STMT is the switch statement being parsed. */
void
push_switch ()
push_switch (switch_stmt)
tree switch_stmt;
{
struct cp_switch *p
= (struct cp_switch *) xmalloc (sizeof (struct cp_switch));
p->level = current_binding_level;
p->next = switch_stack;
p->switch_stmt = switch_stmt;
p->cases = splay_tree_new (case_compare, NULL, NULL);
switch_stack = p;
}
@ -5196,6 +5232,7 @@ pop_switch ()
struct cp_switch *cs;
cs = switch_stack;
splay_tree_delete (cs->cases);
switch_stack = switch_stack->next;
free (cs);
}
@ -5204,14 +5241,150 @@ pop_switch ()
is a bad place for one. */
void
define_case_label ()
finish_case_label (low_value, high_value)
tree low_value;
tree high_value;
{
tree cleanup = last_cleanup_this_contour ();
tree label;
tree cleanup;
tree type;
tree cond;
tree case_label;
splay_tree_node node;
if (! switch_stack)
/* Don't crash; we'll complain in do_case. */
{
if (high_value)
error ("case label not within a switch statement");
else if (low_value)
cp_error ("case label `%E' not within a switch statement",
low_value);
else
error ("`default' label not within a switch statement");
return;
}
label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
if (processing_template_decl)
{
/* For templates, just add the case label; we'll do semantic
analysis at instantiation-time. */
add_stmt (build_case_label (low_value, high_value, label));
return;
}
/* Find the condition on which this switch statement depends. */
cond = SWITCH_COND (switch_stack->switch_stmt);
if (cond && TREE_CODE (cond) == TREE_LIST)
cond = TREE_VALUE (cond);
/* If there was an error processing the switch condition, bail now
before we get more confused. */
if (!cond || cond == error_mark_node)
return;
type = TREE_TYPE (cond);
if ((low_value && TREE_TYPE (low_value)
&& POINTER_TYPE_P (TREE_TYPE (low_value)))
|| (high_value && TREE_TYPE (high_value)
&& POINTER_TYPE_P (TREE_TYPE (high_value))))
error ("pointers are not permitted as case values");
/* Case ranges are a GNU extension. */
if (high_value && pedantic)
pedwarn ("ISO C++ forbids range expressions in switch statement");
if (low_value)
{
low_value = check_case_value (low_value);
low_value = convert_and_check (type, low_value);
}
if (high_value)
{
high_value = check_case_value (high_value);
high_value = convert_and_check (type, high_value);
}
/* If an error has occurred, bail out now. */
if (low_value == error_mark_node || high_value == error_mark_node)
return;
/* If the LOW_VALUE and HIGH_VALUE are the same, then this isn't
really a case range, even though it was written that way. Remove
the HIGH_VALUE to simplify later processing. */
if (tree_int_cst_equal (low_value, high_value))
high_value = NULL_TREE;
if (low_value && high_value
&& !tree_int_cst_lt (low_value, high_value))
warning ("empty range specified");
/* Look up the LOW_VALUE in the table of case labels we already
have. */
node = splay_tree_lookup (switch_stack->cases, (splay_tree_key) low_value);
/* If there was not an exact match, check for overlapping ranges.
There's no need to do this if there's no LOW_VALUE or HIGH_VALUE;
that's a `default' label and the only overlap is an exact match. */
if (!node && (low_value || high_value))
{
splay_tree_node low_bound;
splay_tree_node high_bound;
/* Even though there wasn't an exact match, there might be an
overlap between this case range and another case range.
Since we've (inductively) not allowed any overlapping case
ranges, we simply need to find the greatest low case label
that is smaller that LOW_VALUE, and the smallest low case
label that is greater than LOW_VALUE. If there is an overlap
it will occur in one of these two ranges. */
low_bound = splay_tree_predecessor (switch_stack->cases,
(splay_tree_key) low_value);
high_bound = splay_tree_successor (switch_stack->cases,
(splay_tree_key) low_value);
/* Check to see if the LOW_BOUND overlaps. It is smaller than
the LOW_VALUE, so there is no need to check unless the
LOW_BOUND is in fact itself a case range. */
if (low_bound
&& CASE_HIGH ((tree) low_bound->value)
&& tree_int_cst_compare (CASE_HIGH ((tree) low_bound->value),
low_value) >= 0)
node = low_bound;
/* Check to see if the HIGH_BOUND overlaps. The low end of that
range is bigger than the low end of the current range, so we
are only interested if the current range is a real range, and
not an ordinary case label. */
else if (high_bound
&& high_value
&& (tree_int_cst_compare ((tree) high_bound->key,
high_value)
<= 0))
node = high_bound;
}
/* If there was an overlap, issue an error. */
if (node)
{
tree duplicate = CASE_LABEL_DECL ((tree) node->value);
if (high_value)
{
error ("duplicate (or overlapping) case value");
cp_error_at ("this is the first entry overlapping that value",
duplicate);
}
else if (low_value)
{
cp_error ("duplicate case value `%E'", low_value) ;
cp_error_at ("previously used here", duplicate);
}
else
{
error ("multiple default labels in one switch");
cp_error_at ("this is the first default label", duplicate);
}
return;
}
cleanup = last_cleanup_this_contour ();
if (cleanup)
{
static int explained = 0;
@ -5228,9 +5401,18 @@ define_case_label ()
/* After labels, make any new cleanups go into their
own new (temporary) binding contour. */
current_binding_level->more_cleanups_ok = 0;
current_function_return_value = NULL_TREE;
/* Add a representation for the case label to the statement
tree. */
case_label = build_case_label (low_value, high_value, label);
add_stmt (case_label);
/* Register this case label in the splay tree. */
splay_tree_insert (switch_stack->cases,
(splay_tree_key) low_value,
(splay_tree_value) case_label);
}
/* Return the list of declarations of the current level.
@ -13601,7 +13783,7 @@ start_function (declspecs, declarator, attrs, flags)
if (flags & SF_INCLASS_INLINE)
maybe_begin_member_template_processing (decl1);
/* Effective C++ rule 15. See also c_expand_return. */
/* Effective C++ rule 15. */
if (warn_ecpp
&& DECL_OVERLOADED_OPERATOR_P (decl1) == NOP_EXPR
&& TREE_CODE (TREE_TYPE (fntype)) == VOID_TYPE)

View File

@ -4329,35 +4329,6 @@ finish_decl_parsing (decl)
}
}
tree
check_cp_case_value (value)
tree value;
{
if (value == NULL_TREE)
return value;
/* Strip NON_LVALUE_EXPRs since we aren't using as an lvalue. */
STRIP_TYPE_NOPS (value);
value = decl_constant_value (value);
STRIP_TYPE_NOPS (value);
value = fold (value);
if (TREE_CODE (value) != INTEGER_CST
&& value != error_mark_node)
{
cp_error ("case label `%E' does not reduce to an integer constant",
value);
value = error_mark_node;
}
else
/* Promote char or short to int. */
value = default_conversion (value);
constant_expression_warning (value);
return value;
}
/* Return 1 if root encloses child. */
static int

View File

@ -205,82 +205,3 @@ extract_init (decl, init)
return 0;
}
void
do_case (start, end)
tree start, end;
{
tree value1 = NULL_TREE, value2 = NULL_TREE, label;
if (start != NULL_TREE && TREE_TYPE (start) != NULL_TREE
&& POINTER_TYPE_P (TREE_TYPE (start)))
error ("pointers are not permitted as case values");
if (end && pedantic)
pedwarn ("ISO C++ forbids range expressions in switch statement");
if (start)
value1 = check_cp_case_value (start);
if (end)
value2 = check_cp_case_value (end);
label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE);
if (value1 != error_mark_node
&& value2 != error_mark_node)
{
tree duplicate;
int success;
if (end)
success = pushcase_range (value1, value2, convert_and_check,
label, &duplicate);
else if (start)
success = pushcase (value1, convert_and_check, label, &duplicate);
else
success = pushcase (NULL_TREE, 0, label, &duplicate);
if (success == 1)
{
if (end)
error ("case label not within a switch statement");
else if (start)
cp_error ("case label `%E' not within a switch statement", start);
else
error ("default label not within a switch statement");
}
else if (success == 2)
{
if (end)
{
error ("duplicate (or overlapping) case value");
cp_error_at ("this is the first entry overlapping that value",
duplicate);
}
else if (start)
{
cp_error ("duplicate case value `%E'", start);
cp_error_at ("previously used here", duplicate);
}
else
{
error ("multiple default labels in one switch");
cp_error_at ("this is the first default label", duplicate);
}
}
else if (success == 3)
warning ("case value out of range");
else if (success == 4)
warning ("empty range specified");
else if (success == 5)
{
if (end)
error ("case label within scope of cleanup or variable array");
else if (! start)
error ("`default' label within scope of cleanup or variable array");
else
cp_error ("case label `%E' within scope of cleanup or variable array", start);
}
}
current_function_return_value = NULL_TREE;
}

View File

@ -7269,7 +7269,8 @@ tsubst_expr (t, args, complain, in_decl)
case CASE_LABEL:
prep_stmt (t);
finish_case_label (tsubst_expr (CASE_LOW (t), args, complain, in_decl),
tsubst_expr (CASE_HIGH (t), args, complain, in_decl));
tsubst_expr (CASE_HIGH (t), args, complain,
in_decl));
break;
case LABEL_STMT:

View File

@ -55,23 +55,9 @@ static void genrtl_handler PARAMS ((tree));
static void genrtl_catch_block PARAMS ((tree));
static void genrtl_ctor_stmt PARAMS ((tree));
static void genrtl_subobject PARAMS ((tree));
static tree genrtl_do_poplevel PARAMS ((void));
static void genrtl_named_return_value PARAMS ((void));
static void cp_expand_stmt PARAMS ((tree));
/* When parsing a template, LAST_TREE contains the last statement
parsed. These are chained together through the TREE_CHAIN field,
but often need to be re-organized since the parse is performed
bottom-up. This macro makes LAST_TREE the indicated SUBSTMT of
STMT. */
#define RECHAIN_STMTS(stmt, substmt) \
do { \
substmt = TREE_CHAIN (stmt); \
TREE_CHAIN (stmt) = NULL_TREE; \
last_tree = stmt; \
} while (0)
/* Finish processing the COND, the SUBSTMT condition for STMT. */
#define FINISH_COND(cond, stmt, substmt) \
@ -520,7 +506,7 @@ finish_for_stmt (for_stmt)
void
finish_break_stmt ()
{
add_stmt (build_stmt (BREAK_STMT));
add_stmt (build_break_stmt ());
}
/* Finish a continue-statement. */
@ -528,7 +514,7 @@ finish_break_stmt ()
void
finish_continue_stmt ()
{
add_stmt (build_stmt (CONTINUE_STMT));
add_stmt (build_continue_stmt ());
}
/* Begin a switch-statement. Returns a new SWITCH_STMT if
@ -553,6 +539,9 @@ finish_switch_cond (cond, switch_stmt)
{
if (!processing_template_decl)
{
tree type;
tree index;
/* Convert the condition to an integer or enumeration type. */
cond = build_expr_type_conversion (WANT_INT | WANT_ENUM, cond, 1);
if (cond == NULL_TREE)
@ -565,9 +554,19 @@ finish_switch_cond (cond, switch_stmt)
cond = default_conversion (cond);
cond = fold (build1 (CLEANUP_POINT_EXPR, TREE_TYPE (cond), cond));
}
type = TREE_TYPE (cond);
index = get_unwidened (cond, NULL_TREE);
/* We can't strip a conversion from a signed type to an unsigned,
because if we did, int_fits_type_p would do the wrong thing
when checking case values for being in range,
and it's too hard to do the right thing. */
if (TREE_UNSIGNED (TREE_TYPE (cond))
== TREE_UNSIGNED (TREE_TYPE (index)))
cond = index;
}
FINISH_COND (cond, switch_stmt, SWITCH_COND (switch_stmt));
push_switch ();
push_switch (switch_stmt);
}
/* Finish the body of a switch-statement, which may be given by
@ -583,21 +582,6 @@ finish_switch_stmt (switch_stmt)
finish_stmt ();
}
/* Finish a case-label. */
void
finish_case_label (low_value, high_value)
tree low_value;
tree high_value;
{
/* Add a representation for the case label to the statement
tree. */
add_stmt (build_stmt (CASE_LABEL, low_value, high_value));
/* And warn about crossing initializations, etc. */
if (!processing_template_decl)
define_case_label ();
}
/* Generate the RTL for T, which is a TRY_BLOCK. */
static void

View File

@ -6839,56 +6839,7 @@ check_return_expr (retval)
return retval;
}
/* Expand a C `return' statement.
RETVAL is the expression for what to return,
or a null pointer for `return;' with no value.
C++: upon seeing a `return', we must call destructors on all
variables in scope which had constructors called on them.
This means that if in a destructor, the base class destructors
must be called before returning.
The RETURN statement in C++ has initialization semantics. */
void
c_expand_return (retval)
tree retval;
{
if (!retval)
expand_null_return ();
else
{
expand_start_target_temps ();
expand_return (retval);
expand_end_target_temps ();
}
}
/* Start a C switch statement, testing expression EXP.
Return EXP if it is valid, an error node otherwise. */
tree
c_expand_start_case (exp)
tree exp;
{
tree type;
tree index;
type = TREE_TYPE (exp);
index = get_unwidened (exp, NULL_TREE);
/* We can't strip a conversion from a signed type to an unsigned,
because if we did, int_fits_type_p would do the wrong thing
when checking case values for being in range,
and it's too hard to do the right thing. */
if (TREE_UNSIGNED (TREE_TYPE (exp))
== TREE_UNSIGNED (TREE_TYPE (index)))
exp = index;
expand_start_case (1, exp, type, "switch statement");
return exp;
}
/* Returns non-zero if the pointer-type FROM can be converted to the
pointer-type TO via a qualification conversion. If CONSTP is -1,
then we return non-zero if the pointers are similar, and the

View File

@ -240,8 +240,6 @@ struct nesting
tree index_expr;
/* Type that INDEX_EXPR should be converted to. */
tree nominal_type;
/* Number of range exprs in case statement. */
int num_ranges;
/* Name of this kind of statement, for warnings. */
const char *printname;
/* Used to save no_line_numbers till we see the first case label.
@ -421,7 +419,6 @@ static int node_has_high_bound PARAMS ((case_node_ptr, tree));
static int node_is_bounded PARAMS ((case_node_ptr, tree));
static void emit_jump_if_reachable PARAMS ((rtx));
static void emit_case_nodes PARAMS ((rtx, case_node_ptr, rtx, tree));
static int add_case_node PARAMS ((tree, tree, tree, tree *));
static struct case_node *case_tree2list PARAMS ((case_node *, case_node *));
static void mark_cond_nesting PARAMS ((struct nesting *));
static void mark_loop_nesting PARAMS ((struct nesting *));
@ -4426,7 +4423,6 @@ expand_start_case (exit_flag, expr, type, printname)
thiscase->data.case_stmt.index_expr = expr;
thiscase->data.case_stmt.nominal_type = type;
thiscase->data.case_stmt.default_label = 0;
thiscase->data.case_stmt.num_ranges = 0;
thiscase->data.case_stmt.printname = printname;
thiscase->data.case_stmt.line_number_status = force_line_numbers ();
case_stack = thiscase;
@ -4464,7 +4460,6 @@ expand_start_case_dummy ()
thiscase->data.case_stmt.start = 0;
thiscase->data.case_stmt.nominal_type = 0;
thiscase->data.case_stmt.default_label = 0;
thiscase->data.case_stmt.num_ranges = 0;
case_stack = thiscase;
nesting_stack = thiscase;
start_cleanup_deferral ();
@ -4580,21 +4575,7 @@ pushcase (value, converter, label, duplicate)
|| ! int_fits_type_p (value, index_type)))
return 3;
/* Fail if this is a duplicate or overlaps another entry. */
if (value == 0)
{
if (case_stack->data.case_stmt.default_label != 0)
{
*duplicate = case_stack->data.case_stmt.default_label;
return 2;
}
case_stack->data.case_stmt.default_label = label;
}
else
return add_case_node (value, value, label, duplicate);
expand_label (label);
return 0;
return add_case_node (value, value, label, duplicate);
}
/* Like pushcase but this case applies to all values between VALUE1 and
@ -4670,7 +4651,7 @@ pushcase_range (value1, value2, converter, label, duplicate)
into case_stack->data.case_stmt.case_list. Use an AVL tree to avoid
slowdown for large switch statements. */
static int
int
add_case_node (low, high, label, duplicate)
tree low, high;
tree label;
@ -4678,6 +4659,25 @@ add_case_node (low, high, label, duplicate)
{
struct case_node *p, **q, *r;
/* If there's no HIGH value, then this is not a case range; it's
just a simple case label. But that's just a degenerate case
range. */
if (!high)
high = low;
/* Handle default labels specially. */
if (!high && !low)
{
if (case_stack->data.case_stmt.default_label != 0)
{
*duplicate = case_stack->data.case_stmt.default_label;
return 2;
}
case_stack->data.case_stmt.default_label = label;
expand_label (label);
return 0;
}
q = &case_stack->data.case_stmt.case_list;
p = *q;
@ -4709,14 +4709,10 @@ add_case_node (low, high, label, duplicate)
r->low = copy_node (low);
/* If the bounds are equal, turn this into the one-value case. */
if (tree_int_cst_equal (low, high))
r->high = r->low;
else
{
r->high = copy_node (high);
case_stack->data.case_stmt.num_ranges++;
}
r->high = copy_node (high);
r->code_label = label;
expand_label (label);

View File

@ -4293,6 +4293,21 @@ tree_int_cst_lt (t1, t2)
return INT_CST_LT_UNSIGNED (t1, t2);
}
/* Returns -1 if T1 < T2, 0 if T1 == T2, and 1 if T1 > T2. */
int
tree_int_cst_compare (t1, t2)
tree t1;
tree t2;
{
if (tree_int_cst_lt (t1, t2))
return -1;
else if (tree_int_cst_lt (t2, t1))
return 1;
else
return 0;
}
/* Return 1 if T is an INTEGER_CST that can be represented in a single
HOST_WIDE_INT value. If POS is nonzero, the result must be positive. */

View File

@ -1943,6 +1943,7 @@ extern int attribute_list_equal PARAMS ((tree, tree));
extern int attribute_list_contained PARAMS ((tree, tree));
extern int tree_int_cst_equal PARAMS ((tree, tree));
extern int tree_int_cst_lt PARAMS ((tree, tree));
extern int tree_int_cst_compare PARAMS ((tree, tree));
extern int host_integerp PARAMS ((tree, int));
extern HOST_WIDE_INT tree_low_cst PARAMS ((tree, int));
extern int tree_int_cst_msb PARAMS ((tree));
@ -2497,6 +2498,8 @@ extern int expand_dcc_cleanup PARAMS ((tree));
extern void expand_start_case PARAMS ((int, tree, tree,
const char *));
extern void expand_end_case PARAMS ((tree));
extern int add_case_node PARAMS ((tree, tree,
tree, tree *));
extern int pushcase PARAMS ((tree,
tree (*) (tree, tree),
tree, tree *));