Author: epilk Date: Tue Oct 18 10:26:43 2016 New Revision: 284486 URL: http://llvm.org/viewvc/llvm-project?rev=284486&view=rev Log: Revert r284265 "[Sema] Refactor context checking for availability diagnostics"
This has a bug in it, pointed out by Bob Wilson! Modified: cfe/trunk/include/clang/Sema/Sema.h cfe/trunk/lib/Sema/SemaDecl.cpp cfe/trunk/lib/Sema/SemaDeclAttr.cpp cfe/trunk/lib/Sema/SemaExpr.cpp cfe/trunk/test/SemaObjC/class-unavail-warning.m Modified: cfe/trunk/include/clang/Sema/Sema.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=284486&r1=284485&r2=284486&view=diff ============================================================================== --- cfe/trunk/include/clang/Sema/Sema.h (original) +++ cfe/trunk/include/clang/Sema/Sema.h Tue Oct 18 10:26:43 2016 @@ -9890,16 +9890,23 @@ public: return OriginalLexicalContext ? OriginalLexicalContext : CurContext; } + AvailabilityResult getCurContextAvailability() const; + + /// \brief Get the verison that this context implies. + /// For instance, a method in an interface that is annotated with an + /// availability attribuite effectively has the availability of the interface. + VersionTuple getVersionForDecl(const Decl *Ctx) const; + /// \brief The diagnostic we should emit for \c D, or \c AR_Available. /// /// \param D The declaration to check. Note that this may be altered to point /// to another declaration that \c D gets it's availability from. i.e., we /// walk the list of typedefs to find an availability attribute. /// - /// \param Message If non-null, this will be populated with the message from - /// the availability attribute that is selected. - AvailabilityResult ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, - std::string *Message); + /// \param ContextVersion The version to compare availability against. + AvailabilityResult + ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, VersionTuple ContextVersion, + std::string *Message); const DeclContext *getCurObjCLexicalContext() const { const DeclContext *DC = getCurLexicalContext(); Modified: cfe/trunk/lib/Sema/SemaDecl.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDecl.cpp?rev=284486&r1=284485&r2=284486&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp (original) +++ cfe/trunk/lib/Sema/SemaDecl.cpp Tue Oct 18 10:26:43 2016 @@ -15628,3 +15628,29 @@ void Sema::ActOnPragmaWeakAlias(Identifi Decl *Sema::getObjCDeclContext() const { return (dyn_cast_or_null<ObjCContainerDecl>(CurContext)); } + +AvailabilityResult Sema::getCurContextAvailability() const { + const Decl *D = cast_or_null<Decl>(getCurObjCLexicalContext()); + if (!D) + return AR_Available; + + // If we are within an Objective-C method, we should consult + // both the availability of the method as well as the + // enclosing class. If the class is (say) deprecated, + // the entire method is considered deprecated from the + // purpose of checking if the current context is deprecated. + if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + AvailabilityResult R = MD->getAvailability(); + if (R != AR_Available) + return R; + D = MD->getClassInterface(); + } + // If we are within an Objective-c @implementation, it + // gets the same availability context as the @interface. + else if (const ObjCImplementationDecl *ID = + dyn_cast<ObjCImplementationDecl>(D)) { + D = ID->getClassInterface(); + } + // Recover from user error. + return D ? D->getAvailability() : AR_Available; +} Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=284486&r1=284485&r2=284486&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original) +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Tue Oct 18 10:26:43 2016 @@ -6327,6 +6327,30 @@ static void handleDelayedForbiddenType(S diag.Triggered = true; } +static bool isDeclDeprecated(Decl *D) { + do { + if (D->isDeprecated()) + return true; + // A category implicitly has the availability of the interface. + if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) + if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) + return Interface->isDeprecated(); + } while ((D = cast_or_null<Decl>(D->getDeclContext()))); + return false; +} + +static bool isDeclUnavailable(Decl *D) { + do { + if (D->isUnavailable()) + return true; + // A category implicitly has the availability of the interface. + if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) + if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) + return Interface->isUnavailable(); + } while ((D = cast_or_null<Decl>(D->getDeclContext()))); + return false; +} + static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, const Decl *D) { // Check each AvailabilityAttr to find the one for this platform. @@ -6355,49 +6379,6 @@ static const AvailabilityAttr *getAttrFo return nullptr; } -/// \brief whether we should emit a diagnostic for \c K and \c DeclVersion in -/// the context of \c Ctx. For example, we should emit an unavailable diagnostic -/// in a deprecated context, but not the other way around. -static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, - VersionTuple DeclVersion, - Decl *Ctx) { - assert(K != AR_Available && "Expected an unavailable declaration here!"); - - // Checks if we should emit the availability diagnostic in the context of C. - auto CheckContext = [&](const Decl *C) { - if (K == AR_NotYetIntroduced) { - if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C)) - if (AA->getIntroduced() >= DeclVersion) - return true; - } else if (K == AR_Deprecated) - if (C->isDeprecated()) - return true; - - if (C->isUnavailable()) - return true; - return false; - }; - - do { - if (CheckContext(Ctx)) - return false; - - // An implementation implicitly has the availability of the interface. - if (auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) { - if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) - if (CheckContext(Interface)) - return false; - } - // A category implicitly has the availability of the interface. - else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx)) - if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) - if (CheckContext(Interface)) - return false; - } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext()))); - - return true; -} - static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, @@ -6414,15 +6395,11 @@ static void DoEmitAvailabilityWarning(Se // Matches diag::note_availability_specified_here. unsigned available_here_select_kind; - VersionTuple DeclVersion; - if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, D)) - DeclVersion = AA->getIntroduced(); - - if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) - return; - + // Don't warn if our current context is deprecated or unavailable. switch (K) { case AR_Deprecated: + if (isDeclDeprecated(Ctx) || isDeclUnavailable(Ctx)) + return; diag = !ObjCPropertyAccess ? diag::warn_deprecated : diag::warn_property_method_deprecated; diag_message = diag::warn_deprecated_message; @@ -6432,6 +6409,8 @@ static void DoEmitAvailabilityWarning(Se break; case AR_Unavailable: + if (isDeclUnavailable(Ctx)) + return; diag = !ObjCPropertyAccess ? diag::err_unavailable : diag::err_property_method_unavailable; diag_message = diag::err_unavailable_message; @@ -6646,6 +6625,29 @@ void Sema::EmitAvailabilityWarning(Avail ObjCProperty, ObjCPropertyAccess); } +VersionTuple Sema::getVersionForDecl(const Decl *D) const { + assert(D && "Expected a declaration here!"); + + VersionTuple DeclVersion; + if (const auto *AA = getAttrForPlatform(getASTContext(), D)) + DeclVersion = AA->getIntroduced(); + + const ObjCInterfaceDecl *Interface = nullptr; + + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) + Interface = MD->getClassInterface(); + else if (const auto *ID = dyn_cast<ObjCImplementationDecl>(D)) + Interface = ID->getClassInterface(); + + if (Interface) { + if (const auto *AA = getAttrForPlatform(getASTContext(), Interface)) + if (AA->getIntroduced() > DeclVersion) + DeclVersion = AA->getIntroduced(); + } + + return std::max(DeclVersion, Context.getTargetInfo().getPlatformMinVersion()); +} + namespace { /// \brief This class implements -Wunguarded-availability. @@ -6659,7 +6661,6 @@ class DiagnoseUnguardedAvailability typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base; Sema &SemaRef; - Decl *Ctx; /// Stack of potentially nested 'if (@available(...))'s. SmallVector<VersionTuple, 8> AvailabilityStack; @@ -6667,10 +6668,9 @@ class DiagnoseUnguardedAvailability void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range); public: - DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx) - : SemaRef(SemaRef), Ctx(Ctx) { - AvailabilityStack.push_back( - SemaRef.Context.getTargetInfo().getPlatformMinVersion()); + DiagnoseUnguardedAvailability(Sema &SemaRef, VersionTuple BaseVersion) + : SemaRef(SemaRef) { + AvailabilityStack.push_back(BaseVersion); } void IssueDiagnostics(Stmt *S) { TraverseStmt(S); } @@ -6703,8 +6703,8 @@ void DiagnoseUnguardedAvailability::Diag NamedDecl *D, SourceRange Range) { VersionTuple ContextVersion = AvailabilityStack.back(); - if (AvailabilityResult Result = - SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr)) { + if (AvailabilityResult Result = SemaRef.ShouldDiagnoseAvailabilityOfDecl( + D, ContextVersion, nullptr)) { // All other diagnostic kinds have already been handled in // DiagnoseAvailabilityOfDecl. if (Result != AR_NotYetIntroduced) @@ -6713,14 +6713,6 @@ void DiagnoseUnguardedAvailability::Diag const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), D); VersionTuple Introduced = AA->getIntroduced(); - if (ContextVersion >= Introduced) - return; - - // If the context of this function is less available than D, we should not - // emit a diagnostic. - if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx)) - return; - SemaRef.Diag(Range.getBegin(), diag::warn_unguarded_availability) << Range << D << AvailabilityAttr::getPrettyPlatformName( @@ -6795,5 +6787,6 @@ void Sema::DiagnoseUnguardedAvailability assert(Body && "Need a body here!"); - DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body); + VersionTuple BaseVersion = getVersionForDecl(D); + DiagnoseUnguardedAvailability(*this, BaseVersion).IssueDiagnostics(Body); } Modified: cfe/trunk/lib/Sema/SemaExpr.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=284486&r1=284485&r2=284486&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp (original) +++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Oct 18 10:26:43 2016 @@ -103,9 +103,9 @@ static bool HasRedeclarationWithoutAvail return false; } -AvailabilityResult -Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) { - AvailabilityResult Result = D->getAvailability(Message); +AvailabilityResult Sema::ShouldDiagnoseAvailabilityOfDecl( + NamedDecl *&D, VersionTuple ContextVersion, std::string *Message) { + AvailabilityResult Result = D->getAvailability(Message, ContextVersion); // For typedefs, if the typedef declaration appears available look // to the underlying type to see if it is more restrictive. @@ -113,7 +113,7 @@ Sema::ShouldDiagnoseAvailabilityOfDecl(N if (Result == AR_Available) { if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { D = TT->getDecl(); - Result = D->getAvailability(Message); + Result = D->getAvailability(Message, ContextVersion); continue; } } @@ -124,7 +124,7 @@ Sema::ShouldDiagnoseAvailabilityOfDecl(N if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); - Result = D->getAvailability(Message); + Result = D->getAvailability(Message, ContextVersion); } } @@ -132,10 +132,18 @@ Sema::ShouldDiagnoseAvailabilityOfDecl(N if (Result == AR_Available) { const DeclContext *DC = ECD->getDeclContext(); if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC)) - Result = TheEnumDecl->getAvailability(Message); + Result = TheEnumDecl->getAvailability(Message, ContextVersion); } - if (Result == AR_NotYetIntroduced) { + switch (Result) { + case AR_Available: + return Result; + + case AR_Unavailable: + case AR_Deprecated: + return getCurContextAvailability() != Result ? Result : AR_Available; + + case AR_NotYetIntroduced: { // Don't do this for enums, they can't be redeclared. if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D)) return AR_Available; @@ -158,18 +166,23 @@ Sema::ShouldDiagnoseAvailabilityOfDecl(N return Warn ? AR_NotYetIntroduced : AR_Available; } - - return Result; + } + llvm_unreachable("Unknown availability result!"); } static void DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, bool ObjCPropertyAccess) { + VersionTuple ContextVersion; + if (const DeclContext *DC = S.getCurObjCLexicalContext()) + ContextVersion = S.getVersionForDecl(cast<Decl>(DC)); + std::string Message; - // See if this declaration is unavailable, deprecated, or partial. + // See if this declaration is unavailable, deprecated, or partial in the + // current context. if (AvailabilityResult Result = - S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) { + S.ShouldDiagnoseAvailabilityOfDecl(D, ContextVersion, &Message)) { if (Result == AR_NotYetIntroduced && S.getCurFunctionOrMethodDecl()) { S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true; @@ -179,7 +192,8 @@ DiagnoseAvailabilityOfDecl(Sema &S, Name const ObjCPropertyDecl *ObjCPDecl = nullptr; if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { - AvailabilityResult PDeclResult = PD->getAvailability(nullptr); + AvailabilityResult PDeclResult = + PD->getAvailability(nullptr, ContextVersion); if (PDeclResult == Result) ObjCPDecl = PD; } Modified: cfe/trunk/test/SemaObjC/class-unavail-warning.m URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/class-unavail-warning.m?rev=284486&r1=284485&r2=284486&view=diff ============================================================================== --- cfe/trunk/test/SemaObjC/class-unavail-warning.m (original) +++ cfe/trunk/test/SemaObjC/class-unavail-warning.m Tue Oct 18 10:26:43 2016 @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -fblocks -triple x86_64-apple-darwin10 -verify %s +// RUN: %clang_cc1 -fsyntax-only -triple x86_64-apple-darwin10 -verify %s // rdar://9092208 __attribute__((unavailable("not available"))) @@ -98,19 +98,3 @@ UNAVAILABLE @end @interface UnavailSub(cat)<SomeProto> // no error @end - -int unavail_global UNAVAILABLE; - -UNAVAILABLE __attribute__((objc_root_class)) -@interface TestAttrContext --meth; -@end - -@implementation TestAttrContext --meth { - unavail_global = 2; // no warn - (void) ^{ - unavail_global = 4; // no warn - }; -} -@end _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits