mirror of git://gcc.gnu.org/git/gcc.git
In gcc/: 2010-12-10 Nicola Pero <nicola.pero@meta-innovation.com>
In gcc/: 2010-12-10 Nicola Pero <nicola.pero@meta-innovation.com> * c-parser.c (c_parser_objc_class_definition): Recognize Objective-C 2.0 class extensions. In gcc/cp/: 2010-12-10 Nicola Pero <nicola.pero@meta-innovation.com> * parser.c (cp_parser_objc_superclass_or_category): Recognize Objective-C 2.0 class extensions. Added iface_p and is_class_extension arguments. (cp_parser_objc_class_interface): Updated call to cp_parser_objc_superclass_or_category. (cp_parser_objc_class_implementation): Same change. In gcc/objc/: 2010-12-10 Nicola Pero <nicola.pero@meta-innovation.com> * objc-act.c (objc_in_class_extension): New. (objc_start_category_interface): If -fobjc-std=objc1 was specified, produce an error if a class extension is used. (objc_finish_interface): Reset objc_in_class_extension to false. (objc_add_property_declaration): Allow a class extension to extend readonly properties in the main @interface to be readwrite. (start_class): Added code to deal with class extensions. In that case, return the existing interface after adding any additional protocols to it and setting objc_in_class_extension to true. (continue_class): If in a class extension, do not generate the instance variable template. In gcc/testsuite/: 2010-12-10 Nicola Pero <nicola.pero@meta-innovation.com> * objc.dg/class-extension-1.m: New. * objc.dg/class-extension-2.m: New. * objc.dg/class-extension-3.m: New. * objc.dg/property/at-property-26.m: New. * objc.dg/property/at-property-27.m: New. * objc.dg/property/at-property-28.m: New. * obj-c++.dg/class-extension-1.mm: New. * obj-c++.dg/class-extension-2.mm: New. * obj-c++.dg/class-extension-3.mm: New. * obj-c++.dg/property/at-property-26.mm: New. * obj-c++.dg/property/at-property-27.mm: New. * obj-c++.dg/property/at-property-28.mm: New. From-SVN: r167680
This commit is contained in:
parent
aff7f4c416
commit
ec3e9f8267
|
@ -1,3 +1,8 @@
|
||||||
|
2010-12-10 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||||
|
|
||||||
|
* c-parser.c (c_parser_objc_class_definition): Recognize
|
||||||
|
Objective-C 2.0 class extensions.
|
||||||
|
|
||||||
2010-12-10 Iain Sandoe <iains@gcc.gnu.org>
|
2010-12-10 Iain Sandoe <iains@gcc.gnu.org>
|
||||||
|
|
||||||
* config/darwin.c: Remove c-tree.h and c-lang.h
|
* config/darwin.c: Remove c-tree.h and c-lang.h
|
||||||
|
|
|
@ -6743,6 +6743,8 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
|
||||||
objc-class-instance-variables[opt]
|
objc-class-instance-variables[opt]
|
||||||
@interface identifier ( identifier ) objc-protocol-refs[opt]
|
@interface identifier ( identifier ) objc-protocol-refs[opt]
|
||||||
objc-methodprotolist @end
|
objc-methodprotolist @end
|
||||||
|
@interface identifier ( ) objc-protocol-refs[opt]
|
||||||
|
objc-methodprotolist @end
|
||||||
@implementation identifier ( identifier )
|
@implementation identifier ( identifier )
|
||||||
|
|
||||||
objc-superclass:
|
objc-superclass:
|
||||||
|
@ -6777,17 +6779,29 @@ c_parser_objc_class_definition (c_parser *parser, tree attributes)
|
||||||
c_parser_consume_token (parser);
|
c_parser_consume_token (parser);
|
||||||
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
|
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
|
||||||
{
|
{
|
||||||
|
/* We have a category or class extension. */
|
||||||
tree id2;
|
tree id2;
|
||||||
tree proto = NULL_TREE;
|
tree proto = NULL_TREE;
|
||||||
c_parser_consume_token (parser);
|
c_parser_consume_token (parser);
|
||||||
if (c_parser_next_token_is_not (parser, CPP_NAME))
|
if (c_parser_next_token_is_not (parser, CPP_NAME))
|
||||||
{
|
{
|
||||||
c_parser_error (parser, "expected identifier");
|
if (iface_p && c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
|
||||||
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
|
{
|
||||||
return;
|
/* We have a class extension. */
|
||||||
|
id2 = NULL_TREE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
c_parser_error (parser, "expected identifier or %<)%>");
|
||||||
|
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
id2 = c_parser_peek_token (parser)->value;
|
||||||
|
c_parser_consume_token (parser);
|
||||||
}
|
}
|
||||||
id2 = c_parser_peek_token (parser)->value;
|
|
||||||
c_parser_consume_token (parser);
|
|
||||||
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
|
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
|
||||||
if (!iface_p)
|
if (!iface_p)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,3 +1,12 @@
|
||||||
|
2010-12-10 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||||
|
|
||||||
|
* parser.c (cp_parser_objc_superclass_or_category): Recognize
|
||||||
|
Objective-C 2.0 class extensions. Added iface_p and
|
||||||
|
is_class_extension arguments.
|
||||||
|
(cp_parser_objc_class_interface): Updated call to
|
||||||
|
cp_parser_objc_superclass_or_category.
|
||||||
|
(cp_parser_objc_class_implementation): Same change.
|
||||||
|
|
||||||
2010-12-09 Nathan Froyd <froydnj@codesourcery.com>
|
2010-12-09 Nathan Froyd <froydnj@codesourcery.com>
|
||||||
|
|
||||||
* call.c (print_conversion_rejection): Indent messages two spaces.
|
* call.c (print_conversion_rejection): Indent messages two spaces.
|
||||||
|
|
|
@ -22435,12 +22435,15 @@ cp_parser_objc_protocol_declaration (cp_parser* parser, tree attributes)
|
||||||
/* Parse an Objective-C superclass or category. */
|
/* Parse an Objective-C superclass or category. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
cp_parser_objc_superclass_or_category (cp_parser *parser, tree *super,
|
cp_parser_objc_superclass_or_category (cp_parser *parser,
|
||||||
tree *categ)
|
bool iface_p,
|
||||||
|
tree *super,
|
||||||
|
tree *categ, bool *is_class_extension)
|
||||||
{
|
{
|
||||||
cp_token *next = cp_lexer_peek_token (parser->lexer);
|
cp_token *next = cp_lexer_peek_token (parser->lexer);
|
||||||
|
|
||||||
*super = *categ = NULL_TREE;
|
*super = *categ = NULL_TREE;
|
||||||
|
*is_class_extension = false;
|
||||||
if (next->type == CPP_COLON)
|
if (next->type == CPP_COLON)
|
||||||
{
|
{
|
||||||
cp_lexer_consume_token (parser->lexer); /* Eat ':'. */
|
cp_lexer_consume_token (parser->lexer); /* Eat ':'. */
|
||||||
|
@ -22449,7 +22452,17 @@ cp_parser_objc_superclass_or_category (cp_parser *parser, tree *super,
|
||||||
else if (next->type == CPP_OPEN_PAREN)
|
else if (next->type == CPP_OPEN_PAREN)
|
||||||
{
|
{
|
||||||
cp_lexer_consume_token (parser->lexer); /* Eat '('. */
|
cp_lexer_consume_token (parser->lexer); /* Eat '('. */
|
||||||
*categ = cp_parser_identifier (parser);
|
|
||||||
|
/* If there is no category name, and this is an @interface, we
|
||||||
|
have a class extension. */
|
||||||
|
if (iface_p && cp_lexer_next_token_is (parser->lexer, CPP_CLOSE_PAREN))
|
||||||
|
{
|
||||||
|
*categ = NULL_TREE;
|
||||||
|
*is_class_extension = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*categ = cp_parser_identifier (parser);
|
||||||
|
|
||||||
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
|
cp_parser_require (parser, CPP_CLOSE_PAREN, RT_CLOSE_PAREN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22460,6 +22473,7 @@ static void
|
||||||
cp_parser_objc_class_interface (cp_parser* parser, tree attributes)
|
cp_parser_objc_class_interface (cp_parser* parser, tree attributes)
|
||||||
{
|
{
|
||||||
tree name, super, categ, protos;
|
tree name, super, categ, protos;
|
||||||
|
bool is_class_extension;
|
||||||
|
|
||||||
cp_lexer_consume_token (parser->lexer); /* Eat '@interface'. */
|
cp_lexer_consume_token (parser->lexer); /* Eat '@interface'. */
|
||||||
name = cp_parser_identifier (parser);
|
name = cp_parser_identifier (parser);
|
||||||
|
@ -22472,11 +22486,12 @@ cp_parser_objc_class_interface (cp_parser* parser, tree attributes)
|
||||||
*/
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cp_parser_objc_superclass_or_category (parser, &super, &categ);
|
cp_parser_objc_superclass_or_category (parser, true, &super, &categ,
|
||||||
|
&is_class_extension);
|
||||||
protos = cp_parser_objc_protocol_refs_opt (parser);
|
protos = cp_parser_objc_protocol_refs_opt (parser);
|
||||||
|
|
||||||
/* We have either a class or a category on our hands. */
|
/* We have either a class or a category on our hands. */
|
||||||
if (categ)
|
if (categ || is_class_extension)
|
||||||
objc_start_category_interface (name, categ, protos, attributes);
|
objc_start_category_interface (name, categ, protos, attributes);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -22495,6 +22510,7 @@ static void
|
||||||
cp_parser_objc_class_implementation (cp_parser* parser)
|
cp_parser_objc_class_implementation (cp_parser* parser)
|
||||||
{
|
{
|
||||||
tree name, super, categ;
|
tree name, super, categ;
|
||||||
|
bool is_class_extension;
|
||||||
|
|
||||||
cp_lexer_consume_token (parser->lexer); /* Eat '@implementation'. */
|
cp_lexer_consume_token (parser->lexer); /* Eat '@implementation'. */
|
||||||
name = cp_parser_identifier (parser);
|
name = cp_parser_identifier (parser);
|
||||||
|
@ -22508,7 +22524,8 @@ cp_parser_objc_class_implementation (cp_parser* parser)
|
||||||
*/
|
*/
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
cp_parser_objc_superclass_or_category (parser, &super, &categ);
|
cp_parser_objc_superclass_or_category (parser, false, &super, &categ,
|
||||||
|
&is_class_extension);
|
||||||
|
|
||||||
/* We have either a class or a category on our hands. */
|
/* We have either a class or a category on our hands. */
|
||||||
if (categ)
|
if (categ)
|
||||||
|
|
|
@ -1,3 +1,17 @@
|
||||||
|
2010-12-10 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||||
|
|
||||||
|
* objc-act.c (objc_in_class_extension): New.
|
||||||
|
(objc_start_category_interface): If -fobjc-std=objc1
|
||||||
|
was specified, produce an error if a class extension is used.
|
||||||
|
(objc_finish_interface): Reset objc_in_class_extension to false.
|
||||||
|
(objc_add_property_declaration): Allow a class extension to extend
|
||||||
|
readonly properties in the main @interface to be readwrite.
|
||||||
|
(start_class): Added code to deal with class extensions. In that
|
||||||
|
case, return the existing interface after adding any additional
|
||||||
|
protocols to it and setting objc_in_class_extension to true.
|
||||||
|
(continue_class): If in a class extension, do not generate the
|
||||||
|
instance variable template.
|
||||||
|
|
||||||
2010-12-08 Nicola Pero <nicola.pero@meta-innovation.com>
|
2010-12-08 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||||
|
|
||||||
* objc-act.c (objc_build_throw_stmt): Check that the argument of
|
* objc-act.c (objc_build_throw_stmt): Check that the argument of
|
||||||
|
|
|
@ -402,6 +402,12 @@ static bool objc_method_optional_flag = false;
|
||||||
|
|
||||||
static int objc_collecting_ivars = 0;
|
static int objc_collecting_ivars = 0;
|
||||||
|
|
||||||
|
/* Flag that is set to 'true' while we are processing a class
|
||||||
|
extension. Since a class extension just "reopens" the main
|
||||||
|
@interface, this can be used to determine if we are in the main
|
||||||
|
@interface, or in a class extension. */
|
||||||
|
static bool objc_in_class_extension = false;
|
||||||
|
|
||||||
#define BUFSIZE 1024
|
#define BUFSIZE 1024
|
||||||
|
|
||||||
static char *errbuf; /* Buffer for error diagnostics */
|
static char *errbuf; /* Buffer for error diagnostics */
|
||||||
|
@ -748,6 +754,11 @@ objc_start_category_interface (tree klass, tree categ,
|
||||||
"category attributes are not available in this version"
|
"category attributes are not available in this version"
|
||||||
" of the compiler, (ignored)");
|
" of the compiler, (ignored)");
|
||||||
}
|
}
|
||||||
|
if (categ == NULL_TREE)
|
||||||
|
{
|
||||||
|
if (flag_objc1_only)
|
||||||
|
error_at (input_location, "class extensions are not available in Objective-C 1.0");
|
||||||
|
}
|
||||||
objc_interface_context
|
objc_interface_context
|
||||||
= start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos, NULL_TREE);
|
= start_class (CATEGORY_INTERFACE_TYPE, klass, categ, protos, NULL_TREE);
|
||||||
objc_ivar_chain
|
objc_ivar_chain
|
||||||
|
@ -778,6 +789,7 @@ objc_finish_interface (void)
|
||||||
finish_class (objc_interface_context);
|
finish_class (objc_interface_context);
|
||||||
objc_interface_context = NULL_TREE;
|
objc_interface_context = NULL_TREE;
|
||||||
objc_method_optional_flag = false;
|
objc_method_optional_flag = false;
|
||||||
|
objc_in_class_extension = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -952,6 +964,7 @@ objc_add_property_declaration (location_t location, tree decl,
|
||||||
is readwrite). */
|
is readwrite). */
|
||||||
bool property_readonly = false;
|
bool property_readonly = false;
|
||||||
objc_property_assign_semantics property_assign_semantics = OBJC_PROPERTY_ASSIGN;
|
objc_property_assign_semantics property_assign_semantics = OBJC_PROPERTY_ASSIGN;
|
||||||
|
bool property_extension_in_class_extension = false;
|
||||||
|
|
||||||
if (flag_objc1_only)
|
if (flag_objc1_only)
|
||||||
error_at (input_location, "%<@property%> is not available in Objective-C 1.0");
|
error_at (input_location, "%<@property%> is not available in Objective-C 1.0");
|
||||||
|
@ -1125,60 +1138,80 @@ objc_add_property_declaration (location_t location, tree decl,
|
||||||
|
|
||||||
/* Check for duplicate property declarations. We first check the
|
/* Check for duplicate property declarations. We first check the
|
||||||
immediate context for a property with the same name. Any such
|
immediate context for a property with the same name. Any such
|
||||||
declarations are an error. */
|
declarations are an error, unless this is a class extension and
|
||||||
|
we are extending a property from readonly to readwrite. */
|
||||||
for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x))
|
for (x = CLASS_PROPERTY_DECL (objc_interface_context); x; x = TREE_CHAIN (x))
|
||||||
{
|
{
|
||||||
if (PROPERTY_NAME (x) == DECL_NAME (decl))
|
if (PROPERTY_NAME (x) == DECL_NAME (decl))
|
||||||
{
|
{
|
||||||
location_t original_location = DECL_SOURCE_LOCATION (x);
|
if (objc_in_class_extension
|
||||||
|
&& property_readonly == 0
|
||||||
error_at (location, "redeclaration of property %qD", decl);
|
&& PROPERTY_READONLY (x) == 1)
|
||||||
|
{
|
||||||
if (original_location != UNKNOWN_LOCATION)
|
/* This is a class extension, and we are extending an
|
||||||
inform (original_location, "originally specified here");
|
existing readonly property to a readwrite one.
|
||||||
return;
|
That's fine. :-) */
|
||||||
}
|
property_extension_in_class_extension = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
location_t original_location = DECL_SOURCE_LOCATION (x);
|
||||||
|
|
||||||
|
error_at (location, "redeclaration of property %qD", decl);
|
||||||
|
|
||||||
|
if (original_location != UNKNOWN_LOCATION)
|
||||||
|
inform (original_location, "originally specified here");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We now need to check for existing property declarations (in the
|
/* If x is not NULL_TREE, we must be in a class extension and we're
|
||||||
superclass, other categories or protocols) and check that the new
|
extending a readonly property. In that case, no point in
|
||||||
declaration is not in conflict with existing ones. */
|
searching for another declaration. */
|
||||||
|
if (x == NULL_TREE)
|
||||||
/* Search for a previous, existing declaration of a property with
|
|
||||||
the same name in superclasses, protocols etc. If one is found,
|
|
||||||
it will be in the 'x' variable. */
|
|
||||||
x = NULL_TREE;
|
|
||||||
|
|
||||||
/* Note that, for simplicity, the following may search again the
|
|
||||||
local context. That's Ok as nothing will be found (else we'd
|
|
||||||
have thrown an error above); it's only a little inefficient, but
|
|
||||||
the code is simpler. */
|
|
||||||
switch (TREE_CODE (objc_interface_context))
|
|
||||||
{
|
{
|
||||||
case CLASS_INTERFACE_TYPE:
|
/* We now need to check for existing property declarations (in
|
||||||
/* Look up the property in the current @interface (which will
|
the superclass, other categories or protocols) and check that
|
||||||
find nothing), then its protocols and categories and
|
the new declaration is not in conflict with existing
|
||||||
superclasses. */
|
ones. */
|
||||||
x = lookup_property (objc_interface_context, DECL_NAME (decl));
|
|
||||||
break;
|
/* Search for a previous, existing declaration of a property
|
||||||
case CATEGORY_INTERFACE_TYPE:
|
with the same name in superclasses, protocols etc. If one is
|
||||||
/* Look up the property in the main @interface, then protocols
|
found, it will be in the 'x' variable. */
|
||||||
and categories (one of them is ours, and will find nothing)
|
|
||||||
and superclasses. */
|
/* Note that, for simplicity, the following may search again the
|
||||||
x = lookup_property (lookup_interface (CLASS_NAME (objc_interface_context)),
|
local context. That's Ok as nothing will be found (else we'd
|
||||||
DECL_NAME (decl));
|
have thrown an error above); it's only a little inefficient,
|
||||||
break;
|
but the code is simpler. */
|
||||||
case PROTOCOL_INTERFACE_TYPE:
|
switch (TREE_CODE (objc_interface_context))
|
||||||
/* Looks up the property in any protocols attached to the
|
|
||||||
current protocol. */
|
|
||||||
if (PROTOCOL_LIST (objc_interface_context))
|
|
||||||
{
|
{
|
||||||
x = lookup_property_in_protocol_list (PROTOCOL_LIST (objc_interface_context),
|
case CLASS_INTERFACE_TYPE:
|
||||||
DECL_NAME (decl));
|
/* Look up the property in the current @interface (which
|
||||||
|
will find nothing), then its protocols and categories and
|
||||||
|
superclasses. */
|
||||||
|
x = lookup_property (objc_interface_context, DECL_NAME (decl));
|
||||||
|
break;
|
||||||
|
case CATEGORY_INTERFACE_TYPE:
|
||||||
|
/* Look up the property in the main @interface, then
|
||||||
|
protocols and categories (one of them is ours, and will
|
||||||
|
find nothing) and superclasses. */
|
||||||
|
x = lookup_property (lookup_interface (CLASS_NAME (objc_interface_context)),
|
||||||
|
DECL_NAME (decl));
|
||||||
|
break;
|
||||||
|
case PROTOCOL_INTERFACE_TYPE:
|
||||||
|
/* Looks up the property in any protocols attached to the
|
||||||
|
current protocol. */
|
||||||
|
if (PROTOCOL_LIST (objc_interface_context))
|
||||||
|
{
|
||||||
|
x = lookup_property_in_protocol_list (PROTOCOL_LIST (objc_interface_context),
|
||||||
|
DECL_NAME (decl));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
gcc_unreachable ();
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
default:
|
|
||||||
gcc_unreachable ();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (x != NULL_TREE)
|
if (x != NULL_TREE)
|
||||||
|
@ -1278,6 +1311,17 @@ objc_add_property_declaration (location_t location, tree decl,
|
||||||
inform (original_location, "originally specified here");
|
inform (original_location, "originally specified here");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we are in a class extension and we're extending a readonly
|
||||||
|
property in the main @interface, we'll just update the
|
||||||
|
existing property with the readwrite flag and potentially the
|
||||||
|
new setter name. */
|
||||||
|
if (property_extension_in_class_extension)
|
||||||
|
{
|
||||||
|
PROPERTY_READONLY (x) = 0;
|
||||||
|
PROPERTY_SETTER_NAME (x) = parsed_property_setter_ident;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a PROPERTY_DECL node. */
|
/* Create a PROPERTY_DECL node. */
|
||||||
|
@ -9417,21 +9461,24 @@ check_protocols (tree proto_list, const char *type, tree name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure that the class CLASS_NAME is defined
|
/* Make sure that the class CLASS_NAME is defined CODE says which kind
|
||||||
CODE says which kind of thing CLASS_NAME ought to be.
|
of thing CLASS_NAME ought to be. It can be CLASS_INTERFACE_TYPE,
|
||||||
It can be CLASS_INTERFACE_TYPE, CLASS_IMPLEMENTATION_TYPE,
|
CLASS_IMPLEMENTATION_TYPE, CATEGORY_INTERFACE_TYPE, or
|
||||||
CATEGORY_INTERFACE_TYPE, or CATEGORY_IMPLEMENTATION_TYPE. */
|
CATEGORY_IMPLEMENTATION_TYPE. For a CATEGORY_INTERFACE_TYPE,
|
||||||
|
SUPER_NAME is the name of the category. For a class extension,
|
||||||
|
CODE is CATEGORY_INTERFACE_TYPE and SUPER_NAME is NULL_TREE. */
|
||||||
static tree
|
static tree
|
||||||
start_class (enum tree_code code, tree class_name, tree super_name,
|
start_class (enum tree_code code, tree class_name, tree super_name,
|
||||||
tree protocol_list, tree attributes)
|
tree protocol_list, tree attributes)
|
||||||
{
|
{
|
||||||
tree klass, decl;
|
tree klass = NULL_TREE;
|
||||||
|
tree decl;
|
||||||
|
|
||||||
#ifdef OBJCPLUS
|
#ifdef OBJCPLUS
|
||||||
if (current_namespace != global_namespace) {
|
if (current_namespace != global_namespace)
|
||||||
error ("Objective-C declarations may only appear in global scope");
|
{
|
||||||
}
|
error ("Objective-C declarations may only appear in global scope");
|
||||||
|
}
|
||||||
#endif /* OBJCPLUS */
|
#endif /* OBJCPLUS */
|
||||||
|
|
||||||
if (objc_implementation_context)
|
if (objc_implementation_context)
|
||||||
|
@ -9442,8 +9489,14 @@ start_class (enum tree_code code, tree class_name, tree super_name,
|
||||||
objc_implementation_context = NULL_TREE;
|
objc_implementation_context = NULL_TREE;
|
||||||
}
|
}
|
||||||
|
|
||||||
klass = make_node (code);
|
/* If this is a class extension, we'll be "reopening" the existing
|
||||||
TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
|
CLASS_INTERFACE_TYPE, so in that case there is no need to create
|
||||||
|
a new node. */
|
||||||
|
if (code != CATEGORY_INTERFACE_TYPE || super_name != NULL_TREE)
|
||||||
|
{
|
||||||
|
klass = make_node (code);
|
||||||
|
TYPE_LANG_SLOT_1 (klass) = make_tree_vec (CLASS_LANG_SLOT_ELTS);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check for existence of the super class, if one was specified. Note
|
/* Check for existence of the super class, if one was specified. Note
|
||||||
that we must have seen an @interface, not just a @class. If we
|
that we must have seen an @interface, not just a @class. If we
|
||||||
|
@ -9473,9 +9526,12 @@ start_class (enum tree_code code, tree class_name, tree super_name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CLASS_NAME (klass) = class_name;
|
if (code != CATEGORY_INTERFACE_TYPE || super_name != NULL_TREE)
|
||||||
CLASS_SUPER_NAME (klass) = super_name;
|
{
|
||||||
CLASS_CLS_METHODS (klass) = NULL_TREE;
|
CLASS_NAME (klass) = class_name;
|
||||||
|
CLASS_SUPER_NAME (klass) = super_name;
|
||||||
|
CLASS_CLS_METHODS (klass) = NULL_TREE;
|
||||||
|
}
|
||||||
|
|
||||||
if (! objc_is_class_name (class_name)
|
if (! objc_is_class_name (class_name)
|
||||||
&& (decl = lookup_name (class_name)))
|
&& (decl = lookup_name (class_name)))
|
||||||
|
@ -9592,15 +9648,35 @@ start_class (enum tree_code code, tree class_name, tree super_name,
|
||||||
if (TREE_DEPRECATED (class_category_is_assoc_with))
|
if (TREE_DEPRECATED (class_category_is_assoc_with))
|
||||||
warning (OPT_Wdeprecated_declarations, "class %qE is deprecated",
|
warning (OPT_Wdeprecated_declarations, "class %qE is deprecated",
|
||||||
class_name);
|
class_name);
|
||||||
add_category (class_category_is_assoc_with, klass);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (protocol_list)
|
if (super_name == NULL_TREE)
|
||||||
CLASS_PROTOCOL_LIST (klass)
|
{
|
||||||
= lookup_and_install_protocols (protocol_list);
|
/* This is a class extension. Get the original
|
||||||
|
interface, and continue working on it. */
|
||||||
|
objc_in_class_extension = true;
|
||||||
|
klass = class_category_is_assoc_with;
|
||||||
|
|
||||||
|
if (protocol_list)
|
||||||
|
{
|
||||||
|
/* Append protocols to the original protocol
|
||||||
|
list. */
|
||||||
|
CLASS_PROTOCOL_LIST (klass)
|
||||||
|
= chainon (CLASS_PROTOCOL_LIST (klass),
|
||||||
|
lookup_and_install_protocols (protocol_list));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
add_category (class_category_is_assoc_with, klass);
|
||||||
|
|
||||||
|
if (protocol_list)
|
||||||
|
CLASS_PROTOCOL_LIST (klass)
|
||||||
|
= lookup_and_install_protocols (protocol_list);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CATEGORY_IMPLEMENTATION_TYPE:
|
case CATEGORY_IMPLEMENTATION_TYPE:
|
||||||
/* Reset for multiple classes per file. */
|
/* Reset for multiple classes per file. */
|
||||||
method_slot = 0;
|
method_slot = 0;
|
||||||
|
@ -9673,6 +9749,8 @@ continue_class (tree klass)
|
||||||
}
|
}
|
||||||
case CLASS_INTERFACE_TYPE:
|
case CLASS_INTERFACE_TYPE:
|
||||||
{
|
{
|
||||||
|
if (objc_in_class_extension)
|
||||||
|
return NULL_TREE;
|
||||||
#ifdef OBJCPLUS
|
#ifdef OBJCPLUS
|
||||||
push_lang_context (lang_name_c);
|
push_lang_context (lang_name_c);
|
||||||
#endif /* OBJCPLUS */
|
#endif /* OBJCPLUS */
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
|
2010-12-10 Nicola Pero <nicola.pero@meta-innovation.com>
|
||||||
|
|
||||||
|
* objc.dg/class-extension-1.m: New.
|
||||||
|
* objc.dg/class-extension-2.m: New.
|
||||||
|
* objc.dg/class-extension-3.m: New.
|
||||||
|
* objc.dg/property/at-property-26.m: New.
|
||||||
|
* objc.dg/property/at-property-27.m: New.
|
||||||
|
* objc.dg/property/at-property-28.m: New.
|
||||||
|
* obj-c++.dg/class-extension-1.mm: New.
|
||||||
|
* obj-c++.dg/class-extension-2.mm: New.
|
||||||
|
* obj-c++.dg/class-extension-3.mm: New.
|
||||||
|
* obj-c++.dg/property/at-property-26.mm: New.
|
||||||
|
* obj-c++.dg/property/at-property-27.mm: New.
|
||||||
|
* obj-c++.dg/property/at-property-28.mm: New.
|
||||||
|
|
||||||
2010-12-09 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
|
2010-12-09 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
|
||||||
|
|
||||||
PR target/46057
|
PR target/46057
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
/* This test tests the basic of class extensions. */
|
||||||
|
|
||||||
|
#include <objc/objc.h>
|
||||||
|
|
||||||
|
@interface MyObject
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
}
|
||||||
|
- (int) test;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject ()
|
||||||
|
- (int) test2;
|
||||||
|
- (int) test3;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyObject
|
||||||
|
- (int) test
|
||||||
|
{
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
- (int) test2
|
||||||
|
{
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
@end /* { dg-warning "incomplete implementation of class .MyObject." } */
|
||||||
|
/* { dg-warning "method definition for .-test3. not found" "" { target *-*-* } 29 } */
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
/* This test tests class extensions and protocols. */
|
||||||
|
|
||||||
|
#include <objc/objc.h>
|
||||||
|
|
||||||
|
/* First, a simple test where a plain class has a protocol attached to
|
||||||
|
it in a class extension. */
|
||||||
|
@interface MyObject
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol MyProtocol
|
||||||
|
- (void) test;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject () <MyProtocol>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyObject
|
||||||
|
@end /* { dg-warning "incomplete implementation of class .MyObject." } */
|
||||||
|
/* { dg-warning "method definition for .-test. not found" "" { target *-*-* } 24 } */
|
||||||
|
/* { dg-warning "class .MyObject. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 24 } */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Second, a more interesting test where protocols are added from the
|
||||||
|
main class and from two different class extensions. */
|
||||||
|
@interface MyObject2 : MyObject <MyProtocol>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol MyProtocol2
|
||||||
|
- (void) test2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol MyProtocol3
|
||||||
|
- (void) test3;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject2 () <MyProtocol2>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject2 () <MyProtocol3>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyObject2
|
||||||
|
@end /* { dg-warning "incomplete implementation of class .MyObject2." } */
|
||||||
|
/* { dg-warning "method definition for .-test. not found" "" { target *-*-* } 50 } */
|
||||||
|
/* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 50 } */
|
||||||
|
/* { dg-warning "method definition for .-test2. not found" "" { target *-*-* } 50 } */
|
||||||
|
/* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 50 } */
|
||||||
|
/* { dg-warning "method definition for .-test3. not found" "" { target *-*-* } 50 } */
|
||||||
|
/* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol3. protocol" "" { target *-*-* } 50 } */
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
/* This test tests warnings on class extensions. */
|
||||||
|
|
||||||
|
#include <objc/objc.h>
|
||||||
|
|
||||||
|
@interface MyObject
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
int count;
|
||||||
|
}
|
||||||
|
- (int) test;
|
||||||
|
@property int count; /* { dg-warning "originally specified here" } */
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject ()
|
||||||
|
- (void) test; /* { dg-error "duplicate declaration of method .-test." } */
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject ()
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject ()
|
||||||
|
@property int count; /* { dg-error "redeclaration of property .count." } */
|
||||||
|
@end
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
|
||||||
|
|
||||||
|
/* Test @properties in class extensions. */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <objc/objc.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
|
||||||
|
@interface MyRootClass
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
}
|
||||||
|
+ (id) initialize;
|
||||||
|
+ (id) alloc;
|
||||||
|
- (id) init;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyRootClass
|
||||||
|
+ (id) initialize { return self; }
|
||||||
|
+ (id) alloc { return class_createInstance (self, 0); }
|
||||||
|
- (id) init { return self; }
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol count4
|
||||||
|
/* Use a different getters/setters, so that the only way to compile
|
||||||
|
object.countX is to find the actual @property. */
|
||||||
|
@property (getter=number4, setter=setNumber4:) int count4;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass : MyRootClass
|
||||||
|
{
|
||||||
|
int count1;
|
||||||
|
int count2;
|
||||||
|
int count3;
|
||||||
|
int count4;
|
||||||
|
}
|
||||||
|
@property (getter=number1, setter=setNumber1:) int count1;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass ()
|
||||||
|
@property (getter=number2, setter=setNumber2:) int count2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass () <count4>
|
||||||
|
@property (getter=number3, setter=setNumber3:) int count3;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MySubClass
|
||||||
|
@synthesize count1;
|
||||||
|
@synthesize count2;
|
||||||
|
- (int) number3
|
||||||
|
{
|
||||||
|
return count3;
|
||||||
|
}
|
||||||
|
- (void) setNumber3: (int)value
|
||||||
|
{
|
||||||
|
count3 = value;
|
||||||
|
}
|
||||||
|
@synthesize count4;
|
||||||
|
@end
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
MySubClass *object = [[MySubClass alloc] init];
|
||||||
|
|
||||||
|
object.count1 = 20;
|
||||||
|
if (object.count1 != 20)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
object.count2 = 11;
|
||||||
|
if (object.count2 != 11)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
object.count3 = 19;
|
||||||
|
if (object.count3 != 19)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
object.count4 = 74;
|
||||||
|
if (object.count4 != 74)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
|
||||||
|
|
||||||
|
/* Test overriding a readonly @property with a readwrite one in a class extension. */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <objc/objc.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
|
||||||
|
@interface MyRootClass
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
}
|
||||||
|
+ (id) initialize;
|
||||||
|
+ (id) alloc;
|
||||||
|
- (id) init;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyRootClass
|
||||||
|
+ (id) initialize { return self; }
|
||||||
|
+ (id) alloc { return class_createInstance (self, 0); }
|
||||||
|
- (id) init { return self; }
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol count2
|
||||||
|
/* Use a different getters/setters, so that the only way to compile
|
||||||
|
object.countX is to find the actual @property. */
|
||||||
|
@property (readonly, getter=number2) int count2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass : MyRootClass
|
||||||
|
{
|
||||||
|
int count1;
|
||||||
|
int count2;
|
||||||
|
}
|
||||||
|
@property (readonly, getter=number1) int count1;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass ()
|
||||||
|
@property (readwrite, getter=number1, setter=setNumber1:) int count1;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass () <count2>
|
||||||
|
@property (readwrite, getter=number2, setter=setNumber2:) int count2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MySubClass
|
||||||
|
@synthesize count1;
|
||||||
|
@synthesize count2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
MySubClass *object = [[MySubClass alloc] init];
|
||||||
|
|
||||||
|
object.count1 = 20;
|
||||||
|
if (object.count1 != 20)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
object.count2 = 11;
|
||||||
|
if (object.count2 != 11)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
/* Test errors when extending a property in a class extension. */
|
||||||
|
|
||||||
|
#include <objc/objc.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
|
||||||
|
@interface MyRootClass
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
}
|
||||||
|
@property (readonly, retain) id property1; /* { dg-warning "originally specified here" } */
|
||||||
|
@property (readonly) int property2; /* { dg-warning "originally specified here" } */
|
||||||
|
@property (readonly, getter=y) int property3; /* { dg-warning "originally specified here" } */
|
||||||
|
@property (readonly) int property4; /* Ok */
|
||||||
|
@property (readonly) int property5; /* { dg-warning "originally specified here" } */
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyRootClass ()
|
||||||
|
@property (readwrite, copy) id property1; /* { dg-warning "assign semantics attributes of property .property1. conflict with previous declaration" } */
|
||||||
|
@property (readwrite, nonatomic) int property2; /* { dg-warning ".nonatomic. attribute of property .property2. conflicts with previous declaration" } */
|
||||||
|
@property (readwrite, getter=x) int property3; /* { dg-warning ".getter. attribute of property .property3. conflicts with previous declaration" } */
|
||||||
|
@property (readwrite) int property4; /* Ok */
|
||||||
|
@property (readwrite) float property5; /* { dg-warning "type of property .property5. conflicts with previous declaration" } */
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
/* This test tests the basic of class extensions. */
|
||||||
|
|
||||||
|
#include <objc/objc.h>
|
||||||
|
|
||||||
|
@interface MyObject
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
}
|
||||||
|
- (int) test;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject ()
|
||||||
|
- (int) test2;
|
||||||
|
- (int) test3;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyObject
|
||||||
|
- (int) test
|
||||||
|
{
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
- (int) test2
|
||||||
|
{
|
||||||
|
return 20;
|
||||||
|
}
|
||||||
|
@end /* { dg-warning "incomplete implementation of class .MyObject." } */
|
||||||
|
/* { dg-warning "method definition for .-test3. not found" "" { target *-*-* } 29 } */
|
|
@ -0,0 +1,56 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
/* This test tests class extensions and protocols. */
|
||||||
|
|
||||||
|
#include <objc/objc.h>
|
||||||
|
|
||||||
|
/* First, a simple test where a plain class has a protocol attached to
|
||||||
|
it in a class extension. */
|
||||||
|
@interface MyObject
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol MyProtocol
|
||||||
|
- (void) test;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject () <MyProtocol>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyObject
|
||||||
|
@end /* { dg-warning "incomplete implementation of class .MyObject." } */
|
||||||
|
/* { dg-warning "method definition for .-test. not found" "" { target *-*-* } 24 } */
|
||||||
|
/* { dg-warning "class .MyObject. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 24 } */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Second, a more interesting test where protocols are added from the
|
||||||
|
main class and from two different class extensions. */
|
||||||
|
@interface MyObject2 : MyObject <MyProtocol>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol MyProtocol2
|
||||||
|
- (void) test2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol MyProtocol3
|
||||||
|
- (void) test3;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject2 () <MyProtocol2>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject2 () <MyProtocol3>
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyObject2
|
||||||
|
@end /* { dg-warning "incomplete implementation of class .MyObject2." } */
|
||||||
|
/* { dg-warning "method definition for .-test. not found" "" { target *-*-* } 50 } */
|
||||||
|
/* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol. protocol" "" { target *-*-* } 50 } */
|
||||||
|
/* { dg-warning "method definition for .-test2. not found" "" { target *-*-* } 50 } */
|
||||||
|
/* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol2. protocol" "" { target *-*-* } 50 } */
|
||||||
|
/* { dg-warning "method definition for .-test3. not found" "" { target *-*-* } 50 } */
|
||||||
|
/* { dg-warning "class .MyObject2. does not fully implement the .MyProtocol3. protocol" "" { target *-*-* } 50 } */
|
|
@ -0,0 +1,26 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
/* This test tests warnings on class extensions. */
|
||||||
|
|
||||||
|
#include <objc/objc.h>
|
||||||
|
|
||||||
|
@interface MyObject
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
int count;
|
||||||
|
}
|
||||||
|
- (int) test;
|
||||||
|
@property int count; /* { dg-message "originally specified here" } */
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject ()
|
||||||
|
- (void) test; /* { dg-error "duplicate declaration of method .-test." } */
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject ()
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyObject ()
|
||||||
|
@property int count; /* { dg-error "redeclaration of property .count." } */
|
||||||
|
@end
|
|
@ -0,0 +1,85 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
|
||||||
|
|
||||||
|
/* Test @properties in class extensions. */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <objc/objc.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
|
||||||
|
@interface MyRootClass
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
}
|
||||||
|
+ (id) initialize;
|
||||||
|
+ (id) alloc;
|
||||||
|
- (id) init;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyRootClass
|
||||||
|
+ (id) initialize { return self; }
|
||||||
|
+ (id) alloc { return class_createInstance (self, 0); }
|
||||||
|
- (id) init { return self; }
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol count4
|
||||||
|
/* Use a different getters/setters, so that the only way to compile
|
||||||
|
object.countX is to find the actual @property. */
|
||||||
|
@property (getter=number4, setter=setNumber4:) int count4;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass : MyRootClass
|
||||||
|
{
|
||||||
|
int count1;
|
||||||
|
int count2;
|
||||||
|
int count3;
|
||||||
|
int count4;
|
||||||
|
}
|
||||||
|
@property (getter=number1, setter=setNumber1:) int count1;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass ()
|
||||||
|
@property (getter=number2, setter=setNumber2:) int count2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass () <count4>
|
||||||
|
@property (getter=number3, setter=setNumber3:) int count3;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MySubClass
|
||||||
|
@synthesize count1;
|
||||||
|
@synthesize count2;
|
||||||
|
- (int) number3
|
||||||
|
{
|
||||||
|
return count3;
|
||||||
|
}
|
||||||
|
- (void) setNumber3: (int)value
|
||||||
|
{
|
||||||
|
count3 = value;
|
||||||
|
}
|
||||||
|
@synthesize count4;
|
||||||
|
@end
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
MySubClass *object = [[MySubClass alloc] init];
|
||||||
|
|
||||||
|
object.count1 = 20;
|
||||||
|
if (object.count1 != 20)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
object.count2 = 11;
|
||||||
|
if (object.count2 != 11)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
object.count3 = 19;
|
||||||
|
if (object.count3 != 19)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
object.count4 = 74;
|
||||||
|
if (object.count4 != 74)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do run } */
|
||||||
|
/* { dg-xfail-run-if "Needs OBJC2 ABI" { *-*-darwin* && { lp64 && { ! objc2 } } } { "-fnext-runtime" } { "" } } */
|
||||||
|
|
||||||
|
/* Test overriding a readonly @property with a readwrite one in a class extension. */
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <objc/objc.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
|
||||||
|
@interface MyRootClass
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
}
|
||||||
|
+ (id) initialize;
|
||||||
|
+ (id) alloc;
|
||||||
|
- (id) init;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MyRootClass
|
||||||
|
+ (id) initialize { return self; }
|
||||||
|
+ (id) alloc { return class_createInstance (self, 0); }
|
||||||
|
- (id) init { return self; }
|
||||||
|
@end
|
||||||
|
|
||||||
|
@protocol count2
|
||||||
|
/* Use a different getters/setters, so that the only way to compile
|
||||||
|
object.countX is to find the actual @property. */
|
||||||
|
@property (readonly, getter=number2) int count2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass : MyRootClass
|
||||||
|
{
|
||||||
|
int count1;
|
||||||
|
int count2;
|
||||||
|
}
|
||||||
|
@property (readonly, getter=number1) int count1;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass ()
|
||||||
|
@property (readwrite, getter=number1, setter=setNumber1:) int count1;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MySubClass () <count2>
|
||||||
|
@property (readwrite, getter=number2, setter=setNumber2:) int count2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation MySubClass
|
||||||
|
@synthesize count1;
|
||||||
|
@synthesize count2;
|
||||||
|
@end
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
MySubClass *object = [[MySubClass alloc] init];
|
||||||
|
|
||||||
|
object.count1 = 20;
|
||||||
|
if (object.count1 != 20)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
object.count2 = 11;
|
||||||
|
if (object.count2 != 11)
|
||||||
|
abort ();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* Contributed by Nicola Pero <nicola.pero@meta-innovation.com>, December 2010. */
|
||||||
|
/* { dg-do compile } */
|
||||||
|
|
||||||
|
/* Test errors when extending a property in a class extension. */
|
||||||
|
|
||||||
|
#include <objc/objc.h>
|
||||||
|
#include <objc/runtime.h>
|
||||||
|
|
||||||
|
@interface MyRootClass
|
||||||
|
{
|
||||||
|
Class isa;
|
||||||
|
}
|
||||||
|
@property (readonly, retain) id property1; /* { dg-message "originally specified here" } */
|
||||||
|
@property (readonly) int property2; /* { dg-message "originally specified here" } */
|
||||||
|
@property (readonly, getter=y) int property3; /* { dg-message "originally specified here" } */
|
||||||
|
@property (readonly) int property4; /* Ok */
|
||||||
|
@property (readonly) int property5; /* { dg-message "originally specified here" } */
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface MyRootClass ()
|
||||||
|
@property (readwrite, copy) id property1; /* { dg-warning "assign semantics attributes of property .property1. conflict with previous declaration" } */
|
||||||
|
@property (readwrite, nonatomic) int property2; /* { dg-warning ".nonatomic. attribute of property .property2. conflicts with previous declaration" } */
|
||||||
|
@property (readwrite, getter=x) int property3; /* { dg-warning ".getter. attribute of property .property3. conflicts with previous declaration" } */
|
||||||
|
@property (readwrite) int property4; /* Ok */
|
||||||
|
@property (readwrite) float property5; /* { dg-warning "type of property .property5. conflicts with previous declaration" } */
|
||||||
|
@end
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue