r240154 - Extend type nullability qualifiers for Objective-C.

Douglas Gregor dgregor at apple.com
Fri Jun 19 11:14:39 PDT 2015


Author: dgregor
Date: Fri Jun 19 13:14:38 2015
New Revision: 240154

URL: http://llvm.org/viewvc/llvm-project?rev=240154&view=rev
Log:
Extend type nullability qualifiers for Objective-C.

Introduce context-sensitive, non-underscored nullability specifiers
(nonnull, nullable, null_unspecified) for Objective-C method return
types, method parameter types, and properties.

Introduce Objective-C-specific semantics, including computation of the
nullability of the result of a message send, merging of nullability
information from the @interface of a class into its @implementation,
etc .

This is the Objective-C part of rdar://problem/18868820.

Added:
    cfe/trunk/test/SemaObjC/nullable-weak-property.m
    cfe/trunk/test/SemaObjC/override-nullability.m
Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/DeclBase.h
    cfe/trunk/include/clang/AST/DeclObjC.h
    cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Basic/Specifiers.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/include/clang/Sema/AttributeList.h
    cfe/trunk/include/clang/Sema/DeclSpec.h
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/lib/AST/ASTImporter.cpp
    cfe/trunk/lib/AST/DeclObjC.cpp
    cfe/trunk/lib/AST/DeclPrinter.cpp
    cfe/trunk/lib/Basic/IdentifierTable.cpp
    cfe/trunk/lib/Parse/ParseObjc.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/SemaDecl.cpp
    cfe/trunk/lib/Sema/SemaDeclObjC.cpp
    cfe/trunk/lib/Sema/SemaExprObjC.cpp
    cfe/trunk/lib/Sema/SemaObjCProperty.cpp
    cfe/trunk/lib/Sema/SemaType.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
    cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
    cfe/trunk/test/Index/comment-objc-decls.m
    cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m
    cfe/trunk/test/SemaObjC/arc-unavailable-for-weakref.m
    cfe/trunk/test/SemaObjC/nullability.m

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Fri Jun 19 13:14:38 2015
@@ -1854,6 +1854,36 @@ public:
            getCanonicalType(T2).getTypePtr();
   }
 
+  bool hasSameNullabilityTypeQualifier(QualType SubT, QualType SuperT,
+                                       bool IsParam) const {
+    auto SubTnullability = SubT->getNullability(*this);
+    auto SuperTnullability = SuperT->getNullability(*this);
+    if (SubTnullability.hasValue() == SuperTnullability.hasValue()) {
+      // Neither has nullability; return true
+      if (!SubTnullability)
+        return true;
+      // Both have nullability qualifier.
+      if (*SubTnullability == *SuperTnullability ||
+          *SubTnullability == NullabilityKind::Unspecified ||
+          *SuperTnullability == NullabilityKind::Unspecified)
+        return true;
+      
+      if (IsParam) {
+        // Ok for the superclass method parameter to be “nonnull” and the subclass
+        // method parameter to be “nullable”
+        return (*SuperTnullability == NullabilityKind::NonNull &&
+                *SubTnullability == NullabilityKind::Nullable);
+      }
+      else {
+        // For the return type, it’s okay for the superclass method to specify
+        // “nullable” and the subclass method specify “nonnull”
+        return (*SuperTnullability == NullabilityKind::Nullable &&
+                *SubTnullability == NullabilityKind::NonNull);
+      }
+    }
+    return true;
+  }
+
   bool ObjCMethodsAreEqual(const ObjCMethodDecl *MethodDecl,
                            const ObjCMethodDecl *MethodImp);
   

Modified: cfe/trunk/include/clang/AST/DeclBase.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclBase.h?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclBase.h (original)
+++ cfe/trunk/include/clang/AST/DeclBase.h Fri Jun 19 13:14:38 2015
@@ -178,7 +178,12 @@ public:
     OBJC_TQ_Out = 0x4,
     OBJC_TQ_Bycopy = 0x8,
     OBJC_TQ_Byref = 0x10,
-    OBJC_TQ_Oneway = 0x20
+    OBJC_TQ_Oneway = 0x20,
+
+    /// The nullability qualifier is set when the nullability of the
+    /// result or parameter was expressed via a context-sensitive
+    /// keyword.
+    OBJC_TQ_CSNullability = 0x40
   };
 
 protected:

Modified: cfe/trunk/include/clang/AST/DeclObjC.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/DeclObjC.h?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/DeclObjC.h (original)
+++ cfe/trunk/include/clang/AST/DeclObjC.h Fri Jun 19 13:14:38 2015
@@ -141,7 +141,7 @@ private:
 
   // NOTE: VC++ treats enums as signed, avoid using the ObjCDeclQualifier enum
   /// in, inout, etc.
-  unsigned objcDeclQualifier : 6;
+  unsigned objcDeclQualifier : 7;
 
   /// \brief Indicates whether this method has a related result type.
   unsigned RelatedResultType : 1;
@@ -2203,13 +2203,16 @@ public:
     OBJC_PR_atomic    = 0x100,
     OBJC_PR_weak      = 0x200,
     OBJC_PR_strong    = 0x400,
-    OBJC_PR_unsafe_unretained = 0x800
+    OBJC_PR_unsafe_unretained = 0x800,
+    /// Indicates that the nullability of the type was spelled with a
+    /// property attribute rather than a type qualifier.
+    OBJC_PR_nullability = 0x1000
     // Adding a property should change NumPropertyAttrsBits
   };
 
   enum {
     /// \brief Number of bits fitting all the property attributes.
-    NumPropertyAttrsBits = 12
+    NumPropertyAttrsBits = 13
   };
 
   enum SetterKind { Assign, Retain, Copy, Weak };
@@ -2217,7 +2220,8 @@ public:
 private:
   SourceLocation AtLoc;   // location of \@property
   SourceLocation LParenLoc; // location of '(' starting attribute list or null.
-  TypeSourceInfo *DeclType;
+  QualType DeclType;
+  TypeSourceInfo *DeclTypeSourceInfo;
   unsigned PropertyAttributes : NumPropertyAttrsBits;
   unsigned PropertyAttributesAsWritten : NumPropertyAttrsBits;
   // \@required/\@optional
@@ -2232,12 +2236,13 @@ private:
 
   ObjCPropertyDecl(DeclContext *DC, SourceLocation L, IdentifierInfo *Id,
                    SourceLocation AtLocation,  SourceLocation LParenLocation,
-                   TypeSourceInfo *T)
+                   QualType T, TypeSourceInfo *TSI,
+                   PropertyControl propControl)
     : NamedDecl(ObjCProperty, DC, L, Id), AtLoc(AtLocation), 
-      LParenLoc(LParenLocation), DeclType(T),
+      LParenLoc(LParenLocation), DeclType(T), DeclTypeSourceInfo(TSI),
       PropertyAttributes(OBJC_PR_noattr),
       PropertyAttributesAsWritten(OBJC_PR_noattr),
-      PropertyImplementation(None),
+      PropertyImplementation(propControl),
       GetterName(Selector()),
       SetterName(Selector()),
       GetterMethodDecl(nullptr), SetterMethodDecl(nullptr),
@@ -2248,7 +2253,8 @@ public:
                                   SourceLocation L,
                                   IdentifierInfo *Id, SourceLocation AtLocation,
                                   SourceLocation LParenLocation,
-                                  TypeSourceInfo *T,
+                                  QualType T,
+                                  TypeSourceInfo *TSI,
                                   PropertyControl propControl = None);
   
   static ObjCPropertyDecl *CreateDeserialized(ASTContext &C, unsigned ID);
@@ -2259,9 +2265,14 @@ public:
   SourceLocation getLParenLoc() const { return LParenLoc; }
   void setLParenLoc(SourceLocation L) { LParenLoc = L; }
 
-  TypeSourceInfo *getTypeSourceInfo() const { return DeclType; }
-  QualType getType() const { return DeclType->getType(); }
-  void setType(TypeSourceInfo *T) { DeclType = T; }
+  TypeSourceInfo *getTypeSourceInfo() const { return DeclTypeSourceInfo; }
+
+  QualType getType() const { return DeclType; }
+
+  void setType(QualType T, TypeSourceInfo *TSI) { 
+    DeclType = T;
+    DeclTypeSourceInfo = TSI; 
+  }
 
   PropertyAttributeKind getPropertyAttributes() const {
     return PropertyAttributeKind(PropertyAttributes);

Modified: cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticCommonKinds.td Fri Jun 19 13:14:38 2015
@@ -101,15 +101,32 @@ def err_enum_template : Error<"enumerati
 
 let CategoryName = "Nullability Issue" in {
 
-def warn_mismatched_nullability_attr : Warning<
-  "nullability specifier "
-  "'__%select{nonnull|nullable|null_unspecified}0' "
-  "conflicts with existing specifier "
-  "'__%select{nonnull|nullable|null_unspecified}1'">,
+def warn_nullability_duplicate : Warning<
+  "duplicate nullability specifier "
+  "'%select{__|}1%select{nonnull|nullable|null_unspecified}0'">,
+  InGroup<Nullability>;
+  
+def warn_conflicting_nullability_attr_overriding_ret_types : Warning<
+  "conflicting nullability specifier on return types, "
+  "'%select{%select{__|}1nonnull|"
+  "%select{__|}1nullable|%select{__|}1null_unspecified}0' "
+  "conflicts with existing specifier '%select{%select{__|}3nonnull|"
+  "%select{__|}3nullable|%select{__|}3null_unspecified}2'">,
   InGroup<Nullability>;
 
-def note_nullability_here : Note<
-  "'%select{__nonnull|__nullable|__null_unspecified}0' specified here">;
+def warn_conflicting_nullability_attr_overriding_param_types : Warning<
+  "conflicting nullability specifier on parameter types, "
+  "'%select{%select{__|}1nonnull|"
+  "%select{__|}1nullable|%select{__|}1null_unspecified}0' "
+  "conflicts with existing specifier '%select{%select{__|}3nonnull|"
+  "%select{__|}3nullable|%select{__|}3null_unspecified}2'">,
+  InGroup<Nullability>;
+
+def err_nullability_conflicting : Error<
+  "nullability specifier "
+  "'%select{__|}1%select{nonnull|nullable|null_unspecified}0' conflicts with "
+  "existing specifier '%select{__|}3%select{nonnull|nullable|"
+  "null_unspecified}2'">;
 
 }
 

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Fri Jun 19 13:14:38 2015
@@ -7676,9 +7676,11 @@ def warn_profile_data_unprofiled : Warni
 
 let CategoryName = "Nullability Issue" in {
 
-def warn_duplicate_nullability : Warning<
-  "duplicate nullability specifier "
-  "'%select{__nonnull|__nullable|__null_unspecified}0'">,
+def warn_mismatched_nullability_attr : Warning<
+  "nullability specifier "
+  "'%select{__|}1%select{nonnull|nullable|null_unspecified}0' "
+  "conflicts with existing specifier "
+  "'%select{__|}3%select{nonnull|nullable|null_unspecified}2'">,
   InGroup<Nullability>;
 
 def warn_nullability_declspec : Warning<
@@ -7690,21 +7692,28 @@ def warn_nullability_declspec : Warning<
   InGroup<NullabilityDeclSpec>,
   DefaultError;
 
-def err_nullability_nonpointer : Error<
-  "nullability specifier "
-  "'%select{__nonnull|__nullable|__null_unspecified}0' cannot be applied to "
-  "non-pointer type %1">;
+def note_nullability_here : Note<
+  "'%select{__nonnull|__nullable|__null_unspecified}0' specified here">;
 
-def err_nullability_conflicting : Error<
+def err_nullability_nonpointer : Error<
   "nullability specifier "
-  "'%select{__nonnull|__nullable|__null_unspecified}0' conflicts with existing "
-  "specifier '%select{__nonnull|__nullable|__null_unspecified}1'">;
+  "'%select{__|}1%select{nonnull|nullable|null_unspecified}0' cannot be applied "
+  "to non-pointer type %2">;
 
 def warn_nullability_lost : Warning<
   "implicit conversion from nullable pointer %0 to non-nullable pointer "
   "type %1">,
   InGroup<NullableToNonNullConversion>, DefaultIgnore;
 
+def err_nullability_cs_multilevel : Error<
+  "nullability keyword "
+  "'%select{nonnull|nullable|null_unspecified}0' cannot be applied to "
+  "multi-level pointer type %1">;
+def note_nullability_type_specifier : Note<
+  "use nullability type specifier "
+  "'%select{__nonnull|__nullable|__null_unspecified}0' to affect the innermost "
+  "pointer type of %1">;
+
 }
 
 } // end of sema component.

Modified: cfe/trunk/include/clang/Basic/Specifiers.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Specifiers.h?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Specifiers.h (original)
+++ cfe/trunk/include/clang/Basic/Specifiers.h Fri Jun 19 13:14:38 2015
@@ -16,6 +16,7 @@
 #ifndef LLVM_CLANG_BASIC_SPECIFIERS_H
 #define LLVM_CLANG_BASIC_SPECIFIERS_H
 
+#include "llvm/ADT/StringRef.h"
 #include "llvm/Support/DataTypes.h"
 
 namespace clang {
@@ -254,6 +255,9 @@ namespace clang {
     /// though it has been considered.
     Unspecified
   };
+
+  /// Retrieve the spelling of the given nullability kind.
+  llvm::StringRef getNullabilitySpelling(NullabilityKind kind);
 } // end namespace clang
 
 #endif // LLVM_CLANG_BASIC_SPECIFIERS_H

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri Jun 19 13:14:38 2015
@@ -139,6 +139,11 @@ class Parser : public CodeCompletionHand
   // used as type traits.
   llvm::SmallDenseMap<IdentifierInfo *, tok::TokenKind> RevertibleTypeTraits;
 
+  /// Nullability type specifiers.
+  IdentifierInfo *Ident___nonnull = nullptr;
+  IdentifierInfo *Ident___nullable = nullptr;
+  IdentifierInfo *Ident___null_unspecified = nullptr;
+
   std::unique_ptr<PragmaHandler> AlignHandler;
   std::unique_ptr<PragmaHandler> GCCVisibilityHandler;
   std::unique_ptr<PragmaHandler> OptionsHandler;
@@ -303,6 +308,10 @@ public:
     return true;
   }
 
+  /// Retrieve the underscored keyword (__nonnull, __nullable,
+  /// __null_unspecified) that corresponds to the given nullability kind.
+  IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability);
+
 private:
   //===--------------------------------------------------------------------===//
   // Low-Level token peeking and consumption methods.
@@ -1282,6 +1291,7 @@ private:
   // Definitions for Objective-c context sensitive keywords recognition.
   enum ObjCTypeQual {
     objc_in=0, objc_out, objc_inout, objc_oneway, objc_bycopy, objc_byref,
+    objc_nonnull, objc_nullable, objc_null_unspecified,
     objc_NumQuals
   };
   IdentifierInfo *ObjCTypeQuals[objc_NumQuals];

Modified: cfe/trunk/include/clang/Sema/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/AttributeList.h?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/AttributeList.h (original)
+++ cfe/trunk/include/clang/Sema/AttributeList.h Fri Jun 19 13:14:38 2015
@@ -120,6 +120,9 @@ private:
   /// True if this has a ParsedType
   unsigned HasParsedType : 1;
 
+  /// True when this keyword attribute is a context-sensitive keyword.
+  unsigned IsContextSensitiveKeyword : 1;
+
   unsigned AttrKind : 8;
 
   /// \brief The location of the 'unavailable' keyword in an
@@ -220,7 +223,8 @@ private:
       ScopeLoc(scopeLoc), EllipsisLoc(ellipsisLoc), NumArgs(numArgs),
       SyntaxUsed(syntaxUsed), Invalid(false), UsedAsTypeAttr(false),
       IsAvailability(false), IsTypeTagForDatatype(false), IsProperty(false),
-      HasParsedType(false), NextInPosition(nullptr), NextInPool(nullptr) {
+      HasParsedType(false), IsContextSensitiveKeyword(false),
+      NextInPosition(nullptr), NextInPool(nullptr) {
     if (numArgs) memcpy(getArgsBuffer(), args, numArgs * sizeof(ArgsUnion));
     AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
@@ -238,8 +242,8 @@ private:
       ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed),
       Invalid(false), UsedAsTypeAttr(false), IsAvailability(true),
       IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
-      UnavailableLoc(unavailable), MessageExpr(messageExpr),
-      NextInPosition(nullptr), NextInPool(nullptr) {
+      IsContextSensitiveKeyword(false), UnavailableLoc(unavailable),
+      MessageExpr(messageExpr), NextInPosition(nullptr), NextInPool(nullptr) {
     ArgsUnion PVal(Parm);
     memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
     new (&getAvailabilitySlot(IntroducedSlot)) AvailabilityChange(introduced);
@@ -259,7 +263,8 @@ private:
     ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(3), SyntaxUsed(syntaxUsed),
     Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
     IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(false),
-    NextInPosition(nullptr), NextInPool(nullptr) {
+    IsContextSensitiveKeyword(false), NextInPosition(nullptr),
+    NextInPool(nullptr) {
     ArgsVector Args;
     Args.push_back(Parm1);
     Args.push_back(Parm2);
@@ -277,7 +282,8 @@ private:
       ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(1), SyntaxUsed(syntaxUsed),
       Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
       IsTypeTagForDatatype(true), IsProperty(false), HasParsedType(false),
-      NextInPosition(nullptr), NextInPool(nullptr) {
+      IsContextSensitiveKeyword(false), NextInPosition(nullptr),
+      NextInPool(nullptr) {
     ArgsUnion PVal(ArgKind);
     memcpy(getArgsBuffer(), &PVal, sizeof(ArgsUnion));
     TypeTagForDatatypeData &ExtraData = getTypeTagForDatatypeDataSlot();
@@ -295,7 +301,8 @@ private:
         ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed),
         Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
         IsTypeTagForDatatype(false), IsProperty(false), HasParsedType(true),
-        NextInPosition(nullptr), NextInPool(nullptr) {
+        IsContextSensitiveKeyword(false), NextInPosition(nullptr),
+        NextInPool(nullptr) {
     new (&getTypeBuffer()) ParsedType(typeArg);
     AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
@@ -309,7 +316,8 @@ private:
       ScopeLoc(scopeLoc), EllipsisLoc(), NumArgs(0), SyntaxUsed(syntaxUsed),
       Invalid(false), UsedAsTypeAttr(false), IsAvailability(false),
       IsTypeTagForDatatype(false), IsProperty(true), HasParsedType(false),
-      NextInPosition(nullptr), NextInPool(nullptr) {
+      IsContextSensitiveKeyword(false), NextInPosition(nullptr),
+      NextInPool(nullptr) {
     new (&getPropertyDataBuffer()) PropertyData(getterId, setterId);
     AttrKind = getKind(getName(), getScopeName(), syntaxUsed);
   }
@@ -352,6 +360,15 @@ public:
   }
   bool isKeywordAttribute() const { return SyntaxUsed == AS_Keyword; }
 
+  bool isContextSensitiveKeywordAttribute() const {
+    return IsContextSensitiveKeyword;
+  }
+
+  void setContextSensitiveKeywordAttribute() {
+    assert(SyntaxUsed == AS_Keyword);
+    IsContextSensitiveKeyword = true;
+  }
+
   bool isInvalid() const { return Invalid; }
   void setInvalid(bool b = true) const { Invalid = b; }
 

Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
+++ cfe/trunk/include/clang/Sema/DeclSpec.h Fri Jun 19 13:14:38 2015
@@ -31,6 +31,7 @@
 #include "clang/Lex/Token.h"
 #include "clang/Sema/AttributeList.h"
 #include "clang/Sema/Ownership.h"
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -785,7 +786,8 @@ public:
     DQ_Out = 0x4,
     DQ_Bycopy = 0x8,
     DQ_Byref = 0x10,
-    DQ_Oneway = 0x20
+    DQ_Oneway = 0x20,
+    DQ_CSNullability = 0x40
   };
 
   /// PropertyAttributeKind - list of property attributes.
@@ -802,17 +804,21 @@ public:
     DQ_PR_atomic = 0x100,
     DQ_PR_weak =   0x200,
     DQ_PR_strong = 0x400,
-    DQ_PR_unsafe_unretained = 0x800
+    DQ_PR_unsafe_unretained = 0x800,
+    DQ_PR_nullability = 0x1000
   };
 
-
   ObjCDeclSpec()
     : objcDeclQualifier(DQ_None), PropertyAttributes(DQ_PR_noattr),
-      GetterName(nullptr), SetterName(nullptr) { }
+      Nullability(0), GetterName(nullptr), SetterName(nullptr) { }
+
   ObjCDeclQualifier getObjCDeclQualifier() const { return objcDeclQualifier; }
   void setObjCDeclQualifier(ObjCDeclQualifier DQVal) {
     objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier | DQVal);
   }
+  void clearObjCDeclQualifier(ObjCDeclQualifier DQVal) {
+    objcDeclQualifier = (ObjCDeclQualifier) (objcDeclQualifier & ~DQVal);
+  }
 
   ObjCPropertyAttributeKind getPropertyAttributes() const {
     return ObjCPropertyAttributeKind(PropertyAttributes);
@@ -822,6 +828,28 @@ public:
       (ObjCPropertyAttributeKind)(PropertyAttributes | PRVal);
   }
 
+  NullabilityKind getNullability() const {
+    assert(((getObjCDeclQualifier() & DQ_CSNullability) ||
+            (getPropertyAttributes() & DQ_PR_nullability)) &&
+           "Objective-C declspec doesn't have nullability");
+    return static_cast<NullabilityKind>(Nullability);
+  }
+
+  SourceLocation getNullabilityLoc() const {
+    assert(((getObjCDeclQualifier() & DQ_CSNullability) ||
+            (getPropertyAttributes() & DQ_PR_nullability)) &&
+           "Objective-C declspec doesn't have nullability");
+    return NullabilityLoc;
+  }
+
+  void setNullability(SourceLocation loc, NullabilityKind kind) {
+    assert(((getObjCDeclQualifier() & DQ_CSNullability) ||
+            (getPropertyAttributes() & DQ_PR_nullability)) &&
+           "Set the nullability declspec or property attribute first");
+    Nullability = static_cast<unsigned>(kind);
+    NullabilityLoc = loc;
+  }
+
   const IdentifierInfo *getGetterName() const { return GetterName; }
   IdentifierInfo *getGetterName() { return GetterName; }
   void setGetterName(IdentifierInfo *name) { GetterName = name; }
@@ -834,10 +862,15 @@ private:
   // FIXME: These two are unrelated and mutually exclusive. So perhaps
   // we can put them in a union to reflect their mutual exclusivity
   // (space saving is negligible).
-  ObjCDeclQualifier objcDeclQualifier : 6;
+  ObjCDeclQualifier objcDeclQualifier : 7;
 
   // NOTE: VC++ treats enums as signed, avoid using ObjCPropertyAttributeKind
-  unsigned PropertyAttributes : 12;
+  unsigned PropertyAttributes : 13;
+
+  unsigned Nullability : 2;
+
+  SourceLocation NullabilityLoc;
+
   IdentifierInfo *GetterName;    // getter name or NULL if no getter
   IdentifierInfo *SetterName;    // setter name or NULL if no setter
 };

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Fri Jun 19 13:14:38 2015
@@ -2859,6 +2859,26 @@ public:
   /// Valid types should not have multiple attributes with different CCs.
   const AttributedType *getCallingConvAttributedType(QualType T) const;
 
+  /// Check whether a nullability type specifier can be added to the given
+  /// type.
+  ///
+  /// \param type The type to which the nullability specifier will be
+  /// added. On success, this type will be updated appropriately.
+  ///
+  /// \param nullability The nullability specifier to add.
+  ///
+  /// \param nullabilityLoc The location of the nullability specifier.
+  ///
+  /// \param isContextSensitive Whether this nullability specifier was
+  /// written as a context-sensitive keyword (in an Objective-C
+  /// method) or an Objective-C property attribute, rather than as an
+  /// underscored type specifier.
+  ///
+  /// \returns true if nullability cannot be applied, false otherwise.
+  bool checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability,
+                                     SourceLocation nullabilityLoc,
+                                     bool isContextSensitive);
+
   /// \brief Stmt attributes - this routine is the top level dispatcher.
   StmtResult ProcessStmtAttributes(Stmt *Stmt, AttributeList *Attrs,
                                    SourceRange Range);
@@ -2934,7 +2954,8 @@ public:
                       const unsigned Attributes,
                       const unsigned AttributesAsWritten,
                       bool *isOverridingProperty,
-                      TypeSourceInfo *T,
+                      QualType T,
+                      TypeSourceInfo *TSI,
                       tok::ObjCKeywordKind MethodImplKind);
 
   /// Called by ActOnProperty and HandlePropertyInClassExtension to
@@ -2950,7 +2971,8 @@ public:
                                        const bool isReadWrite,
                                        const unsigned Attributes,
                                        const unsigned AttributesAsWritten,
-                                       TypeSourceInfo *T,
+                                       QualType T,
+                                       TypeSourceInfo *TSI,
                                        tok::ObjCKeywordKind MethodImplKind,
                                        DeclContext *lexicalDC = nullptr);
 

Modified: cfe/trunk/lib/AST/ASTImporter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTImporter.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTImporter.cpp (original)
+++ cfe/trunk/lib/AST/ASTImporter.cpp Fri Jun 19 13:14:38 2015
@@ -3922,8 +3922,8 @@ Decl *ASTNodeImporter::VisitObjCProperty
   }
 
   // Import the type.
-  TypeSourceInfo *T = Importer.Import(D->getTypeSourceInfo());
-  if (!T)
+  TypeSourceInfo *TSI = Importer.Import(D->getTypeSourceInfo());
+  if (!TSI)
     return nullptr;
 
   // Create the new property.
@@ -3932,7 +3932,8 @@ Decl *ASTNodeImporter::VisitObjCProperty
                                Name.getAsIdentifierInfo(), 
                                Importer.Import(D->getAtLoc()),
                                Importer.Import(D->getLParenLoc()),
-                               T,
+                               Importer.Import(D->getType()),
+                               TSI,
                                D->getPropertyImplementation());
   Importer.Imported(D, ToProperty);
   ToProperty->setLexicalDeclContext(LexicalDC);

Modified: cfe/trunk/lib/AST/DeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclObjC.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclObjC.cpp (original)
+++ cfe/trunk/lib/AST/DeclObjC.cpp Fri Jun 19 13:14:38 2015
@@ -1862,16 +1862,18 @@ ObjCPropertyDecl *ObjCPropertyDecl::Crea
                                            IdentifierInfo *Id,
                                            SourceLocation AtLoc,
                                            SourceLocation LParenLoc,
-                                           TypeSourceInfo *T,
+                                           QualType T,
+                                           TypeSourceInfo *TSI,
                                            PropertyControl propControl) {
-  return new (C, DC) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T);
+  return new (C, DC) ObjCPropertyDecl(DC, L, Id, AtLoc, LParenLoc, T, TSI,
+                                      propControl);
 }
 
 ObjCPropertyDecl *ObjCPropertyDecl::CreateDeserialized(ASTContext &C,
                                                        unsigned ID) {
   return new (C, ID) ObjCPropertyDecl(nullptr, SourceLocation(), nullptr,
                                       SourceLocation(), SourceLocation(),
-                                      nullptr);
+                                      QualType(), nullptr, None);
 }
 
 //===----------------------------------------------------------------------===//

Modified: cfe/trunk/lib/AST/DeclPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/DeclPrinter.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/AST/DeclPrinter.cpp (original)
+++ cfe/trunk/lib/AST/DeclPrinter.cpp Fri Jun 19 13:14:38 2015
@@ -37,6 +37,13 @@ namespace {
 
     void Print(AccessSpecifier AS);
 
+    /// Print an Objective-C method type in parentheses.
+    ///
+    /// \param Quals The Objective-C declaration qualifiers.
+    /// \param T The type to print.
+    void PrintObjCMethodType(ASTContext &Ctx, Decl::ObjCDeclQualifier Quals, 
+                             QualType T);
+
   public:
     DeclPrinter(raw_ostream &Out, const PrintingPolicy &Policy,
                 unsigned Indentation = 0, bool PrintInstantiation = false)
@@ -930,24 +937,64 @@ void DeclPrinter::VisitClassTemplateDecl
 // Objective-C declarations
 //----------------------------------------------------------------------------
 
+/// Strip off the top-level nullability annotation, if it's there.
+static Optional<NullabilityKind> stripOuterNullability(QualType &T) {
+  if (auto attributed = dyn_cast<AttributedType>(T.getTypePtr())) {
+    if (auto nullability = attributed->getImmediateNullability()) {
+      T = attributed->getModifiedType();
+      return nullability;
+    }
+  }
+
+  return None;
+ }
+
+void DeclPrinter::PrintObjCMethodType(ASTContext &Ctx, 
+                                      Decl::ObjCDeclQualifier Quals, 
+                                      QualType T) {
+  Out << '(';
+  if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_In)
+    Out << "in ";
+  if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Inout)
+    Out << "inout ";
+  if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Out)
+    Out << "out ";
+  if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Bycopy)
+    Out << "bycopy ";
+  if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Byref)
+    Out << "byref ";
+  if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_Oneway)
+    Out << "oneway ";
+  if (Quals & Decl::ObjCDeclQualifier::OBJC_TQ_CSNullability) {
+    if (auto nullability = stripOuterNullability(T)) {
+      Out << getNullabilitySpelling(*nullability).substr(2) << ' ';
+    }
+  }
+  
+  Out << Ctx.getUnqualifiedObjCPointerType(T).getAsString(Policy);
+  Out << ')';
+}
+
 void DeclPrinter::VisitObjCMethodDecl(ObjCMethodDecl *OMD) {
   if (OMD->isInstanceMethod())
     Out << "- ";
   else
     Out << "+ ";
-  if (!OMD->getReturnType().isNull())
-    Out << '(' << OMD->getASTContext()
-                      .getUnqualifiedObjCPointerType(OMD->getReturnType())
-                      .getAsString(Policy) << ")";
+  if (!OMD->getReturnType().isNull()) {
+    PrintObjCMethodType(OMD->getASTContext(), OMD->getObjCDeclQualifier(),
+                        OMD->getReturnType());
+  }
 
   std::string name = OMD->getSelector().getAsString();
   std::string::size_type pos, lastPos = 0;
   for (const auto *PI : OMD->params()) {
     // FIXME: selector is missing here!
     pos = name.find_first_of(':', lastPos);
-    Out << " " << name.substr(lastPos, pos - lastPos);
-    Out << ":(" << PI->getASTContext().getUnqualifiedObjCPointerType(PI->getType()).
-                      getAsString(Policy) << ')' << *PI;
+    Out << " " << name.substr(lastPos, pos - lastPos) << ':';
+    PrintObjCMethodType(OMD->getASTContext(), 
+                        PI->getObjCDeclQualifier(),
+                        PI->getType());
+    Out << *PI;
     lastPos = pos + 1;
   }
 
@@ -1103,6 +1150,8 @@ void DeclPrinter::VisitObjCPropertyDecl(
   else if (PDecl->getPropertyImplementation() == ObjCPropertyDecl::Optional)
     Out << "@optional\n";
 
+  QualType T = PDecl->getType();
+
   Out << "@property";
   if (PDecl->getPropertyAttributes() != ObjCPropertyDecl::OBJC_PR_noattr) {
     bool first = true;
@@ -1161,10 +1210,19 @@ void DeclPrinter::VisitObjCPropertyDecl(
       first = false;
     }
     
+    if (PDecl->getPropertyAttributes() &
+        ObjCPropertyDecl::OBJC_PR_nullability) {
+      if (auto nullability = stripOuterNullability(T)) {
+        Out << (first ? ' ' : ',') 
+            << getNullabilitySpelling(*nullability).substr(2);
+        first = false;
+      }
+    }
+
     (void) first; // Silence dead store warning due to idiomatic code.
     Out << " )";
   }
-  Out << ' ' << PDecl->getASTContext().getUnqualifiedObjCPointerType(PDecl->getType()).
+  Out << ' ' << PDecl->getASTContext().getUnqualifiedObjCPointerType(T).
                   getAsString(Policy) << ' ' << *PDecl;
   if (Policy.PolishForDeclaration)
     Out << ';';

Modified: cfe/trunk/lib/Basic/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/IdentifierTable.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Basic/IdentifierTable.cpp (original)
+++ cfe/trunk/lib/Basic/IdentifierTable.cpp Fri Jun 19 13:14:38 2015
@@ -16,6 +16,7 @@
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Basic/OperatorKinds.h"
+#include "clang/Basic/Specifiers.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/SmallString.h"
@@ -645,3 +646,16 @@ const char *clang::getOperatorSpelling(O
 
   llvm_unreachable("Invalid OverloadedOperatorKind!");
 }
+
+StringRef clang::getNullabilitySpelling(NullabilityKind kind) {
+  switch (kind) {
+  case NullabilityKind::NonNull:
+    return "__nonnull";
+
+  case NullabilityKind::Nullable:
+    return "__nullable";
+
+  case NullabilityKind::Unspecified:
+    return "__null_unspecified";
+  }
+}

Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
+++ cfe/trunk/lib/Parse/ParseObjc.cpp Fri Jun 19 13:14:38 2015
@@ -13,6 +13,7 @@
 
 #include "clang/Parse/Parser.h"
 #include "RAIIObjectsForParser.h"
+#include "clang/AST/ASTContext.h"
 #include "clang/Basic/CharInfo.h"
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Sema/DeclSpec.h"
@@ -307,6 +308,58 @@ Decl *Parser::ParseObjCAtInterfaceDeclar
   return ClsType;
 }
 
+IdentifierInfo *Parser::getNullabilityKeyword(NullabilityKind nullability) {
+  switch (nullability) {
+  case NullabilityKind::NonNull:
+    if (!Ident___nonnull)
+      Ident___nonnull = PP.getIdentifierInfo("__nonnull");
+    return Ident___nonnull;
+
+  case NullabilityKind::Nullable:
+    if (!Ident___nullable)
+      Ident___nullable = PP.getIdentifierInfo("__nullable");
+    return Ident___nullable;
+
+  case NullabilityKind::Unspecified:
+    if (!Ident___null_unspecified)
+      Ident___null_unspecified = PP.getIdentifierInfo("__null_unspecified");
+    return Ident___null_unspecified;
+  }
+}
+
+/// Add an attribute for a context-sensitive type nullability to the given
+/// declarator.
+static void addContextSensitiveTypeNullability(Parser &P,
+                                               Declarator &D,
+                                               NullabilityKind nullability,
+                                               SourceLocation nullabilityLoc,
+                                               bool &addedToDeclSpec) {
+  // Create the attribute.
+  auto getNullabilityAttr = [&]() -> AttributeList * {
+    auto attr = D.getAttributePool().create(
+                  P.getNullabilityKeyword(nullability),
+                  SourceRange(nullabilityLoc),
+                  nullptr, SourceLocation(),
+                  nullptr, 0,
+                  AttributeList::AS_Keyword);
+    attr->setContextSensitiveKeywordAttribute();
+    return attr;
+  };
+
+  if (D.getNumTypeObjects() > 0) {
+    // Add the attribute to the declarator chunk nearest the declarator.
+    auto nullabilityAttr = getNullabilityAttr();
+    DeclaratorChunk &chunk = D.getTypeObject(0);
+    nullabilityAttr->setNext(chunk.getAttrListRef());
+    chunk.getAttrListRef() = nullabilityAttr;
+  } else if (!addedToDeclSpec) {
+    // Otherwise, just put it on the declaration specifiers (if one
+    // isn't there already).
+    D.getMutableDeclSpec().addAttributes(getNullabilityAttr());
+    addedToDeclSpec = true;
+  }
+}
+
 ///   objc-interface-decl-list:
 ///     empty
 ///     objc-interface-decl-list objc-property-decl [OBJC2]
@@ -445,6 +498,7 @@ void Parser::ParseObjCInterfaceDeclList(
         ParseObjCPropertyAttribute(OCDS);
       }
 
+      bool addedToDeclSpec = false;
       auto ObjCPropertyCallback = [&](ParsingFieldDeclarator &FD) {
         if (FD.D.getIdentifier() == nullptr) {
           Diag(AtLoc, diag::err_objc_property_requires_field_name)
@@ -457,6 +511,13 @@ void Parser::ParseObjCInterfaceDeclList(
           return;
         }
 
+        // Map a nullability property attribute to a context-sensitive keyword
+        // attribute.
+        if (OCDS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+          addContextSensitiveTypeNullability(*this, FD.D, OCDS.getNullability(),
+                                             OCDS.getNullabilityLoc(),
+                                             addedToDeclSpec);
+
         // Install the property declarator into interfaceDecl.
         IdentifierInfo *SelName =
             OCDS.getGetterName() ? OCDS.getGetterName() : FD.D.getIdentifier();
@@ -510,6 +571,24 @@ void Parser::ParseObjCInterfaceDeclList(
   Actions.ActOnAtEnd(getCurScope(), AtEnd, allMethods, allTUVariables);
 }
 
+/// Diagnose redundant or conflicting nullability information.
+static void diagnoseRedundantPropertyNullability(Parser &P,
+                                                 ObjCDeclSpec &DS,
+                                                 NullabilityKind nullability,
+                                                 SourceLocation nullabilityLoc){
+  if (DS.getNullability() == nullability) {
+    P.Diag(nullabilityLoc, diag::warn_nullability_duplicate)
+      << static_cast<unsigned>(nullability) << true
+      << SourceRange(DS.getNullabilityLoc());
+    return;
+  }
+
+  P.Diag(nullabilityLoc, diag::err_nullability_conflicting)
+    << static_cast<unsigned>(nullability) << true
+    << static_cast<unsigned>(DS.getNullability()) << true
+    << SourceRange(DS.getNullabilityLoc());
+}
+
 ///   Parse property attribute declarations.
 ///
 ///   property-attr-decl: '(' property-attrlist ')'
@@ -529,6 +608,9 @@ void Parser::ParseObjCInterfaceDeclList(
 ///     strong
 ///     weak
 ///     unsafe_unretained
+///     nonnull
+///     nullable
+///     null_unspecified
 ///
 void Parser::ParseObjCPropertyAttribute(ObjCDeclSpec &DS) {
   assert(Tok.getKind() == tok::l_paren);
@@ -614,6 +696,27 @@ void Parser::ParseObjCPropertyAttribute(
         DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_getter);
         DS.setGetterName(SelIdent);
       }
+    } else if (II->isStr("nonnull")) {
+      if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+        diagnoseRedundantPropertyNullability(*this, DS,
+                                             NullabilityKind::NonNull,
+                                             Tok.getLocation());
+      DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+      DS.setNullability(Tok.getLocation(), NullabilityKind::NonNull);
+    } else if (II->isStr("nullable")) {
+      if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+        diagnoseRedundantPropertyNullability(*this, DS,
+                                             NullabilityKind::Nullable,
+                                             Tok.getLocation());
+      DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+      DS.setNullability(Tok.getLocation(), NullabilityKind::Nullable);
+    } else if (II->isStr("null_unspecified")) {
+      if (DS.getPropertyAttributes() & ObjCDeclSpec::DQ_PR_nullability)
+        diagnoseRedundantPropertyNullability(*this, DS,
+                                             NullabilityKind::Unspecified,
+                                             Tok.getLocation());
+      DS.setPropertyAttributes(ObjCDeclSpec::DQ_PR_nullability);
+      DS.setNullability(Tok.getLocation(), NullabilityKind::Unspecified);
     } else {
       Diag(AttrName, diag::err_objc_expected_property_attr) << II;
       SkipUntil(tok::r_paren, StopAtSemi);
@@ -779,6 +882,17 @@ bool Parser::isTokIdentifier_in() const
 ///     objc-type-qualifier
 ///     objc-type-qualifiers objc-type-qualifier
 ///
+///   objc-type-qualifier:
+///     'in'
+///     'out'
+///     'inout'
+///     'oneway'
+///     'bycopy'
+///     'byref'
+///     'nonnull'
+///     'nullable'
+///     'null_unspecified'
+///
 void Parser::ParseObjCTypeQualifierList(ObjCDeclSpec &DS,
                                         Declarator::TheContext Context) {
   assert(Context == Declarator::ObjCParameterContext ||
@@ -796,10 +910,13 @@ void Parser::ParseObjCTypeQualifierList(
 
     const IdentifierInfo *II = Tok.getIdentifierInfo();
     for (unsigned i = 0; i != objc_NumQuals; ++i) {
-      if (II != ObjCTypeQuals[i])
+      if (II != ObjCTypeQuals[i] ||
+          NextToken().is(tok::less) ||
+          NextToken().is(tok::coloncolon))
         continue;
 
       ObjCDeclSpec::ObjCDeclQualifier Qual;
+      NullabilityKind Nullability;
       switch (i) {
       default: llvm_unreachable("Unknown decl qualifier");
       case objc_in:     Qual = ObjCDeclSpec::DQ_In; break;
@@ -808,8 +925,28 @@ void Parser::ParseObjCTypeQualifierList(
       case objc_oneway: Qual = ObjCDeclSpec::DQ_Oneway; break;
       case objc_bycopy: Qual = ObjCDeclSpec::DQ_Bycopy; break;
       case objc_byref:  Qual = ObjCDeclSpec::DQ_Byref; break;
+
+      case objc_nonnull: 
+        Qual = ObjCDeclSpec::DQ_CSNullability;
+        Nullability = NullabilityKind::NonNull;
+        break;
+
+      case objc_nullable: 
+        Qual = ObjCDeclSpec::DQ_CSNullability;
+        Nullability = NullabilityKind::Nullable;
+        break;
+
+      case objc_null_unspecified: 
+        Qual = ObjCDeclSpec::DQ_CSNullability;
+        Nullability = NullabilityKind::Unspecified;
+        break;
       }
+
+      // FIXME: Diagnose redundant specifiers.
       DS.setObjCDeclQualifier(Qual);
+      if (Qual == ObjCDeclSpec::DQ_CSNullability)
+        DS.setNullability(Tok.getLocation(), Nullability);
+
       ConsumeToken();
       II = nullptr;
       break;
@@ -889,6 +1026,14 @@ ParsedType Parser::ParseObjCTypeName(Obj
 
     // If that's not invalid, extract a type.
     if (!declarator.isInvalidType()) {
+      // Map a nullability specifier to a context-sensitive keyword attribute.
+      bool addedToDeclSpec = false;
+      if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability)
+        addContextSensitiveTypeNullability(*this, declarator,
+                                           DS.getNullability(),
+                                           DS.getNullabilityLoc(),
+                                           addedToDeclSpec);
+
       TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
       if (!type.isInvalid())
         Ty = type.get();
@@ -904,8 +1049,34 @@ ParsedType Parser::ParseObjCTypeName(Obj
       Ident_instancetype = PP.getIdentifierInfo("instancetype");
     
     if (Tok.getIdentifierInfo() == Ident_instancetype) {
-      Ty = Actions.ActOnObjCInstanceType(Tok.getLocation());
-      ConsumeToken();
+      SourceLocation loc = ConsumeToken();
+      Ty = Actions.ActOnObjCInstanceType(loc);
+
+      // Map a nullability specifier to a context-sensitive keyword attribute.
+      if (DS.getObjCDeclQualifier() & ObjCDeclSpec::DQ_CSNullability) {
+        // Synthesize an abstract declarator so we can use Sema::ActOnTypeName.
+        bool addedToDeclSpec = false;
+        const char *prevSpec;
+        unsigned diagID;
+        DeclSpec declSpec(AttrFactory);
+        declSpec.setObjCQualifiers(&DS);
+        declSpec.SetTypeSpecType(DeclSpec::TST_typename, loc, prevSpec, diagID,
+                                 Ty,
+                                 Actions.getASTContext().getPrintingPolicy());
+        declSpec.SetRangeEnd(loc);
+        Declarator declarator(declSpec, context);
+
+        // Add the context-sensitive keyword attribute.
+        addContextSensitiveTypeNullability(*this, declarator,
+                                           DS.getNullability(),
+                                           DS.getNullabilityLoc(),
+                                           addedToDeclSpec);
+
+
+        TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
+        if (!type.isInvalid())
+          Ty = type.get();
+      }
     }
   }
 

Modified: cfe/trunk/lib/Parse/Parser.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/Parser.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Fri Jun 19 13:14:38 2015
@@ -463,6 +463,10 @@ void Parser::Initialize() {
     ObjCTypeQuals[objc_oneway] = &PP.getIdentifierTable().get("oneway");
     ObjCTypeQuals[objc_bycopy] = &PP.getIdentifierTable().get("bycopy");
     ObjCTypeQuals[objc_byref] = &PP.getIdentifierTable().get("byref");
+    ObjCTypeQuals[objc_nonnull] = &PP.getIdentifierTable().get("nonnull");
+    ObjCTypeQuals[objc_nullable] = &PP.getIdentifierTable().get("nullable");
+    ObjCTypeQuals[objc_null_unspecified]
+      = &PP.getIdentifierTable().get("null_unspecified");
   }
 
   Ident_instancetype = nullptr;

Modified: cfe/trunk/lib/Sema/SemaDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDecl.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDecl.cpp Fri Jun 19 13:14:38 2015
@@ -2471,9 +2471,13 @@ static void mergeParamDeclTypes(ParmVarD
   if (auto Oldnullability = OldParam->getType()->getNullability(S.Context)) {
     if (auto Newnullability = NewParam->getType()->getNullability(S.Context)) {
       if (*Oldnullability != *Newnullability) {
+        unsigned unsNewnullability = static_cast<unsigned>(*Newnullability);
+        unsigned unsOldnullability = static_cast<unsigned>(*Oldnullability);
         S.Diag(NewParam->getLocation(), diag::warn_mismatched_nullability_attr)
-          << static_cast<unsigned>(*Newnullability)
-          << static_cast<unsigned>(*Oldnullability);
+          << unsNewnullability
+          << ((NewParam->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0)
+          << unsOldnullability
+          << ((OldParam->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0);
         S.Diag(OldParam->getLocation(), diag::note_previous_declaration);
       }
     }

Modified: cfe/trunk/lib/Sema/SemaDeclObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclObjC.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclObjC.cpp Fri Jun 19 13:14:38 2015
@@ -1366,6 +1366,13 @@ static SourceRange getTypeRange(TypeSour
   return (TSI ? TSI->getTypeLoc().getSourceRange() : SourceRange());
 }
 
+/// Determine whether two set of Objective-C declaration qualifiers conflict.
+static bool objcModifiersConflict(Decl::ObjCDeclQualifier x,
+                                  Decl::ObjCDeclQualifier y) {
+  return (x & ~Decl::OBJC_TQ_CSNullability) !=
+         (y & ~Decl::OBJC_TQ_CSNullability);
+}
+
 static bool CheckMethodOverrideReturn(Sema &S,
                                       ObjCMethodDecl *MethodImpl,
                                       ObjCMethodDecl *MethodDecl,
@@ -1373,8 +1380,8 @@ static bool CheckMethodOverrideReturn(Se
                                       bool IsOverridingMode,
                                       bool Warn) {
   if (IsProtocolMethodDecl &&
-      (MethodDecl->getObjCDeclQualifier() !=
-       MethodImpl->getObjCDeclQualifier())) {
+      objcModifiersConflict(MethodDecl->getObjCDeclQualifier(),
+                            MethodImpl->getObjCDeclQualifier())) {
     if (Warn) {
       S.Diag(MethodImpl->getLocation(),
              (IsOverridingMode
@@ -1388,7 +1395,24 @@ static bool CheckMethodOverrideReturn(Se
     else
       return false;
   }
-
+  if (Warn && IsOverridingMode &&
+      !isa<ObjCImplementationDecl>(MethodImpl->getDeclContext()) &&
+      !S.Context.hasSameNullabilityTypeQualifier(MethodImpl->getReturnType(),
+                                                 MethodDecl->getReturnType(),
+                                                 false)) {
+    unsigned unsNullabilityMethodImpl =
+      static_cast<unsigned>(*MethodImpl->getReturnType()->getNullability(S.Context));
+    unsigned unsNullabilityMethodDecl =
+      static_cast<unsigned>(*MethodDecl->getReturnType()->getNullability(S.Context));
+      S.Diag(MethodImpl->getLocation(),
+             diag::warn_conflicting_nullability_attr_overriding_ret_types)
+        << unsNullabilityMethodImpl
+        << ((MethodImpl->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0)
+        << unsNullabilityMethodDecl
+        << ((MethodDecl->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0);
+      S.Diag(MethodDecl->getLocation(), diag::note_previous_declaration);
+  }
+    
   if (S.Context.hasSameUnqualifiedType(MethodImpl->getReturnType(),
                                        MethodDecl->getReturnType()))
     return true;
@@ -1438,8 +1462,8 @@ static bool CheckMethodOverrideParam(Sem
                                      bool IsOverridingMode,
                                      bool Warn) {
   if (IsProtocolMethodDecl &&
-      (ImplVar->getObjCDeclQualifier() !=
-       IfaceVar->getObjCDeclQualifier())) {
+      objcModifiersConflict(ImplVar->getObjCDeclQualifier(),
+                            IfaceVar->getObjCDeclQualifier())) {
     if (Warn) {
       if (IsOverridingMode)
         S.Diag(ImplVar->getLocation(), 
@@ -1459,7 +1483,19 @@ static bool CheckMethodOverrideParam(Sem
       
   QualType ImplTy = ImplVar->getType();
   QualType IfaceTy = IfaceVar->getType();
-  
+  if (Warn && IsOverridingMode &&
+      !isa<ObjCImplementationDecl>(MethodImpl->getDeclContext()) &&
+      !S.Context.hasSameNullabilityTypeQualifier(ImplTy, IfaceTy, true)) {
+    unsigned unsImplTy = static_cast<unsigned>(*ImplTy->getNullability(S.Context));
+    unsigned unsIfaceTy = static_cast<unsigned>(*IfaceTy->getNullability(S.Context));
+    S.Diag(ImplVar->getLocation(),
+           diag::warn_conflicting_nullability_attr_overriding_param_types)
+        << unsImplTy
+        << ((ImplVar->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0)
+        << unsIfaceTy
+        << ((IfaceVar->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) != 0);
+        S.Diag(IfaceVar->getLocation(), diag::note_previous_declaration);
+  }
   if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy))
     return true;
   
@@ -3121,6 +3157,89 @@ void Sema::CheckObjCMethodOverrides(ObjC
   ObjCMethod->setOverriding(hasOverriddenMethodsInBaseOrProtocol);
 }
 
+/// Merge type nullability from for a redeclaration of the same entity,
+/// producing the updated type of the redeclared entity.
+static QualType mergeTypeNullabilityForRedecl(Sema &S, SourceLocation loc,
+                                              QualType type,
+                                              bool usesCSKeyword,
+                                              SourceLocation prevLoc,
+                                              QualType prevType,
+                                              bool prevUsesCSKeyword) {
+  // Determine the nullability of both types.
+  auto nullability = type->getNullability(S.Context);
+  auto prevNullability = prevType->getNullability(S.Context);
+
+  // Easy case: both have nullability.
+  if (nullability.hasValue() == prevNullability.hasValue()) {
+    // Neither has nullability; continue.
+    if (!nullability)
+      return type;
+
+    // The nullabilities are equivalent; do nothing.
+    if (*nullability == *prevNullability)
+      return type;
+
+    // Complain about mismatched nullability.
+    S.Diag(loc, diag::err_nullability_conflicting)
+      << static_cast<unsigned>(*nullability) << usesCSKeyword
+      << static_cast<unsigned>(*prevNullability) << prevUsesCSKeyword;
+    return type;
+  }
+
+  // If it's the redeclaration that has nullability, don't change anything.
+  if (nullability)
+    return type;
+
+  // Otherwise, provide the result with the same nullability.
+  return S.Context.getAttributedType(
+           AttributedType::getNullabilityAttrKind(*prevNullability),
+           type, type);
+}
+
+/// Merge information from the declaration of a method in the @interface
+/// (or a category/extension) into the corresponding method in the
+/// @implementation (for a class or category).
+static void mergeInterfaceMethodToImpl(Sema &S,
+                                       ObjCMethodDecl *method,
+                                       ObjCMethodDecl *prevMethod) {
+  // Merge the objc_requires_super attribute.
+  if (prevMethod->hasAttr<ObjCRequiresSuperAttr>() &&
+      !method->hasAttr<ObjCRequiresSuperAttr>()) {
+    // merge the attribute into implementation.
+    method->addAttr(
+      ObjCRequiresSuperAttr::CreateImplicit(S.Context,
+                                            method->getLocation()));
+  }
+
+  // Merge nullability of the result type.
+  QualType newReturnType
+    = mergeTypeNullabilityForRedecl(
+        S, method->getReturnTypeSourceRange().getBegin(),
+        method->getReturnType(),
+        method->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability,
+        prevMethod->getReturnTypeSourceRange().getBegin(),
+        prevMethod->getReturnType(),
+        prevMethod->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability);
+  method->setReturnType(newReturnType);
+
+  // Handle each of the parameters.
+  unsigned numParams = method->param_size();
+  unsigned numPrevParams = prevMethod->param_size();
+  for (unsigned i = 0, n = std::min(numParams, numPrevParams); i != n; ++i) {
+    ParmVarDecl *param = method->param_begin()[i];
+    ParmVarDecl *prevParam = prevMethod->param_begin()[i];
+
+    // Merge nullability.
+    QualType newParamType
+      = mergeTypeNullabilityForRedecl(
+          S, param->getLocation(), param->getType(),
+          param->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability,
+          prevParam->getLocation(), prevParam->getType(),
+          prevParam->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability);
+    param->setType(newParamType);
+  }
+}
+
 Decl *Sema::ActOnMethodDeclaration(
     Scope *S,
     SourceLocation MethodLoc, SourceLocation EndLoc,
@@ -3151,7 +3270,9 @@ Decl *Sema::ActOnMethodDeclaration(
     if (CheckFunctionReturnType(resultDeclType, MethodLoc))
       return nullptr;
 
-    HasRelatedResultType = (resultDeclType == Context.getObjCInstanceType());
+    QualType bareResultType = resultDeclType;
+    (void)AttributedType::stripOuterNullability(bareResultType);
+    HasRelatedResultType = (bareResultType == Context.getObjCInstanceType());
   } else { // get the type for "id".
     resultDeclType = Context.getObjCIdType();
     Diag(MethodLoc, diag::warn_missing_method_return_type)
@@ -3252,22 +3373,20 @@ Decl *Sema::ActOnMethodDeclaration(
       ImpDecl->addClassMethod(ObjCMethod);
     }
 
-    ObjCMethodDecl *IMD = nullptr;
-    if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface())
-      IMD = IDecl->lookupMethod(ObjCMethod->getSelector(), 
-                                ObjCMethod->isInstanceMethod());
-    if (IMD && IMD->hasAttr<ObjCRequiresSuperAttr>() &&
-        !ObjCMethod->hasAttr<ObjCRequiresSuperAttr>()) {
-      // merge the attribute into implementation.
-      ObjCMethod->addAttr(ObjCRequiresSuperAttr::CreateImplicit(Context,
-                                                   ObjCMethod->getLocation()));
-    }
-    if (isa<ObjCCategoryImplDecl>(ImpDecl)) {
-      ObjCMethodFamily family = 
-        ObjCMethod->getSelector().getMethodFamily();
-      if (family == OMF_dealloc && IMD && IMD->isOverriding()) 
-        Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category)
-          << ObjCMethod->getDeclName();
+    // Merge information from the @interface declaration into the
+    // @implementation.
+    if (ObjCInterfaceDecl *IDecl = ImpDecl->getClassInterface()) {
+      if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(),
+                                          ObjCMethod->isInstanceMethod())) {
+        mergeInterfaceMethodToImpl(*this, ObjCMethod, IMD);
+
+        // Warn about defining -dealloc in a category.
+        if (isa<ObjCCategoryImplDecl>(ImpDecl) && IMD->isOverriding() &&
+            ObjCMethod->getSelector().getMethodFamily() == OMF_dealloc) {
+          Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category)
+            << ObjCMethod->getDeclName();
+        }
+      }
     }
   } else {
     cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod);

Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Fri Jun 19 13:14:38 2015
@@ -1135,49 +1135,150 @@ ObjCMethodDecl *Sema::tryCaptureObjCSelf
 }
 
 static QualType stripObjCInstanceType(ASTContext &Context, QualType T) {
+  QualType origType = T;
+  if (auto nullability = AttributedType::stripOuterNullability(T)) {
+    if (T == Context.getObjCInstanceType()) {
+      return Context.getAttributedType(
+               AttributedType::getNullabilityAttrKind(*nullability),
+               Context.getObjCIdType(),
+               Context.getObjCIdType());
+    }
+
+    return origType;
+  }
+
   if (T == Context.getObjCInstanceType())
     return Context.getObjCIdType();
   
-  return T;
+  return origType;
 }
 
-QualType Sema::getMessageSendResultType(QualType ReceiverType,
-                                        ObjCMethodDecl *Method,
-                                    bool isClassMessage, bool isSuperMessage) {
+/// Determine the result type of a message send based on the receiver type,
+/// method, and the kind of message send.
+///
+/// This is the "base" result type, which will still need to be adjusted
+/// to account for nullability.
+static QualType getBaseMessageSendResultType(Sema &S,
+                                             QualType ReceiverType,
+                                             ObjCMethodDecl *Method,
+                                             bool isClassMessage,
+                                             bool isSuperMessage) {
   assert(Method && "Must have a method");
   if (!Method->hasRelatedResultType())
     return Method->getSendResultType();
-  
+
+  ASTContext &Context = S.Context;
+
+  // Local function that transfers the nullability of the method's
+  // result type to the returned result.
+  auto transferNullability = [&](QualType type) -> QualType {
+    // If the method's result type has nullability, extract it.
+    if (auto nullability = Method->getSendResultType()->getNullability(Context)){
+      // Strip off any outer nullability sugar from the provided type.
+      (void)AttributedType::stripOuterNullability(type);
+
+      // Form a new attributed type using the method result type's nullability.
+      return Context.getAttributedType(
+               AttributedType::getNullabilityAttrKind(*nullability),
+               type,
+               type);
+    }
+
+    return type;
+  };
+
   // If a method has a related return type:
   //   - if the method found is an instance method, but the message send
   //     was a class message send, T is the declared return type of the method
   //     found
   if (Method->isInstanceMethod() && isClassMessage)
     return stripObjCInstanceType(Context, Method->getSendResultType());
-  
-  //   - if the receiver is super, T is a pointer to the class of the 
+
+  //   - if the receiver is super, T is a pointer to the class of the
   //     enclosing method definition
   if (isSuperMessage) {
-    if (ObjCMethodDecl *CurMethod = getCurMethodDecl())
-      if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface())
-        return Context.getObjCObjectPointerType(
-                                        Context.getObjCInterfaceType(Class));
+    if (ObjCMethodDecl *CurMethod = S.getCurMethodDecl())
+      if (ObjCInterfaceDecl *Class = CurMethod->getClassInterface()) {
+        return transferNullability(
+                 Context.getObjCObjectPointerType(
+                   Context.getObjCInterfaceType(Class)));
+      }
   }
-    
+
   //   - if the receiver is the name of a class U, T is a pointer to U
   if (ReceiverType->getAs<ObjCInterfaceType>() ||
       ReceiverType->isObjCQualifiedInterfaceType())
-    return Context.getObjCObjectPointerType(ReceiverType);
-  //   - if the receiver is of type Class or qualified Class type, 
+    return transferNullability(Context.getObjCObjectPointerType(ReceiverType));
+  //   - if the receiver is of type Class or qualified Class type,
   //     T is the declared return type of the method.
   if (ReceiverType->isObjCClassType() ||
       ReceiverType->isObjCQualifiedClassType())
     return stripObjCInstanceType(Context, Method->getSendResultType());
-  
+
   //   - if the receiver is id, qualified id, Class, or qualified Class, T
   //     is the receiver type, otherwise
   //   - T is the type of the receiver expression.
-  return ReceiverType;
+  return transferNullability(ReceiverType);
+}
+
+QualType Sema::getMessageSendResultType(QualType ReceiverType,
+                                        ObjCMethodDecl *Method,
+                                        bool isClassMessage,
+                                        bool isSuperMessage) {
+  // Produce the result type.
+  QualType resultType = getBaseMessageSendResultType(*this, ReceiverType,
+                                                     Method,
+                                                     isClassMessage,
+                                                     isSuperMessage);
+
+  // Map the nullability of the result into a table index.
+  unsigned receiverNullabilityIdx = 0;
+  if (auto nullability = ReceiverType->getNullability(Context))
+    receiverNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
+
+  unsigned resultNullabilityIdx = 0;
+  if (auto nullability = resultType->getNullability(Context))
+    resultNullabilityIdx = 1 + static_cast<unsigned>(*nullability);
+
+  // The table of nullability mappings, indexed by the receiver's nullability
+  // and then the result type's nullability.
+  static const uint8_t None = 0;
+  static const uint8_t NonNull = 1;
+  static const uint8_t Nullable = 2;
+  static const uint8_t Unspecified = 3;
+  static const uint8_t nullabilityMap[4][4] = {
+    //                  None        NonNull       Nullable    Unspecified
+    /* None */        { None,       None,         Nullable,   None },
+    /* NonNull */     { None,       NonNull,      Nullable,   Unspecified },
+    /* Nullable */    { Nullable,   Nullable,     Nullable,   Nullable },
+    /* Unspecified */ { None,       Unspecified,  Nullable,   Unspecified }
+  };
+
+  unsigned newResultNullabilityIdx
+    = nullabilityMap[receiverNullabilityIdx][resultNullabilityIdx];
+  if (newResultNullabilityIdx == resultNullabilityIdx)
+    return resultType;
+
+  // Strip off the existing nullability. This removes as little type sugar as
+  // possible.
+  do {
+    if (auto attributed = dyn_cast<AttributedType>(resultType.getTypePtr())) {
+      resultType = attributed->getModifiedType();
+    } else {
+      resultType = resultType.getDesugaredType(Context);
+    }
+  } while (resultType->getNullability(Context));
+
+  // Add nullability back if needed.
+  if (newResultNullabilityIdx > 0) {
+    auto newNullability
+      = static_cast<NullabilityKind>(newResultNullabilityIdx-1);
+    return Context.getAttributedType(
+             AttributedType::getNullabilityAttrKind(newNullability),
+             resultType, resultType);
+  }
+
+  return resultType;
 }
 
 /// Look for an ObjC method whose result type exactly matches the given type.

Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
+++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Fri Jun 19 13:14:38 2015
@@ -149,7 +149,6 @@ Decl *Sema::ActOnProperty(Scope *S, Sour
   TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
   QualType T = TSI->getType();
   Attributes |= deduceWeakPropertyFromType(*this, T);
-  
   bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
                       // default is readwrite!
                       !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
@@ -173,7 +172,7 @@ Decl *Sema::ActOnProperty(Scope *S, Sour
                                            isAssign, isReadWrite,
                                            Attributes,
                                            ODS.getPropertyAttributes(),
-                                           isOverridingProperty, TSI,
+                                           isOverridingProperty, T, TSI,
                                            MethodImplKind);
       if (!Res)
         return nullptr;
@@ -184,7 +183,7 @@ Decl *Sema::ActOnProperty(Scope *S, Sour
     Res = CreatePropertyDecl(S, ClassDecl, AtLoc, LParenLoc, FD,
                              GetterSel, SetterSel, isAssign, isReadWrite,
                              Attributes, ODS.getPropertyAttributes(),
-                             TSI, MethodImplKind);
+                             T, TSI, MethodImplKind);
     if (lexicalDC)
       Res->setLexicalDeclContext(lexicalDC);
   }
@@ -322,7 +321,8 @@ Sema::HandlePropertyInClassExtension(Sco
                                      const unsigned Attributes,
                                      const unsigned AttributesAsWritten,
                                      bool *isOverridingProperty,
-                                     TypeSourceInfo *T,
+                                     QualType T,
+                                     TypeSourceInfo *TSI,
                                      tok::ObjCKeywordKind MethodImplKind) {
   ObjCCategoryDecl *CDecl = cast<ObjCCategoryDecl>(CurContext);
   // Diagnose if this property is already in continuation class.
@@ -348,7 +348,7 @@ Sema::HandlePropertyInClassExtension(Sco
   // FIXME. We should really be using CreatePropertyDecl for this.
   ObjCPropertyDecl *PDecl =
     ObjCPropertyDecl::Create(Context, DC, FD.D.getIdentifierLoc(),
-                             PropertyId, AtLoc, LParenLoc, T);
+                             PropertyId, AtLoc, LParenLoc, T, TSI);
   PDecl->setPropertyAttributesAsWritten(
                           makePropertyAttributesAsWritten(AttributesAsWritten));
   if (Attributes & ObjCDeclSpec::DQ_PR_readonly)
@@ -359,6 +359,8 @@ Sema::HandlePropertyInClassExtension(Sco
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic);
   if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
     PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic);
+  if (Attributes & ObjCDeclSpec::DQ_PR_nullability)
+    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability);
   // Set setter/getter selector name. Needed later.
   PDecl->setGetterName(GetterSel);
   PDecl->setSetterName(SetterSel);
@@ -383,7 +385,8 @@ Sema::HandlePropertyInClassExtension(Sco
     ObjCPropertyDecl *PrimaryPDecl =
       CreatePropertyDecl(S, CCPrimary, AtLoc, LParenLoc,
                          FD, GetterSel, SetterSel, isAssign, isReadWrite,
-                         Attributes,AttributesAsWritten, T, MethodImplKind, DC);
+                         Attributes,AttributesAsWritten, T, TSI, MethodImplKind, 
+                         DC);
 
     // A case of continuation class adding a new property in the class. This
     // is not what it was meant for. However, gcc supports it and so should we.
@@ -531,11 +534,11 @@ ObjCPropertyDecl *Sema::CreatePropertyDe
                                            const bool isReadWrite,
                                            const unsigned Attributes,
                                            const unsigned AttributesAsWritten,
+                                           QualType T,
                                            TypeSourceInfo *TInfo,
                                            tok::ObjCKeywordKind MethodImplKind,
                                            DeclContext *lexicalDC){
   IdentifierInfo *PropertyId = FD.D.getIdentifier();
-  QualType T = TInfo->getType();
 
   // Issue a warning if property is 'assign' as default and its object, which is
   // gc'able conforms to NSCopying protocol
@@ -564,7 +567,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDe
   DeclContext *DC = cast<DeclContext>(CDecl);
   ObjCPropertyDecl *PDecl = ObjCPropertyDecl::Create(Context, DC,
                                                      FD.D.getIdentifierLoc(),
-                                                     PropertyId, AtLoc, LParenLoc, TInfo);
+                                                     PropertyId, AtLoc, 
+                                                     LParenLoc, T, TInfo);
 
   if (ObjCPropertyDecl *prevDecl =
         ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) {
@@ -639,6 +643,9 @@ ObjCPropertyDecl *Sema::CreatePropertyDe
   else if (MethodImplKind == tok::objc_optional)
     PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional);
 
+  if (Attributes & ObjCDeclSpec::DQ_PR_nullability)
+    PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability);
+
   return PDecl;
 }
 
@@ -2228,6 +2235,23 @@ void Sema::CheckObjCPropertyAttributes(D
       Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
   }
 
+  if ((Attributes & ObjCDeclSpec::DQ_PR_weak) &&
+      !(Attributes & ObjCDeclSpec::DQ_PR_readonly)) {
+    // 'weak' and 'nonnull' are mutually exclusive.
+    if (auto nullability = PropertyTy->getNullability(Context)) {
+      if (*nullability == NullabilityKind::NonNull)
+        Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)
+          << "nonnull" << "weak";
+    } else {
+        PropertyTy =
+          Context.getAttributedType(
+            AttributedType::getNullabilityAttrKind(NullabilityKind::Nullable),
+            PropertyTy, PropertyTy);
+        TypeSourceInfo *TSInfo = PropertyDecl->getTypeSourceInfo();
+        PropertyDecl->setType(PropertyTy, TSInfo);
+    }
+  }
+
   if ((Attributes & ObjCDeclSpec::DQ_PR_atomic) &&
       (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) {
       Diag(Loc, diag::err_objc_property_attr_mutually_exclusive)

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri Jun 19 13:14:38 2015
@@ -4522,34 +4522,10 @@ static bool handleMSPointerTypeQualifier
   return false;
 }
 
-/// Map a nullability attribute kind to a nullability kind.
-static NullabilityKind mapNullabilityAttrKind(AttributeList::Kind kind) {
-  switch (kind) {
-  case AttributeList::AT_TypeNonNull:
-    return NullabilityKind::NonNull;
-
-  case AttributeList::AT_TypeNullable:
-    return NullabilityKind::Nullable;
-
-  case AttributeList::AT_TypeNullUnspecified:
-    return NullabilityKind::Unspecified;
-
-  default:
-    llvm_unreachable("not a nullability attribute kind");
-  }
-}
-
-/// Handle a nullability type attribute.
-static bool handleNullabilityTypeAttr(TypeProcessingState &state,
-                                      AttributeList &attr,
-                                      QualType &type) {
-  Sema &S = state.getSema();
-  ASTContext &Context = S.Context;
-
-  // Determine the nullability.
-  AttributeList::Kind kind = attr.getKind();
-  NullabilityKind nullability = mapNullabilityAttrKind(kind);
-
+bool Sema::checkNullabilityTypeSpecifier(QualType &type, 
+                                         NullabilityKind nullability,
+                                         SourceLocation nullabilityLoc,
+                                         bool isContextSensitive) {
   // Check for existing nullability attributes on the type.
   QualType desugared = type;
   while (auto attributed = dyn_cast<AttributedType>(desugared.getTypePtr())) {
@@ -4557,19 +4533,24 @@ static bool handleNullabilityTypeAttr(Ty
     if (auto existingNullability = attributed->getImmediateNullability()) {
       // Duplicated nullability.
       if (nullability == *existingNullability) {
-        S.Diag(attr.getLoc(), diag::warn_duplicate_nullability)
-          << static_cast<unsigned>(nullability);
-        return true;
-      }
+        Diag(nullabilityLoc, diag::warn_nullability_duplicate)
+          << static_cast<unsigned>(nullability)
+          << isContextSensitive
+          << FixItHint::CreateRemoval(nullabilityLoc);
+
+        break;
+      } 
 
       // Conflicting nullability.
-      S.Diag(attr.getLoc(), diag::err_nullability_conflicting)
-        <<  static_cast<unsigned>(nullability) 
-        << static_cast<unsigned>(*existingNullability);
+      Diag(nullabilityLoc, diag::err_nullability_conflicting)
+        << static_cast<unsigned>(nullability) 
+        << isContextSensitive
+        << static_cast<unsigned>(*existingNullability)
+        << false;
       return true;
     }
 
-    desugared = attributed->getEquivalentType();
+    desugared = attributed->getModifiedType();
   }
 
   // If there is already a different nullability specifier, complain.
@@ -4578,8 +4559,9 @@ static bool handleNullabilityTypeAttr(Ty
   // provide a useful Fix-It.
   if (auto existingNullability = desugared->getNullability(Context)) {
     if (nullability != *existingNullability) {
-      S.Diag(attr.getLoc(), diag::err_nullability_conflicting)
+      Diag(nullabilityLoc, diag::err_nullability_conflicting)
         << static_cast<unsigned>(nullability)
+        << isContextSensitive
         << static_cast<unsigned>(*existingNullability);
 
       // Try to find the typedef with the existing nullability specifier.
@@ -4589,7 +4571,7 @@ static bool handleNullabilityTypeAttr(Ty
         if (auto typedefNullability
               = AttributedType::stripOuterNullability(underlyingType)) {
           if (*typedefNullability == *existingNullability) {
-            S.Diag(typedefDecl->getLocation(), diag::note_nullability_here)
+            Diag(typedefDecl->getLocation(), diag::note_nullability_here)
               << static_cast<unsigned>(*existingNullability);
           }
         }
@@ -4600,31 +4582,35 @@ static bool handleNullabilityTypeAttr(Ty
   }
 
   // If this definitely isn't a pointer type, reject the specifier.
-  if (!type->canHaveNullability()) {
-    S.Diag(attr.getLoc(), diag::err_nullability_nonpointer)
-      << static_cast<unsigned>(nullability) << type;
+  if (!desugared->canHaveNullability()) {
+    Diag(nullabilityLoc, diag::err_nullability_nonpointer)
+      << static_cast<unsigned>(nullability) << isContextSensitive << type;
     return true;
   }
+  
+  // For the context-sensitive keywords/Objective-C property
+  // attributes, require that the type be a single-level pointer.
+  if (isContextSensitive) {
+    // Make sure that the pointee isn't itself a pointer type.
+    QualType pointeeType = desugared->getPointeeType();
+    if (pointeeType->isAnyPointerType() ||
+        pointeeType->isObjCObjectPointerType() ||
+        pointeeType->isMemberPointerType()) {
+      Diag(nullabilityLoc, diag::err_nullability_cs_multilevel)
+        << static_cast<unsigned>(nullability)
+        << type;
+      Diag(nullabilityLoc, diag::note_nullability_type_specifier)
+        << static_cast<unsigned>(nullability)
+        << type
+        << FixItHint::CreateReplacement(nullabilityLoc,
+                                        getNullabilitySpelling(nullability));
+      return true;
+    }
+  }
 
   // Form the attributed type.
-  AttributedType::Kind typeAttrKind;
-  switch (kind) {
-  case AttributeList::AT_TypeNonNull: 
-    typeAttrKind = AttributedType::attr_nonnull; 
-    break;
-
-  case AttributeList::AT_TypeNullable: 
-    typeAttrKind = AttributedType::attr_nullable; 
-    break;
-
-  case AttributeList::AT_TypeNullUnspecified: 
-    typeAttrKind = AttributedType::attr_null_unspecified; 
-    break;
-
-  default:
-    llvm_unreachable("Not a nullability specifier");
-  }
-  type = S.Context.getAttributedType(typeAttrKind, type, type);
+  type = Context.getAttributedType(
+           AttributedType::getNullabilityAttrKind(nullability), type, type);
   return false;
 }
 
@@ -4642,6 +4628,23 @@ static bool hasNullabilityAttr(const Att
   return false;
 }
 
+/// Map a nullability attribute kind to a nullability kind.
+static NullabilityKind mapNullabilityAttrKind(AttributeList::Kind kind) {
+  switch (kind) {
+  case AttributeList::AT_TypeNonNull:
+    return NullabilityKind::NonNull;
+
+  case AttributeList::AT_TypeNullable:
+    return NullabilityKind::Nullable;
+
+  case AttributeList::AT_TypeNullUnspecified:
+    return NullabilityKind::Unspecified;
+
+  default:
+    llvm_unreachable("not a nullability attribute kind");
+  }
+}
+
 /// Distribute a nullability type attribute that cannot be applied to
 /// the type specifier to a pointer, block pointer, or member pointer
 /// declarator, complaining if necessary.
@@ -5233,7 +5236,11 @@ static void processTypeAttrs(TypeProcess
       // dependent type, because that complicates the user model.
       if (type->canHaveNullability() || type->isDependentType() ||
           !distributeNullabilityTypeAttr(state, type, attr)) {
-        if (handleNullabilityTypeAttr(state, attr, type)) {
+        if (state.getSema().checkNullabilityTypeSpecifier(
+              type,
+              mapNullabilityAttrKind(attr.getKind()),
+              attr.getLoc(),
+              attr.isContextSensitiveKeywordAttribute())) {
           attr.setInvalid();
         }
 

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Fri Jun 19 13:14:38 2015
@@ -5392,7 +5392,7 @@ QualType TreeTransform<Derived>::Transfo
     if (auto nullability = oldType->getImmediateNullability()) {
       if (!modifiedType->canHaveNullability()) {
         SemaRef.Diag(TL.getAttrNameLoc(), diag::err_nullability_nonpointer)
-          << static_cast<unsigned>(*nullability) << modifiedType;
+          << static_cast<unsigned>(*nullability) << false << modifiedType;
         return QualType();
       }
     }

Modified: cfe/trunk/lib/Serialization/ASTReaderDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTReaderDecl.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTReaderDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTReaderDecl.cpp Fri Jun 19 13:14:38 2015
@@ -1042,7 +1042,9 @@ void ASTDeclReader::VisitObjCPropertyDec
   VisitNamedDecl(D);
   D->setAtLoc(ReadSourceLocation(Record, Idx));
   D->setLParenLoc(ReadSourceLocation(Record, Idx));
-  D->setType(GetTypeSourceInfo(Record, Idx));
+  QualType T = Reader.readType(F, Record, Idx);
+  TypeSourceInfo *TSI = GetTypeSourceInfo(Record, Idx);
+  D->setType(T, TSI);
   // FIXME: stable encoding
   D->setPropertyAttributes(
                       (ObjCPropertyDecl::PropertyAttributeKind)Record[Idx++]);

Modified: cfe/trunk/lib/Serialization/ASTWriterDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Serialization/ASTWriterDecl.cpp?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/lib/Serialization/ASTWriterDecl.cpp (original)
+++ cfe/trunk/lib/Serialization/ASTWriterDecl.cpp Fri Jun 19 13:14:38 2015
@@ -542,7 +542,7 @@ void ASTDeclWriter::VisitObjCMethodDecl(
 
   // FIXME: stable encoding for @required/@optional
   Record.push_back(D->getImplementationControl());
-  // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway
+  // FIXME: stable encoding for in/out/inout/bycopy/byref/oneway/nullability
   Record.push_back(D->getObjCDeclQualifier());
   Record.push_back(D->hasRelatedResultType());
   Writer.AddTypeRef(D->getReturnType(), Record);
@@ -678,6 +678,7 @@ void ASTDeclWriter::VisitObjCPropertyDec
   VisitNamedDecl(D);
   Writer.AddSourceLocation(D->getAtLoc(), Record);
   Writer.AddSourceLocation(D->getLParenLoc(), Record);
+  Writer.AddTypeRef(D->getType(), Record);
   Writer.AddTypeSourceInfo(D->getTypeSourceInfo(), Record);
   // FIXME: stable encoding
   Record.push_back((unsigned)D->getPropertyAttributes());

Modified: cfe/trunk/test/Index/comment-objc-decls.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Index/comment-objc-decls.m?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/test/Index/comment-objc-decls.m (original)
+++ cfe/trunk/test/Index/comment-objc-decls.m Fri Jun 19 13:14:38 2015
@@ -20,19 +20,19 @@
  * \param[in] range output value is unsigned int
  * \result return index
  */
-- (unsigned int)MethodMyProto:(id)anObject inRange:(unsigned int)range;
+- (unsigned int)MethodMyProto:(nullable id)anObject inRange:(unsigned int)range;
 /**
  * \brief PropertyMyProto - This is protocol's property.
 */
- at property (copy) id PropertyMyProto;
+ at property (copy, nonnull) id PropertyMyProto;
 /**
  * \brief ClassMethodMyProto
 */
 + ClassMethodMyProto;
 @end
 // CHECK: <Declaration>@protocol MyProto\n at end</Declaration>
-// CHECK: <Declaration>- (unsigned int)MethodMyProto:(id)anObject inRange:(unsigned int)range;</Declaration>
-// CHECK: <Declaration>@optional\n at property(readwrite, copy, atomic) id PropertyMyProto;</Declaration>
+// CHECK: <Declaration>- (unsigned int)MethodMyProto:(nullable id)anObject inRange:(unsigned int)range;</Declaration>
+// CHECK: <Declaration>@optional\n at property(readwrite, copy, atomic, nonnull) id PropertyMyProto;</Declaration>
 // CHECK: <Declaration>+ (id)ClassMethodMyProto;</Declaration>
 
 /**

Modified: cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m (original)
+++ cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m Fri Jun 19 13:14:38 2015
@@ -79,3 +79,11 @@
 @property (readwrite) id frr;
 @end
 
+// rdar://20152386
+ at interface NSObject @end
+
+ at interface rdar20152386_2: NSObject
+ at property(nonatomic, weak, nonnull) id delegate; // expected-error {{property attributes 'nonnull' and 'weak' are mutually exclusive}}
+ at property(nonatomic, weak, nonnull, readonly) id ReadDelegate; // no warning
+ at end
+

Modified: cfe/trunk/test/SemaObjC/arc-unavailable-for-weakref.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/arc-unavailable-for-weakref.m?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/arc-unavailable-for-weakref.m (original)
+++ cfe/trunk/test/SemaObjC/arc-unavailable-for-weakref.m Fri Jun 19 13:14:38 2015
@@ -56,7 +56,7 @@ __attribute__((objc_arc_weak_reference_u
 @interface I
 {
 }
- at property (weak) NSFont *font; // expected-error {{synthesizing __weak instance variable of type 'NSFont *', which does not support weak references}}
+ at property (weak) NSFont *font; // expected-error {{synthesizing __weak instance variable of type 'NSFont * __nullable', which does not support weak references}}
 @end
 
 @implementation I // expected-note {{when implemented by class I}}
@@ -65,7 +65,7 @@ __attribute__((objc_arc_weak_reference_u
 
 // rdar://13676793
 @protocol MyProtocol
- at property (weak) NSFont *font; // expected-error {{synthesizing __weak instance variable of type 'NSFont *', which does not support weak references}}
+ at property (weak) NSFont *font; // expected-error {{synthesizing __weak instance variable of type 'NSFont * __nullable', which does not support weak references}}
 @end
 
 @interface I1 <MyProtocol>
@@ -76,7 +76,7 @@ __attribute__((objc_arc_weak_reference_u
 @end
 
 @interface Super
- at property (weak) NSFont *font;  // expected-error {{synthesizing __weak instance variable of type 'NSFont *', which does not support weak references}}
+ at property (weak) NSFont *font;  // expected-error {{synthesizing __weak instance variable of type 'NSFont * __nullable', which does not support weak references}}
 @end
 
 

Modified: cfe/trunk/test/SemaObjC/nullability.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/nullability.m?rev=240154&r1=240153&r2=240154&view=diff
==============================================================================
--- cfe/trunk/test/SemaObjC/nullability.m (original)
+++ cfe/trunk/test/SemaObjC/nullability.m Fri Jun 19 13:14:38 2015
@@ -20,9 +20,6 @@ typedef __nonnull NSFoo * __nullable con
 void testBlocksPrinting(NSFoo * __nullable (^bp)(int)) {
   int *ip = bp; // expected-error{{'NSFoo * __nullable (^)(int)'}}
 }
-void test_accepts_nonnull_null_pointer_literal(NSFoo *foo) {
-  [foo methodTakingIntPtr: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
-}
 
 // Check returning nil from a __nonnull-returning method.
 @implementation NSFoo
@@ -31,3 +28,151 @@ void test_accepts_nonnull_null_pointer_l
   return 0; // no warning
 }
 @end
+
+// Context-sensitive keywords and property attributes for nullability.
+__attribute__((objc_root_class))
+ at interface NSBar
+- (nonnull NSFoo *)methodWithFoo:(nonnull NSFoo *)foo;
+
+- (nonnull NSFoo **)invalidMethod1; // expected-error{{nullability keyword 'nonnull' cannot be applied to multi-level pointer type 'NSFoo **'}}
+// expected-note at -1{{use nullability type specifier '__nonnull' to affect the innermost pointer type of 'NSFoo **'}}
+- (nonnull NSFoo * __nullable)conflictingMethod1; // expected-error{{nullability specifier '__nullable' conflicts with existing specifier '__nonnull'}}
+- (nonnull NSFoo * __nonnull)redundantMethod1; // expected-warning{{duplicate nullability specifier '__nonnull'}}
+
+ at property(nonnull,retain) NSFoo *property1;
+ at property(nullable,assign) NSFoo ** invalidProperty1; // expected-error{{nullability keyword 'nullable' cannot be applied to multi-level pointer type 'NSFoo **'}}
+// expected-note at -1{{use nullability type specifier '__nullable' to affect the innermost pointer type of 'NSFoo **'}}
+ at property(null_unspecified,retain) NSFoo * __nullable conflictingProperty1; // expected-error{{nullability specifier '__nullable' conflicts with existing specifier '__null_unspecified'}}
+ at property(retain,nonnull) NSFoo * __nonnull redundantProperty1; // expected-warning{{duplicate nullability specifier '__nonnull'}}
+
+ at property(null_unspecified,retain,nullable) NSFoo *conflictingProperty3; // expected-error{{nullability specifier 'nullable' conflicts with existing specifier 'null_unspecified'}}
+ at property(nullable,retain,nullable) NSFoo *redundantProperty3; // expected-warning{{duplicate nullability specifier 'nullable'}}
+ at end
+
+ at interface NSBar ()
+ at property(nonnull,retain) NSFoo *property2;
+ at property(nullable,assign) NSFoo ** invalidProperty2; // expected-error{{nullability keyword 'nullable' cannot be applied to multi-level pointer type 'NSFoo **'}}
+// expected-note at -1{{use nullability type specifier '__nullable' to affect the innermost pointer type of 'NSFoo **'}}
+ at property(null_unspecified,retain) NSFoo * __nullable conflictingProperty2; // expected-error{{nullability specifier '__nullable' conflicts with existing specifier '__null_unspecified'}}
+ at property(retain,nonnull) NSFoo * __nonnull redundantProperty2; // expected-warning{{duplicate nullability specifier '__nonnull'}}
+ at end
+
+void test_accepts_nonnull_null_pointer_literal(NSFoo *foo, __nonnull NSBar *bar) {
+  [foo methodTakingIntPtr: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+  [bar methodWithFoo: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+  bar.property1 = 0; // expected-warning{{null passed to a callee that requires a non-null argument}}
+  bar.property2 = 0; // expected-warning{{null passed to a callee that requires a non-null argument}}
+  [bar setProperty1: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+  [bar setProperty2: 0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
+  int *ptr = bar.property1; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'NSFoo * __nonnull'}}
+}
+
+// Check returning nil from a nonnull-returning method.
+ at implementation NSBar
+- (nonnull NSFoo *)methodWithFoo:(nonnull NSFoo *)foo {
+  return 0; // no warning
+}
+
+- (NSFoo **)invalidMethod1 { 
+  return 0; 
+}
+
+- (NSFoo *)conflictingMethod1 { 
+  return 0; // no warning
+}
+- (NSFoo *)redundantMethod1 {
+  int *ip = 0;
+  return ip; // expected-warning{{result type 'NSFoo * __nonnull'}}
+}
+ at end
+
+__attribute__((objc_root_class))
+ at interface NSMerge
+- (nonnull NSFoo *)methodA:(nonnull NSFoo*)foo;
+- (nonnull NSFoo *)methodB:(nonnull NSFoo*)foo;
+- (NSFoo *)methodC:(NSFoo*)foo;
+ at end
+
+ at implementation NSMerge
+- (NSFoo *)methodA:(NSFoo*)foo {
+  int *ptr = foo; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'NSFoo * __nonnull'}}
+  return ptr; // expected-warning{{result type 'NSFoo * __nonnull'}}
+}
+
+- (nullable NSFoo *)methodB:(null_unspecified NSFoo*)foo { // expected-error{{nullability specifier 'nullable' conflicts with existing specifier 'nonnull'}} \
+  // expected-error{{nullability specifier 'null_unspecified' conflicts with existing specifier 'nonnull'}}
+  return 0;
+}
+
+- (nonnull NSFoo *)methodC:(nullable NSFoo*)foo {
+  int *ip = 0;
+  return ip; // expected-warning{{result type 'NSFoo * __nonnull'}}
+}
+ at end
+
+// Checking merging of nullability when sending a message.
+ at interface NSMergeReceiver
+- (id)returnsNone;
+- (nonnull id)returnsNonNull;
+- (nullable id)returnsNullable;
+- (null_unspecified id)returnsNullUnspecified;
+ at end
+
+void test_receiver_merge(NSMergeReceiver *none,
+                         __nonnull NSMergeReceiver *nonnull,
+                         __nullable NSMergeReceiver *nullable,
+                         __null_unspecified NSMergeReceiver *null_unspecified) {
+  int *ptr;
+
+  ptr = [nullable returnsNullable]; // expected-warning{{'id __nullable'}}
+  ptr = [nullable returnsNullUnspecified]; // expected-warning{{'id __nullable'}}
+  ptr = [nullable returnsNonNull]; // expected-warning{{'id __nullable'}}
+  ptr = [nullable returnsNone]; // expected-warning{{'id __nullable'}}
+
+  ptr = [null_unspecified returnsNullable]; // expected-warning{{'id __nullable'}}
+  ptr = [null_unspecified returnsNullUnspecified]; // expected-warning{{'id __null_unspecified'}}
+  ptr = [null_unspecified returnsNonNull]; // expected-warning{{'id __null_unspecified'}}
+  ptr = [null_unspecified returnsNone]; // expected-warning{{'id'}}
+
+  ptr = [nonnull returnsNullable]; // expected-warning{{'id __nullable'}}
+  ptr = [nonnull returnsNullUnspecified]; // expected-warning{{'id __null_unspecified'}}
+  ptr = [nonnull returnsNonNull]; // expected-warning{{'id __nonnull'}}
+  ptr = [nonnull returnsNone]; // expected-warning{{'id'}}
+
+  ptr = [none returnsNullable]; // expected-warning{{'id __nullable'}}
+  ptr = [none returnsNullUnspecified]; // expected-warning{{'id'}}
+  ptr = [none returnsNonNull]; // expected-warning{{'id'}}
+  ptr = [none returnsNone]; // expected-warning{{'id'}}
+  
+}
+
+// instancetype
+ at protocol Initializable
+- (instancetype)initWithBlah:(id)blah;
+ at end
+
+__attribute__((objc_root_class))
+ at interface InitializableClass <Initializable>
+- (nonnull instancetype)initWithBlah:(nonnull id)blah;
+- (nullable instancetype)returnMe;
++ (nullable instancetype)returnInstanceOfMe;
+ at end
+
+void test_instancetype(InitializableClass * __nonnull ic, id __nonnull object) {
+  int *ip = [ic returnMe]; // expected-warning{{incompatible pointer types initializing 'int *' with an expression of type 'InitializableClass * __nullable'}}
+  ip = [InitializableClass returnMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'id __nullable'}}
+  ip = [InitializableClass returnInstanceOfMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'InitializableClass * __nullable'}}
+  ip = [object returnMe]; // expected-warning{{incompatible pointer types assigning to 'int *' from 'id __nullable'}}
+}
+// rdar://problem/19814852
+ at interface MultiProp
+ at property (nullable, copy) id a, b, c;
+ at property (nullable, copy) MultiProp *d, *(^e)(int);
+ at end
+
+void testMultiProp(MultiProp *foo) {
+  int *ip;
+  ip = foo.a; // expected-warning{{from 'id __nullable'}}
+  ip = foo.d; // expected-warning{{from 'MultiProp * __nullable'}}
+  ip = foo.e; // expected-error{{incompatible type 'MultiProp *(^ __nullable)(int)'}}
+}

Added: cfe/trunk/test/SemaObjC/nullable-weak-property.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/nullable-weak-property.m?rev=240154&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/nullable-weak-property.m (added)
+++ cfe/trunk/test/SemaObjC/nullable-weak-property.m Fri Jun 19 13:14:38 2015
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -Wnullable-to-nonnull-conversion %s -verify
+
+
+// rdar://19985330
+ at interface NSObject @end
+
+ at class NSFoo;
+void foo (NSFoo * __nonnull);
+
+ at interface NSBar : NSObject
+ at property(weak) NSFoo *property1;
+ at end
+
+ at implementation NSBar 
+- (void) Meth {
+   foo (self.property1); // expected-warning {{implicit conversion from nullable pointer 'NSFoo * __nullable' to non-nullable pointer type 'NSFoo * __nonnull'}}
+}
+ at end

Added: cfe/trunk/test/SemaObjC/override-nullability.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/override-nullability.m?rev=240154&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/override-nullability.m (added)
+++ cfe/trunk/test/SemaObjC/override-nullability.m Fri Jun 19 13:14:38 2015
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -fobjc-arc -fobjc-runtime-has-weak -Wnonnull %s -verify
+//rdar://19211059
+
+ at interface NSObject @end
+
+ at interface Base : NSObject
+- (nonnull id)bad:(nullable id)obj; // expected-note 2 {{previous declaration is here}}
+- (nullable id)notAsBad:(nonnull id)obj;
+ at end
+
+ at interface Sub : Base
+- (nullable id)bad:(nonnull id)obj; // expected-warning {{conflicting nullability specifier on return types, 'nullable' conflicts with existing specifier 'nonnull'}} \
+                                    // expected-warning {{conflicting nullability specifier on parameter types, 'nonnull' conflicts with existing specifier 'nullable'}}
+- (nonnull id)notAsBad:(nullable id)obj;
+ at end






More information about the cfe-commits mailing list