erik.pilkington created this revision. erik.pilkington added a reviewer: manmanren. erik.pilkington added a subscriber: cfe-commits.
This patch removes the enum `Sema::AvailabilityDiagnostic`, which is redundant with `clang::AvailabilityResult`, and pulls out a function, `ShouldDiagnoseAvailabiltyOfDecl` from `DiagnoseAvailabiltyOfDecl`. This is so we can call `ShouldDiagnoseAvailabilityOfDecl` when emitting `-Wunguarded-availabilty`, which is done after Sema of a function. This patch was originally part of https://reviews.llvm.org/D23003, but it was suggested that I separate it out. https://reviews.llvm.org/D23221 Files: include/clang/Sema/DelayedDiagnostic.h include/clang/Sema/Sema.h lib/Sema/DelayedDiagnostic.cpp lib/Sema/SemaDeclAttr.cpp lib/Sema/SemaExpr.cpp
Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -103,108 +103,99 @@ return false; } -static AvailabilityResult -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)); - - // See if this declaration is unavailable, deprecated, or partial in the - // current context. - std::string Message; - AvailabilityResult Result = D->getAvailability(&Message, ContextVersion); +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. while (const TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) { if (Result == AR_Available) { if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { D = TT->getDecl(); - Result = D->getAvailability(&Message, ContextVersion); + Result = D->getAvailability(Message, ContextVersion); continue; } } break; } - + // Forward class declarations get their attributes from their definition. if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); - Result = D->getAvailability(&Message, ContextVersion); + Result = D->getAvailability(Message, ContextVersion); } } if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) if (Result == AR_Available) { const DeclContext *DC = ECD->getDeclContext(); if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC)) - Result = TheEnumDecl->getAvailability(&Message, ContextVersion); + Result = TheEnumDecl->getAvailability(Message, ContextVersion); } - const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (Result == AR_Deprecated || Result == AR_Unavailable || - 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; + + bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited(); + // Objective-C method declarations in categories are not modelled as + // redeclarations, so manually look for a redeclaration in a category + // if necessary. + if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D)) + Warn = false; + // In general, D will point to the most recent redeclaration. However, + // for `@class A;` decls, this isn't true -- manually go through the + // redecl chain in that case. + if (Warn && isa<ObjCInterfaceDecl>(D)) + for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; + Redecl = Redecl->getPreviousDecl()) + if (!Redecl->hasAttr<AvailabilityAttr>() || + Redecl->getAttr<AvailabilityAttr>()->isInherited()) + Warn = false; + + return Warn ? AR_NotYetIntroduced : AR_Available; + } + } +} + +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 in the + // current context. + if (AvailabilityResult Result = + S.ShouldDiagnoseAvailabilityOfDecl(D, ContextVersion, &Message)) { + + const ObjCPropertyDecl *ObjCPDecl = nullptr; if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { AvailabilityResult PDeclResult = PD->getAvailability(nullptr, ContextVersion); if (PDeclResult == Result) ObjCPDecl = PD; } } - } - - switch (Result) { - case AR_Available: - break; - - case AR_Deprecated: - if (S.getCurContextAvailability() != AR_Deprecated) - S.EmitAvailabilityWarning(Sema::AD_Deprecation, - D, Message, Loc, UnknownObjCClass, ObjCPDecl, - ObjCPropertyAccess); - break; - - case AR_NotYetIntroduced: { - // Don't do this for enums, they can't be redeclared. - if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D)) - break; - - bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited(); - // Objective-C method declarations in categories are not modelled as - // redeclarations, so manually look for a redeclaration in a category - // if necessary. - if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D)) - Warn = false; - // In general, D will point to the most recent redeclaration. However, - // for `@class A;` decls, this isn't true -- manually go through the - // redecl chain in that case. - if (Warn && isa<ObjCInterfaceDecl>(D)) - for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; - Redecl = Redecl->getPreviousDecl()) - if (!Redecl->hasAttr<AvailabilityAttr>() || - Redecl->getAttr<AvailabilityAttr>()->isInherited()) - Warn = false; - - if (Warn) - S.EmitAvailabilityWarning(Sema::AD_Partial, D, Message, Loc, - UnknownObjCClass, ObjCPDecl, - ObjCPropertyAccess); - break; - } - - case AR_Unavailable: - if (S.getCurContextAvailability() != AR_Unavailable) - S.EmitAvailabilityWarning(Sema::AD_Unavailable, - D, Message, Loc, UnknownObjCClass, ObjCPDecl, - ObjCPropertyAccess); - break; - } - return Result; + S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass, + ObjCPDecl, ObjCPropertyAccess); + } } /// \brief Emit a note explaining that this function is deleted. Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -6246,7 +6246,7 @@ return nullptr; } -static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, +static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, @@ -6264,7 +6264,7 @@ // Don't warn if our current context is deprecated or unavailable. switch (K) { - case Sema::AD_Deprecation: + case AR_Deprecated: if (isDeclDeprecated(Ctx) || isDeclUnavailable(Ctx)) return; diag = !ObjCPropertyAccess ? diag::warn_deprecated @@ -6275,7 +6275,7 @@ available_here_select_kind = /* deprecated */ 2; break; - case Sema::AD_Unavailable: + case AR_Unavailable: if (isDeclUnavailable(Ctx)) return; diag = !ObjCPropertyAccess ? diag::err_unavailable @@ -6329,18 +6329,21 @@ } break; - case Sema::AD_Partial: + case AR_NotYetIntroduced: diag = diag::warn_partial_availability; diag_message = diag::warn_partial_message; diag_fwdclass_message = diag::warn_partial_fwdclass_message; property_note_select = /* partial */ 2; available_here_select_kind = /* partial */ 3; break; + + case AR_Available: + llvm_unreachable("Warning for availability of available declaration?"); } CharSourceRange UseRange; StringRef Replacement; - if (K == Sema::AD_Deprecation) { + if (K == AR_Deprecated) { if (auto attr = D->getAttr<DeprecatedAttr>()) Replacement = attr->getReplacement(); if (auto attr = getAttrForPlatform(S.Context, D)) @@ -6393,20 +6396,20 @@ S.Diag(D->getLocation(), diag_available_here) << D << available_here_select_kind; - if (K == Sema::AD_Partial) + if (K == AR_NotYetIntroduced) S.Diag(Loc, diag::note_partial_availability_silence) << D; } static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, Decl *Ctx) { assert(DD.Kind == DelayedDiagnostic::Deprecation || DD.Kind == DelayedDiagnostic::Unavailable); - Sema::AvailabilityDiagnostic AD = DD.Kind == DelayedDiagnostic::Deprecation - ? Sema::AD_Deprecation - : Sema::AD_Unavailable; + AvailabilityResult AR = DD.Kind == DelayedDiagnostic::Deprecation + ? AR_Deprecated + : AR_Unavailable; DD.Triggered = true; DoEmitAvailabilityWarning( - S, AD, Ctx, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc, + S, AR, Ctx, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc, DD.getUnknownObjCClass(), DD.getObjCProperty(), false); } @@ -6466,22 +6469,23 @@ curPool->steal(pool); } -void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, +void Sema::EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. - if (DelayedDiagnostics.shouldDelayDiagnostics() && AD != AD_Partial) { + if (DelayedDiagnostics.shouldDelayDiagnostics() && + AR != AR_NotYetIntroduced) { DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability( - AD, Loc, D, UnknownObjCClass, ObjCProperty, Message, + AR, Loc, D, UnknownObjCClass, ObjCProperty, Message, ObjCPropertyAccess)); return; } Decl *Ctx = cast<Decl>(getCurLexicalContext()); - DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass, + DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); } Index: lib/Sema/DelayedDiagnostic.cpp =================================================================== --- lib/Sema/DelayedDiagnostic.cpp +++ lib/Sema/DelayedDiagnostic.cpp @@ -20,23 +20,23 @@ using namespace sema; DelayedDiagnostic -DelayedDiagnostic::makeAvailability(Sema::AvailabilityDiagnostic AD, +DelayedDiagnostic::makeAvailability(AvailabilityResult AD, SourceLocation Loc, const NamedDecl *D, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, StringRef Msg, bool ObjCPropertyAccess) { DelayedDiagnostic DD; switch (AD) { - case Sema::AD_Deprecation: - DD.Kind = Deprecation; - break; - case Sema::AD_Unavailable: - DD.Kind = Unavailable; - break; - case Sema::AD_Partial: - llvm_unreachable("AD_Partial diags should not be delayed"); + case AR_Deprecated: + DD.Kind = Deprecation; + break; + case AR_Unavailable: + DD.Kind = Unavailable; + break; + default: + llvm_unreachable("partial diags should not be delayed"); } DD.Triggered = false; DD.Loc = Loc; Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -3629,13 +3629,10 @@ void redelayDiagnostics(sema::DelayedDiagnosticPool &pool); - enum AvailabilityDiagnostic { AD_Deprecation, AD_Unavailable, AD_Partial }; - - void EmitAvailabilityWarning(AvailabilityDiagnostic AD, - NamedDecl *D, StringRef Message, - SourceLocation Loc, + void EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D, + StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty, + const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess); bool makeUnavailableInSystemHeader(SourceLocation loc, @@ -9602,6 +9599,17 @@ /// 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 ContextVersion The version to compare availability against. + AvailabilityResult + ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, VersionTuple ContextVersion, + std::string *Message); + const DeclContext *getCurObjCLexicalContext() const { const DeclContext *DC = getCurLexicalContext(); // A category implicitly has the attribute of the interface. Index: include/clang/Sema/DelayedDiagnostic.h =================================================================== --- include/clang/Sema/DelayedDiagnostic.h +++ include/clang/Sema/DelayedDiagnostic.h @@ -122,7 +122,7 @@ void Destroy(); - static DelayedDiagnostic makeAvailability(Sema::AvailabilityDiagnostic AD, + static DelayedDiagnostic makeAvailability(AvailabilityResult AR, SourceLocation Loc, const NamedDecl *D, const ObjCInterfaceDecl *UnknownObjCClass,
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits