summaryrefslogtreecommitdiffstats
path: root/gcc/c-typeck.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-typeck.c')
-rw-r--r--gcc/c-typeck.c142
1 files changed, 107 insertions, 35 deletions
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 002d4e704fe..f4b42b991a5 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -4999,7 +4999,8 @@ start_init (decl, asmspec_tree, top_level)
|| TREE_CODE (TREE_TYPE (decl)) == UNION_TYPE
|| TREE_CODE (TREE_TYPE (decl)) == QUAL_UNION_TYPE));
locus = IDENTIFIER_POINTER (DECL_NAME (decl));
- constructor_incremental |= TREE_STATIC (decl);
+ constructor_incremental
+ |= (TREE_STATIC (decl) && !DECL_CONTEXT (decl));
}
else
{
@@ -6541,7 +6542,7 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
if (TREE_CODE (string) == ADDR_EXPR)
string = TREE_OPERAND (string, 0);
- if (TREE_CODE (string) != STRING_CST)
+ if (last_tree && TREE_CODE (string) != STRING_CST)
{
error ("asm template is not a string constant");
return;
@@ -6567,7 +6568,8 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|| TREE_CODE (output) == FIX_CEIL_EXPR)
output = TREE_OPERAND (output, 0);
- lvalue_or_else (o[i], "invalid lvalue in asm statement");
+ if (last_tree)
+ lvalue_or_else (o[i], "invalid lvalue in asm statement");
}
/* Perform default conversions on array and function inputs. */
@@ -6578,6 +6580,14 @@ c_expand_asm_operands (string, outputs, inputs, clobbers, vol, filename, line)
|| TREE_CODE (TREE_TYPE (TREE_VALUE (tail))) == FUNCTION_TYPE)
TREE_VALUE (tail) = default_conversion (TREE_VALUE (tail));
+ if (last_tree)
+ {
+ add_stmt (build_stmt (ASM_STMT,
+ vol ? ridpointers[(int) RID_VOLATILE] : NULL_TREE,
+ string, outputs, inputs, clobbers));
+ return;
+ }
+
/* Generate the ASM_OPERANDS insn;
store into the TREE_VALUEs of OUTPUTS some trees for
where the values were actually stored. */
@@ -6703,53 +6713,115 @@ c_expand_return (retval)
current_function_returns_value = 1;
}
- genrtl_return_stmt (build_return_stmt (retval));
+ add_stmt (build_return_stmt (retval));
}
-/* Start a C switch statement, testing expression EXP.
- Return EXP if it is valid, an error node otherwise. */
+struct c_switch {
+ /* 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;
+ /* The next node on the stack. */
+ struct c_switch *next;
+};
+
+/* 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 c_switch *switch_stack;
+
+/* Start a C switch statement, testing expression EXP. Return the new
+ SWITCH_STMT. */
tree
-c_expand_start_case (exp)
+c_start_case (exp)
tree exp;
{
register enum tree_code code;
tree type;
+ struct c_switch *cs;
- if (TREE_CODE (exp) == ERROR_MARK)
- return exp;
+ if (exp != error_mark_node)
+ {
+ code = TREE_CODE (TREE_TYPE (exp));
+ type = TREE_TYPE (exp);
- code = TREE_CODE (TREE_TYPE (exp));
- type = TREE_TYPE (exp);
+ if (code != INTEGER_TYPE
+ && code != ENUMERAL_TYPE
+ && code != ERROR_MARK)
+ {
+ error ("switch quantity not an integer");
+ exp = integer_zero_node;
+ }
+ else
+ {
+ tree index;
+ type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
- if (code != INTEGER_TYPE && code != ENUMERAL_TYPE && code != ERROR_MARK)
- {
- error ("switch quantity not an integer");
- exp = error_mark_node;
+ if (warn_traditional && !in_system_header
+ && (type == long_integer_type_node
+ || type == long_unsigned_type_node))
+ warning ("`long' switch expression not converted to `int' in ISO C");
+
+ exp = default_conversion (exp);
+ 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;
+ }
}
+
+ /* Add this new SWITCH_STMT to the stack. */
+ cs = (struct c_switch *) xmalloc (sizeof (cs));
+ cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, NULL_TREE);
+ cs->cases = splay_tree_new (case_compare, NULL, NULL);
+ cs->next = switch_stack;
+ switch_stack = cs;
+
+ return add_stmt (switch_stack->switch_stmt);
+}
+
+/* Process a case label. */
+
+void
+do_case (low_value, high_value)
+ tree low_value;
+ tree high_value;
+{
+ if (switch_stack)
+ c_add_case_label (switch_stack->cases,
+ SWITCH_COND (switch_stack->switch_stmt),
+ low_value,
+ high_value);
+ else if (low_value)
+ error ("case label not within a switch statement");
else
- {
- tree index;
- type = TYPE_MAIN_VARIANT (TREE_TYPE (exp));
+ error ("`default' label not within a switch statement");
+}
- if (warn_traditional && !in_system_header
- && (type == long_integer_type_node
- || type == long_unsigned_type_node))
- warning ("`long' switch expression not converted to `int' in ISO C");
+/* Finish the switch statement. */
- exp = default_conversion (exp);
- 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;
- }
+void
+c_finish_case ()
+{
+ struct c_switch *cs = switch_stack;
- expand_start_case (1, exp, type, "switch statement");
+ RECHAIN_STMTS (cs->switch_stmt, SWITCH_BODY (cs->switch_stmt));
- return exp;
+ /* Pop the stack. */
+ switch_stack = switch_stack->next;
+ splay_tree_delete (cs->cases);
+ free (cs);
}
OpenPOWER on IntegriCloud