Index: cfe/trunk/include/clang/Sema/DelayedDiagnostic.h =================================================================== --- cfe/trunk/include/clang/Sema/DelayedDiagnostic.h +++ cfe/trunk/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, Index: cfe/trunk/include/clang/Sema/Sema.h =================================================================== --- cfe/trunk/include/clang/Sema/Sema.h +++ cfe/trunk/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, @@ -9608,6 +9605,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: cfe/trunk/lib/Sema/DelayedDiagnostic.cpp =================================================================== --- cfe/trunk/lib/Sema/DelayedDiagnostic.cpp +++ cfe/trunk/lib/Sema/DelayedDiagnostic.cpp @@ -20,7 +20,7 @@ using namespace sema; DelayedDiagnostic -DelayedDiagnostic::makeAvailability(Sema::AvailabilityDiagnostic AD, +DelayedDiagnostic::makeAvailability(AvailabilityResult AD, SourceLocation Loc, const NamedDecl *D, const ObjCInterfaceDecl *UnknownObjCClass, @@ -29,14 +29,14 @@ 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: cfe/trunk/lib/Sema/SemaDeclAttr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp +++ cfe/trunk/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()) Replacement = attr->getReplacement(); if (auto attr = getAttrForPlatform(S.Context, D)) @@ -6393,7 +6396,7 @@ 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; } @@ -6401,12 +6404,12 @@ 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(getCurLexicalContext()); - DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass, + DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); } Index: cfe/trunk/lib/Sema/SemaExpr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaExpr.cpp +++ cfe/trunk/lib/Sema/SemaExpr.cpp @@ -103,18 +103,9 @@ 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(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. @@ -122,18 +113,18 @@ if (Result == AR_Available) { if (const TagType *TT = TD->getUnderlyingType()->getAs()) { 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(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); - Result = D->getAvailability(&Message, ContextVersion); + Result = D->getAvailability(Message, ContextVersion); } } @@ -141,12 +132,58 @@ if (Result == AR_Available) { const DeclContext *DC = ECD->getDeclContext(); if (const EnumDecl *TheEnumDecl = dyn_cast(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(D) || isa(D)) + return AR_Available; + + bool Warn = !D->getAttr()->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(D)) + for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; + Redecl = Redecl->getPreviousDecl()) + if (!Redecl->hasAttr() || + Redecl->getAttr()->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(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(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { AvailabilityResult PDeclResult = @@ -155,56 +192,10 @@ 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(D) || isa(D)) - break; - - bool Warn = !D->getAttr()->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(D)) - for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; - Redecl = Redecl->getPreviousDecl()) - if (!Redecl->hasAttr() || - Redecl->getAttr()->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.