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:
parent
2c9f4db73a
commit
56cb97339b
@ -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.
|
||||
|
@ -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)
|
||||
|
@ -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. */
|
||||
|
@ -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));
|
||||
|
@ -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++;
|
||||
|
@ -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:
|
||||
|
@ -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. */
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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));
|
||||
|
194
gcc/cp/decl.c
194
gcc/cp/decl.c
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
48
gcc/stmt.c
48
gcc/stmt.c
@ -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);
|
||||
|
15
gcc/tree.c
15
gcc/tree.c
@ -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. */
|
||||
|
||||
|
@ -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 *));
|
||||
|
Loading…
Reference in New Issue
Block a user