Commit d11dd684 by Ziemowit Laski Committed by Mike Stump

objc-act.c (objc_build_struct): New function.

        * objc-act.c (objc_build_struct): New function.
        (objc_derived_from_p): Likewise.
        (objc_build_component_ref): Likewise.
        (objc_copy_binfo): Likewise.
        (objc_xref_basetypes): Likewise.
        (objc_lookup_protocol): Likewise.
        (objc_compare_protocols): Likewise.
        (objc_volatilize_decl): Likewise.
        (encode_aggregate_fields): Likewise.
        (volatilized_hash): Likewise.
        (volatilized_eq): Likewise.
        (objc_compare_types): Likewise.
        (objc_type_quals_match): Likewise.
        (DERIVED_FROM_P): New ObjC macro, corresponding to C++ macro
        of same name.
        (get_class_ivars): Add second parameter indicating if entire
        hierarchy is desired.
        (struct volatilized_type): New type.
        (volatilized_htab): New hash table.
        (objc_types_compatible_p, objc_comptypes): Remove functions.
        (synth_module_prologue): Do not initialize 'unused_list'.
        (objc_get_class_reference): Fix ObjC++ impedance mismatches.
        (objc_declare_alias): Implement as a typedef.
        (objc_substitute_decl, objc_gimplify_expr): Reformat.
        (objc_get_class_ivars): Adjust call to get_class_ivars().
        (next_sjlj_build_enter_and_setjmp, synth_forward_declarations,
        build_ivar_reference, get_super_receiver): Call
        objc_build_component_ref() instead of build_component_ref().
        (objc_begin_catch_clause): Use DERIVED_FROM_P() instead of
        objc_comptypes().
        (build_private_template): Call objc_build_struct() instead of
        start_struct() and finish_struct().
        (hash_init): Initialize volatilized_htab.
        (objc_is_public): Adjust calls to objc_get_ivars(); adjust
        ObjC++ impedance mismatches.
        (encode_aggregate_within): Streamline by calling
        encode_aggregate_fields().
        * objc-act.h (objc_types_compatible_p): Remove prototype.
        (OCTI_UNUSED_LIST, unused_list): Remove slot.
        * objc-lang.c (LANG_HOOKS_TYPES_COMPATIBLE_P): Remove.

From-SVN: r100123
parent 18d311d8
2005-05-24 Ziemowit Laski <zlaski@apple.com>
* objc-act.c (objc_build_struct): New function.
(objc_derived_from_p): Likewise.
(objc_build_component_ref): Likewise.
(objc_copy_binfo): Likewise.
(objc_xref_basetypes): Likewise.
(objc_lookup_protocol): Likewise.
(objc_compare_protocols): Likewise.
(objc_volatilize_decl): Likewise.
(encode_aggregate_fields): Likewise.
(volatilized_hash): Likewise.
(volatilized_eq): Likewise.
(objc_compare_types): Likewise.
(objc_type_quals_match): Likewise.
(DERIVED_FROM_P): New ObjC macro, corresponding to C++ macro
of same name.
(get_class_ivars): Add second parameter indicating if entire
hierarchy is desired.
(struct volatilized_type): New type.
(volatilized_htab): New hash table.
(objc_types_compatible_p, objc_comptypes): Remove functions.
(synth_module_prologue): Do not initialize 'unused_list'.
(objc_get_class_reference): Fix ObjC++ impedance mismatches.
(objc_declare_alias): Implement as a typedef.
(objc_substitute_decl, objc_gimplify_expr): Reformat.
(objc_get_class_ivars): Adjust call to get_class_ivars().
(next_sjlj_build_enter_and_setjmp, synth_forward_declarations,
build_ivar_reference, get_super_receiver): Call
objc_build_component_ref() instead of build_component_ref().
(objc_begin_catch_clause): Use DERIVED_FROM_P() instead of
objc_comptypes().
(build_private_template): Call objc_build_struct() instead of
start_struct() and finish_struct().
(hash_init): Initialize volatilized_htab.
(objc_is_public): Adjust calls to objc_get_ivars(); adjust
ObjC++ impedance mismatches.
(encode_aggregate_within): Streamline by calling
encode_aggregate_fields().
* objc-act.h (objc_types_compatible_p): Remove prototype.
(OCTI_UNUSED_LIST, unused_list): Remove slot.
* objc-lang.c (LANG_HOOKS_TYPES_COMPATIBLE_P): Remove.
2005-05-18 Geoffrey Keating <geoffk@apple.com>
* Make-lang.in (cc1obj-dummy): New.
......
......@@ -169,12 +169,20 @@ static tree is_ivar (tree, tree);
static void build_objc_exception_stuff (void);
static void build_next_objc_exception_stuff (void);
/* We only need the following for ObjC; ObjC++ will use C++'s definition
of DERIVED_FROM_P. */
#ifndef OBJCPLUS
static bool objc_derived_from_p (tree, tree);
#define DERIVED_FROM_P(PARENT, CHILD) objc_derived_from_p (PARENT, CHILD)
#endif
static void objc_xref_basetypes (tree, tree);
static void build_class_template (void);
static void build_selector_template (void);
static void build_category_template (void);
static void build_super_template (void);
static tree build_protocol_initializer (tree, tree, tree, tree, tree);
static tree get_class_ivars (tree);
static tree get_class_ivars (tree, bool);
static tree generate_protocol_list (tree);
static void build_protocol_reference (tree);
......@@ -388,6 +396,14 @@ struct string_descriptor GTY(())
static GTY((param_is (struct string_descriptor))) htab_t string_htab;
/* Store the EH-volatilized types in a hash table, for easy retrieval. */
struct volatilized_type GTY(())
{
tree type;
};
static GTY((param_is (struct volatilized_type))) htab_t volatilized_htab;
FILE *gen_declaration_file;
/* Tells "encode_pointer/encode_aggregate" whether we are generating
......@@ -777,351 +793,470 @@ objc_is_class_id (tree type)
return OBJC_TYPE_NAME (type) == objc_class_id;
}
/* Construct a C struct with tag NAME, a base struct with tag
SUPER_NAME (if any), and FIELDS indicated. */
int
objc_types_compatible_p (tree type1, tree type2)
static tree
objc_build_struct (tree name, tree fields, tree super_name)
{
tree s = start_struct (RECORD_TYPE, name);
tree super = (super_name ? xref_tag (RECORD_TYPE, super_name) : NULL_TREE);
if (super)
{
/* Prepend a packed variant of the base class into the layout. This
is necessary to preserve ObjC ABI compatibility. */
tree base = build_decl (FIELD_DECL, NULL_TREE, super);
tree field = TYPE_FIELDS (super);
while (field && TREE_CHAIN (field)
&& TREE_CODE (TREE_CHAIN (field)) == FIELD_DECL)
field = TREE_CHAIN (field);
/* For ObjC ABI purposes, the "packed" size of a base class is
the the sum of the offset and the size (in bits) of the last
field in the class. */
DECL_SIZE (base)
= (field && TREE_CODE (field) == FIELD_DECL
? size_binop (PLUS_EXPR,
size_binop (PLUS_EXPR,
size_binop
(MULT_EXPR,
convert (bitsizetype,
DECL_FIELD_OFFSET (field)),
bitsize_int (BITS_PER_UNIT)),
DECL_FIELD_BIT_OFFSET (field)),
DECL_SIZE (field))
: bitsize_zero_node);
DECL_SIZE_UNIT (base)
= size_binop (FLOOR_DIV_EXPR, convert (sizetype, DECL_SIZE (base)),
size_int (BITS_PER_UNIT));
DECL_ARTIFICIAL (base) = 1;
DECL_ALIGN (base) = 1;
DECL_FIELD_CONTEXT (base) = s;
#ifdef OBJCPLUS
DECL_FIELD_IS_BASE (base) = 1;
if (fields)
TREE_NO_WARNING (fields) = 1; /* Suppress C++ ABI warnings -- we */
#endif /* are following the ObjC ABI here. */
TREE_CHAIN (base) = fields;
fields = base;
}
s = finish_struct (s, fields, NULL_TREE);
/* Use TYPE_BINFO structures to point at the super class, if any. */
objc_xref_basetypes (s, super);
return s;
}
/* Mark DECL as being 'volatile' for purposes of Darwin
_setjmp()/_longjmp() exception handling. Called from
objc_mark_locals_volatile(). */
void
objc_volatilize_decl (tree decl)
{
/* Do not mess with variables that are 'static' or (already)
'volatile'. */
if (!TREE_THIS_VOLATILE (decl) && !TREE_STATIC (decl)
&& (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == PARM_DECL))
{
tree t = TREE_TYPE (decl);
struct volatilized_type key;
void **loc;
t = build_qualified_type (t, (TYPE_QUALS (t)
| TYPE_QUAL_VOLATILE));
key.type = t;
loc = htab_find_slot (volatilized_htab, &key, INSERT);
if (!*loc)
{
*loc = ggc_alloc (sizeof (key));
((struct volatilized_type *) *loc)->type = t;
}
TREE_TYPE (decl) = t;
TREE_THIS_VOLATILE (decl) = 1;
TREE_SIDE_EFFECTS (decl) = 1;
DECL_REGISTER (decl) = 0;
#ifndef OBJCPLUS
C_DECL_REGISTER (decl) = 0;
#endif
}
}
/* Check if protocol PROTO is adopted (directly or indirectly) by class CLS
(including its categoreis and superclasses) or by object type TYP.
Issue a warning if PROTO is not adopted anywhere and WARN is set. */
static bool
objc_lookup_protocol (tree proto, tree cls, tree typ, bool warn)
{
bool class_type = (cls != NULL_TREE);
if (objc_is_object_ptr (type1) || objc_is_object_ptr (type2)
|| objc_is_class_name (type1) || objc_is_class_name (type2))
while (cls)
{
return lhd_types_compatible_p (type1, type2);
tree c;
/* Check protocols adopted by the class and its categories. */
for (c = cls; c; c = CLASS_CATEGORY_LIST (c))
{
if (lookup_protocol_in_reflist (CLASS_PROTOCOL_LIST (c), proto))
return true;
}
/* Repeat for superclasses. */
cls = lookup_interface (CLASS_SUPER_NAME (cls));
}
else
/* Check for any protocols attached directly to the object type. */
if (TYPE_HAS_OBJC_INFO (typ))
{
#ifdef OBJCPLUS
return cxx_types_compatible_p (type1, type2);
#else
return c_types_compatible_p (type1, type2);
#endif
if (lookup_protocol_in_reflist (TYPE_OBJC_PROTOCOL_LIST (typ), proto))
return true;
}
if (warn)
{
strcpy (errbuf, class_type ? "class \'" : "type \'");
gen_type_name_0 (class_type ? typ : TYPE_POINTER_TO (typ));
strcat (errbuf, "\' does not ");
/* NB: Types 'id' and 'Class' cannot reasonably be described as
"implementing" a given protocol, since they do not have an
implementation. */
strcat (errbuf, class_type ? "implement" : "conform to");
strcat (errbuf, " the \'");
strcat (errbuf, IDENTIFIER_POINTER (PROTOCOL_NAME (proto)));
strcat (errbuf, "\' protocol");
warning (0, errbuf);
}
return false;
}
/* Check if class RCLS and instance struct type RTYP conform to at least the
same protocols that LCLS and LTYP conform to. */
static bool
objc_compare_protocols (tree lcls, tree ltyp, tree rcls, tree rtyp, bool warn)
{
tree p;
bool have_lproto = false;
while (lcls)
{
/* NB: We do _not_ look at categories defined for LCLS; these may or
may not get loaded in, and therefore it is unreasonable to require
that RCLS/RTYP must implement any of their protocols. */
for (p = CLASS_PROTOCOL_LIST (lcls); p; p = TREE_CHAIN (p))
{
have_lproto = true;
/* Return 1 if LHS and RHS are compatible types for assignment or
various other operations. Return 0 if they are incompatible, and
return -1 if we choose to not decide (because the types are really
just C types, not ObjC specific ones). When the operation is
REFLEXIVE (typically comparisons), check for compatibility in
either direction; when it's not (typically assignments), don't.
if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn))
return warn;
}
This function is called in two cases: when both lhs and rhs are
pointers to records (in which case we check protocols too), and
when both lhs and rhs are records (in which case we check class
inheritance only).
/* Repeat for superclasses. */
lcls = lookup_interface (CLASS_SUPER_NAME (lcls));
}
Warnings about classes/protocols not implementing a protocol are
emitted here (multiple of those warnings might be emitted for a
single line!); generic warnings about incompatible assignments and
lacks of casts in comparisons are/must be emitted by the caller if
we return 0.
*/
/* Check for any protocols attached directly to the object type. */
if (TYPE_HAS_OBJC_INFO (ltyp))
{
for (p = TYPE_OBJC_PROTOCOL_LIST (ltyp); p; p = TREE_CHAIN (p))
{
have_lproto = true;
int
objc_comptypes (tree lhs, tree rhs, int reflexive)
if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn))
return warn;
}
}
/* NB: If LTYP and LCLS have no protocols to search for, return 'true'
vacuously, _unless_ RTYP is a protocol-qualified 'id'. We can get
away with simply checking for 'id' or 'Class' (!RCLS), since this
routine will not get called in other cases. */
return have_lproto || (rcls != NULL_TREE);
}
/* Determine if it is permissible to assign (if ARGNO is greater than -3)
an instance of RTYP to an instance of LTYP or to compare the two
(if ARGNO is equal to -3), per ObjC type system rules. Before
returning 'true', this routine may issue warnings related to, e.g.,
protocol conformance. When returning 'false', the routine must
produce absolutely no warnings; the C or C++ front-end will do so
instead, if needed. If either LTYP or RTYP is not an Objective-C type,
the routine must return 'false'.
The ARGNO parameter is encoded as follows:
>= 1 Parameter number (CALLEE contains function being called);
0 Return value;
-1 Assignment;
-2 Initialization;
-3 Comparison (LTYP and RTYP may match in either direction). */
bool
objc_compare_types (tree ltyp, tree rtyp, int argno, tree callee)
{
/* New clause for protocols. */
tree lcls, rcls, lproto, rproto;
bool pointers_compatible;
/* We must be dealing with pointer types */
if (!POINTER_TYPE_P (ltyp) || !POINTER_TYPE_P (rtyp))
return false;
/* Here we manage the case of a POINTER_TYPE = POINTER_TYPE. We only
manage the ObjC ones, and leave the rest to the C code. */
if (TREE_CODE (lhs) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (lhs)) == RECORD_TYPE
&& TREE_CODE (rhs) == POINTER_TYPE
&& TREE_CODE (TREE_TYPE (rhs)) == RECORD_TYPE)
do
{
int lhs_is_proto = IS_PROTOCOL_QUALIFIED_UNTYPED (lhs);
int rhs_is_proto = IS_PROTOCOL_QUALIFIED_UNTYPED (rhs);
ltyp = TREE_TYPE (ltyp); /* Remove indirections. */
rtyp = TREE_TYPE (rtyp);
}
while (POINTER_TYPE_P (ltyp) && POINTER_TYPE_P (rtyp));
if (lhs_is_proto)
{
tree lproto, lproto_list = TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (lhs));
tree rproto, rproto_list;
tree p;
/* Past this point, we are only interested in ObjC class instances,
or 'id' or 'Class'. */
if (TREE_CODE (ltyp) != RECORD_TYPE || TREE_CODE (rtyp) != RECORD_TYPE)
return false;
/* <Protocol> = <Protocol> */
if (rhs_is_proto)
{
/* Class <Protocol> != id <Protocol>;
id <Protocol> != Class <Protocol> */
if (IS_ID (lhs) != IS_ID (rhs))
return 0;
if (!objc_is_object_id (ltyp) && !objc_is_class_id (ltyp)
&& !TYPE_HAS_OBJC_INFO (ltyp))
return false;
rproto_list = TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rhs));
if (!objc_is_object_id (rtyp) && !objc_is_class_id (rtyp)
&& !TYPE_HAS_OBJC_INFO (rtyp))
return false;
if (!reflexive)
{
/* An assignment between objects of type 'id
<Protocol>'; make sure the protocol on the lhs is
supported by the object on the rhs. */
for (lproto = lproto_list; lproto;
lproto = TREE_CHAIN (lproto))
{
p = TREE_VALUE (lproto);
rproto = lookup_protocol_in_reflist (rproto_list, p);
/* Past this point, we are committed to returning 'true' to the caller.
However, we can still warn about type and/or protocol mismatches. */
if (!rproto)
warning
(0, "object does not conform to the %qs protocol",
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
return 1;
}
else
{
/* Obscure case - a comparison between two objects
of type 'id <Protocol>'. Check that either the
protocol on the lhs is supported by the object on
the rhs, or viceversa. */
/* Check if the protocol on the lhs is supported by the
object on the rhs. */
for (lproto = lproto_list; lproto;
lproto = TREE_CHAIN (lproto))
{
p = TREE_VALUE (lproto);
rproto = lookup_protocol_in_reflist (rproto_list, p);
if (!rproto)
{
/* Check failed - check if the protocol on the rhs
is supported by the object on the lhs. */
for (rproto = rproto_list; rproto;
rproto = TREE_CHAIN (rproto))
{
p = TREE_VALUE (rproto);
lproto = lookup_protocol_in_reflist (lproto_list,
p);
if (!lproto)
{
/* This check failed too: incompatible */
return 0;
}
}
return 1;
}
}
return 1;
}
}
/* <Protocol> = <class> * */
else if (TYPED_OBJECT (TREE_TYPE (rhs)))
{
tree rname = OBJC_TYPE_NAME (TREE_TYPE (rhs));
tree rinter;
if (TYPE_HAS_OBJC_INFO (ltyp))
{
lcls = TYPE_OBJC_INTERFACE (ltyp);
lproto = TYPE_OBJC_PROTOCOL_LIST (ltyp);
}
else
lcls = lproto = NULL_TREE;
/* Class <Protocol> != <class> * */
if (IS_CLASS (lhs))
return 0;
if (TYPE_HAS_OBJC_INFO (rtyp))
{
rcls = TYPE_OBJC_INTERFACE (rtyp);
rproto = TYPE_OBJC_PROTOCOL_LIST (rtyp);
}
else
rcls = rproto = NULL_TREE;
/* Make sure the protocol is supported by the object on
the rhs. */
for (lproto = lproto_list; lproto; lproto = TREE_CHAIN (lproto))
{
p = TREE_VALUE (lproto);
rproto = 0;
rinter = lookup_interface (rname);
/* If either type is an unqualified 'id', we're done. */
if ((!lproto && objc_is_object_id (ltyp))
|| (!rproto && objc_is_object_id (rtyp)))
return true;
while (rinter && !rproto)
{
tree cat;
rproto_list = CLASS_PROTOCOL_LIST (rinter);
rproto = lookup_protocol_in_reflist (rproto_list, p);
/* If the underlying ObjC class does not have
the protocol we're looking for, check for "one-off"
protocols (e.g., `NSObject<MyProt> *foo;') attached
to the rhs. */
if (!rproto && TYPE_HAS_OBJC_INFO (TREE_TYPE (rhs)))
{
rproto_list = TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rhs));
rproto = lookup_protocol_in_reflist (rproto_list, p);
}
/* Check for protocols adopted by categories. */
cat = CLASS_CATEGORY_LIST (rinter);
while (cat && !rproto)
{
rproto_list = CLASS_PROTOCOL_LIST (cat);
rproto = lookup_protocol_in_reflist (rproto_list, p);
cat = CLASS_CATEGORY_LIST (cat);
}
rinter = lookup_interface (CLASS_SUPER_NAME (rinter));
}
pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp));
if (!rproto)
warning (0, "class %qs does not implement the %qs protocol",
IDENTIFIER_POINTER (OBJC_TYPE_NAME (TREE_TYPE (rhs))),
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
return 1;
}
/* id <Protocol> = id; Class <Protocol> = id */
else if (objc_is_object_id (TREE_TYPE (rhs)))
{
return 1;
}
/* id <Protocol> != Class; Class <Protocol> = Class */
else if (objc_is_class_id (TREE_TYPE (rhs)))
{
return IS_CLASS (lhs);
}
/* <Protocol> = ?? : let comptypes decide. */
return -1;
}
else if (rhs_is_proto)
{
/* <class> * = <Protocol> */
if (TYPED_OBJECT (TREE_TYPE (lhs)))
{
/* <class> * != Class <Protocol> */
if (IS_CLASS (rhs))
return 0;
/* If the underlying types are the same, and at most one of them has
a protocol list, we do not need to issue any diagnostics. */
if (pointers_compatible && (!lproto || !rproto))
return true;
if (reflexive)
{
tree rname = OBJC_TYPE_NAME (TREE_TYPE (lhs));
tree rinter;
tree rproto, rproto_list = TYPE_OBJC_PROTOCOL_LIST (TREE_TYPE (rhs));
/* Make sure the protocol is supported by the object on
the lhs. */
for (rproto = rproto_list; rproto;
rproto = TREE_CHAIN (rproto))
{
tree p = TREE_VALUE (rproto);
tree lproto = 0;
rinter = lookup_interface (rname);
while (rinter && !lproto)
{
tree cat;
tree lproto_list = CLASS_PROTOCOL_LIST (rinter);
lproto = lookup_protocol_in_reflist (lproto_list, p);
/* If the underlying ObjC class does not
have the protocol we're looking for,
check for "one-off" protocols (e.g.,
`NSObject<MyProt> *foo;') attached to the
lhs. */
if (!lproto && TYPE_HAS_OBJC_INFO (TREE_TYPE (lhs)))
{
lproto_list = TYPE_OBJC_PROTOCOL_LIST
(TREE_TYPE (lhs));
lproto = lookup_protocol_in_reflist
(lproto_list, p);
}
/* Check for protocols adopted by categories. */
cat = CLASS_CATEGORY_LIST (rinter);
while (cat && !lproto)
{
lproto_list = CLASS_PROTOCOL_LIST (cat);
lproto = lookup_protocol_in_reflist (lproto_list,
p);
cat = CLASS_CATEGORY_LIST (cat);
}
rinter = lookup_interface (CLASS_SUPER_NAME
(rinter));
}
if (!lproto)
warning (0, "class %qs does not implement the %qs protocol",
IDENTIFIER_POINTER (OBJC_TYPE_NAME
(TREE_TYPE (lhs))),
IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
}
return 1;
}
else
return 0;
}
/* id = id <Protocol>; id = Class <Protocol> */
else if (objc_is_object_id (TREE_TYPE (lhs)))
{
return 1;
}
/* Class != id <Protocol>; Class = Class <Protocol> */
else if (objc_is_class_id (TREE_TYPE (lhs)))
{
return IS_CLASS (rhs);
}
/* ??? = <Protocol> : let comptypes decide */
else
{
return -1;
}
}
else
/* If exactly one of the types is 'Class', issue a diagnostic; any
exceptions of this rule have already been handled. */
if (objc_is_class_id (ltyp) ^ objc_is_class_id (rtyp))
pointers_compatible = false;
/* Otherwise, check for inheritance relations. */
else
{
if (!pointers_compatible)
pointers_compatible
= (objc_is_object_id (ltyp) || objc_is_object_id (rtyp));
if (!pointers_compatible)
pointers_compatible = DERIVED_FROM_P (ltyp, rtyp);
if (!pointers_compatible && argno == -3)
pointers_compatible = DERIVED_FROM_P (rtyp, ltyp);
}
/* If the pointers match modulo protocols, check for protocol conformance
mismatches. */
if (pointers_compatible)
{
pointers_compatible = objc_compare_protocols (lcls, ltyp, rcls, rtyp,
argno != -3);
if (!pointers_compatible && argno == -3)
pointers_compatible = objc_compare_protocols (rcls, rtyp, lcls, ltyp,
argno != -3);
}
if (!pointers_compatible)
{
/* NB: For the time being, we shall make our warnings look like their
C counterparts. In the future, we may wish to make them more
ObjC-specific. */
switch (argno)
{
/* Attention: we shouldn't defer to comptypes here. One bad
side effect would be that we might loose the REFLEXIVE
information.
*/
lhs = TREE_TYPE (lhs);
rhs = TREE_TYPE (rhs);
case -3:
warning (0, "comparison of distinct Objective-C types lacks a cast");
break;
case -2:
warning (0, "initialization from distinct Objective-C type");
break;
case -1:
warning (0, "assignment from distinct Objective-C type");
break;
case 0:
warning (0, "distinct Objective-C type in return");
break;
default:
warning (0, "passing argument %d of %qE from distinct "
"Objective-C type", argno, callee);
break;
}
}
if (TREE_CODE (lhs) != RECORD_TYPE || TREE_CODE (rhs) != RECORD_TYPE)
return true;
}
/* Check if LTYP and RTYP have the same type qualifiers. If either type
lives in the volatilized hash table, ignore the 'volatile' bit when
making the comparison. */
bool
objc_type_quals_match (tree ltyp, tree rtyp)
{
int lquals = TYPE_QUALS (ltyp), rquals = TYPE_QUALS (rtyp);
struct volatilized_type key;
key.type = ltyp;
if (htab_find_slot (volatilized_htab, &key, NO_INSERT))
lquals &= ~TYPE_QUAL_VOLATILE;
key.type = rtyp;
if (htab_find_slot (volatilized_htab, &key, NO_INSERT))
rquals &= ~TYPE_QUAL_VOLATILE;
return (lquals == rquals);
}
#ifndef OBJCPLUS
/* Determine if CHILD is derived from PARENT. The routine assumes that
both parameters are RECORD_TYPEs, and is non-reflexive. */
static bool
objc_derived_from_p (tree parent, tree child)
{
parent = TYPE_MAIN_VARIANT (parent);
for (child = TYPE_MAIN_VARIANT (child);
TYPE_BINFO (child) && BINFO_N_BASE_BINFOS (TYPE_BINFO (child));)
{
/* Nothing to do with ObjC - let immediately comptypes take
responsibility for checking. */
return -1;
child = TYPE_MAIN_VARIANT (BINFO_TYPE (BINFO_BASE_BINFO
(TYPE_BINFO (child),
0)));
if (child == parent)
return true;
}
/* `id' = `<class> *' `<class> *' = `id': always allow it.
Please note that
'Object *o = [[Object alloc] init]; falls
in the case <class> * = `id'.
*/
if ((objc_is_object_id (lhs) && TYPED_OBJECT (rhs))
|| (objc_is_object_id (rhs) && TYPED_OBJECT (lhs)))
return 1;
return false;
}
#endif
static tree
objc_build_component_ref (tree datum, tree component)
{
/* If COMPONENT is NULL, the caller is referring to the anonymous
base class field. */
if (!component)
{
tree base = TYPE_FIELDS (TREE_TYPE (datum));
/* `id' = `Class', `Class' = `id' */
return build3 (COMPONENT_REF, TREE_TYPE (base), datum, base, NULL_TREE);
}
else if ((objc_is_object_id (lhs) && objc_is_class_id (rhs))
|| (objc_is_class_id (lhs) && objc_is_object_id (rhs)))
return 1;
/* The 'build_component_ref' routine has been removed from the C++
front-end, but 'finish_class_member_access_expr' seems to be
a worthy substitute. */
#ifdef OBJCPLUS
return finish_class_member_access_expr (datum, component);
#else
return build_component_ref (datum, component);
#endif
}
/* `Class' != `<class> *' && `<class> *' != `Class'! */
else if ((OBJC_TYPE_NAME (lhs) == objc_class_id && TYPED_OBJECT (rhs))
|| (OBJC_TYPE_NAME (rhs) == objc_class_id && TYPED_OBJECT (lhs)))
return 0;
/* Recursively copy inheritance information rooted at BINFO. To do this,
we emulate the song and dance performed by cp/tree.c:copy_binfo(). */
/* `<class> *' = `<class> *' */
static tree
objc_copy_binfo (tree binfo)
{
tree btype = BINFO_TYPE (binfo);
tree binfo2 = make_tree_binfo (BINFO_N_BASE_BINFOS (binfo));
tree base_binfo;
int ix;
else if (TYPED_OBJECT (lhs) && TYPED_OBJECT (rhs))
BINFO_TYPE (binfo2) = btype;
BINFO_OFFSET (binfo2) = BINFO_OFFSET (binfo);
BINFO_BASE_ACCESSES (binfo2) = BINFO_BASE_ACCESSES (binfo);
/* Recursively copy base binfos of BINFO. */
for (ix = 0; BINFO_BASE_ITERATE (binfo, ix, base_binfo); ix++)
{
tree lname = OBJC_TYPE_NAME (lhs);
tree rname = OBJC_TYPE_NAME (rhs);
tree inter;
tree base_binfo2 = objc_copy_binfo (base_binfo);
BINFO_INHERITANCE_CHAIN (base_binfo2) = binfo2;
BINFO_BASE_APPEND (binfo2, base_binfo2);
}
return binfo2;
}
/* Record superclass information provided in BASETYPE for ObjC class REF.
This is loosely based on cp/decl.c:xref_basetypes(). */
if (lname == rname)
return 1;
static void
objc_xref_basetypes (tree ref, tree basetype)
{
tree binfo = make_tree_binfo (basetype ? 1 : 0);
/* If the left hand side is a super class of the right hand side,
allow it. */
for (inter = lookup_interface (rname); inter;
inter = lookup_interface (CLASS_SUPER_NAME (inter)))
if (lname == CLASS_SUPER_NAME (inter))
return 1;
TYPE_BINFO (ref) = binfo;
BINFO_OFFSET (binfo) = size_zero_node;
BINFO_TYPE (binfo) = ref;
/* Allow the reverse when reflexive. */
if (reflexive)
for (inter = lookup_interface (lname); inter;
inter = lookup_interface (CLASS_SUPER_NAME (inter)))
if (rname == CLASS_SUPER_NAME (inter))
return 1;
if (basetype)
{
tree base_binfo = objc_copy_binfo (TYPE_BINFO (basetype));
return 0;
BINFO_INHERITANCE_CHAIN (base_binfo) = binfo;
BINFO_BASE_ACCESSES (binfo) = VEC_alloc (tree, gc, 1);
BINFO_BASE_APPEND (binfo, base_binfo);
BINFO_BASE_ACCESS_APPEND (binfo, access_public_node);
}
else
/* Not an ObjC type - let comptypes do the check. */
return -1;
}
static hashval_t
volatilized_hash (const void *ptr)
{
tree typ = ((struct volatilized_type *)ptr)->type;
return (hashval_t) typ;
}
static int
volatilized_eq (const void *ptr1, const void *ptr2)
{
tree typ1 = ((struct volatilized_type *)ptr1)->type;
tree typ2 = ((struct volatilized_type *)ptr2)->type;
return typ1 == typ2;
}
/* Called from finish_decl. */
......@@ -1532,10 +1667,6 @@ synth_module_prologue (void)
/* Pre-build the following entities - for speed/convenience. */
self_id = get_identifier ("self");
ucmd_id = get_identifier ("_cmd");
#ifndef OBJCPLUS
/* The C++ front-end does not appear to grok __attribute__((__unused__)). */
unused_list = build_tree_list (get_identifier ("__unused__"), NULL_TREE);
#endif
#ifdef OBJCPLUS
pop_lang_context ();
......@@ -2512,23 +2643,29 @@ add_class_reference (tree ident)
tree
objc_get_class_reference (tree ident)
{
tree orig_ident;
tree orig_ident = (DECL_P (ident)
? DECL_NAME (ident)
: TYPE_P (ident)
? OBJC_TYPE_NAME (ident)
: ident);
bool local_scope = false;
#ifdef OBJCPLUS
if (processing_template_decl)
/* Must wait until template instantiation time. */
return build_min_nt (CLASS_REFERENCE_EXPR, ident);
#endif
if (TREE_CODE (ident) == TYPE_DECL)
{
/* The type must exist in the global namespace. */
if (DECL_CONTEXT (ident) && DECL_CONTEXT (ident) != global_namespace)
local_scope = true;
ident = (DECL_ORIGINAL_TYPE (ident)
? DECL_ORIGINAL_TYPE (ident)
: TREE_TYPE (ident));
ident = DECL_NAME (ident);
}
#ifdef OBJCPLUS
if (TYPE_P (ident) && TYPE_CONTEXT (ident)
&& TYPE_CONTEXT (ident) != global_namespace)
local_scope = true;
#endif
orig_ident = ident;
if (local_scope || !(ident = objc_is_class_name (ident)))
{
......@@ -2656,7 +2793,20 @@ objc_declare_alias (tree alias_ident, tree class_ident)
else if (objc_is_class_name (alias_ident))
warning (0, "class %qs already exists", IDENTIFIER_POINTER (alias_ident));
else
alias_chain = tree_cons (underlying_class, alias_ident, alias_chain);
{
/* Implement @compatibility_alias as a typedef. */
#ifdef OBJCPLUS
push_lang_context (lang_name_c); /* extern "C" */
#endif
lang_hooks.decls.pushdecl (build_decl
(TYPE_DECL,
alias_ident,
xref_tag (RECORD_TYPE, underlying_class)));
#ifdef OBJCPLUS
pop_lang_context ();
#endif
alias_chain = tree_cons (underlying_class, alias_ident, alias_chain);
}
}
void
......@@ -2807,10 +2957,11 @@ objc_substitute_decl (tree expr, tree oldexpr, tree newexpr)
switch (TREE_CODE (expr))
{
case COMPONENT_REF:
return build_component_ref (objc_substitute_decl (TREE_OPERAND (expr, 0),
oldexpr,
newexpr),
DECL_NAME (TREE_OPERAND (expr, 1)));
return objc_build_component_ref
(objc_substitute_decl (TREE_OPERAND (expr, 0),
oldexpr,
newexpr),
DECL_NAME (TREE_OPERAND (expr, 1)));
case ARRAY_REF:
return build_array_ref (objc_substitute_decl (TREE_OPERAND (expr, 0),
oldexpr,
......@@ -3103,7 +3254,7 @@ objc_get_class_ivars (tree class_name)
tree interface = lookup_interface (class_name);
if (interface)
return get_class_ivars (interface);
return get_class_ivars (interface, true);
error ("cannot find interface declaration for %qs",
IDENTIFIER_POINTER (class_name));
......@@ -3115,7 +3266,7 @@ objc_get_class_ivars (tree class_name)
and for @defs constructs. */
static tree
get_class_ivars (tree interface)
get_class_ivars (tree interface, bool inherited)
{
tree ivar_chain = copy_list (CLASS_RAW_IVARS (interface));
......@@ -3126,6 +3277,9 @@ get_class_ivars (tree interface)
if (!CLASS_IVARS (interface))
CLASS_IVARS (interface) = ivar_chain;
if (!inherited)
return ivar_chain;
while (CLASS_SUPER_NAME (interface))
{
/* Prepend super-class ivars. */
......@@ -3283,8 +3437,8 @@ next_sjlj_build_enter_and_setjmp (void)
t = tree_cons (NULL, t, NULL);
enter = build_function_call (objc_exception_try_enter_decl, t);
t = build_component_ref (cur_try_context->stack_decl,
get_identifier ("buf"));
t = objc_build_component_ref (cur_try_context->stack_decl,
get_identifier ("buf"));
t = build_fold_addr_expr (t);
#ifdef OBJCPLUS
/* Convert _setjmp argument to type that is expected. */
......@@ -3569,7 +3723,7 @@ objc_begin_catch_clause (tree decl)
t = CATCH_TYPES (stmt);
if (t == error_mark_node)
continue;
if (!t || objc_comptypes (TREE_TYPE (t), TREE_TYPE (type), 0) == 1)
if (!t || DERIVED_FROM_P (TREE_TYPE (t), TREE_TYPE (type)))
{
warning (0, "exception of type %<%T%> will be caught",
TREE_TYPE (type));
......@@ -3869,9 +4023,10 @@ build_private_template (tree class)
{
if (!CLASS_STATIC_TEMPLATE (class))
{
tree record = start_struct (RECORD_TYPE, CLASS_NAME (class));
tree record = objc_build_struct (CLASS_NAME (class),
get_class_ivars (class, false),
CLASS_SUPER_NAME (class));
finish_struct (record, get_class_ivars (class), NULL_TREE);
/* mark this record as class template - for class type checking */
INIT_TYPE_OBJC_INFO (record);
TYPE_OBJC_INTERFACE (record) = class;
......@@ -4702,8 +4857,8 @@ synth_forward_declarations (void)
/* Pre-build the following entities - for speed/convenience. */
an_id = get_identifier ("super_class");
ucls_super_ref = build_component_ref (UOBJC_CLASS_decl, an_id);
uucls_super_ref = build_component_ref (UOBJC_METACLASS_decl, an_id);
ucls_super_ref = objc_build_component_ref (UOBJC_CLASS_decl, an_id);
uucls_super_ref = objc_build_component_ref (UOBJC_METACLASS_decl, an_id);
}
static void
......@@ -6482,7 +6637,7 @@ build_ivar_reference (tree id)
self_decl = convert (objc_instance_type, self_decl); /* cast */
}
return build_component_ref (build_indirect_ref (self_decl, "->"), id);
return objc_build_component_ref (build_indirect_ref (self_decl, "->"), id);
}
/* Compute a hash value for a given method SEL_NAME. */
......@@ -6510,6 +6665,10 @@ hash_init (void)
/* Initialize the hash table used to hold the constant string objects. */
string_htab = htab_create_ggc (31, string_hash,
string_eq, NULL);
/* Initialize the hash table used to hold EH-volatilized types. */
volatilized_htab = htab_create_ggc (31, volatilized_hash,
volatilized_eq, NULL);
}
/* WARNING!!!! hash_enter is called with a method, and will peek
......@@ -6924,8 +7083,14 @@ is_private (tree decl)
int
objc_is_public (tree expr, tree identifier)
{
tree basetype = TREE_TYPE (expr);
tree decl;
tree basetype, decl;
#ifdef OBJCPLUS
if (processing_template_decl)
return 1;
#endif
basetype = TYPE_MAIN_VARIANT (TREE_TYPE (expr));
if (basetype && TREE_CODE (basetype) == RECORD_TYPE)
{
......@@ -6940,7 +7105,7 @@ objc_is_public (tree expr, tree identifier)
return 0;
}
if ((decl = is_ivar (get_class_ivars (class), identifier)))
if ((decl = is_ivar (get_class_ivars (class, true), identifier)))
{
if (TREE_PUBLIC (decl))
return 1;
......@@ -6949,19 +7114,26 @@ objc_is_public (tree expr, tree identifier)
all instance variables should be public within the context
of the implementation. */
if (objc_implementation_context
&& (((TREE_CODE (objc_implementation_context)
== CLASS_IMPLEMENTATION_TYPE)
|| (TREE_CODE (objc_implementation_context)
== CATEGORY_IMPLEMENTATION_TYPE))
&& (CLASS_NAME (objc_implementation_context)
== OBJC_TYPE_NAME (basetype))))
&& ((TREE_CODE (objc_implementation_context)
== CLASS_IMPLEMENTATION_TYPE)
|| (TREE_CODE (objc_implementation_context)
== CATEGORY_IMPLEMENTATION_TYPE)))
{
int private = is_private (decl);
tree curtype = TYPE_MAIN_VARIANT
(CLASS_STATIC_TEMPLATE
(implementation_template));
if (private)
error ("instance variable %qs is declared private",
IDENTIFIER_POINTER (DECL_NAME (decl)));
return !private;
if (basetype == curtype
|| DERIVED_FROM_P (basetype, curtype))
{
int private = is_private (decl);
if (private)
error ("instance variable %qs is declared private",
IDENTIFIER_POINTER (DECL_NAME (decl)));
return !private;
}
}
/* The 2.95.2 compiler sometimes allowed C functions to access
......@@ -7396,7 +7568,7 @@ continue_class (tree class)
pop_lang_context ();
#endif /* OBJCPLUS */
return get_class_ivars (implementation_template);
return get_class_ivars (implementation_template, true);
}
else if (TREE_CODE (class) == CLASS_INTERFACE_TYPE)
......@@ -7682,6 +7854,47 @@ encode_array (tree type, int curtype, int format)
}
static void
encode_aggregate_fields (tree type, int pointed_to, int curtype, int format)
{
tree field = TYPE_FIELDS (type);
for (; field; field = TREE_CHAIN (field))
{
#ifdef OBJCPLUS
/* C++ static members, and things that are not field at all,
should not appear in the encoding. */
if (TREE_CODE (field) != FIELD_DECL || TREE_STATIC (field))
continue;
#endif
/* Recursively encode fields of embedded base classes. */
if (DECL_ARTIFICIAL (field) && !DECL_NAME (field)
&& TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
{
encode_aggregate_fields (TREE_TYPE (field),
pointed_to, curtype, format);
continue;
}
if (generating_instance_variables && !pointed_to)
{
tree fname = DECL_NAME (field);
obstack_1grow (&util_obstack, '"');
if (fname && TREE_CODE (fname) == IDENTIFIER_NODE)
obstack_grow (&util_obstack,
IDENTIFIER_POINTER (fname),
strlen (IDENTIFIER_POINTER (fname)));
obstack_1grow (&util_obstack, '"');
}
encode_field_decl (field, curtype, format);
}
}
static void
encode_aggregate_within (tree type, int curtype, int format, int left,
int right)
{
......@@ -7721,30 +7934,8 @@ encode_aggregate_within (tree type, int curtype, int format, int left,
if required. */
if (inline_contents)
{
tree fields = TYPE_FIELDS (type);
obstack_1grow (&util_obstack, '=');
for (; fields; fields = TREE_CHAIN (fields))
{
#ifdef OBJCPLUS
/* C++ static members, and things that are not fields at all,
should not appear in the encoding. */
if (TREE_CODE (fields) != FIELD_DECL || TREE_STATIC (fields))
continue;
#endif
if (generating_instance_variables && !pointed_to)
{
tree fname = DECL_NAME (fields);
obstack_1grow (&util_obstack, '"');
if (fname && TREE_CODE (fname) == IDENTIFIER_NODE)
obstack_grow (&util_obstack,
IDENTIFIER_POINTER (fname),
strlen (IDENTIFIER_POINTER (fname)));
obstack_1grow (&util_obstack, '"');
}
encode_field_decl (fields, curtype, format);
}
encode_aggregate_fields (type, pointed_to, curtype, format);
}
/* Close parenth/bracket. */
obstack_1grow (&util_obstack, right);
......@@ -8392,13 +8583,13 @@ get_super_receiver (void)
}
/* Set receiver to self. */
super_expr = build_component_ref (UOBJC_SUPER_decl, self_id);
super_expr = objc_build_component_ref (UOBJC_SUPER_decl, self_id);
super_expr = build_modify_expr (super_expr, NOP_EXPR, self_decl);
super_expr_list = super_expr;
/* Set class to begin searching. */
super_expr = build_component_ref (UOBJC_SUPER_decl,
get_identifier ("super_class"));
super_expr = objc_build_component_ref (UOBJC_SUPER_decl,
get_identifier ("super_class"));
if (TREE_CODE (objc_implementation_context) == CLASS_IMPLEMENTATION_TYPE)
{
......@@ -9174,14 +9365,14 @@ objc_rewrite_function_call (tree function, tree params)
a function in OBJ_TYPE_REF_EXPR (presumably objc_msgSend or one
of its cousins). */
enum gimplify_status objc_gimplify_expr (tree *expr_p, tree *pre_p,
tree *post_p)
enum gimplify_status
objc_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p)
{
enum gimplify_status r0, r1;
if (TREE_CODE (*expr_p) == OBJ_TYPE_REF
if (TREE_CODE (*expr_p) == OBJ_TYPE_REF
&& TREE_CODE (OBJ_TYPE_REF_EXPR (*expr_p)) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (OBJ_TYPE_REF_EXPR (*expr_p), 0))
== FUNCTION_DECL)
&& TREE_CODE (TREE_OPERAND (OBJ_TYPE_REF_EXPR (*expr_p), 0))
== FUNCTION_DECL)
{
/* Postincrements in OBJ_TYPE_REF_OBJECT don't affect the
value of the OBJ_TYPE_REF, so force them to be emitted
......@@ -9193,8 +9384,10 @@ enum gimplify_status objc_gimplify_expr (tree *expr_p, tree *pre_p,
is_gimple_val, fb_rvalue);
r1 = gimplify_expr (&OBJ_TYPE_REF_EXPR (*expr_p), pre_p, post_p,
is_gimple_val, fb_rvalue);
return MIN (r0, r1);
}
#ifdef OBJCPLUS
return cp_gimplify_expr (expr_p, pre_p, post_p);
#else
......
......@@ -32,7 +32,6 @@ const char *objc_printable_name (tree, int);
tree objc_get_callee_fndecl (tree);
void objc_finish_file (void);
tree objc_fold_obj_type_ref (tree, tree);
int objc_types_compatible_p (tree, tree);
enum gimplify_status objc_gimplify_expr (tree *, tree *, tree *);
/* NB: The remaining public functions are prototyped in c-common.h, for the
......@@ -190,7 +189,6 @@ enum objc_tree_index
OCTI_STATIC_NST_DECL,
OCTI_SELF_ID,
OCTI_UCMD_ID,
OCTI_UNUSED_LIST,
OCTI_SELF_DECL,
OCTI_UMSG_DECL,
......@@ -305,7 +303,6 @@ extern GTY(()) tree objc_global_trees[OCTI_MAX];
#define self_id objc_global_trees[OCTI_SELF_ID]
#define ucmd_id objc_global_trees[OCTI_UCMD_ID]
#define unused_list objc_global_trees[OCTI_UNUSED_LIST]
#define self_decl objc_global_trees[OCTI_SELF_DECL]
#define umsg_decl objc_global_trees[OCTI_UMSG_DECL]
......
......@@ -45,8 +45,6 @@ enum c_language_kind c_language = clk_objc;
#define LANG_HOOKS_INIT objc_init
#undef LANG_HOOKS_DECL_PRINTABLE_NAME
#define LANG_HOOKS_DECL_PRINTABLE_NAME objc_printable_name
#undef LANG_HOOKS_TYPES_COMPATIBLE_P
#define LANG_HOOKS_TYPES_COMPATIBLE_P objc_types_compatible_p
#undef LANG_HOOKS_GIMPLIFY_EXPR
#define LANG_HOOKS_GIMPLIFY_EXPR objc_gimplify_expr
#undef LANG_HOOKS_GET_CALLEE_FNDECL
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment