📄 objc-act.c
字号:
/* Everything matches up! */ return t; } /* Ok, we could not re-use any of the pre-existing variants. Create a new one. */ t = build_variant_type_copy (type); TYPE_VOLATILE (t) = 1; return t;}/* Mark DECL as being 'volatile' for purposes of Darwin _setjmp()/_longjmp() exception handling. Called from objc_mark_locals_volatile(). */voidobjc_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 = objc_build_volatilized_type (t); 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 boolobjc_lookup_protocol (tree proto, tree cls, tree typ, bool warn){ bool class_type = (cls != NULL_TREE); while (cls) { 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)); } /* Check for any protocols attached directly to the object type. */ if (TYPE_HAS_OBJC_INFO (typ)) { 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 boolobjc_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; if (!objc_lookup_protocol (TREE_VALUE (p), rcls, rtyp, warn)) return warn; } /* Repeat for superclasses. */ lcls = lookup_interface (CLASS_SUPER_NAME (lcls)); } /* 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; 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). */boolobjc_compare_types (tree ltyp, tree rtyp, int argno, tree callee){ 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; do { ltyp = TREE_TYPE (ltyp); /* Remove indirections. */ rtyp = TREE_TYPE (rtyp); } while (POINTER_TYPE_P (ltyp) && POINTER_TYPE_P (rtyp)); /* 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; if (!objc_is_object_id (ltyp) && !objc_is_class_id (ltyp) && !TYPE_HAS_OBJC_INFO (ltyp)) return false; if (!objc_is_object_id (rtyp) && !objc_is_class_id (rtyp) && !TYPE_HAS_OBJC_INFO (rtyp)) return false; /* Past this point, we are committed to returning 'true' to the caller. However, we can still warn about type and/or protocol mismatches. */ if (TYPE_HAS_OBJC_INFO (ltyp)) { lcls = TYPE_OBJC_INTERFACE (ltyp); lproto = TYPE_OBJC_PROTOCOL_LIST (ltyp); } else lcls = lproto = NULL_TREE; if (TYPE_HAS_OBJC_INFO (rtyp)) { rcls = TYPE_OBJC_INTERFACE (rtyp); rproto = TYPE_OBJC_PROTOCOL_LIST (rtyp); } else rcls = rproto = NULL_TREE; /* If we could not find an @interface declaration, we must have only seen a @class declaration; for purposes of type comparison, treat it as a stand-alone (root) class. */ if (lcls && TREE_CODE (lcls) == IDENTIFIER_NODE) lcls = NULL_TREE; if (rcls && TREE_CODE (rcls) == IDENTIFIER_NODE) rcls = NULL_TREE; /* 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; pointers_compatible = (TYPE_MAIN_VARIANT (ltyp) == TYPE_MAIN_VARIANT (rtyp)); /* 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 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) { 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; } } 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. */boolobjc_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 boolobjc_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));) { child = TYPE_MAIN_VARIANT (BINFO_TYPE (BINFO_BASE_BINFO (TYPE_BINFO (child), 0))); if (child == parent) return true; } return false;}#endifstatic treeobjc_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)); return build3 (COMPONENT_REF, TREE_TYPE (base), datum, base, NULL_TREE); } /* 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, false);#else return build_component_ref (datum, component);#endif}/* Recursively copy inheritance information rooted at BINFO. To do this, we emulate the song and dance performed by cp/tree.c:copy_binfo(). */static treeobjc_copy_binfo (tree binfo){ tree btype = BINFO_TYPE (binfo); tree binfo2 = make_tree_binfo (BINFO_N_BASE_BINFOS (binfo)); tree base_binfo; int ix; 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 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(). */static voidobjc_xref_basetypes (tree ref, tree basetype){ tree binfo = make_tree_binfo (basetype ? 1 : 0); TYPE_BINFO (ref) = binfo; BINFO_OFFSET (binfo) = size_zero_node; BINFO_TYPE (binfo) = ref; if (basetype) { tree base_binfo = objc_copy_binfo (TYPE_BINFO (basetype)); 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); }}static hashval_tvolatilized_hash (const void *ptr){ tree typ = ((struct volatilized_type *)ptr)->type; return htab_hash_pointer(typ);}static intvolatilized_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. */voidobjc_check_decl (tree decl){ tree type = TREE_TYPE (decl); if (TREE_CODE (type) != RECORD_TYPE) return; if (OBJC_TYPE_NAME (type) && (type = objc_is_class_name (OBJC_TYPE_NAME (type)))) error ("statically allocated instance of Objective-C class %qs", IDENTIFIER_POINTER (type));}/* Construct a PROTOCOLS-qualified variant of INTERFACE, where INTERFACE may either name an Objective-C class, or refer to the special 'id' or 'Class' types. If INTERFACE is not a valid ObjC type, just return it unchanged. */treeobjc_get_protocol_qualified_type (tree interface, tree protocols){ /* If INTERFACE is not provided, default to 'id'. */ tree type = (interface ? objc_is_id (interface) : objc_object_type); bool is_ptr = (type != NULL_TREE);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -