aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-typeck.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-typeck.c')
-rw-r--r--gcc/c-typeck.c552
1 files changed, 493 insertions, 59 deletions
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 3a202929e9f..6c779e9c46f 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -64,6 +64,8 @@ int in_sizeof;
/* The level of nesting inside "typeof". */
int in_typeof;
+struct c_label_context *label_context_stack;
+
/* Nonzero if we've already printed a "missing braces around initializer"
message within this initializer. */
static int missing_braces_mentioned;
@@ -375,29 +377,51 @@ composite_type (tree t1, tree t2)
&& TREE_VALUE (p1) != TREE_VALUE (p2))
{
tree memb;
+ tree mv2 = TREE_VALUE (p2);
+ if (mv2 && mv2 != error_mark_node
+ && TREE_CODE (mv2) != ARRAY_TYPE)
+ mv2 = TYPE_MAIN_VARIANT (mv2);
for (memb = TYPE_FIELDS (TREE_VALUE (p1));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (p2)))
- {
- TREE_VALUE (n) = TREE_VALUE (p2);
- if (pedantic)
- pedwarn ("function types not truly compatible in ISO C");
- goto parm_done;
- }
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv2))
+ {
+ TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
+ TREE_VALUE (p2));
+ if (pedantic)
+ pedwarn ("function types not truly compatible in ISO C");
+ goto parm_done;
+ }
+ }
}
if (TREE_CODE (TREE_VALUE (p2)) == UNION_TYPE
&& TREE_VALUE (p2) != TREE_VALUE (p1))
{
tree memb;
+ tree mv1 = TREE_VALUE (p1);
+ if (mv1 && mv1 != error_mark_node
+ && TREE_CODE (mv1) != ARRAY_TYPE)
+ mv1 = TYPE_MAIN_VARIANT (mv1);
for (memb = TYPE_FIELDS (TREE_VALUE (p2));
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), TREE_VALUE (p1)))
- {
- TREE_VALUE (n) = TREE_VALUE (p1);
- if (pedantic)
- pedwarn ("function types not truly compatible in ISO C");
- goto parm_done;
- }
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv1))
+ {
+ TREE_VALUE (n) = composite_type (TREE_TYPE (memb),
+ TREE_VALUE (p1));
+ if (pedantic)
+ pedwarn ("function types not truly compatible in ISO C");
+ goto parm_done;
+ }
+ }
}
TREE_VALUE (n) = composite_type (TREE_VALUE (p1), TREE_VALUE (p2));
parm_done: ;
@@ -827,6 +851,10 @@ struct tagged_tu_seen {
const struct tagged_tu_seen * next;
tree t1;
tree t2;
+ /* APPLE LOCAL begin IMA speed up */
+ int isEnum;
+ int enumMatched;
+ /* APPLE LOCAL end IMA speed up */
};
/* Can they be compatible with each other? We choose to break the
@@ -877,45 +905,72 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
const struct tagged_tu_seen * tts_i;
for (tts_i = tagged_tu_seen_base; tts_i != NULL; tts_i = tts_i->next)
if (tts_i->t1 == t1 && tts_i->t2 == t2)
- return 1;
+ /* APPLE LOCAL IMA speed up */
+ return tts_i->isEnum ? tts_i->enumMatched : 1;
}
switch (TREE_CODE (t1))
{
case ENUMERAL_TYPE:
{
-
- /* Speed up the case where the type values are in the same order. */
- tree tv1 = TYPE_VALUES (t1);
- tree tv2 = TYPE_VALUES (t2);
-
- if (tv1 == tv2)
- return 1;
-
+ /* APPLE LOCAL begin IMA speed up */
+ struct tagged_tu_seen *tts;
+ int res;
+ bool done;
+ /* Speed up the case where the type values are in the same order. */
+ tree tv1 = TYPE_VALUES (t1);
+ tree tv2 = TYPE_VALUES (t2);
+ if (tv1 == tv2)
+ return 1;
+
+ res = 0;
+ done = false;
for (;tv1 && tv2; tv1 = TREE_CHAIN (tv1), tv2 = TREE_CHAIN (tv2))
{
if (TREE_PURPOSE (tv1) != TREE_PURPOSE (tv2))
break;
if (simple_cst_equal (TREE_VALUE (tv1), TREE_VALUE (tv2)) != 1)
- return 0;
+ {
+ res = 0;
+ done = true;
+ break;
+ }
}
+
+ if (!done)
+ {
+ if (tv1 == NULL_TREE && tv2 == NULL_TREE)
+ res = 1, done = true;
+ else if (tv1 == NULL_TREE || tv2 == NULL_TREE)
+ res = 0, done = true;
+ }
- if (tv1 == NULL_TREE && tv2 == NULL_TREE)
- return 1;
- if (tv1 == NULL_TREE || tv2 == NULL_TREE)
- return 0;
-
- if (list_length (TYPE_VALUES (t1)) != list_length (TYPE_VALUES (t2)))
- return 0;
-
- for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1))
+ if (!done && list_length (TYPE_VALUES (t1)) == list_length (TYPE_VALUES (t2)))
+ {
+ res = 1;
+ for (s1 = TYPE_VALUES (t1); s1; s1 = TREE_CHAIN (s1))
{
s2 = purpose_member (TREE_PURPOSE (s1), TYPE_VALUES (t2));
if (s2 == NULL
|| simple_cst_equal (TREE_VALUE (s1), TREE_VALUE (s2)) != 1)
- return 0;
+ {
+ res = 0;
+ break;
+ }
}
- return 1;
+ }
+ if (tagged_tu_seen_base)
+ {
+ tts = xmalloc(sizeof (struct tagged_tu_seen));
+ tts->next = tagged_tu_seen_base;
+ tts->t1 = t1;
+ tts->t2 = t2;
+ tts->isEnum = 1;
+ tts->enumMatched = res;
+ tagged_tu_seen_base = tts;
+ }
+ return res;
+ /* APPLE LOCAL end IMA speed up */
}
case UNION_TYPE:
@@ -927,10 +982,14 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
{
bool ok = false;
struct tagged_tu_seen tts;
+ /* APPLE LOCAL IMA speed up */
+ const struct tagged_tu_seen * tts_i;
tts.next = tagged_tu_seen_base;
tts.t1 = t1;
tts.t2 = t2;
+ /* APPLE LOCAL IMA speed up */
+ tts.isEnum = 0;
tagged_tu_seen_base = &tts;
if (DECL_NAME (s1) != NULL)
@@ -952,6 +1011,15 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
ok = true;
break;
}
+ /* APPLE LOCAL begin IMA speed up */
+ tts_i = tagged_tu_seen_base;
+ while (tts_i->isEnum)
+ {
+ const struct tagged_tu_seen* p = tts_i->next;
+ free((struct tagged_tu_seen*)tts_i);
+ tts_i = p;
+ }
+ /* APPLE LOCAL end IMA speed up */
tagged_tu_seen_base = tts.next;
if (!ok)
return 0;
@@ -962,10 +1030,14 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
case RECORD_TYPE:
{
struct tagged_tu_seen tts;
+ /* APPLE LOCAL IMA speedup */
+ const struct tagged_tu_seen * tts_i;
tts.next = tagged_tu_seen_base;
tts.t1 = t1;
tts.t2 = t2;
+ /* APPLE LOCAL IMA speedup */
+ tts.isEnum = 0;
tagged_tu_seen_base = &tts;
for (s1 = TYPE_FIELDS (t1), s2 = TYPE_FIELDS (t2);
@@ -987,6 +1059,16 @@ tagged_types_tu_compatible_p (tree t1, tree t2)
DECL_FIELD_BIT_OFFSET (s2)) != 1)
break;
}
+
+ /* APPLE LOCAL begin IMA speed up */
+ tts_i = tagged_tu_seen_base;
+ while (tts_i->isEnum)
+ {
+ const struct tagged_tu_seen* p = tts_i->next;
+ free((struct tagged_tu_seen*)tts_i);
+ tts_i = p;
+ }
+ /* APPLE LOCAL end IMA speed up */
tagged_tu_seen_base = tts.next;
if (s1 && s2)
return 0;
@@ -1122,8 +1204,14 @@ type_lists_compatible_p (tree args1, tree args2)
tree memb;
for (memb = TYPE_FIELDS (a1);
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), a2))
- break;
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv2))
+ break;
+ }
if (memb == 0)
return 0;
}
@@ -1137,8 +1225,14 @@ type_lists_compatible_p (tree args1, tree args2)
tree memb;
for (memb = TYPE_FIELDS (a2);
memb; memb = TREE_CHAIN (memb))
- if (comptypes (TREE_TYPE (memb), a1))
- break;
+ {
+ tree mv3 = TREE_TYPE (memb);
+ if (mv3 && mv3 != error_mark_node
+ && TREE_CODE (mv3) != ARRAY_TYPE)
+ mv3 = TYPE_MAIN_VARIANT (mv3);
+ if (comptypes (mv3, mv1))
+ break;
+ }
if (memb == 0)
return 0;
}
@@ -1549,6 +1643,11 @@ build_component_ref (tree datum, tree component)
if (TREE_DEPRECATED (subdatum))
warn_deprecated_use (subdatum);
+ /* APPLE LOCAL begin "unavailable" attribute (radar 2809697) */
+ if (TREE_UNAVAILABLE (subdatum))
+ warn_unavailable_use (subdatum);
+ /* APPLE LOCAL end "unavailable" attribute (radar 2809697) */
+
datum = ref;
field = TREE_CHAIN (field);
@@ -1760,6 +1859,34 @@ build_external_ref (tree id, int fun)
tree ref;
tree decl = lookup_name (id);
+ /* APPLE LOCAL begin CW asm blocks */
+ /* CW assembly has automagical handling of register names. It's
+ also handy to assume undeclared names as labels, although it
+ would be better to have a second pass and complain about names in
+ the block that are not labels. */
+ if (inside_cw_asm_block)
+ {
+ if (decl)
+ {
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ TREE_USED (decl) = 1;
+ /* Locals and parms just need to be left alone for now. */
+ }
+ else
+ {
+ tree newid;
+ if ((newid = cw_asm_reg_name (id)))
+ return newid;
+#ifdef CW_ASM_SPECIAL_LABEL
+ if ((newid = CW_ASM_SPECIAL_LABEL (id)))
+ return newid;
+#endif
+ /* Assume undeclared symbols are labels. */
+ return get_cw_asm_label (id);
+ }
+ }
+ /* APPLE LOCAL end CW asm blocks */
+
/* In Objective-C, an instance variable (ivar) may be preferred to
whatever lookup_name() found. */
decl = objc_lookup_ivar (decl, id);
@@ -1785,6 +1912,11 @@ build_external_ref (tree id, int fun)
if (TREE_DEPRECATED (ref))
warn_deprecated_use (ref);
+ /* APPLE LOCAL begin "unavailable" attribute (radar 2809697) */
+ if (TREE_UNAVAILABLE (ref))
+ warn_unavailable_use (ref);
+ /* APPLE LOCAL end "unavailable" attribute (radar 2809697) */
+
if (!skip_evaluation)
assemble_external (ref);
TREE_USED (ref) = 1;
@@ -1942,6 +2074,12 @@ build_function_call (tree function, tree params)
else
function = default_conversion (function);
+ /* APPLE LOCAL begin Radar 4055183 */
+ /* For Objective-C, convert any calls via a cast to OBJC_TYPE_REF
+ expressions, like those used for ObjC messenger dispatches. */
+ function = objc_rewrite_function_call (function, params);
+
+ /* APPLE LOCAL end Radar 4055183 */
fntype = TREE_TYPE (function);
if (TREE_CODE (fntype) == ERROR_MARK)
@@ -2066,6 +2204,8 @@ convert_arguments (tree typelist, tree values, tree function, tree fundecl)
tree result = NULL;
int parmnum;
tree selector;
+ /* APPLE LOCAL mainline 2005-04-14 */
+ const char *invalid_func_diag;
/* Change pointer to function to the function itself for
diagnostics. */
@@ -2238,6 +2378,14 @@ convert_arguments (tree typelist, tree values, tree function, tree fundecl)
< TYPE_PRECISION (double_type_node)))
/* Convert `float' to `double'. */
result = tree_cons (NULL_TREE, convert (double_type_node, val), result);
+ /* APPLE LOCAL begin mainline 2005-04-14 */
+ else if ((invalid_func_diag =
+ targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
+ {
+ error (invalid_func_diag);
+ return error_mark_node;
+ }
+ /* APPLE LOCAL end mainline 2005-04-14 */
else
/* Convert `short' and `char' to full-size `int'. */
result = tree_cons (NULL_TREE, default_conversion (val), result);
@@ -2270,6 +2418,17 @@ parser_build_binary_op (enum tree_code code, struct c_expr arg1,
enum tree_code code1 = arg1.original_code;
enum tree_code code2 = arg2.original_code;
+ /* APPLE LOCAL begin CW asm blocks */
+ if (inside_cw_asm_block
+ && (TREE_CODE (arg1.value) == IDENTIFIER_NODE
+ || TREE_CODE (arg2.value) == IDENTIFIER_NODE))
+ {
+ result.value = error_mark_node;
+ result.original_code = code;
+ return result;
+ }
+ /* APPLE LOCAL end CW asm blocks */
+
result.value = build_binary_op (code, arg1.value, arg2.value, 1);
result.original_code = code;
@@ -2619,10 +2778,12 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
inc = convert (argtype, inc);
/* Complain about anything else that is not a true lvalue. */
- if (!lvalue_or_else (arg, ((code == PREINCREMENT_EXPR
- || code == POSTINCREMENT_EXPR)
- ? lv_increment
- : lv_decrement)))
+ /* APPLE LOCAL begin non lvalue assign */
+ if (!lvalue_or_else (&arg, ((code == PREINCREMENT_EXPR
+ || code == POSTINCREMENT_EXPR)
+ ? lv_increment
+ : lv_decrement)))
+ /* APPLE LOCAL end non lvalue assign */
return error_mark_node;
/* Report a read-only lvalue. */
@@ -2667,7 +2828,8 @@ build_unary_op (enum tree_code code, tree xarg, int flag)
/* Anything not already handled and not a true memory reference
or a non-lvalue array is an error. */
else if (typecode != FUNCTION_TYPE && !flag
- && !lvalue_or_else (arg, lv_addressof))
+ /* APPLE LOCAL non lvalue assign */
+ && !lvalue_or_else (&arg, lv_addressof))
return error_mark_node;
/* Ordinary case; arg is a COMPONENT_REF or a decl. */
@@ -3031,6 +3193,11 @@ build_compound_expr (tree expr1, tree expr2)
/* Convert arrays and functions to pointers. */
expr2 = default_function_array_conversion (expr2);
+ /* APPLE LOCAL begin AltiVec */
+ if (targetm.cast_expr_as_vector_init)
+ ;
+ else
+ /* APPLE LOCAL end AltiVec */
if (!TREE_SIDE_EFFECTS (expr1))
{
/* The left-hand operand of a comma expression is like an expression
@@ -3062,6 +3229,13 @@ build_c_cast (tree type, tree expr)
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
+ /* APPLE LOCAL begin AltiVec */
+ /* If we are casting to a vector type, treat the expression as a vector
+ initializer if this target supports it. */
+ if (TREE_CODE (type) == VECTOR_TYPE && targetm.cast_expr_as_vector_init)
+ return vector_constructor_from_expr (expr, type);
+ /* APPLE LOCAL end AltiVec */
+
/* The ObjC front-end uses TYPE_MAIN_VARIANT to tie together types differing
only in <protocol> qualifications. But when constructing cast expressions,
the protocols do matter and must be kept around. */
@@ -3251,6 +3425,13 @@ build_c_cast (tree type, tree expr)
pedwarn ("ISO C forbids conversion of object pointer to function pointer type");
ovalue = value;
+ /* APPLE LOCAL begin don't sign-extend pointers cast to integers */
+ if (TREE_CODE (type) == INTEGER_TYPE
+ && TREE_CODE (otype) == POINTER_TYPE
+ && TYPE_PRECISION (type) > TYPE_PRECISION (otype)
+ && TYPE_UNSIGNED (type))
+ value = convert (c_common_type_for_size (POINTER_SIZE, 1), value);
+ /* APPLE LOCAL end don't sign-extend pointers cast to integers */
value = convert (type, value);
/* Ignore any integer overflow caused by the cast. */
@@ -3332,7 +3513,8 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
newrhs = build_binary_op (modifycode, lhs, rhs, 1);
}
- if (!lvalue_or_else (lhs, lv_assign))
+ /* APPLE LOCAL non lvalue assign */
+ if (!lvalue_or_else (&lhs, lv_assign))
return error_mark_node;
/* Give an error for storing in something that is 'const'. */
@@ -3371,6 +3553,16 @@ build_modify_expr (tree lhs, enum tree_code modifycode, tree rhs)
if (TREE_CODE (newrhs) == ERROR_MARK)
return error_mark_node;
+ /* APPLE LOCAL begin ObjC GC */
+ /* Emit ObjC write barrier, if necessary. */
+ if (c_dialect_objc () && flag_objc_gc)
+ {
+ result = objc_generate_write_barrier (lhs, modifycode, newrhs);
+ if (result)
+ return result;
+ }
+ /* APPLE LOCAL end ObjC GC */
+
/* Scan operands. */
result = build2 (MODIFY_EXPR, lhstype, lhs, newrhs);
@@ -3621,7 +3813,9 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
N_("return makes qualified function "
"pointer from unqualified"));
}
- else if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
+ /* APPLE LOCAL begin 4086969 */
+ else if (warn_discard_qual
+ && (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl)))
WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE discards "
"qualifiers from pointer target type"),
N_("assignment discards qualifiers "
@@ -3630,6 +3824,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
"from pointer target type"),
N_("return discards qualifiers from "
"pointer target type"));
+ /* APPLE LOCAL end 4086969 */
}
if (pedantic && !DECL_IN_SYSTEM_HEADER (fundecl))
@@ -3691,15 +3886,20 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
else if (TREE_CODE (ttr) != FUNCTION_TYPE
&& TREE_CODE (ttl) != FUNCTION_TYPE)
{
+ /* APPLE LOCAL begin 4086969 */
if (TYPE_QUALS (ttr) & ~TYPE_QUALS (ttl))
- WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE discards "
- "qualifiers from pointer target type"),
- N_("assignment discards qualifiers "
- "from pointer target type"),
- N_("initialization discards qualifiers "
- "from pointer target type"),
- N_("return discards qualifiers from "
- "pointer target type"));
+ {
+ if (warn_discard_qual)
+ WARN_FOR_ASSIGNMENT (N_("passing argument %d of %qE discards "
+ "qualifiers from pointer target type"),
+ N_("assignment discards qualifiers "
+ "from pointer target type"),
+ N_("initialization discards qualifiers "
+ "from pointer target type"),
+ N_("return discards qualifiers from "
+ "pointer target type"));
+ }
+ /* APPLE LOCAL end 4086969 */
/* If this is not a case of ignoring a mismatch in signedness,
no warning. */
else if (VOID_TYPE_P (ttl) || VOID_TYPE_P (ttr)
@@ -4146,6 +4346,8 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
{
struct c_expr expr;
bool char_string;
+ /* APPLE LOCAL pascal strings */
+ bool pascal_string;
expr.value = inside_init;
expr.original_code = (strict_string ? STRING_CST : ERROR_MARK);
maybe_warn_string_init (type, expr);
@@ -4154,16 +4356,24 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
= (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
== char_type_node);
+ /* APPLE LOCAL begin pascal strings */
+ pascal_string
+ = (TYPE_MAIN_VARIANT (TREE_TYPE (TREE_TYPE (inside_init)))
+ == unsigned_char_type_node);
+ /* APPLE LOCAL end pascal strings */
+
if (comptypes (TYPE_MAIN_VARIANT (TREE_TYPE (inside_init)),
TYPE_MAIN_VARIANT (type)))
return inside_init;
- if (!wchar_array && !char_string)
+ /* APPLE LOCAL pascal strings */
+ if (!wchar_array && !pascal_string && !char_string)
{
error_init ("char-array initialized from wide string");
return error_mark_node;
}
- if (char_string && !char_array)
+ /* APPLE LOCAL pascal strings */
+ if ((char_string || pascal_string) && !char_array)
{
error_init ("wchar_t-array initialized from non-wide string");
return error_mark_node;
@@ -4296,6 +4506,34 @@ digest_init (tree type, tree init, bool strict_string, int require_constant)
if (flag_pedantic_errors)
inside_init = error_mark_node;
}
+ /* APPLE LOCAL begin AltiVec */
+ /* This test catches a Motorola-syntax Altivec vector
+ represented as a constructor of vector type. This tree
+ is not constant but can be initializer to a const vector. */
+ else if (require_constant
+ && (code == VECTOR_TYPE && TREE_CODE (init) == CONSTRUCTOR))
+ return inside_init;
+ else if (require_constant
+ && (code == VECTOR_TYPE && TREE_CODE (init) == NOP_EXPR))
+ {
+ /* User is using FSF style vector const. It must be converted to
+ VECTOR_CST so it is generated at assebly time. */
+ while (TREE_CODE (init) == NOP_EXPR)
+ init = TREE_OPERAND (init, 0);
+ if (TREE_CODE (init) == COMPOUND_LITERAL_EXPR)
+ {
+ init = COMPOUND_LITERAL_EXPR_DECL (init);
+ if (TREE_CODE (init) == VAR_DECL && DECL_INITIAL (init))
+ {
+ init = DECL_INITIAL (init);
+ if (TREE_CODE (init) == VECTOR_CST)
+ return convert (type, init);
+ }
+ }
+ error_init ("initializer element is not constant");
+ inside_init = error_mark_node;
+ }
+ /* APPLE LOCAL end AltiVec */
else if (require_constant
&& !initializer_constant_valid_p (inside_init,
TREE_TYPE (inside_init)))
@@ -6372,7 +6610,8 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
get an error. Gross, but ... */
STRIP_NOPS (output);
- if (!lvalue_or_else (output, lv_asm))
+ /* APPLE LOCAL non lvalue assign */
+ if (!lvalue_or_else (&output, lv_asm))
output = error_mark_node;
constraint = TREE_STRING_POINTER (TREE_VALUE (TREE_PURPOSE (tail)));
@@ -6424,7 +6663,8 @@ build_asm_expr (tree string, tree outputs, tree inputs, tree clobbers,
TREE_VALUE (tail) = input;
}
- args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers);
+ /* APPLE LOCAL CW asm blocks. */
+ args = build_stmt (ASM_EXPR, string, outputs, inputs, clobbers, NULL);
/* Simple asm statements are treated as volatile. */
if (simple)
@@ -6445,6 +6685,23 @@ c_finish_goto_label (tree label)
if (!decl)
return NULL_TREE;
+ if (C_DECL_UNJUMPABLE_STMT_EXPR (decl))
+ {
+ error ("jump into statement expression");
+ return NULL_TREE;
+ }
+
+ if (!C_DECL_UNDEFINABLE_STMT_EXPR (decl))
+ {
+ /* No jump from outside this statement expression context, so
+ record that there is a jump from within this context. */
+ struct c_label_list *nlist;
+ nlist = XOBNEW (&parser_obstack, struct c_label_list);
+ nlist->next = label_context_stack->labels_used;
+ nlist->label = decl;
+ label_context_stack->labels_used = nlist;
+ }
+
TREE_USED (decl) = 1;
return add_stmt (build1 (GOTO_EXPR, void_type_node, decl));
}
@@ -6460,6 +6717,120 @@ c_finish_goto_ptr (tree expr)
return add_stmt (build1 (GOTO_EXPR, void_type_node, expr));
}
+/* APPLE LOCAL begin CW asm blocks */
+int
+cw_asm_typename_or_reserved (tree value)
+{
+ return (C_IS_RESERVED_WORD (value));
+}
+
+/* Given a typename and a component, collect the component's offset.
+ Do this by creating a fake decl with that type and walking it
+ through the usual process. */
+
+tree
+cw_asm_c_build_component_ref (tree typename, tree component)
+{
+ tree val, type, fake_datum;
+ enum tree_code code;
+ tree field = NULL;
+ tree ref;
+
+ /* Intercept variables here and make a component ref instead. */
+ if (TREE_CODE (typename) == VAR_DECL)
+ {
+ return build_component_ref (typename, component);
+ }
+
+ val = lookup_name (typename);
+ if (val)
+ {
+ type = TREE_TYPE (val);
+ }
+ else
+ {
+ /* A structure tag will have been assumed to be a label; pick
+ out the original name. */
+ if (strncmp ("LASM", IDENTIFIER_POINTER (typename), 4) == 0)
+ {
+ char *pos = strchr (IDENTIFIER_POINTER (typename), '$');
+ typename = get_identifier (pos + 1);
+ }
+ type = lookup_struct_or_union_tag (typename);
+ if (!type)
+ {
+ error ("no structure or union tag named `%s'", IDENTIFIER_POINTER (typename));
+ return error_mark_node;
+ }
+ }
+
+ fake_datum = make_node (VAR_DECL);
+ TREE_TYPE (fake_datum) = type;
+
+ code = TREE_CODE (type);
+
+ /* See if there is a field or component with name COMPONENT. */
+
+ if (code == RECORD_TYPE || code == UNION_TYPE)
+ {
+ if (!COMPLETE_TYPE_P (type))
+ {
+ c_incomplete_type_error (NULL_TREE, type);
+ return error_mark_node;
+ }
+
+ field = lookup_field (fake_datum, component);
+
+ if (!field)
+ {
+ error ("%s has no member named `%s'",
+ code == RECORD_TYPE ? "structure" : "union",
+ IDENTIFIER_POINTER (component));
+ return error_mark_node;
+ }
+
+ /* Chain the COMPONENT_REFs if necessary down to the FIELD.
+ This might be better solved in future the way the C++ front
+ end does it - by giving the anonymous entities each a
+ separate name and type, and then have build_component_ref
+ recursively call itself. We can't do that here. */
+ for (; field; field = TREE_CHAIN (field))
+ {
+ tree subdatum = TREE_VALUE (field);
+
+ if (TREE_TYPE (subdatum) == error_mark_node)
+ return error_mark_node;
+
+ ref = build3 (COMPONENT_REF, TREE_TYPE (subdatum), fake_datum,
+ subdatum, NULL_TREE);
+
+ if (TREE_READONLY (fake_datum) || TREE_READONLY (subdatum))
+ TREE_READONLY (ref) = 1;
+ if (TREE_THIS_VOLATILE (fake_datum) || TREE_THIS_VOLATILE (subdatum))
+ TREE_THIS_VOLATILE (ref) = 1;
+
+ if (TREE_DEPRECATED (subdatum))
+ warn_deprecated_use (subdatum);
+
+ /* APPLE LOCAL begin "unavailable" attribute (radar 2809697) */
+ if (TREE_UNAVAILABLE (subdatum))
+ warn_unavailable_use (subdatum);
+ /* APPLE LOCAL end "unavailable" attribute (radar 2809697) */
+
+ fake_datum = ref;
+ }
+
+ /* Return the field decl by itself. */
+ return TREE_OPERAND (ref, 1);
+ }
+ else if (code != ERROR_MARK)
+ error ("request for member `%s' in something not a structure or union",
+ IDENTIFIER_POINTER (component));
+
+ return error_mark_node;
+}
+/* APPLE LOCAL end CW asm blocks */
+
/* Generate a C `return' statement. RETVAL is the expression for what
to return, or a null pointer for `return;' with no value. */
@@ -6571,6 +6942,11 @@ struct c_switch {
of the GNU case range extension. */
splay_tree cases;
+ /* Number of nested statement expressions within this switch
+ statement; if nonzero, case and default labels may not
+ appear. */
+ unsigned int blocked_stmt_expr;
+
/* The next node on the stack. */
struct c_switch *next;
};
@@ -6625,6 +7001,7 @@ c_start_case (tree exp)
cs->switch_stmt = build_stmt (SWITCH_STMT, exp, NULL_TREE, orig_type);
cs->orig_type = orig_type;
cs->cases = splay_tree_new (case_compare, NULL, NULL);
+ cs->blocked_stmt_expr = 0;
cs->next = c_switch_stack;
c_switch_stack = cs;
@@ -6638,7 +7015,7 @@ do_case (tree low_value, tree high_value)
{
tree label = NULL_TREE;
- if (c_switch_stack)
+ if (c_switch_stack && !c_switch_stack->blocked_stmt_expr)
{
label = c_add_case_label (c_switch_stack->cases,
SWITCH_STMT_COND (c_switch_stack->switch_stmt),
@@ -6647,6 +7024,15 @@ do_case (tree low_value, tree high_value)
if (label == error_mark_node)
label = NULL_TREE;
}
+ else if (c_switch_stack && c_switch_stack->blocked_stmt_expr)
+ {
+ if (low_value)
+ error ("case label in statement expression not containing "
+ "enclosing switch statement");
+ else
+ error ("%<default%> label in statement expression not containing "
+ "enclosing switch statement");
+ }
else if (low_value)
error ("case label not within a switch statement");
else
@@ -6664,6 +7050,8 @@ c_finish_case (tree body)
SWITCH_STMT_BODY (cs->switch_stmt) = body;
+ gcc_assert (!cs->blocked_stmt_expr);
+
/* Emit warnings as needed. */
c_do_switch_warnings (cs->cases, cs->switch_stmt);
@@ -6930,12 +7318,30 @@ tree
c_begin_stmt_expr (void)
{
tree ret;
+ struct c_label_context *nstack;
+ struct c_label_list *glist;
/* We must force a BLOCK for this level so that, if it is not expanded
later, there is a way to turn off the entire subtree of blocks that
are contained in it. */
keep_next_level ();
ret = c_begin_compound_stmt (true);
+ if (c_switch_stack)
+ {
+ c_switch_stack->blocked_stmt_expr++;
+ gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
+ }
+ for (glist = label_context_stack->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 1;
+ }
+ nstack = XOBNEW (&parser_obstack, struct c_label_context);
+ nstack->labels_def = NULL;
+ nstack->labels_used = NULL;
+ nstack->next = label_context_stack;
+ label_context_stack = nstack;
/* Mark the current statement list as belonging to a statement list. */
STATEMENT_LIST_STMT_EXPR (ret) = 1;
@@ -6948,8 +7354,36 @@ c_finish_stmt_expr (tree body)
{
tree last, type, tmp, val;
tree *last_p;
+ struct c_label_list *dlist, *glist, *glist_prev = NULL;
body = c_end_compound_stmt (body, true);
+ if (c_switch_stack)
+ {
+ gcc_assert (c_switch_stack->blocked_stmt_expr != 0);
+ c_switch_stack->blocked_stmt_expr--;
+ }
+ /* It is no longer possible to jump to labels defined within this
+ statement expression. */
+ for (dlist = label_context_stack->labels_def;
+ dlist != NULL;
+ dlist = dlist->next)
+ {
+ C_DECL_UNJUMPABLE_STMT_EXPR (dlist->label) = 1;
+ }
+ /* It is again possible to define labels with a goto just outside
+ this statement expression. */
+ for (glist = label_context_stack->next->labels_used;
+ glist != NULL;
+ glist = glist->next)
+ {
+ C_DECL_UNDEFINABLE_STMT_EXPR (glist->label) = 0;
+ glist_prev = glist;
+ }
+ if (glist_prev != NULL)
+ glist_prev->next = label_context_stack->labels_used;
+ else
+ label_context_stack->next->labels_used = label_context_stack->labels_used;
+ label_context_stack = label_context_stack->next;
/* Locate the last statement in BODY. See c_end_compound_stmt
about always returning a BIND_EXPR. */