r240156 - Introduced pragmas for audited nullability regions.

Douglas Gregor dgregor at apple.com
Mon Jun 22 11:15:43 PDT 2015


> On Jun 20, 2015, at 12:24 PM, Aaron Ballman <aaron at aaronballman.com> wrote:
> 
> On Fri, Jun 19, 2015 at 2:25 PM, Douglas Gregor <dgregor at apple.com <mailto: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).

FWIW, I find it hideous to elide braces in some parts of an if-else chain and not others.

> 
>> +
>> +/// 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 >=?

Because of the way we deal with the type-specifier being a pointer (via a typedef), below.

	- Doug

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20150622/e4a0051d/attachment.html>


More information about the cfe-commits mailing list