r240154 - Extend type nullability qualifiers for Objective-C.

Nico Weber thakis at chromium.org
Sat Jun 20 14:02:57 PDT 2015


On Sat, Jun 20, 2015 at 12:04 PM, Aaron Ballman <aaron at aaronballman.com>
wrote:

> On Fri, Jun 19, 2015 at 2:14 PM, Douglas Gregor <dgregor at apple.com> wrote:
> > 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â€
>
> Non-ASCII characters in the comments.
>
> > +        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â€
>
> Non-ASCII characters in the comments.
>

(chapuni fixed the two non-ASCII lines in r240211)


>
> > +        return (*SuperTnullability == NullabilityKind::Nullable &&
> > +                *SubTnullability == NullabilityKind::NonNull);
> > +      }
> > +    }
> > +    return true;
>
> This appears to be one of the few functions that care about the
> optionality of getNullability(). I find the dereferences sprinkled all
> over to be really distracting and kind of ugly. Is there a better
> approach we could use (even if it's a different code pattern when
> dealing with optional) so that we don't have to stare at stars all day
> long?
>
> > +  }
> > +
> >    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;
>
> This is more expensive than you might think since the bit field will
> now be 33 bits.
>
> > +
> >    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);
> > +    }
>
> Elide braces (here and elsewhere).
>
> > +  } 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
> >
> >
> >
> > _______________________________________________
> > cfe-commits mailing list
> > cfe-commits at cs.uiuc.edu
> > http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
> ~Aaron
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150620/acb16d7a/attachment.html>


More information about the cfe-commits mailing list