diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c index 24bcd70b26cb0c4afb453b8202c29dec046edb13..abdc32eb7d41bc1c2dff67fdfe337a47cdd9065e 100644 --- a/gcc/c-family/c-attribs.c +++ b/gcc/c-family/c-attribs.c @@ -159,6 +159,7 @@ static tree handle_patchable_function_entry_attribute (tree *, tree, tree, static tree handle_copy_attribute (tree *, tree, tree, int, bool *); static tree handle_nsobject_attribute (tree *, tree, tree, int, bool *); static tree handle_objc_root_class_attribute (tree *, tree, tree, int, bool *); +static tree handle_objc_nullability_attribute (tree *, tree, tree, int, bool *); /* Helper to define attribute exclusions. */ #define ATTR_EXCL(name, function, type, variable) \ @@ -516,6 +517,8 @@ const struct attribute_spec c_common_attribute_table[] = handle_nsobject_attribute, NULL }, { "objc_root_class", 0, 0, true, false, false, false, handle_objc_root_class_attribute, NULL }, + { "objc_nullability", 1, 1, true, false, false, false, + handle_objc_nullability_attribute, NULL }, { NULL, 0, 0, false, false, false, false, NULL, NULL } }; @@ -5182,6 +5185,52 @@ handle_objc_root_class_attribute (tree */*node*/, tree name, tree /*args*/, return NULL_TREE; } +/* Handle an "objc_nullability" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_objc_nullability_attribute (tree *node, tree name, tree args, + int /*flags*/, + bool *no_add_attrs) +{ + *no_add_attrs = true; + + tree type = TREE_TYPE (*node); + if (TREE_CODE (*node) == FUNCTION_DECL) + type = TREE_TYPE (type); + + if (type && !POINTER_TYPE_P (type)) + { + error ("%qE cannot be applied to non-pointer type %qT", name, type); + return NULL_TREE; + } + + /* We accept objc_nullability() with a single argument. + string: "unspecified", "nullable", "nonnull" or "resettable" + integer: 0 and 3 where the values have the same meaning as + the strings. */ + tree val = TREE_VALUE (args); + if (TREE_CODE (val) == INTEGER_CST) + { + val = default_conversion (val); + if (!tree_fits_uhwi_p (val) || tree_to_uhwi (val) > 3) + error ("%qE attribute argument %qE is not an integer constant" + " between 0 and 3", name, val); + else + *no_add_attrs = false; /* OK */ + } + else if (TREE_CODE (val) == STRING_CST + && (strcmp (TREE_STRING_POINTER (val), "nullable") == 0 + || strcmp (TREE_STRING_POINTER (val), "nonnull") == 0 + || strcmp (TREE_STRING_POINTER (val), "unspecified") == 0 + || strcmp (TREE_STRING_POINTER (val), "resettable") == 0)) + *no_add_attrs = false; /* OK */ + else if (val != error_mark_node) + error ("%qE attribute argument %qE is not recognised", name, val); + + return NULL_TREE; +} + /* Attempt to partially validate a single attribute ATTR as if it were to be applied to an entity OPER. */ diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c index 29508bca97b5b9482b45164104c66b98f4920fbf..ab7f64272740b02ae7b1111921bbdb0181b614c5 100644 --- a/gcc/c-family/c-common.c +++ b/gcc/c-family/c-common.c @@ -580,6 +580,12 @@ const struct c_common_resword c_common_reswords[] = { "readwrite", RID_READWRITE, D_OBJC }, { "retain", RID_RETAIN, D_OBJC }, { "setter", RID_SETTER, D_OBJC }, + /* These are Objective C implementation of nullability, accepted only in + specific contexts. */ + { "null_unspecified", RID_NULL_UNSPECIFIED, D_OBJC }, + { "nullable", RID_NULLABLE, D_OBJC }, + { "nonnull", RID_NONNULL, D_OBJC }, + { "null_resettable", RID_NULL_RESETTABLE, D_OBJC }, }; const unsigned int num_c_common_reswords = diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index f47097442ebab0b65cf7c05216305cf3f7ef81aa..3c508979b144e5767a8132a1c1e02c3c58136407 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -87,6 +87,11 @@ enum rid RID_ASSIGN, RID_RETAIN, RID_COPY, RID_PROPATOMIC, RID_NONATOMIC, + /* ObjC nullability support keywords that also can appear in the + property attribute context. These values should remain contiguous + with the other property attributes. */ + RID_NULL_UNSPECIFIED, RID_NULLABLE, RID_NONNULL, RID_NULL_RESETTABLE, + /* C (reserved and imaginary types not implemented, so any use is a syntax error) */ RID_IMAGINARY, @@ -264,7 +269,7 @@ enum rid RID_FIRST_PQ = RID_IN, RID_LAST_PQ = RID_ONEWAY, RID_FIRST_PATTR = RID_GETTER, - RID_LAST_PATTR = RID_NONATOMIC + RID_LAST_PATTR = RID_NULL_RESETTABLE }; #define OBJC_IS_AT_KEYWORD(rid) \ diff --git a/gcc/c-family/c-objc.h b/gcc/c-family/c-objc.h index 9414aecc668a7d9d537c92c2a6fe5ef23c63431d..4b502609eaa953286903115c7348254ebc61a798 100644 --- a/gcc/c-family/c-objc.h +++ b/gcc/c-family/c-objc.h @@ -44,6 +44,7 @@ enum objc_property_attribute_group OBJC_PROPATTR_GROUP_READWRITE, OBJC_PROPATTR_GROUP_ASSIGN, OBJC_PROPATTR_GROUP_ATOMIC, + OBJC_PROPATTR_GROUP_NULLABLE, OBJC_PROPATTR_GROUP_CLASS, OBJC_PROPATTR_GROUP_MAX }; @@ -60,6 +61,10 @@ enum objc_property_attribute_kind OBJC_PROPERTY_ATTR_COPY = ( 7 << 8)|OBJC_PROPATTR_GROUP_ASSIGN, OBJC_PROPERTY_ATTR_ATOMIC = ( 8 << 8)|OBJC_PROPATTR_GROUP_ATOMIC, OBJC_PROPERTY_ATTR_NONATOMIC = ( 9 << 8)|OBJC_PROPATTR_GROUP_ATOMIC, + OBJC_PROPERTY_ATTR_NULL_UNSPECIFIED = (12 << 8)|OBJC_PROPATTR_GROUP_NULLABLE, + OBJC_PROPERTY_ATTR_NULLABLE = (13 << 8)|OBJC_PROPATTR_GROUP_NULLABLE, + OBJC_PROPERTY_ATTR_NONNULL = (14 << 8)|OBJC_PROPATTR_GROUP_NULLABLE, + OBJC_PROPERTY_ATTR_NULL_RESETTABLE = (15 << 8)|OBJC_PROPATTR_GROUP_NULLABLE, OBJC_PROPERTY_ATTR_CLASS = (16 << 8)|OBJC_PROPATTR_GROUP_CLASS, OBJC_PROPERTY_ATTR_MAX = (255 << 8|OBJC_PROPATTR_GROUP_MAX) }; diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index c353eb432b961512500e1d0b7c9928b3cef342da..4e5197fc038fa0762fd5028f29864e8af6a5de46 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -7429,6 +7429,33 @@ data in this way can reduce program startup times. This attribute is specific to ELF targets and relies on the linker to place such data in the right location +@item objc_nullability (@var{nullability kind}) @r{(Objective-C and Objective +-C++ only)} +@cindex @code{objc_nullability} variable attribute +This attribute applies to pointer variables only. It allows marking the +pointer with one of four possible values describing the conditions under +which the pointer might have a @code{nil} value. In most cases, the +attribute is intended to be an internal representation for property and +method nullability (specified by language keywords); it is not recommended +to use it directly. + +When @var{nullability kind} is @code{"unspecified"} or @code{0}, nothing is +known about the conditions in which the pointer might be @code{nil}. Making +this state specific serves to avoid false positives in diagnostics. + +When @var{nullability kind} is @code{"nonnull"} or @code{1}, the pointer has +no meaning if it is @code{nil} and thus the compiler is free to emit +diagnostics if it can be determined that the value will be @code{nil}. + +When @var{nullability kind} is @code{"nullable"} or @code{2}, the pointer might +be @code{nil} and carry meaning as such. + +When @var{nullability kind} is @code{"resettable"} or @code{3} (used only in +the context of property attribute lists) this describes the case in which a +property setter may take the value @code{nil} (which perhaps causes the +property to be reset in some manner to a default) but for which the property +getter will never validly return @code{nil}. + @end table @node ARC Variable Attributes diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c index e4103860aae98b24745c7239d00b0124eebc7240..2700bbee639562ecc4d65378ddda81d13f72c788 100644 --- a/gcc/objc/objc-act.c +++ b/gcc/objc/objc-act.c @@ -825,6 +825,11 @@ objc_prop_attr_kind_for_rid (enum rid prop_rid) case RID_PROPATOMIC: return OBJC_PROPERTY_ATTR_ATOMIC; case RID_NONATOMIC: return OBJC_PROPERTY_ATTR_NONATOMIC; + case RID_NULL_UNSPECIFIED:return OBJC_PROPERTY_ATTR_NULL_UNSPECIFIED; + case RID_NULLABLE: return OBJC_PROPERTY_ATTR_NULLABLE; + case RID_NONNULL: return OBJC_PROPERTY_ATTR_NONNULL; + case RID_NULL_RESETTABLE: return OBJC_PROPERTY_ATTR_NULL_RESETTABLE; + case RID_CLASS: return OBJC_PROPERTY_ATTR_CLASS; } } @@ -995,6 +1000,27 @@ objc_add_property_declaration (location_t location, tree decl, property_nonatomic = attrs[OBJC_PROPATTR_GROUP_CLASS]->prop_kind == OBJC_PROPERTY_ATTR_CLASS; + /* Nullability specifications for the property. */ + enum objc_property_nullability property_nullability + = OBJC_PROPERTY_NULL_UNSET; + if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]) + { + if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind + == OBJC_PROPERTY_ATTR_NULL_UNSPECIFIED) + property_nullability = OBJC_PROPERTY_NULL_UNSPECIFIED; + else if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind + == OBJC_PROPERTY_ATTR_NULLABLE) + property_nullability = OBJC_PROPERTY_NULLABLE; + else if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind + == OBJC_PROPERTY_ATTR_NONNULL) + property_nullability = OBJC_PROPERTY_NONNULL; + else if (attrs[OBJC_PROPATTR_GROUP_NULLABLE]->prop_kind + == OBJC_PROPERTY_ATTR_NULL_RESETTABLE) + property_nullability = OBJC_PROPERTY_NULL_RESETTABLE; + else + gcc_unreachable (); + } + /* TODO: Check that the property type is an Objective-C object or a "POD". */ @@ -1272,7 +1298,8 @@ objc_add_property_declaration (location_t location, tree decl, tree property_decl = make_node (PROPERTY_DECL); /* Copy the basic information from the original decl. */ - TREE_TYPE (property_decl) = TREE_TYPE (decl); + tree p_type = TREE_TYPE (decl); + TREE_TYPE (property_decl) = p_type; DECL_SOURCE_LOCATION (property_decl) = DECL_SOURCE_LOCATION (decl); TREE_DEPRECATED (property_decl) = TREE_DEPRECATED (decl); @@ -1287,6 +1314,28 @@ objc_add_property_declaration (location_t location, tree decl, PROPERTY_IVAR_NAME (property_decl) = NULL_TREE; PROPERTY_DYNAMIC (property_decl) = 0; + /* FIXME: We seem to drop any existing DECL_ATTRIBUTES on the floor. */ + if (property_nullability != OBJC_PROPERTY_NULL_UNSET) + { + if (p_type && !POINTER_TYPE_P (p_type)) + error_at (decl_loc, "nullability specifier %qE cannot be applied to" + " non-pointer type %qT", + attrs[OBJC_PROPATTR_GROUP_NULLABLE]->name, p_type); + else if (p_type && POINTER_TYPE_P (p_type) && TREE_TYPE (p_type) + && POINTER_TYPE_P (TREE_TYPE (p_type))) + error_at (decl_loc, "nullability specifier %qE cannot be applied to" + " multi-level pointer type %qT", + attrs[OBJC_PROPATTR_GROUP_NULLABLE]->name, p_type); + else + { + tree attr_name = get_identifier ("objc_nullability"); + tree attr_value = build_int_cst (unsigned_type_node, + (unsigned)property_nullability); + tree nulla = build_tree_list (attr_name, attr_value); + DECL_ATTRIBUTES (property_decl) = nulla; + } + } + /* Remember the fact that the property was found in the @optional section in a @protocol, or not. */ if (objc_method_optional_flag) diff --git a/gcc/objc/objc-act.h b/gcc/objc/objc-act.h index 5b0433ff0ee7572792bce11dab6518a478514703..2fe409db4fc95a900dc3f6ad1486c4c642be99ff 100644 --- a/gcc/objc/objc-act.h +++ b/gcc/objc/objc-act.h @@ -141,6 +141,16 @@ enum objc_property_assign_semantics { #define PROPERTY_CLASS(DECL) \ DECL_LANG_FLAG_6 (PROPERTY_DECL_CHECK (DECL)) +/* PROPERTY_NULLABILITY attributes added to the decl attributes. + effectively, __attribute__((objc_nullability(kind))), */ +enum objc_property_nullability { + OBJC_PROPERTY_NULL_UNSPECIFIED = 0, + OBJC_PROPERTY_NULLABLE, + OBJC_PROPERTY_NONNULL, + OBJC_PROPERTY_NULL_RESETTABLE, + OBJC_PROPERTY_NULL_UNSET +}; + /* PROPERTY_REF. A PROPERTY_REF represents an 'object.property' expression. It is normally used for property access, but when the Objective-C 2.0 "dot-syntax" (object.component) is used diff --git a/gcc/testsuite/obj-c++.dg/attributes/nullability-00.mm b/gcc/testsuite/obj-c++.dg/attributes/nullability-00.mm new file mode 100644 index 0000000000000000000000000000000000000000..957fca4e3ba1dfefcab5d0fa3f7ea1656567a781 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/attributes/nullability-00.mm @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class -fsyntax-only" } */ + +__attribute__((objc_nullability(0))) id a; +__attribute__((objc_nullability(4))) id e_1; /* { dg-error {'objc_nullability' attribute argument '4' is not an integer constant between 0 and 3} } */ +__attribute__((objc_nullability(-22))) id e_2; /* { dg-error {'objc_nullability' attribute argument '-22' is not an integer constant between 0 and 3} } */ +__attribute__((objc_nullability("unspecified"))) id b; +__attribute__((objc_nullability("nullable"))) id c; +__attribute__((objc_nullability("nonnull"))) id d; +__attribute__((objc_nullability("resettable"))) id e; +__attribute__((objc_nullability("nonsense"))) id e_3; /* { dg-error {'objc_nullability' attribute argument '"nonsense"' is not recognised} } */ +__attribute__((objc_nullability(noGoingToWork))) id e_4; /* { dg-error {'noGoingToWork' was not declared in this scope} } */ + +@interface MyRoot +{ + __attribute__((objc_nullability(0))) id iv_a; + __attribute__((objc_nullability(3))) struct { int bad_a; } s;/* { dg-error {'objc_nullability' cannot be applied to non-pointer type '<unnamed struct>'} } */ + __attribute__((objc_nullability("resettable"))) int iv_b;/* { dg-error {'objc_nullability' cannot be applied to non-pointer type 'int'} } */ +} +@end diff --git a/gcc/testsuite/obj-c++.dg/property/at-property-4.mm b/gcc/testsuite/obj-c++.dg/property/at-property-4.mm index f73d70639b6a4a738d268c1e92cbcc2f14ba66ae..f58935401b97f637e43658b59c937c6909e8e032 100644 --- a/gcc/testsuite/obj-c++.dg/property/at-property-4.mm +++ b/gcc/testsuite/obj-c++.dg/property/at-property-4.mm @@ -26,12 +26,17 @@ @property (class) int property_cl_1; +@property (null_unspecified) int *property_null_1; +@property (nullable) int *property_null_2; +@property (nonnull) int *property_null_3; +@property (null_resettable) int *property_null_4; + @property (release) int property_err_1; /* { dg-error "unknown property attribute" } */ @property (getter=myGetter) int property_g0; @property (setter=mySetter:) int property_s0; -/* Now test various problems. */ +/* Now test various basic problems. */ @property (readonly, readwrite) int a; /* { dg-error ".readwrite. attribute conflicts with .readonly. attribute" } */ @property (readonly, setter=mySetterB:) int b; /* { dg-error ".readonly. attribute conflicts with .setter. attribute" } */ @@ -42,6 +47,19 @@ @property (atomic, nonatomic) int property_j; /* { dg-error {'nonatomic' attribute conflicts with 'atomic' attribute} } */ +@property (null_unspecified) int property_bad_t_1; /* { dg-error {nullability specifier 'null_unspecified' cannot be applied to non-pointer type 'int'} } */ +@property (nullable) int property_bad_t_2;/* { dg-error {nullability specifier 'nullable' cannot be applied to non-pointer type 'int'} } */ +@property (nonnull) int property_bad_t_3;/* { dg-error {nullability specifier 'nonnull' cannot be applied to non-pointer type 'int'} } */ +@property (null_resettable) int property_bad_t_4;/* { dg-error {nullability specifier 'null_resettable' cannot be applied to non-pointer type 'int'} } */ +@property (nullable) int **property_bad_t_5;/* { dg-error {nullability specifier 'nullable' cannot be applied to multi-level pointer type 'int\*\*'} } */ + +@property (null_unspecified, nullable) int *property_ne_1; /* { dg-error {'nullable' attribute conflicts with 'null_unspecified' attribute} } */ +@property (null_unspecified, nonnull) int *property_ne_2; /* { dg-error {'nonnull' attribute conflicts with 'null_unspecified' attribute} } */ +@property (null_unspecified, null_resettable) int *property_ne_3; /* { dg-error {'null_resettable' attribute conflicts with 'null_unspecified' attribute} } */ +@property (nullable,nonnull) int *property_ne_4; /* { dg-error {'nonnull' attribute conflicts with 'nullable' attribute} } */ +@property (nullable,null_resettable) int *property_ne_5; /* { dg-error {'null_resettable' attribute conflicts with 'nullable' attribute} } */ +@property (nonnull, null_resettable) int *property_ne_6; /* { dg-error {'null_resettable' attribute conflicts with 'nonnull' attribute} } */ + @property (setter=mySetter:,setter=mySetter2:) int f; /* { dg-warning {multiple property 'setter' methods specified, the latest one will be used} } */ @property (getter=myGetter, getter=myGetter2 ) int g; /* { dg-warning {multiple property 'getter' methods specified, the latest one will be used} } */ diff --git a/gcc/testsuite/obj-c++.dg/property/nullability-00.mm b/gcc/testsuite/obj-c++.dg/property/nullability-00.mm new file mode 100644 index 0000000000000000000000000000000000000000..9b0c8084cf3b676f60a695475c49f03d03774482 --- /dev/null +++ b/gcc/testsuite/obj-c++.dg/property/nullability-00.mm @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fsyntax-only" } */ + +@interface MyRoot +{ + Class isa __attribute__((deprecated)); + id p; + int x; + int *i; +} + +@property(null_unspecified, assign) MyRoot *p1; +@property(nonnull, assign) MyRoot *p2; +@property(nullable, assign) MyRoot *p3; +@property(null_resettable, assign) MyRoot *p4; +@property(null_exciting, assign) MyRoot *e_5; /* { dg-error {unknown property attribute 'null_exciting'} } */ + +@property(nonnull, retain, nullable) MyRoot *e_6; /* { dg-error {'nullable' attribute conflicts with 'nonnull' attribute} } */ +@property(nonnull, nonnull) int *i; /* { dg-warning {duplicate 'nonnull' attribute} } */ + +@end diff --git a/gcc/testsuite/objc.dg/attributes/nullability-00.m b/gcc/testsuite/objc.dg/attributes/nullability-00.m new file mode 100644 index 0000000000000000000000000000000000000000..81c0145f17b2dccb91cb604adc53556d288ebb03 --- /dev/null +++ b/gcc/testsuite/objc.dg/attributes/nullability-00.m @@ -0,0 +1,20 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-Wno-objc-root-class -fsyntax-only" } */ + +__attribute__((objc_nullability(0))) id a; +__attribute__((objc_nullability(4))) id e_1; /* { dg-error {'objc_nullability' attribute argument '4' is not an integer constant between 0 and 3} } */ +__attribute__((objc_nullability(-22))) id e_2; /* { dg-error {'objc_nullability' attribute argument '-22' is not an integer constant between 0 and 3} } */ +__attribute__((objc_nullability("unspecified"))) id b; +__attribute__((objc_nullability("nullable"))) id c; +__attribute__((objc_nullability("nonnull"))) id d; +__attribute__((objc_nullability("resettable"))) id e; +__attribute__((objc_nullability("nonsense"))) id e_3; /* { dg-error {'objc_nullability' attribute argument '"nonsense"' is not recognised} } */ +__attribute__((objc_nullability(noGoingToWork))) id e_4; /* { dg-error {'noGoingToWork' undeclared here} } */ + +@interface MyRoot +{ + __attribute__((objc_nullability(0))) id iv_a; + __attribute__((objc_nullability(3))) struct { int bad_a; } s;/* { dg-error {'objc_nullability' cannot be applied to non-pointer type 'struct <anonymous>'} } */ + __attribute__((objc_nullability("resettable"))) int iv_b;/* { dg-error {'objc_nullability' cannot be applied to non-pointer type 'int'} } */ +} +@end diff --git a/gcc/testsuite/objc.dg/property/at-property-4.m b/gcc/testsuite/objc.dg/property/at-property-4.m index 0e905db0eb46bb9546cc5eaa643ef2cb2f74a068..04da34eaa0be750d8c7df5431e501dae705929d8 100644 --- a/gcc/testsuite/objc.dg/property/at-property-4.m +++ b/gcc/testsuite/objc.dg/property/at-property-4.m @@ -26,6 +26,11 @@ @property (class) int property_cl_1; +@property (null_unspecified) int *property_null_1; +@property (nullable) int *property_null_2; +@property (nonnull) int *property_null_3; +@property (null_resettable) int *property_null_4; + @property (release) int property_err_1; /* { dg-error "unknown property attribute" } */ @property (getter=myGetter) int property_h; @@ -42,6 +47,19 @@ @property (atomic, nonatomic) int property_j; /* { dg-error {'nonatomic' attribute conflicts with 'atomic' attribute} } */ +@property (null_unspecified) int property_bad_t_1; /* { dg-error {nullability specifier 'null_unspecified' cannot be applied to non-pointer type 'int'} } */ +@property (nullable) int property_bad_t_2;/* { dg-error {nullability specifier 'nullable' cannot be applied to non-pointer type 'int'} } */ +@property (nonnull) int property_bad_t_3;/* { dg-error {nullability specifier 'nonnull' cannot be applied to non-pointer type 'int'} } */ +@property (null_resettable) int property_bad_t_4;/* { dg-error {nullability specifier 'null_resettable' cannot be applied to non-pointer type 'int'} } */ +@property (nullable) int **property_bad_t_5;/* { dg-error {nullability specifier 'nullable' cannot be applied to multi-level pointer type 'int \*\*'} } */ + +@property (null_unspecified, nullable) int *property_ne_1; /* { dg-error {'nullable' attribute conflicts with 'null_unspecified' attribute} } */ +@property (null_unspecified, nonnull) int *property_ne_2; /* { dg-error {'nonnull' attribute conflicts with 'null_unspecified' attribute} } */ +@property (null_unspecified, null_resettable) int *property_ne_3; /* { dg-error {'null_resettable' attribute conflicts with 'null_unspecified' attribute} } */ +@property (nullable,nonnull) int *property_ne_4; /* { dg-error {'nonnull' attribute conflicts with 'nullable' attribute} } */ +@property (nullable,null_resettable) int *property_ne_5; /* { dg-error {'null_resettable' attribute conflicts with 'nullable' attribute} } */ +@property (nonnull, null_resettable) int *property_ne_6; /* { dg-error {'null_resettable' attribute conflicts with 'nonnull' attribute} } */ + @property (setter=mySetter:,setter=mySetter2:) int f; /* { dg-warning {multiple property 'setter' methods specified, the latest one will be used} } */ @property (getter=myGetter, getter=myGetter2 ) int g; /* { dg-warning {multiple property 'getter' methods specified, the latest one will be used} } */ diff --git a/gcc/testsuite/objc.dg/property/nullability-00.m b/gcc/testsuite/objc.dg/property/nullability-00.m new file mode 100644 index 0000000000000000000000000000000000000000..9b0c8084cf3b676f60a695475c49f03d03774482 --- /dev/null +++ b/gcc/testsuite/objc.dg/property/nullability-00.m @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-fsyntax-only" } */ + +@interface MyRoot +{ + Class isa __attribute__((deprecated)); + id p; + int x; + int *i; +} + +@property(null_unspecified, assign) MyRoot *p1; +@property(nonnull, assign) MyRoot *p2; +@property(nullable, assign) MyRoot *p3; +@property(null_resettable, assign) MyRoot *p4; +@property(null_exciting, assign) MyRoot *e_5; /* { dg-error {unknown property attribute 'null_exciting'} } */ + +@property(nonnull, retain, nullable) MyRoot *e_6; /* { dg-error {'nullable' attribute conflicts with 'nonnull' attribute} } */ +@property(nonnull, nonnull) int *i; /* { dg-warning {duplicate 'nonnull' attribute} } */ + +@end