r240156 - Introduced pragmas for audited nullability regions.

Douglas Gregor dgregor at apple.com
Fri Jun 19 11:25:58 PDT 2015


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;
+    } 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)
+        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;
+
+      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'}}
+}





More information about the cfe-commits mailing list