r240156 - Introduced pragmas for audited nullability regions.

Aaron Ballman aaron at aaronballman.com
Sat Jun 20 12:24:58 PDT 2015


On Fri, Jun 19, 2015 at 2:25 PM, Douglas Gregor <dgregor at apple.com> wrote:
> Author: dgregor
> Date: Fri Jun 19 13:25:57 2015
> New Revision: 240156
>
> URL: http://llvm.org/viewvc/llvm-project?rev=240156&view=rev
> Log:
> Introduced pragmas for audited nullability regions.
>
> Introduce the clang pragmas "assume_nonnull begin" and "assume_nonnull
> end" in which we make default assumptions about the nullability of many
> unannotated pointers:
>
>   - Single-level pointers are inferred to __nonnull
>   - NSError** in a (function or method) parameter list is inferred to
>     NSError * __nullable * __nullable.
>   - CFErrorRef * in a (function or method) parameter list is inferred
>     to CFErrorRef __nullable * __nullable.
>   - Other multi-level pointers are never inferred to anything.
>
> Implements rdar://problem/19191042.
>
> Added:
>     cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h   (with props)
>     cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-2.h   (with props)
>     cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-3.h   (with props)
>     cfe/trunk/test/SemaObjCXX/nullability-pragmas.mm
> Modified:
>     cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
>     cfe/trunk/include/clang/Lex/Preprocessor.h
>     cfe/trunk/include/clang/Parse/Parser.h
>     cfe/trunk/include/clang/Sema/DeclSpec.h
>     cfe/trunk/include/clang/Sema/Sema.h
>     cfe/trunk/lib/Lex/PPDirectives.cpp
>     cfe/trunk/lib/Lex/PPLexerChange.cpp
>     cfe/trunk/lib/Lex/PPMacroExpansion.cpp
>     cfe/trunk/lib/Lex/Pragma.cpp
>     cfe/trunk/lib/Parse/ParseObjc.cpp
>     cfe/trunk/lib/Sema/SemaExprObjC.cpp
>     cfe/trunk/lib/Sema/SemaObjCProperty.cpp
>     cfe/trunk/lib/Sema/SemaType.cpp
>     cfe/trunk/test/SemaObjC/arc-property-decl-attrs.m
>
> Modified: cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td (original)
> +++ cfe/trunk/include/clang/Basic/DiagnosticLexKinds.td Fri Jun 19 13:25:57 2015
> @@ -646,5 +646,20 @@ def warn_header_guard : Warning<
>    "%0 is used as a header guard here, followed by #define of a different macro">,
>    InGroup<DiagGroup<"header-guard">>;
>  def note_header_guard : Note<
> -  "%0 is defined here; did you mean %1?">;
> +  "%0 is defined here; did you mean %1?">;
> +
> +let CategoryName = "Nullability Issue" in {
> +
> +def err_pp_assume_nonnull_syntax : Error<"expected 'begin' or 'end'">;
> +def err_pp_double_begin_of_assume_nonnull : Error<
> +  "already inside '#pragma clang assume_nonnull'">;
> +def err_pp_unmatched_end_of_assume_nonnull : Error<
> +  "not currently inside '#pragma clang assume_nonnull'">;
> +def err_pp_include_in_assume_nonnull : Error<
> +  "cannot #include files inside '#pragma clang assume_nonnull'">;
> +def err_pp_eof_in_assume_nonnull : Error<
> +  "'#pragma clang assume_nonnull' was not ended within this file">;
> +
> +}
> +
>  }
>
> Modified: cfe/trunk/include/clang/Lex/Preprocessor.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Lex/Preprocessor.h?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Lex/Preprocessor.h (original)
> +++ cfe/trunk/include/clang/Lex/Preprocessor.h Fri Jun 19 13:25:57 2015
> @@ -256,6 +256,10 @@ class Preprocessor : public RefCountedBa
>    /// \#pragma clang arc_cf_code_audited begin.
>    SourceLocation PragmaARCCFCodeAuditedLoc;
>
> +  /// \brief The source location of the currently-active
> +  /// \#pragma clang assume_nonnull begin.
> +  SourceLocation PragmaAssumeNonNullLoc;
> +
>    /// \brief True if we hit the code-completion point.
>    bool CodeCompletionReached;
>
> @@ -1250,6 +1254,20 @@ public:
>      PragmaARCCFCodeAuditedLoc = Loc;
>    }
>
> +  /// \brief The location of the currently-active \#pragma clang
> +  /// assume_nonnull begin.
> +  ///
> +  /// Returns an invalid location if there is no such pragma active.
> +  SourceLocation getPragmaAssumeNonNullLoc() const {
> +    return PragmaAssumeNonNullLoc;
> +  }
> +
> +  /// \brief Set the location of the currently-active \#pragma clang
> +  /// assume_nonnull begin.  An invalid location ends the pragma.
> +  void setPragmaAssumeNonNullLoc(SourceLocation Loc) {
> +    PragmaAssumeNonNullLoc = Loc;
> +  }
> +
>    /// \brief Set the directory in which the main file should be considered
>    /// to have been found, if it is not a real file.
>    void setMainFileDir(const DirectoryEntry *Dir) {
>
> Modified: cfe/trunk/include/clang/Parse/Parser.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Parse/Parser.h (original)
> +++ cfe/trunk/include/clang/Parse/Parser.h Fri Jun 19 13:25:57 2015
> @@ -139,11 +139,6 @@ 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;
> @@ -308,9 +303,11 @@ public:
>      return true;
>    }
>
> -  /// Retrieve the underscored keyword (__nonnull, __nullable,
> -  /// __null_unspecified) that corresponds to the given nullability kind.
> -  IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability);
> +  /// Retrieve the underscored keyword (__nonnull, __nullable) that corresponds
> +  /// to the given nullability kind.
> +  IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability) {
> +    return Actions.getNullabilityKeyword(nullability);
> +  }
>
>  private:
>    //===--------------------------------------------------------------------===//
>
> Modified: cfe/trunk/include/clang/Sema/DeclSpec.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/DeclSpec.h?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/DeclSpec.h (original)
> +++ cfe/trunk/include/clang/Sema/DeclSpec.h Fri Jun 19 13:25:57 2015
> @@ -1650,7 +1650,13 @@ private:
>    bool InlineParamsUsed;
>
>    /// \brief true if the declaration is preceded by \c __extension__.
> -  bool Extension : 1;
> +  unsigned Extension : 1;
> +
> +  /// Indicates whether this is an Objective-C instance variable.
> +  unsigned ObjCIvar : 1;
> +
> +  /// Indicates whether this is an Objective-C 'weak' property.
> +  unsigned ObjCWeakProperty : 1;
>
>    /// \brief If this is the second or subsequent declarator in this declaration,
>    /// the location of the comma before this declarator.
> @@ -1669,7 +1675,8 @@ public:
>        GroupingParens(false), FunctionDefinition(FDK_Declaration),
>        Redeclaration(false),
>        Attrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr),
> -      InlineParamsUsed(false), Extension(false) {
> +      InlineParamsUsed(false), Extension(false), ObjCIvar(false),
> +      ObjCWeakProperty(false) {
>    }
>
>    ~Declarator() {
> @@ -1747,6 +1754,8 @@ public:
>      Attrs.clear();
>      AsmLabel = nullptr;
>      InlineParamsUsed = false;
> +    ObjCIvar = false;
> +    ObjCWeakProperty = false;
>      CommaLoc = SourceLocation();
>      EllipsisLoc = SourceLocation();
>    }
> @@ -2155,6 +2164,12 @@ public:
>    void setExtension(bool Val = true) { Extension = Val; }
>    bool getExtension() const { return Extension; }
>
> +  void setObjCIvar(bool Val = true) { ObjCIvar = Val; }
> +  bool isObjCIvar() const { return ObjCIvar; }
> +
> +  void setObjCWeakProperty(bool Val = true) { ObjCWeakProperty = Val; }
> +  bool isObjCWeakProperty() const { return ObjCWeakProperty; }
> +
>    void setInvalidType(bool Val = true) { InvalidType = Val; }
>    bool isInvalidType() const {
>      return InvalidType || DS.getTypeSpecType() == DeclSpec::TST_error;
>
> Modified: cfe/trunk/include/clang/Sema/Sema.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Sema/Sema.h (original)
> +++ cfe/trunk/include/clang/Sema/Sema.h Fri Jun 19 13:25:57 2015
> @@ -1157,6 +1157,16 @@ public:
>
>    bool CheckFunctionReturnType(QualType T, SourceLocation Loc);
>
> +  unsigned deduceWeakPropertyFromType(QualType T) {
> +    if ((getLangOpts().getGC() != LangOptions::NonGC &&
> +         T.isObjCGCWeak()) ||
> +        (getLangOpts().ObjCAutoRefCount &&
> +         T.getObjCLifetime() == Qualifiers::OCL_Weak))
> +        return ObjCDeclSpec::DQ_PR_weak;
> +    return 0;
> +  }
> +
> +
>    /// \brief Build a function type.
>    ///
>    /// This routine checks the function type according to C++ rules and
> @@ -8782,6 +8792,13 @@ private:
>    mutable IdentifierInfo *Ident_super;
>    mutable IdentifierInfo *Ident___float128;
>
> +  /// Nullability type specifiers.
> +  IdentifierInfo *Ident___nonnull = nullptr;
> +  IdentifierInfo *Ident___nullable = nullptr;
> +  IdentifierInfo *Ident___null_unspecified = nullptr;
> +
> +  IdentifierInfo *Ident_NSError = nullptr;
> +
>  protected:
>    friend class Parser;
>    friend class InitializationSequence;
> @@ -8790,6 +8807,15 @@ protected:
>    friend class ASTWriter;
>
>  public:
> +  /// Retrieve the keyword associated
> +  IdentifierInfo *getNullabilityKeyword(NullabilityKind nullability);
> +
> +  /// The struct behind the CFErrorRef pointer.
> +  RecordDecl *CFError = nullptr;
> +
> +  /// Retrieve the identifier "NSError".
> +  IdentifierInfo *getNSErrorIdent();
> +
>    /// \brief Retrieve the parser's current scope.
>    ///
>    /// This routine must only be used when it is certain that semantic analysis
>
> Modified: cfe/trunk/lib/Lex/PPDirectives.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPDirectives.cpp?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Lex/PPDirectives.cpp (original)
> +++ cfe/trunk/lib/Lex/PPDirectives.cpp Fri Jun 19 13:25:57 2015
> @@ -1575,6 +1575,15 @@ void Preprocessor::HandleIncludeDirectiv
>      PragmaARCCFCodeAuditedLoc = SourceLocation();
>    }
>
> +  // Complain about attempts to #include files in an assume-nonnull pragma.
> +  if (PragmaAssumeNonNullLoc.isValid()) {
> +    Diag(HashLoc, diag::err_pp_include_in_assume_nonnull);
> +    Diag(PragmaAssumeNonNullLoc, diag::note_pragma_entered_here);
> +
> +    // Immediately leave the pragma.
> +    PragmaAssumeNonNullLoc = SourceLocation();
> +  }
> +
>    if (HeaderInfo.HasIncludeAliasMap()) {
>      // Map the filename with the brackets still attached.  If the name doesn't
>      // map to anything, fall back on the filename we've already gotten the
>
> Modified: cfe/trunk/lib/Lex/PPLexerChange.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPLexerChange.cpp?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Lex/PPLexerChange.cpp (original)
> +++ cfe/trunk/lib/Lex/PPLexerChange.cpp Fri Jun 19 13:25:57 2015
> @@ -355,6 +355,17 @@ bool Preprocessor::HandleEndOfFile(Token
>      PragmaARCCFCodeAuditedLoc = SourceLocation();
>    }
>
> +  // Complain about reaching a true EOF within assume_nonnull.
> +  // We don't want to complain about reaching the end of a macro
> +  // instantiation or a _Pragma.
> +  if (PragmaAssumeNonNullLoc.isValid() &&
> +      !isEndOfMacro && !(CurLexer && CurLexer->Is_PragmaLexer)) {
> +    Diag(PragmaAssumeNonNullLoc, diag::err_pp_eof_in_assume_nonnull);
> +
> +    // Recover by leaving immediately.
> +    PragmaAssumeNonNullLoc = SourceLocation();
> +  }
> +
>    // If this is a #include'd file, pop it off the include stack and continue
>    // lexing the #includer file.
>    if (!IncludeMacroStack.empty()) {
>
> Modified: cfe/trunk/lib/Lex/PPMacroExpansion.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/PPMacroExpansion.cpp?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Lex/PPMacroExpansion.cpp (original)
> +++ cfe/trunk/lib/Lex/PPMacroExpansion.cpp Fri Jun 19 13:25:57 2015
> @@ -1052,6 +1052,7 @@ static bool HasFeature(const Preprocesso
>        .Case("address_sanitizer",
>              LangOpts.Sanitize.hasOneOf(SanitizerKind::Address |
>                                         SanitizerKind::KernelAddress))
> +      .Case("assume_nonnull", LangOpts.ObjC1 || LangOpts.GNUMode)
>        .Case("attribute_analyzer_noreturn", true)
>        .Case("attribute_availability", true)
>        .Case("attribute_availability_with_message", true)
>
> Modified: cfe/trunk/lib/Lex/Pragma.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Lex/Pragma.cpp?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Lex/Pragma.cpp (original)
> +++ cfe/trunk/lib/Lex/Pragma.cpp Fri Jun 19 13:25:57 2015
> @@ -1342,6 +1342,60 @@ struct PragmaARCCFCodeAuditedHandler : p
>    }
>  };
>
> +/// PragmaAssumeNonNullHandler -
> +///   \#pragma clang assume_nonnull begin/end
> +struct PragmaAssumeNonNullHandler : public PragmaHandler {
> +  PragmaAssumeNonNullHandler() : PragmaHandler("assume_nonnull") {}
> +  void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
> +                    Token &NameTok) override {
> +    SourceLocation Loc = NameTok.getLocation();
> +    bool IsBegin;
> +
> +    Token Tok;
> +
> +    // Lex the 'begin' or 'end'.
> +    PP.LexUnexpandedToken(Tok);
> +    const IdentifierInfo *BeginEnd = Tok.getIdentifierInfo();
> +    if (BeginEnd && BeginEnd->isStr("begin")) {
> +      IsBegin = true;

Elide braces (here and elsewhere).

> +    } else if (BeginEnd && BeginEnd->isStr("end")) {
> +      IsBegin = false;
> +    } else {
> +      PP.Diag(Tok.getLocation(), diag::err_pp_assume_nonnull_syntax);
> +      return;
> +    }
> +
> +    // Verify that this is followed by EOD.
> +    PP.LexUnexpandedToken(Tok);
> +    if (Tok.isNot(tok::eod))
> +      PP.Diag(Tok, diag::ext_pp_extra_tokens_at_eol) << "pragma";
> +
> +    // The start location of the active audit.
> +    SourceLocation BeginLoc = PP.getPragmaAssumeNonNullLoc();
> +
> +    // The start location we want after processing this.
> +    SourceLocation NewLoc;
> +
> +    if (IsBegin) {
> +      // Complain about attempts to re-enter an audit.
> +      if (BeginLoc.isValid()) {
> +        PP.Diag(Loc, diag::err_pp_double_begin_of_assume_nonnull);
> +        PP.Diag(BeginLoc, diag::note_pragma_entered_here);
> +      }
> +      NewLoc = Loc;
> +    } else {
> +      // Complain about attempts to leave an audit that doesn't exist.
> +      if (!BeginLoc.isValid()) {
> +        PP.Diag(Loc, diag::err_pp_unmatched_end_of_assume_nonnull);
> +        return;
> +      }
> +      NewLoc = SourceLocation();
> +    }
> +
> +    PP.setPragmaAssumeNonNullLoc(NewLoc);
> +  }
> +};
> +
>  /// \brief Handle "\#pragma region [...]"
>  ///
>  /// The syntax is
> @@ -1393,6 +1447,7 @@ void Preprocessor::RegisterBuiltinPragma
>    AddPragmaHandler("clang", new PragmaDependencyHandler());
>    AddPragmaHandler("clang", new PragmaDiagnosticHandler("clang"));
>    AddPragmaHandler("clang", new PragmaARCCFCodeAuditedHandler());
> +  AddPragmaHandler("clang", new PragmaAssumeNonNullHandler());
>
>    AddPragmaHandler("STDC", new PragmaSTDC_FENV_ACCESSHandler());
>    AddPragmaHandler("STDC", new PragmaSTDC_CX_LIMITED_RANGEHandler());
>
> Modified: cfe/trunk/lib/Parse/ParseObjc.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseObjc.cpp?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Parse/ParseObjc.cpp (original)
> +++ cfe/trunk/lib/Parse/ParseObjc.cpp Fri Jun 19 13:25:57 2015
> @@ -308,25 +308,6 @@ 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,
> @@ -1063,31 +1044,28 @@ ParsedType Parser::ParseObjCTypeName(Obj
>        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);
> +      // 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.
> +      // Map a nullability specifier to a context-sensitive keyword attribute.
> +      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();
> -      }
> +      TypeResult type = Actions.ActOnTypeName(getCurScope(), declarator);
> +      if (!type.isInvalid())
> +        Ty = type.get();
>      }
>    }
>
> @@ -1491,6 +1469,7 @@ void Parser::ParseObjCClassInstanceVaria
>      auto ObjCIvarCallback = [&](ParsingFieldDeclarator &FD) {
>        Actions.ActOnObjCContainerStartDefinition(interfaceDecl);
>        // Install the declarator into the interface decl.
> +      FD.D.setObjCIvar(true);
>        Decl *Field = Actions.ActOnIvar(
>            getCurScope(), FD.D.getDeclSpec().getSourceRange().getBegin(), FD.D,
>            FD.BitfieldSize, visibility);
>
> Modified: cfe/trunk/lib/Sema/SemaExprObjC.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprObjC.cpp?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaExprObjC.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaExprObjC.cpp Fri Jun 19 13:25:57 2015
> @@ -1231,6 +1231,10 @@ QualType Sema::getMessageSendResultType(
>                                                       isClassMessage,
>                                                       isSuperMessage);
>
> +  // If this is a class message, ignore the nullability of the receiver.
> +  if (isClassMessage)
> +    return resultType;
> +
>    // Map the nullability of the result into a table index.
>    unsigned receiverNullabilityIdx = 0;
>    if (auto nullability = ReceiverType->getNullability(Context))
>
> Modified: cfe/trunk/lib/Sema/SemaObjCProperty.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaObjCProperty.cpp?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaObjCProperty.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaObjCProperty.cpp Fri Jun 19 13:25:57 2015
> @@ -103,15 +103,6 @@ static void checkARCPropertyDecl(Sema &S
>      << propertyLifetime;
>  }
>
> -static unsigned deduceWeakPropertyFromType(Sema &S, QualType T) {
> -  if ((S.getLangOpts().getGC() != LangOptions::NonGC &&
> -       T.isObjCGCWeak()) ||
> -      (S.getLangOpts().ObjCAutoRefCount &&
> -       T.getObjCLifetime() == Qualifiers::OCL_Weak))
> -    return ObjCDeclSpec::DQ_PR_weak;
> -  return 0;
> -}
> -
>  /// \brief Check this Objective-C property against a property declared in the
>  /// given protocol.
>  static void
> @@ -146,9 +137,10 @@ Decl *Sema::ActOnProperty(Scope *S, Sour
>                            tok::ObjCKeywordKind MethodImplKind,
>                            DeclContext *lexicalDC) {
>    unsigned Attributes = ODS.getPropertyAttributes();
> +  FD.D.setObjCWeakProperty((Attributes & ObjCDeclSpec::DQ_PR_weak) != 0);
>    TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S);
>    QualType T = TSI->getType();
> -  Attributes |= deduceWeakPropertyFromType(*this, T);
> +  Attributes |= deduceWeakPropertyFromType(T);
>    bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) ||
>                        // default is readwrite!
>                        !(Attributes & ObjCDeclSpec::DQ_PR_readonly));
> @@ -433,7 +425,7 @@ Sema::HandlePropertyInClassExtension(Sco
>    if (isReadWrite && (PIkind & ObjCPropertyDecl::OBJC_PR_readonly)) {
>      PIkind &= ~ObjCPropertyDecl::OBJC_PR_readonly;
>      PIkind |= ObjCPropertyDecl::OBJC_PR_readwrite;
> -    PIkind |= deduceWeakPropertyFromType(*this, PIDecl->getType());
> +    PIkind |= deduceWeakPropertyFromType(PIDecl->getType());
>      unsigned ClassExtensionMemoryModel = getOwnershipRule(Attributes);
>      unsigned PrimaryClassMemoryModel = getOwnershipRule(PIkind);
>      if (PrimaryClassMemoryModel && ClassExtensionMemoryModel &&
> @@ -2293,8 +2285,7 @@ void Sema::CheckObjCPropertyAttributes(D
>        Attributes &= ~ObjCDeclSpec::DQ_PR_weak;
>    }
>
> -  if ((Attributes & ObjCDeclSpec::DQ_PR_weak) &&
> -      !(Attributes & ObjCDeclSpec::DQ_PR_readonly)) {
> +  if (Attributes & ObjCDeclSpec::DQ_PR_weak) {
>      // 'weak' and 'nonnull' are mutually exclusive.
>      if (auto nullability = PropertyTy->getNullability(Context)) {
>        if (*nullability == NullabilityKind::NonNull)
>
> Modified: cfe/trunk/lib/Sema/SemaType.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=240156&r1=240155&r2=240156&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Sema/SemaType.cpp (original)
> +++ cfe/trunk/lib/Sema/SemaType.cpp Fri Jun 19 13:25:57 2015
> @@ -25,6 +25,7 @@
>  #include "clang/Lex/Preprocessor.h"
>  #include "clang/Basic/PartialDiagnostic.h"
>  #include "clang/Basic/TargetInfo.h"
> +#include "clang/Lex/Preprocessor.h"
>  #include "clang/Parse/ParseDiagnostic.h"
>  #include "clang/Sema/DeclSpec.h"
>  #include "clang/Sema/DelayedDiagnostic.h"
> @@ -2553,6 +2554,211 @@ getCCForDeclaratorChunk(Sema &S, Declara
>    return CC;
>  }
>
> +namespace {
> +  /// A simple notion of pointer kinds, which matches up with the various
> +  /// pointer declarators.
> +  enum class SimplePointerKind {
> +    Pointer,
> +    BlockPointer,
> +    MemberPointer,
> +  };
> +}
> +
> +IdentifierInfo *Sema::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;
> +  }
> +}
> +
> +/// Retrieve the identifier "NSError".
> +IdentifierInfo *Sema::getNSErrorIdent() {
> +  if (!Ident_NSError)
> +    Ident_NSError = PP.getIdentifierInfo("NSError");
> +
> +  return Ident_NSError;
> +}
> +
> +/// Check whether there is a nullability attribute of any kind in the given
> +/// attribute list.
> +static bool hasNullabilityAttr(const AttributeList *attrs) {
> +  for (const AttributeList *attr = attrs; attr;
> +       attr = attr->getNext()) {
> +    if (attr->getKind() == AttributeList::AT_TypeNonNull ||
> +        attr->getKind() == AttributeList::AT_TypeNullable ||
> +        attr->getKind() == AttributeList::AT_TypeNullUnspecified)
> +      return true;
> +  }
> +
> +  return false;
> +}
> +
> +namespace {
> +  /// Describes the kind of a pointer a declarator describes.
> +  enum class PointerDeclaratorKind {
> +    // Not a pointer.
> +    NonPointer,
> +    // Single-level pointer.
> +    SingleLevelPointer,
> +    // Multi-level pointer (of any pointer kind).
> +    MultiLevelPointer,
> +    // CFErrorRef*
> +    CFErrorRefPointer,
> +    // NSError**
> +    NSErrorPointerPointer,
> +  };
> +}
> +
> +/// Classify the given declarator, whose type-specified is \c type, based on
> +/// what kind of pointer it refers to.
> +///
> +/// This is used to determine the default nullability.
> +static PointerDeclaratorKind classifyPointerDeclarator(Sema &S,
> +                                                       QualType type,
> +                                                       Declarator &declarator) {
> +  unsigned numNormalPointers = 0;
> +
> +  // For any dependent type, we consider it a non-pointer.
> +  if (type->isDependentType())
> +    return PointerDeclaratorKind::NonPointer;
> +
> +  // Look through the declarator chunks to identify pointers.
> +  for (unsigned i = 0, n = declarator.getNumTypeObjects(); i != n; ++i) {
> +    DeclaratorChunk &chunk = declarator.getTypeObject(i);
> +    switch (chunk.Kind) {
> +    case DeclaratorChunk::Array:
> +    case DeclaratorChunk::Function:
> +      break;
> +
> +    case DeclaratorChunk::BlockPointer:
> +    case DeclaratorChunk::MemberPointer:
> +      return numNormalPointers > 0 ? PointerDeclaratorKind::MultiLevelPointer
> +                                   : PointerDeclaratorKind::SingleLevelPointer;
> +
> +    case DeclaratorChunk::Paren:
> +    case DeclaratorChunk::Reference:
> +      continue;
> +
> +    case DeclaratorChunk::Pointer:
> +      ++numNormalPointers;
> +      if (numNormalPointers > 2)

Why > instead of >=?

> +        return PointerDeclaratorKind::MultiLevelPointer;
> +      continue;
> +    }
> +  }
> +
> +  // Then, dig into the type specifier itself.
> +  unsigned numTypeSpecifierPointers = 0;
> +  do {
> +    // Decompose normal pointers.
> +    if (auto ptrType = type->getAs<PointerType>()) {
> +      ++numNormalPointers;
> +
> +      if (numNormalPointers > 2)
> +        return PointerDeclaratorKind::MultiLevelPointer;

Same question here.

> +
> +      type = ptrType->getPointeeType();
> +      ++numTypeSpecifierPointers;
> +      continue;
> +    }
> +
> +    // Decompose block pointers.
> +    if (type->getAs<BlockPointerType>()) {
> +      return numNormalPointers > 0 ? PointerDeclaratorKind::MultiLevelPointer
> +                                   : PointerDeclaratorKind::SingleLevelPointer;
> +    }
> +
> +    // Decompose member pointers.
> +    if (type->getAs<MemberPointerType>()) {
> +      return numNormalPointers > 0 ? PointerDeclaratorKind::MultiLevelPointer
> +                                   : PointerDeclaratorKind::SingleLevelPointer;
> +    }
> +
> +    // Look at Objective-C object pointers.
> +    if (auto objcObjectPtr = type->getAs<ObjCObjectPointerType>()) {
> +      ++numNormalPointers;
> +      ++numTypeSpecifierPointers;
> +
> +      // If this is NSError**, report that.
> +      if (auto objcClassDecl = objcObjectPtr->getInterfaceDecl()) {
> +        if (objcClassDecl->getIdentifier() == S.getNSErrorIdent() &&
> +            numNormalPointers == 2 && numTypeSpecifierPointers < 2) {
> +          return PointerDeclaratorKind::NSErrorPointerPointer;
> +        }
> +      }
> +
> +      break;
> +    }
> +
> +    // Look at Objective-C class types.
> +    if (auto objcClass = type->getAs<ObjCInterfaceType>()) {
> +      if (objcClass->getInterface()->getIdentifier() == S.getNSErrorIdent()) {
> +        if (numNormalPointers == 2 && numTypeSpecifierPointers < 2)
> +          return PointerDeclaratorKind::NSErrorPointerPointer;;
> +      }
> +
> +      break;
> +    }
> +
> +    // If at this point we haven't seen a pointer, we won't see one.
> +    if (numNormalPointers == 0)
> +      return PointerDeclaratorKind::NonPointer;
> +
> +    if (auto recordType = type->getAs<RecordType>()) {
> +      RecordDecl *recordDecl = recordType->getDecl();
> +
> +      bool isCFError = false;
> +      if (S.CFError) {
> +        // If we already know about CFError, test it directly.
> +        isCFError = (S.CFError == recordDecl);
> +      } else {
> +        // Check whether this is CFError, which we identify based on its bridge
> +        // to NSError.
> +        if (recordDecl->getTagKind() == TTK_Struct && numNormalPointers > 0) {
> +          if (auto bridgeAttr = recordDecl->getAttr<ObjCBridgeAttr>()) {
> +            if (bridgeAttr->getBridgedType() == S.getNSErrorIdent()) {
> +              S.CFError = recordDecl;
> +              isCFError = true;
> +            }
> +          }
> +        }
> +      }
> +
> +      // If this is CFErrorRef*, report it as such.
> +      if (isCFError && numNormalPointers == 2 && numTypeSpecifierPointers < 2) {
> +        return PointerDeclaratorKind::CFErrorRefPointer;
> +      }
> +      break;
> +    }
> +
> +    break;
> +  } while (true);
> +
> +
> +  switch (numNormalPointers) {
> +  case 0:
> +    return PointerDeclaratorKind::NonPointer;
> +
> +  case 1:
> +    return PointerDeclaratorKind::SingleLevelPointer;
> +
> +  default:
> +    return PointerDeclaratorKind::MultiLevelPointer;
> +  }
> +}
> +
>  static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
>                                                  QualType declSpecType,
>                                                  TypeSourceInfo *TInfo) {
> @@ -2620,6 +2826,183 @@ static TypeSourceInfo *GetFullTypeForDec
>      }
>    }
>
> +  // Determine whether we should infer __nonnull on pointer types.
> +  Optional<NullabilityKind> inferNullability;
> +  bool inferNullabilityCS = false;
> +
> +  // Are we in an assume-nonnull region?
> +  bool inAssumeNonNullRegion = false;
> +  if (S.PP.getPragmaAssumeNonNullLoc().isValid() &&
> +      !state.getDeclarator().isObjCWeakProperty() &&
> +      !S.deduceWeakPropertyFromType(T)) {
> +    inAssumeNonNullRegion = true;
> +  }
> +
> +  // Whether to complain about missing nullability specifiers or not.
> +  enum {
> +    /// Never complain.
> +    CAMN_No,
> +    /// Complain on the inner pointers (but not the outermost
> +    /// pointer).
> +    CAMN_InnerPointers,
> +    /// Complain about any pointers that don't have nullability
> +    /// specified or inferred.
> +    CAMN_Yes
> +  } complainAboutMissingNullability = CAMN_No;
> +  unsigned NumPointersRemaining = 0;
> +
> +  if (IsTypedefName) {
> +    // For typedefs, we do not infer any nullability (the default),
> +    // and we only complain about missing nullability specifiers on
> +    // inner pointers.
> +    complainAboutMissingNullability = CAMN_InnerPointers;
> +
> +    if (T->canHaveNullability()) {
> +      ++NumPointersRemaining;
> +    }
> +
> +    for (unsigned i = 0, n = D.getNumTypeObjects(); i != n; ++i) {
> +      DeclaratorChunk &chunk = D.getTypeObject(i);
> +      switch (chunk.Kind) {
> +      case DeclaratorChunk::Array:
> +      case DeclaratorChunk::Function:
> +        break;
> +
> +      case DeclaratorChunk::BlockPointer:
> +      case DeclaratorChunk::MemberPointer:
> +        ++NumPointersRemaining;
> +        break;
> +
> +      case DeclaratorChunk::Paren:
> +      case DeclaratorChunk::Reference:
> +        continue;
> +
> +      case DeclaratorChunk::Pointer:
> +        ++NumPointersRemaining;
> +        continue;
> +      }
> +    }
> +  } else {
> +    bool isFunctionOrMethod = false;
> +    switch (auto context = state.getDeclarator().getContext()) {
> +    case Declarator::ObjCParameterContext:
> +    case Declarator::ObjCResultContext:
> +    case Declarator::PrototypeContext:
> +    case Declarator::TrailingReturnContext:
> +      isFunctionOrMethod = true;
> +      // fallthrough
> +
> +    case Declarator::MemberContext:
> +      if (state.getDeclarator().isObjCIvar() && !isFunctionOrMethod) {
> +        complainAboutMissingNullability = CAMN_No;
> +        break;
> +      }
> +      // fallthrough
> +
> +    case Declarator::FileContext:
> +    case Declarator::KNRTypeListContext:
> +      complainAboutMissingNullability = CAMN_Yes;
> +
> +      // Nullability inference depends on the type and declarator.
> +      switch (classifyPointerDeclarator(S, T, D)) {
> +      case PointerDeclaratorKind::NonPointer:
> +      case PointerDeclaratorKind::MultiLevelPointer:
> +        // Cannot infer nullability.
> +        break;
> +
> +      case PointerDeclaratorKind::SingleLevelPointer:
> +        // Infer __nonnull if we are in an assumes-nonnull region.
> +        if (inAssumeNonNullRegion) {
> +          inferNullability = NullabilityKind::NonNull;
> +          inferNullabilityCS = (context == Declarator::ObjCParameterContext ||
> +                                context == Declarator::ObjCResultContext);
> +        }
> +        break;
> +
> +      case PointerDeclaratorKind::CFErrorRefPointer:
> +      case PointerDeclaratorKind::NSErrorPointerPointer:
> +        // Within a function or method signature, infer __nullable at both
> +        // levels.
> +        if (isFunctionOrMethod && inAssumeNonNullRegion)
> +          inferNullability = NullabilityKind::Nullable;
> +        break;
> +      }
> +      break;
> +
> +    case Declarator::ConversionIdContext:
> +      complainAboutMissingNullability = CAMN_Yes;
> +      break;
> +
> +    case Declarator::AliasDeclContext:
> +    case Declarator::AliasTemplateContext:
> +    case Declarator::BlockContext:
> +    case Declarator::BlockLiteralContext:
> +    case Declarator::ConditionContext:
> +    case Declarator::CXXCatchContext:
> +    case Declarator::CXXNewContext:
> +    case Declarator::ForContext:
> +    case Declarator::LambdaExprContext:
> +    case Declarator::LambdaExprParameterContext:
> +    case Declarator::ObjCCatchContext:
> +    case Declarator::TemplateParamContext:
> +    case Declarator::TemplateTypeArgContext:
> +    case Declarator::TypeNameContext:
> +      // Don't infer in these contexts.
> +      break;
> +    }
> +  }
> +
> +  // Local function that checks the nullability for a given pointer declarator.
> +  // Returns true if __nonnull was inferred.
> +  auto inferPointerNullability = [&](SimplePointerKind pointerKind,
> +                                     SourceLocation pointerLoc,
> +                                     AttributeList *&attrs) -> AttributeList * {
> +    // We've seen a pointer.
> +    if (NumPointersRemaining > 0)
> +      --NumPointersRemaining;
> +
> +    // If a nullability attribute is present, there's nothing to do.
> +    if (hasNullabilityAttr(attrs))
> +      return nullptr;
> +
> +    // If we're supposed to infer nullability, do so now.
> +    if (inferNullability) {
> +      AttributeList *nullabilityAttr = state.getDeclarator().getAttributePool()
> +                                         .create(
> +                                           S.getNullabilityKeyword(
> +                                             *inferNullability),
> +                                           SourceRange(pointerLoc),
> +                                           nullptr, SourceLocation(),
> +                                           nullptr, 0,
> +                                           AttributeList::AS_Keyword);
> +      if (inferNullabilityCS)
> +        nullabilityAttr->setContextSensitiveKeywordAttribute();
> +
> +      spliceAttrIntoList(*nullabilityAttr, attrs);
> +      return nullabilityAttr;
> +    }
> +
> +    return nullptr;
> +  };
> +
> +  // If the type itself could have nullability but does not, infer pointer
> +  // nullability.
> +  if (T->canHaveNullability() && S.ActiveTemplateInstantiations.empty()) {
> +    SimplePointerKind pointerKind = SimplePointerKind::Pointer;
> +    if (T->isBlockPointerType())
> +      pointerKind = SimplePointerKind::BlockPointer;
> +    else if (T->isMemberPointerType())
> +      pointerKind = SimplePointerKind::MemberPointer;
> +
> +    if (auto *attr = inferPointerNullability(
> +                       pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(),
> +                       D.getMutableDeclSpec().getAttributes().getListRef())) {
> +      T = Context.getAttributedType(
> +            AttributedType::getNullabilityAttrKind(*inferNullability), T, T);
> +      attr->setUsedAsTypeAttr();
> +    }
> +  }
> +
>    // Walk the DeclTypeInfo, building the recursive type as we go.
>    // DeclTypeInfos are ordered from the identifier out, which is
>    // opposite of what we want :).
> @@ -2637,6 +3020,10 @@ static TypeSourceInfo *GetFullTypeForDec
>        if (!LangOpts.Blocks)
>          S.Diag(DeclType.Loc, diag::err_blocks_disable);
>
> +      // Handle pointer nullability.
> +      inferPointerNullability(SimplePointerKind::BlockPointer,
> +                              DeclType.Loc, DeclType.getAttrListRef());
> +
>        T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name);
>        if (DeclType.Cls.TypeQuals)
>          T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals);
> @@ -2649,6 +3036,11 @@ static TypeSourceInfo *GetFullTypeForDec
>          D.setInvalidType(true);
>          // Build the type anyway.
>        }
> +
> +      // Handle pointer nullability
> +      inferPointerNullability(SimplePointerKind::Pointer, DeclType.Loc,
> +                              DeclType.getAttrListRef());
> +
>        if (LangOpts.ObjC1 && T->getAs<ObjCObjectType>()) {
>          T = Context.getObjCObjectPointerType(T);
>          if (DeclType.Ptr.TypeQuals)
> @@ -3090,6 +3482,11 @@ static TypeSourceInfo *GetFullTypeForDec
>        // The scope spec must refer to a class, or be dependent.
>        CXXScopeSpec &SS = DeclType.Mem.Scope();
>        QualType ClsType;
> +
> +      // Handle pointer nullability.
> +      inferPointerNullability(SimplePointerKind::MemberPointer,
> +                              DeclType.Loc, DeclType.getAttrListRef());
> +
>        if (SS.isInvalid()) {
>          // Avoid emitting extra errors if we already errored on the scope.
>          D.setInvalidType(true);
> @@ -4614,20 +5011,6 @@ bool Sema::checkNullabilityTypeSpecifier
>    return false;
>  }
>
> -/// Check whether there is a nullability attribute of any kind in the given
> -/// attribute list.
> -static bool hasNullabilityAttr(const AttributeList *attrs) {
> -  for (const AttributeList *attr = attrs; attr;
> -       attr = attr->getNext()) {
> -    if (attr->getKind() == AttributeList::AT_TypeNonNull ||
> -        attr->getKind() == AttributeList::AT_TypeNullable ||
> -        attr->getKind() == AttributeList::AT_TypeNullUnspecified)
> -      return true;
> -  }
> -
> -  return false;
> -}
> -
>  /// Map a nullability attribute kind to a nullability kind.
>  static NullabilityKind mapNullabilityAttrKind(AttributeList::Kind kind) {
>    switch (kind) {
>
> 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=240156&r1=240155&r2=240156&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:25:57 2015
> @@ -80,10 +80,28 @@
>  @end
>
>  // rdar://20152386
> +// rdar://20383235
> +
>  @interface NSObject @end
>
> - at interface rdar20152386_2: NSObject
> +#pragma clang assume_nonnull begin
> + at interface I: NSObject
> + at property(nonatomic, weak) id delegate; // Do not warn, nullable is inferred.
> + at property(nonatomic, weak, readonly) id ROdelegate; // Do not warn, nullable is inferred.
> + at property(nonatomic, weak, nonnull) id NonNulldelete; // expected-error {{property attributes 'nonnull' and 'weak' are mutually exclusive}}
> + at property(nonatomic, weak, nullable) id Nullabledelete; // do not warn
> +
> +// strong cases.
> + at property(nonatomic, strong) id stdelegate; // Do not warn
> + at property(nonatomic, readonly) id stROdelegate; // Do not warn
> + at property(nonatomic, strong, nonnull) id stNonNulldelete; // Do not warn
> + at property(nonatomic, nullable) id stNullabledelete; // do not warn
> + at end
> +#pragma clang assume_nonnull end
> +
> + at interface J: NSObject
> + at property(nonatomic, weak) id ddd;   // Do not warn, nullable is inferred.
>  @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 property(nonatomic, weak, nonnull, readonly) id ROdelegate; // expected-error {{property attributes 'nonnull' and 'weak' are mutually exclusive}}
>  @end
>
>
> Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h?rev=240156&view=auto
> ==============================================================================
> --- cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h (added)
> +++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h Fri Jun 19 13:25:57 2015
> @@ -0,0 +1,98 @@
> +__attribute__((objc_root_class))
> + at interface NSError
> + at end
> +
> +__attribute__((objc_root_class))
> + at interface A
> + at end
> +
> +struct X { };
> +
> +void f1(int *x);
> +
> +typedef struct __attribute__((objc_bridge(NSError))) __CFError *CFErrorRef;
> +typedef NSError *NSErrorPtr;
> +typedef NSError **NSErrorPtrPtr;
> +typedef CFErrorRef *CFErrorRefPtr;
> +typedef int *int_ptr;
> +typedef A *A_ptr;
> +typedef int (^block_ptr)(int, int);
> +
> +#pragma clang assume_nonnull begin
> +
> +void f2(int *x);
> +void f3(A* obj);
> +void f4(int (^block)(int, int));
> +void f5(int_ptr x);
> +void f6(A_ptr obj);
> +void f7(int * __nullable x);
> +void f8(A * __nullable obj);
> +void f9(int X::* mem_ptr);
> +void f10(int (X::*mem_func)(int, int));
> +void f11(int X::* __nullable mem_ptr);
> +void f12(int (X::* __nullable mem_func)(int, int));
> +
> +int_ptr f13(void);
> +A *f14(void);
> +
> +int * __null_unspecified f15(void);
> +A * __null_unspecified f16(void);
> +void f17(CFErrorRef *error); // expected-note{{no known conversion from 'A * __nonnull' to 'CFErrorRef  __nullable * __nullable' (aka '__CFError **') for 1st argument}}
> +void f18(A **);
> +void f19(CFErrorRefPtr error);
> +
> +void g1(int (^)(int, int));
> +void g2(int (^ *bp)(int, int));
> +void g3(block_ptr *bp);
> +void g4(int (*fp)(int, int));
> +void g5(int (**fp)(int, int));
> +
> + at interface A(Pragmas1)
> ++ (instancetype)aWithA:(A *)a;
> +- (A *)method1:(A_ptr)ptr;
> +- (null_unspecified A *)method2;
> +- (void)method3:(NSError **)error; // expected-note{{passing argument to parameter 'error' here}}
> +- (void)method4:(NSErrorPtr *)error; // expected-note{{passing argument to parameter 'error' here}}
> +- (void)method5:(NSErrorPtrPtr)error;
> +
> + at property A *aProp;
> + at property NSError **anError;
> + at end
> +
> +int *global_int_ptr;
> +
> +// typedefs not inferred __nonnull
> +typedef int *int_ptr_2;
> +
> +typedef int *
> +            *int_ptr_ptr;
> +
> +static inline void f30(void) {
> +  float *fp = global_int_ptr; // expected-error{{cannot initialize a variable of type 'float *' with an lvalue of type 'int * __nonnull'}}
> +
> +  int_ptr_2 ip2;
> +  float *fp2 = ip2; // expected-error{{cannot initialize a variable of type 'float *' with an lvalue of type 'int_ptr_2' (aka 'int *')}}
> +
> +  int_ptr_ptr ipp;
> +  float *fp3 = ipp; // expected-error{{lvalue of type 'int_ptr_ptr' (aka 'int **')}}
> +}
> +
> + at interface AA : A {
> + at public
> +  id ivar1;
> +  __nonnull id ivar2;
> +}
> + at end
> +
> +#pragma clang assume_nonnull end
> +
> +void f20(A *a);
> +void f21(int_ptr x);
> +void f22(A_ptr y);
> +void f23(int_ptr __nullable x);
> +void f24(A_ptr __nullable y);
> +void f25(int_ptr_2 x);
> +
> + at interface A(OutsidePragmas1)
> ++ (instancetype)aWithInt:(int)value;
> + at end
>
> Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h
> ------------------------------------------------------------------------------
>     svn:keywords = Id
>
> Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-1.h
> ------------------------------------------------------------------------------
>     svn:mime-type = text/plain
>
> Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-2.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-2.h?rev=240156&view=auto
> ==============================================================================
> --- cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-2.h (added)
> +++ cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-2.h Fri Jun 19 13:25:57 2015
> @@ -0,0 +1,12 @@
> +#pragma clang assume_nonnull start // expected-error{{expected 'begin' or 'end'}}
> +
> +#pragma clang assume_nonnull begin // expected-note{{#pragma entered here}}
> +
> +#include "nullability-pragmas-3.h" // expected-error{{cannot #include files inside '#pragma clang assume_nonnull'}}
> +
> +#pragma clang assume_nonnull begin // expected-note{{#pragma entered here}}
> +#pragma clang assume_nonnull begin // expected-error{{already inside '#pragma clang assume_nonnull'}}
> +#pragma clang assume_nonnull end
> +
> +#pragma clang assume_nonnull begin // expected-error{{'#pragma clang assume_nonnull' was not ended within this file}}
> +
>
> Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-2.h
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-2.h
> ------------------------------------------------------------------------------
>     svn:keywords = Id
>
> Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-2.h
> ------------------------------------------------------------------------------
>     svn:mime-type = text/plain
>
> Added: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-3.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-3.h?rev=240156&view=auto
> ==============================================================================
>     (empty)
>
> Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-3.h
> ------------------------------------------------------------------------------
>     svn:eol-style = native
>
> Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-3.h
> ------------------------------------------------------------------------------
>     svn:keywords = Id
>
> Propchange: cfe/trunk/test/SemaObjCXX/Inputs/nullability-pragmas-3.h
> ------------------------------------------------------------------------------
>     svn:mime-type = text/plain
>
> Added: cfe/trunk/test/SemaObjCXX/nullability-pragmas.mm
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjCXX/nullability-pragmas.mm?rev=240156&view=auto
> ==============================================================================
> --- cfe/trunk/test/SemaObjCXX/nullability-pragmas.mm (added)
> +++ cfe/trunk/test/SemaObjCXX/nullability-pragmas.mm Fri Jun 19 13:25:57 2015
> @@ -0,0 +1,41 @@
> +// RUN: %clang_cc1 -fsyntax-only -fblocks -I %S/Inputs %s -verify
> +
> +#include "nullability-pragmas-1.h"
> +#include "nullability-pragmas-2.h"
> +
> +#if !__has_feature(assume_nonnull)
> +#  error assume_nonnull feature is not set
> +#endif
> +
> +void test_pragmas_1(A * __nonnull a, AA * __nonnull aa) {
> +  f1(0); // okay: no nullability annotations
> +  f2(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
> +  f3(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
> +  f4(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
> +  f5(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
> +  f6(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
> +  f7(0); // okay
> +  f8(0); // okay
> +  f9(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
> +  f10(0); // expected-warning{{null passed to a callee that requires a non-null argument}}
> +  f11(0); // okay
> +  f12(0); // okay
> +  [a method1:0]; // expected-warning{{null passed to a callee that requires a non-null argument}}
> +
> +  f17(a); // expected-error{{no matching function for call to 'f17'}}
> +  [a method3: a]; // expected-error{{cannot initialize a parameter of type 'NSError * __nullable * __nullable' with an lvalue of type 'A * __nonnull'}}
> +  [a method4: a]; // expected-error{{cannot initialize a parameter of type 'NSErrorPtr  __nullable * __nullable' (aka 'NSError **') with an lvalue of type 'A * __nonnull'}}
> +
> +  float *ptr;
> +  ptr = f13(); // expected-error{{assigning to 'float *' from incompatible type 'int_ptr __nonnull' (aka 'int *')}}
> +  ptr = f14(); // expected-error{{assigning to 'float *' from incompatible type 'A * __nonnull'}}
> +  ptr = [a method1:a]; // expected-error{{assigning to 'float *' from incompatible type 'A * __nonnull'}}
> +  ptr = a.aProp; // expected-error{{assigning to 'float *' from incompatible type 'A * __nonnull'}}
> +  ptr = global_int_ptr; // expected-error{{assigning to 'float *' from incompatible type 'int * __nonnull'}}
> +  ptr = f15(); // expected-error{{assigning to 'float *' from incompatible type 'int * __null_unspecified'}}
> +  ptr = f16(); // expected-error{{assigning to 'float *' from incompatible type 'A * __null_unspecified'}}
> +  ptr = [a method2]; // expected-error{{assigning to 'float *' from incompatible type 'A * __null_unspecified'}}
> +
> +  ptr = aa->ivar1; // expected-error{{from incompatible type 'id'}}
> +  ptr = aa->ivar2; // expected-error{{from incompatible type 'id __nonnull'}}
> +}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

~Aaron



More information about the cfe-commits mailing list