summaryrefslogtreecommitdiff
path: root/gcc/objc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/objc')
-rw-r--r--gcc/objc/objc-act.c234
-rw-r--r--gcc/objc/objc-act.h4
2 files changed, 176 insertions, 62 deletions
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 0b99ece7fea..03c3ae4f262 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -253,6 +253,7 @@ static tree build_selector_reference_decl PARAMS ((void));
static tree add_protocol PARAMS ((tree));
static tree lookup_protocol PARAMS ((tree));
+static void check_protocol_recursively PARAMS ((tree, tree));
static tree lookup_and_install_protocols PARAMS ((tree));
/* Type encoding. */
@@ -336,6 +337,8 @@ static tree check_duplicates PARAMS ((hash));
static tree receiver_is_class_object PARAMS ((tree));
static int check_methods PARAMS ((tree, tree, int));
static int conforms_to_protocol PARAMS ((tree, tree));
+static void check_protocol PARAMS ((tree, const char *,
+ const char *));
static void check_protocols PARAMS ((tree, const char *,
const char *));
static tree encode_method_def PARAMS ((tree));
@@ -1010,6 +1013,12 @@ objc_comptypes (lhs, rhs, reflexive)
tree cat;
rproto_list = CLASS_PROTOCOL_LIST (rinter);
+ /* If the underlying ObjC class does not have
+ protocols attached to it, perhaps there are
+ "one-off" protocols attached to the rhs?
+ E.g., 'id<MyProt> foo;'. */
+ if (!rproto_list)
+ rproto_list = TYPE_PROTOCOL_LIST (TREE_TYPE (rhs));
rproto = lookup_protocol_in_reflist (rproto_list, p);
/* Check for protocols adopted by categories. */
@@ -1202,6 +1211,32 @@ get_object_reference (protocols)
return type;
}
+/* Check for circular dependencies in protocols. The arguments are
+ PROTO, the protocol to check, and LIST, a list of protocol it
+ conforms to. */
+
+static void
+check_protocol_recursively (proto, list)
+ tree proto;
+ tree list;
+{
+ tree p;
+
+ for (p = list; p; p = TREE_CHAIN (p))
+ {
+ tree pp = TREE_VALUE (p);
+
+ if (TREE_CODE (pp) == IDENTIFIER_NODE)
+ pp = lookup_protocol (pp);
+
+ if (pp == proto)
+ fatal_error ("protocol `%s' has circular dependency",
+ IDENTIFIER_POINTER (PROTOCOL_NAME (pp)));
+ if (pp)
+ check_protocol_recursively (proto, PROTOCOL_LIST (pp));
+ }
+}
+
static tree
lookup_and_install_protocols (protocols)
tree protocols;
@@ -4871,18 +4906,27 @@ check_duplicates (hsh)
return meth;
}
-/* If RECEIVER is a class reference, return the identifier node for the
- referenced class. RECEIVER is created by get_class_reference, so we
- check the exact form created depending on which runtimes are used. */
+/* If RECEIVER is a class reference, return the identifier node for
+ the referenced class. RECEIVER is created by get_class_reference,
+ so we check the exact form created depending on which runtimes are
+ used. */
static tree
receiver_is_class_object (receiver)
tree receiver;
{
tree chain, exp, arg;
+
if (flag_next_runtime)
{
- /* The receiver is a variable created by build_class_reference_decl. */
+ /* The receiver is 'self' in the context of a class method. */
+ if (objc_method_context
+ && receiver == self_decl
+ && TREE_CODE (objc_method_context) == CLASS_METHOD_DECL)
+ return CLASS_NAME (objc_implementation_context);
+
+ /* The receiver is a variable created by
+ build_class_reference_decl. */
if (TREE_CODE (receiver) == VAR_DECL
&& TREE_TYPE (receiver) == objc_class_type)
/* Look up the identifier. */
@@ -4899,7 +4943,7 @@ receiver_is_class_object (receiver)
&& (exp = TREE_OPERAND (exp, 0))
&& TREE_CODE (exp) == FUNCTION_DECL
&& exp == objc_get_class_decl
- /* we have a call to objc_getClass! */
+ /* We have a call to objc_getClass! */
&& (arg = TREE_OPERAND (receiver, 1))
&& TREE_CODE (arg) == TREE_LIST
&& (arg = TREE_VALUE (arg)))
@@ -5143,7 +5187,8 @@ build_message_expr (mess)
method_prototype = lookup_class_method_static (iface, sel_name);
}
- if (!method_prototype)
+ if (!method_prototype
+ || TREE_CODE (method_prototype) != CLASS_METHOD_DECL)
{
warning ("cannot find class (factory) method.");
warning ("return type for `%s' defaults to id",
@@ -5960,16 +6005,17 @@ check_methods (chain, list, mtype)
return first;
}
+/* Check if CLASS, or its superclasses, explicitly conforms to PROTOCOL. */
+
static int
conforms_to_protocol (class, protocol)
tree class;
tree protocol;
{
- while (protocol)
+ if (TREE_CODE (protocol) == PROTOCOL_INTERFACE_TYPE)
{
tree p = CLASS_PROTOCOL_LIST (class);
-
- while (p && TREE_VALUE (p) != TREE_VALUE (protocol))
+ while (p && TREE_VALUE (p) != protocol)
p = TREE_CHAIN (p);
if (!p)
@@ -5981,8 +6027,6 @@ conforms_to_protocol (class, protocol)
if (!tmp)
return 0;
}
-
- protocol = TREE_CHAIN (protocol);
}
return 1;
@@ -6054,57 +6098,81 @@ check_methods_accessible (chain, context, mtype)
return first;
}
+/* Check whether the current interface (accessible via
+ 'implementation_context') actually implements protocol P, along
+ with any protocols that P inherits. */
+
static void
-check_protocols (proto_list, type, name)
- tree proto_list;
+check_protocol (p, type, name)
+ tree p;
const char *type;
const char *name;
{
- for ( ; proto_list; proto_list = TREE_CHAIN (proto_list))
+ if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
{
- tree p = TREE_VALUE (proto_list);
+ int f1, f2;
- if (TREE_CODE (p) == PROTOCOL_INTERFACE_TYPE)
+ /* Ensure that all protocols have bodies! */
+ if (flag_warn_protocol)
{
- int f1, f2;
-
- /* Ensure that all protocols have bodies. */
- if (flag_warn_protocol) {
- f1 = check_methods (PROTOCOL_CLS_METHODS (p),
- CLASS_CLS_METHODS (implementation_context),
- '+');
- f2 = check_methods (PROTOCOL_NST_METHODS (p),
- CLASS_NST_METHODS (implementation_context),
- '-');
- } else {
- f1 = check_methods_accessible (PROTOCOL_CLS_METHODS (p),
- implementation_context,
- '+');
- f2 = check_methods_accessible (PROTOCOL_NST_METHODS (p),
- implementation_context,
- '-');
- }
-
- if (!f1 || !f2)
- warning ("%s `%s' does not fully implement the `%s' protocol",
- type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
-
+ f1 = check_methods (PROTOCOL_CLS_METHODS (p),
+ CLASS_CLS_METHODS (implementation_context),
+ '+');
+ f2 = check_methods (PROTOCOL_NST_METHODS (p),
+ CLASS_NST_METHODS (implementation_context),
+ '-');
}
else
- {
- ; /* An identifier if we could not find a protocol. */
- }
+ {
+ f1 = check_methods_accessible (PROTOCOL_CLS_METHODS (p),
+ implementation_context,
+ '+');
+ f2 = check_methods_accessible (PROTOCOL_NST_METHODS (p),
+ implementation_context,
+ '-');
+ }
- /* Check protocols recursively. */
- if (PROTOCOL_LIST (p))
+ if (!f1 || !f2)
+ warning ("%s `%s' does not fully implement the `%s' protocol",
+ type, name, IDENTIFIER_POINTER (PROTOCOL_NAME (p)));
+ }
+
+ /* Check protocols recursively. */
+ if (PROTOCOL_LIST (p))
+ {
+ tree subs = PROTOCOL_LIST (p);
+ tree super_class =
+ lookup_interface (CLASS_SUPER_NAME (implementation_template));
+ while (subs)
{
- tree super_class
- = lookup_interface (CLASS_SUPER_NAME (implementation_template));
- if (! conforms_to_protocol (super_class, PROTOCOL_LIST (p)))
- check_protocols (PROTOCOL_LIST (p), type, name);
+ tree sub = TREE_VALUE (subs);
+
+ /* If the superclass does not conform to the protocols
+ inherited by P, then we must! */
+ if (!super_class || !conforms_to_protocol (super_class, sub))
+ check_protocol (sub, type, name);
+ subs = TREE_CHAIN (subs);
}
}
}
+
+/* Check whether the current interface (accessible via
+ 'implementation_context') actually implements the protocols listed
+ in PROTO_LIST. */
+
+static void
+check_protocols (proto_list, type, name)
+ tree proto_list;
+ const char *type;
+ const char *name;
+{
+ for ( ; proto_list; proto_list = TREE_CHAIN (proto_list))
+ {
+ tree p = TREE_VALUE (proto_list);
+
+ check_protocol (p, type, name);
+ }
+}
/* Make sure that the class CLASS_NAME is defined
CODE says which kind of thing CLASS_NAME ought to be.
@@ -6430,6 +6498,33 @@ lookup_protocol (ident)
return NULL_TREE;
}
+/* This function forward declares the protocols named by NAMES. If
+ they are already declared or defined, the function has no effect. */
+
+void
+objc_declare_protocols (names)
+ tree names;
+{
+ tree list;
+
+ for (list = names; list; list = TREE_CHAIN (list))
+ {
+ tree name = TREE_VALUE (list);
+
+ if (lookup_protocol (name) == NULL_TREE)
+ {
+ tree protocol = make_node (PROTOCOL_INTERFACE_TYPE);
+
+ TYPE_BINFO (protocol) = make_tree_vec (2);
+ PROTOCOL_NAME (protocol) = name;
+ PROTOCOL_LIST (protocol) = NULL_TREE;
+ add_protocol (protocol);
+ PROTOCOL_DEFINED (protocol) = 0;
+ PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
+ }
+ }
+}
+
tree
start_protocol (code, name, list)
enum tree_code code;
@@ -6438,26 +6533,38 @@ start_protocol (code, name, list)
{
tree protocol;
- /* This is as good a place as any. Need to invoke push_tag_toplevel. */
+ /* This is as good a place as any. Need to invoke
+ push_tag_toplevel. */
if (!objc_protocol_template)
objc_protocol_template = build_protocol_template ();
- protocol = make_node (code);
- TYPE_BINFO (protocol) = make_tree_vec (2);
+ protocol = lookup_protocol (name);
- PROTOCOL_NAME (protocol) = name;
- PROTOCOL_LIST (protocol) = list;
+ if (!protocol)
+ {
+ protocol = make_node (code);
+ TYPE_BINFO (protocol) = make_tree_vec (2);
- lookup_and_install_protocols (list);
+ PROTOCOL_NAME (protocol) = name;
+ PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
+ add_protocol (protocol);
+ PROTOCOL_DEFINED (protocol) = 1;
+ PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
- if (lookup_protocol (name))
- warning ("duplicate declaration for protocol `%s'",
- IDENTIFIER_POINTER (name));
- else
- add_protocol (protocol);
-
- PROTOCOL_FORWARD_DECL (protocol) = NULL_TREE;
+ check_protocol_recursively (protocol, list);
+ }
+ else if (! PROTOCOL_DEFINED (protocol))
+ {
+ PROTOCOL_DEFINED (protocol) = 1;
+ PROTOCOL_LIST (protocol) = lookup_and_install_protocols (list);
+ check_protocol_recursively (protocol, list);
+ }
+ else
+ {
+ warning ("duplicate declaration for protocol `%s'",
+ IDENTIFIER_POINTER (name));
+ }
return protocol;
}
@@ -6595,6 +6702,11 @@ encode_aggregate_within (type, curtype, format, left, right)
int left;
int right;
{
+ /* The RECORD_TYPE may in fact be a typedef! For purposes
+ of encoding, we need the real underlying enchilada. */
+ if (TYPE_MAIN_VARIANT (type))
+ type = TYPE_MAIN_VARIANT (type);
+
if (obstack_object_size (&util_obstack) > 0
&& *(obstack_next_free (&util_obstack) - 1) == '^')
{
diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h
index f13acc8f192..e659f916525 100644
--- a/gcc/objc/objc-act.h
+++ b/gcc/objc/objc-act.h
@@ -1,5 +1,5 @@
/* Declarations for objc-act.c.
- Copyright (C) 1990, 2000 Free Software Foundation, Inc.
+ Copyright (C) 1990, 2000, 2001 Free Software Foundation, Inc.
This file is part of GNU CC.
@@ -59,6 +59,7 @@ extern tree objc_ellipsis_node;
void objc_declare_alias PARAMS ((tree, tree));
void objc_declare_class PARAMS ((tree));
+void objc_declare_protocols PARAMS ((tree));
extern int objc_receiver_context;
@@ -101,6 +102,7 @@ tree build_encode_expr PARAMS ((tree));
#define PROTOCOL_NST_METHODS(CLASS) ((CLASS)->type.minval)
#define PROTOCOL_CLS_METHODS(CLASS) ((CLASS)->type.maxval)
#define PROTOCOL_FORWARD_DECL(CLASS) TREE_VEC_ELT (TYPE_BINFO (CLASS), 1)
+#define PROTOCOL_DEFINED(CLASS) TREE_USED (CLASS)
#define TYPE_PROTOCOL_LIST(TYPE) ((TYPE)->type.context)
/* Define the Objective-C or Objective-C++ language-specific tree codes. */