diff options
author | shebs <shebs@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-08-01 08:10:00 +0000 |
---|---|---|
committer | shebs <shebs@138bc75d-0d04-0410-961f-82ee72b054a4> | 2001-08-01 08:10:00 +0000 |
commit | b11c01151739961c0ed6cc811ae3af14fa83821a (patch) | |
tree | 648dd272baeb69450a07f51b1c4e7565b12eafb1 | |
parent | 50cf64b79d5e01b075aaa2baf4c731b02aea0249 (diff) | |
download | gcc-b11c01151739961c0ed6cc811ae3af14fa83821a.tar.gz |
2001-08-01 Ziemowit Laski <zlaski@apple.com>
* c-parse.in (OBJC_NEED_RAW_IDENTIFIER): Define macro and flag for
contextualizing Objective-C class name lookup by the lexer.
(typespec_reserved_nonattr): Disable ObjC class name lookup after
seeing a TYPESPEC.
(protocoldef): Add support for forward @protocol declarations.
(yylexname): Suppress ObjC class name lookup in certain contexts;
re-enable after lookup is complete.
(_yylex): Re-enable ObjC class name lookup when certain
punctuation marks are seen.
* objc/objc-act.c (check_protocol_recursively): New function used
for finding circular dependencies in protocols.
(objc_declare_protocols): New function for handling forward
@protocol declarations.
(receiver_is_class_object): Detect the case when 'self' is used
inside of a class method.
(build_message_expr): Issue a warning if class method is desired
but instance method is found instead.
(conforms_to_protocol): Streamline.
(objc_comptypes): Detect the fact that 'Bar<Foo> foo' conforms to
protocol Foo, even if 'Bar foo' does not.
(check_protocols): Streamline.
(start_protocol): Add checks for circular and duplicate protocol
definitions.
(encode_aggregate_within): For typedefs of structs, encode the
underlying struct.
* objc/objc-act.h (PROTOCOL_DEFINED): New tree accessor.
(objc_declare_protocols): New prototype.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@44536 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 31 | ||||
-rw-r--r-- | gcc/c-parse.in | 70 | ||||
-rw-r--r-- | gcc/objc/objc-act.c | 234 | ||||
-rw-r--r-- | gcc/objc/objc-act.h | 4 |
4 files changed, 263 insertions, 76 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 857a75db7d5..01ef78a5bef 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,34 @@ +2001-08-01 Ziemowit Laski <zlaski@apple.com> + + * c-parse.in (OBJC_NEED_RAW_IDENTIFIER): Define macro and flag for + contextualizing Objective-C class name lookup by the lexer. + (typespec_reserved_nonattr): Disable ObjC class name lookup after + seeing a TYPESPEC. + (protocoldef): Add support for forward @protocol declarations. + (yylexname): Suppress ObjC class name lookup in certain contexts; + re-enable after lookup is complete. + (_yylex): Re-enable ObjC class name lookup when certain + punctuation marks are seen. + + * objc/objc-act.c (check_protocol_recursively): New function used + for finding circular dependencies in protocols. + (objc_declare_protocols): New function for handling forward + @protocol declarations. + (receiver_is_class_object): Detect the case when 'self' is used + inside of a class method. + (build_message_expr): Issue a warning if class method is desired + but instance method is found instead. + (conforms_to_protocol): Streamline. + (objc_comptypes): Detect the fact that 'Bar<Foo> foo' conforms to + protocol Foo, even if 'Bar foo' does not. + (check_protocols): Streamline. + (start_protocol): Add checks for circular and duplicate protocol + definitions. + (encode_aggregate_within): For typedefs of structs, encode the + underlying struct. + * objc/objc-act.h (PROTOCOL_DEFINED): New tree accessor. + (objc_declare_protocols): New prototype. + 2001-08-01 Neil Booth <neil@cat.daikokuya.demon.co.uk> * cpphash.h (struct cpp_reader): New members line, pseudo_newlines. diff --git a/gcc/c-parse.in b/gcc/c-parse.in index 7d87e2004fd..d1320565bfc 100644 --- a/gcc/c-parse.in +++ b/gcc/c-parse.in @@ -29,10 +29,10 @@ Boston, MA 02111-1307, USA. */ written by AT&T, but I have never seen it. */ ifobjc -%expect 31 +%expect 31 /* shift/reduce conflicts, and 1 reduce/reduce conflict. */ end ifobjc ifc -%expect 10 +%expect 10 /* shift/reduce conflicts, and no reduce/reduce conflicts. */ end ifc %{ @@ -295,8 +295,18 @@ int objc_receiver_context; int objc_public_flag; int objc_pq_context; +/* The following flag is needed to contextualize ObjC lexical analysis. + In some cases (e.g., 'int NSObject;'), it is undesirable to bind + an identifier to an ObjC class, even if a class with that name + exists. */ +int objc_need_raw_identifier; +#define OBJC_NEED_RAW_IDENTIFIER(VAL) objc_need_raw_identifier = VAL end ifobjc +ifc +#define OBJC_NEED_RAW_IDENTIFIER(VAL) /* nothing */ +end ifc + /* Tell yyparse how to print a token's value, if yydebug is set. */ #define YYPRINT(FILE,YYCHAR,YYLVAL) yyprint(FILE,YYCHAR,YYLVAL) @@ -444,7 +454,7 @@ identifier: | TYPENAME ifobjc | OBJECTNAME - | CLASSNAME + | CLASSNAME end ifobjc ; @@ -1384,6 +1394,7 @@ typespec_attr: typespec_reserved_nonattr: TYPESPEC + { OBJC_NEED_RAW_IDENTIFIER (1); } | structsp_nonattr ; @@ -1694,6 +1705,9 @@ parm_declarator_starttypename: | parm_declarator_starttypename array_declarator %prec '.' { $$ = set_array_declarator_type ($2, $1, 0); } | TYPENAME +ifobjc + | OBJECTNAME +end ifobjc ; parm_declarator_nostarttypename: @@ -2836,6 +2850,13 @@ protocoldef: finish_protocol(objc_interface_context); objc_interface_context = NULL_TREE; } + /* The @protocol forward-declaration production introduces a + reduce/reduce conflict on ';', which should be resolved in + favor of the production 'identifier_list -> identifier'. */ + | PROTOCOL identifier_list ';' + { + objc_declare_protocols ($2); + } ; protocolrefs: @@ -3119,8 +3140,9 @@ keywordselector: selector: IDENTIFIER - | TYPENAME - | OBJECTNAME + | TYPENAME + | CLASSNAME + | OBJECTNAME | reservedwords ; @@ -3615,12 +3637,26 @@ static int yylexname () { tree decl; - + +ifobjc + int objc_force_identifier = objc_need_raw_identifier; + OBJC_NEED_RAW_IDENTIFIER (0); +end ifobjc + if (C_IS_RESERVED_WORD (yylval.ttype)) { enum rid rid_code = C_RID_CODE (yylval.ttype); ifobjc + /* Turn non-typedefed refs to "id" into plain identifiers; this + allows constructs like "void foo(id id);" to work. */ + if (rid_code == RID_ID) + { + decl = lookup_name (yylval.ttype); + if (decl == NULL_TREE || TREE_CODE (decl) != TYPE_DECL) + return IDENTIFIER; + } + if (!OBJC_IS_AT_KEYWORD (rid_code) && (!OBJC_IS_PQ_KEYWORD (rid_code) || objc_pq_context)) end ifobjc @@ -3653,8 +3689,11 @@ ifobjc else { tree objc_interface_decl = is_class_name (yylval.ttype); - - if (objc_interface_decl) + /* ObjC class names are in the same namespace as variables and + typedefs, and hence are shadowed by local declarations. */ + if (objc_interface_decl + && (global_bindings_p () + || (!objc_force_identifier && !decl))) { yylval.ttype = objc_interface_decl; return CLASSNAME; @@ -3692,10 +3731,7 @@ _yylex () case CPP_AND_AND: return ANDAND; case CPP_OR_OR: return OROR; case CPP_QUERY: return '?'; - case CPP_COLON: return ':'; - case CPP_COMMA: return ','; case CPP_OPEN_PAREN: return '('; - case CPP_CLOSE_PAREN: return ')'; case CPP_EQ_EQ: yylval.code = EQ_EXPR; return EQCOMPARE; case CPP_NOT_EQ: yylval.code = NE_EXPR; return EQCOMPARE; case CPP_GREATER_EQ:yylval.code = GE_EXPR; return ARITHCOMPARE; @@ -3716,7 +3752,6 @@ _yylex () case CPP_CLOSE_SQUARE: return ']'; case CPP_OPEN_BRACE: return '{'; case CPP_CLOSE_BRACE: return '}'; - case CPP_SEMICOLON: return ';'; case CPP_ELLIPSIS: return ELLIPSIS; case CPP_PLUS_PLUS: return PLUSPLUS; @@ -3724,6 +3759,13 @@ _yylex () case CPP_DEREF: return POINTSAT; case CPP_DOT: return '.'; + /* The following tokens may affect the interpretation of any + identifiers following, if doing Objective-C. */ + case CPP_COLON: OBJC_NEED_RAW_IDENTIFIER (0); return ':'; + case CPP_COMMA: OBJC_NEED_RAW_IDENTIFIER (0); return ','; + case CPP_CLOSE_PAREN: OBJC_NEED_RAW_IDENTIFIER (0); return ')'; + case CPP_SEMICOLON: OBJC_NEED_RAW_IDENTIFIER (0); return ';'; + case CPP_EOF: if (cpp_pop_buffer (parse_in) == 0) return 0; @@ -3741,8 +3783,8 @@ _yylex () case CPP_WSTRING: return STRING; - /* This token is Objective-C specific. It gives the next - token special significance. */ + /* This token is Objective-C specific. It gives the next token + special significance. */ case CPP_ATSIGN: ifobjc { 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. */ |