diff mbox series

C-Family, Objective-C : Implement Objective-C nullability Part 1 [PR90707].

Message ID 1D33C0A6-38D7-49EC-8407-60F20925FBAB@sandoe.co.uk
State New
Headers show
Series C-Family, Objective-C : Implement Objective-C nullability Part 1 [PR90707]. | expand

Commit Message

Iain Sandoe Nov. 12, 2020, 9:31 p.m. UTC
Hi,

The PR notes that our inability to parse these keywords in GNU Objective-C
is one of the contributing factors to being unable to use some important  
system
headers (at least, on Darwin platforms).

tested on x86_64-darwin and x86_64-linux-gnu,
OK for the C-family changes?
thanks
Iain

— commit log

Part 1 of the implementation covers property nullability attributes
and includes the changes to common code. Follow-on changes will be needed
to cover Objective-C method definitions, but those are expected to be
local to the Objective-C front end.

The basis of the implementation is to translate the Objective-C-specific
keywords into an attribute (objc_nullability) which has the required
states to carry the attribute markup.

We introduce the keywords, and these are parsed and validated in the same
manner as other property attributes.  The resulting value is attached to
the property as an objc_nullability attribute.

gcc/c-family/ChangeLog:

	PR objc/90707
	* c-common.c (c_common_reswords): null_unspecified, nullable,
	nonnull, null_resettable: New keywords.
	* c-common.h (enum rid): RID_NULL_UNSPECIFIED, RID_NULLABLE,
	RID_NONNULL, RID_NULL_RESETTABLE: New.
	(OBJC_IS_PATTR_KEYWORD): Include nullability keywords in the
	ranges accepted for property attributes.
	* c-attribs.c (handle_objc_nullability_attribute): New.
	* c-objc.h (enum objc_property_attribute_group): Add
	OBJC_PROPATTR_GROUP_NULLABLE.
	(enum objc_property_attribute_kind):Add
	OBJC_PROPERTY_ATTR_NULL_UNSPECIFIED, OBJC_PROPERTY_ATTR_NULLABLE,
	OBJC_PROPERTY_ATTR_NONNULL, OBJC_PROPERTY_ATTR_NULL_RESETTABLE.

gcc/objc/ChangeLog:

         PR objc/90707
	* objc-act.c (objc_prop_attr_kind_for_rid): Handle nullability.
	(objc_add_property_declaration): Handle nullability attributes.
	Check that these are applicable to the property type.
	* objc-act.h (enum objc_property_nullability): New.

gcc/testsuite/ChangeLog:

         PR objc/90707
	* obj-c++.dg/property/at-property-4.mm: Add basic nullability
	tests.
	* objc.dg/property/at-property-4.m: Likewise.
	* obj-c++.dg/attributes/nullability-00.mm: New test.
	* obj-c++.dg/property/nullability-00.mm: New test.
	* objc.dg/attributes/nullability-00.m: New test.
	* objc.dg/property/nullability-00.m: New test.

gcc/ChangeLog:

         PR objc/90707
	* doc/extend.texi: Document the objc_nullability attribute.
---
  gcc/c-family/c-attribs.c                      | 49 ++++++++++++++++++
  gcc/c-family/c-common.c                       |  6 +++
  gcc/c-family/c-common.h                       |  7 ++-
  gcc/c-family/c-objc.h                         |  5 ++
  gcc/doc/extend.texi                           | 27 ++++++++++
  gcc/objc/objc-act.c                           | 51 ++++++++++++++++++-
  gcc/objc/objc-act.h                           | 10 ++++
  .../obj-c++.dg/attributes/nullability-00.mm   | 20 ++++++++
  .../obj-c++.dg/property/at-property-4.mm      | 20 +++++++-
  .../obj-c++.dg/property/nullability-00.mm     | 21 ++++++++
  .../objc.dg/attributes/nullability-00.m       | 20 ++++++++
  .../objc.dg/property/at-property-4.m          | 18 +++++++
  .../objc.dg/property/nullability-00.m         | 21 ++++++++
  13 files changed, 272 insertions(+), 3 deletions(-)
  create mode 100644 gcc/testsuite/obj-c++.dg/attributes/nullability-00.mm
  create mode 100644 gcc/testsuite/obj-c++.dg/property/nullability-00.mm
  create mode 100644 gcc/testsuite/objc.dg/attributes/nullability-00.m
  create mode 100644 gcc/testsuite/objc.dg/property/nullability-00.m

attribute} } */
+
+@end

Comments

Joseph Myers Nov. 12, 2020, 11:47 p.m. UTC | #1
On Thu, 12 Nov 2020, Iain Sandoe wrote:

> OK for the C-family changes?

OK.

> +When @var{nullability kind} is @var{"unspecified"} or @var{0}, nothing is

I think you mean @code or @samp for the second and third @var on this 
line, they look like literal code not metasyntactic variables.  Likewise 
below.
diff mbox series

Patch

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 6718fff6efb..9c62508651c 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -161,6 +161,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)	\
@@ -520,6 +521,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 }
  };
 
@@ -5251,6 +5254,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 29508bca97b..ab7f6427274 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 94f4868915a..0e28cd9a44b 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 9414aecc668..4b502609eaa 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 aaa5faf76c7..4aff989e4b7 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7458,6 +7458,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 @var{"unspecified"} or @var{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 @var{"nonnull"} or @var{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 @var{"nullable"} or @var{2}, the pointer  
might
+be @code{nil} and carry meaning as such.
+
+When @var{nullability kind} is @var{"resettable"} or @var{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 0cab12eec50..69284e5a913 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);
    TREE_UNAVAILABLE (property_decl) = TREE_UNAVAILABLE (decl);
@@ -1288,6 +1315,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 5b0433ff0ee..2fe409db4fc 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 00000000000..957fca4e3ba
--- /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 f73d70639b6..f58935401b9 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 00000000000..9b0c8084cf3
--- /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 00000000000..81c0145f17b
--- /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 0e905db0eb4..04da34eaa0b 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 00000000000..9b0c8084cf3
--- /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'