From a80039721a0ecef6bf60c622f1cd587769b30cb3 Mon Sep 17 00:00:00 2001 From: Erik Pilkington Date: Fri, 28 Oct 2016 21:39:27 +0000 Subject: [PATCH] [Sema] Delay partial availability diagnostics, just like deprecated This is done so that the following compiles with no warnings: int fn(type_10_12) __attribute__((availability(macos, introduced=10.12))); Differential revision: https://reviews.llvm.org/D25284 llvm-svn: 285457 --- clang/include/clang/Sema/DelayedDiagnostic.h | 42 +++++++++++++++------------- clang/lib/Sema/DelayedDiagnostic.cpp | 33 ++++++++-------------- clang/lib/Sema/SemaDeclAttr.cpp | 22 ++++++--------- clang/test/SemaObjC/unguarded-availability.m | 5 ++-- 4 files changed, 44 insertions(+), 58 deletions(-) diff --git a/clang/include/clang/Sema/DelayedDiagnostic.h b/clang/include/clang/Sema/DelayedDiagnostic.h index 1d184fb..b73ec08 100644 --- a/clang/include/clang/Sema/DelayedDiagnostic.h +++ b/clang/include/clang/Sema/DelayedDiagnostic.h @@ -113,9 +113,9 @@ private: /// the complete parsing of the current declaration. class DelayedDiagnostic { public: - enum DDKind { Deprecation, Unavailable, Access, ForbiddenType }; + enum DDKind : unsigned char { Availability, Access, ForbiddenType }; - unsigned char Kind; // actually a DDKind + DDKind Kind; bool Triggered; SourceLocation Loc; @@ -164,17 +164,19 @@ public: return *reinterpret_cast(AccessData); } - const NamedDecl *getDeprecationDecl() const { - assert((Kind == Deprecation || Kind == Unavailable) && - "Not a deprecation diagnostic."); - return DeprecationData.Decl; + const NamedDecl *getAvailabilityDecl() const { + assert(Kind == Availability && "Not an availability diagnostic."); + return AvailabilityData.Decl; } - StringRef getDeprecationMessage() const { - assert((Kind == Deprecation || Kind == Unavailable) && - "Not a deprecation diagnostic."); - return StringRef(DeprecationData.Message, - DeprecationData.MessageLen); + StringRef getAvailabilityMessage() const { + assert(Kind == Availability && "Not an availability diagnostic."); + return StringRef(AvailabilityData.Message, AvailabilityData.MessageLen); + } + + AvailabilityResult getAvailabilityResult() const { + assert(Kind == Availability && "Not an availability diagnostic."); + return AvailabilityData.AR; } /// The diagnostic ID to emit. Used like so: @@ -195,27 +197,28 @@ public: assert(Kind == ForbiddenType && "not a forbidden-type diagnostic"); return QualType::getFromOpaquePtr(ForbiddenTypeData.OperandType); } - + const ObjCInterfaceDecl *getUnknownObjCClass() const { - return DeprecationData.UnknownObjCClass; + return AvailabilityData.UnknownObjCClass; } const ObjCPropertyDecl *getObjCProperty() const { - return DeprecationData.ObjCProperty; + return AvailabilityData.ObjCProperty; } - + bool getObjCPropertyAccess() const { - return DeprecationData.ObjCPropertyAccess; + return AvailabilityData.ObjCPropertyAccess; } - + private: - struct DD { + struct AD { const NamedDecl *Decl; const ObjCInterfaceDecl *UnknownObjCClass; const ObjCPropertyDecl *ObjCProperty; const char *Message; size_t MessageLen; + AvailabilityResult AR; bool ObjCPropertyAccess; }; @@ -226,8 +229,7 @@ private: }; union { - /// Deprecation - struct DD DeprecationData; + struct AD AvailabilityData; struct FTD ForbiddenTypeData; /// Access control. diff --git a/clang/lib/Sema/DelayedDiagnostic.cpp b/clang/lib/Sema/DelayedDiagnostic.cpp index f695030..2fa5718 100644 --- a/clang/lib/Sema/DelayedDiagnostic.cpp +++ b/clang/lib/Sema/DelayedDiagnostic.cpp @@ -20,7 +20,7 @@ using namespace clang; using namespace sema; DelayedDiagnostic -DelayedDiagnostic::makeAvailability(AvailabilityResult AD, +DelayedDiagnostic::makeAvailability(AvailabilityResult AR, SourceLocation Loc, const NamedDecl *D, const ObjCInterfaceDecl *UnknownObjCClass, @@ -28,42 +28,33 @@ DelayedDiagnostic::makeAvailability(AvailabilityResult AD, StringRef Msg, bool ObjCPropertyAccess) { DelayedDiagnostic DD; - switch (AD) { - case AR_Deprecated: - DD.Kind = Deprecation; - break; - case AR_Unavailable: - DD.Kind = Unavailable; - break; - default: - llvm_unreachable("partial diags should not be delayed"); - } + DD.Kind = Availability; DD.Triggered = false; DD.Loc = Loc; - DD.DeprecationData.Decl = D; - DD.DeprecationData.UnknownObjCClass = UnknownObjCClass; - DD.DeprecationData.ObjCProperty = ObjCProperty; + DD.AvailabilityData.Decl = D; + DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass; + DD.AvailabilityData.ObjCProperty = ObjCProperty; char *MessageData = nullptr; if (Msg.size()) { MessageData = new char [Msg.size()]; memcpy(MessageData, Msg.data(), Msg.size()); } - DD.DeprecationData.Message = MessageData; - DD.DeprecationData.MessageLen = Msg.size(); - DD.DeprecationData.ObjCPropertyAccess = ObjCPropertyAccess; + DD.AvailabilityData.Message = MessageData; + DD.AvailabilityData.MessageLen = Msg.size(); + DD.AvailabilityData.AR = AR; + DD.AvailabilityData.ObjCPropertyAccess = ObjCPropertyAccess; return DD; } void DelayedDiagnostic::Destroy() { - switch (static_cast(Kind)) { + switch (Kind) { case Access: getAccessData().~AccessedEntity(); break; - case Deprecation: - case Unavailable: - delete [] DeprecationData.Message; + case Availability: + delete[] AvailabilityData.Message; break; case ForbiddenType: diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 936c297..df5720f 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6510,9 +6510,6 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, break; case AR_NotYetIntroduced: - assert(!S.getCurFunctionOrMethodDecl() && - "Function-level partial availablity should not be diagnosed here!"); - diag = diag::warn_partial_availability; diag_message = diag::warn_partial_message; diag_fwdclass_message = diag::warn_partial_fwdclass_message; @@ -6585,15 +6582,14 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, Decl *Ctx) { - assert(DD.Kind == DelayedDiagnostic::Deprecation || - DD.Kind == DelayedDiagnostic::Unavailable); - AvailabilityResult AR = DD.Kind == DelayedDiagnostic::Deprecation - ? AR_Deprecated - : AR_Unavailable; + assert(DD.Kind == DelayedDiagnostic::Availability && + "Expected an availability diagnostic here"); + DD.Triggered = true; DoEmitAvailabilityWarning( - S, AR, Ctx, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc, - DD.getUnknownObjCClass(), DD.getObjCProperty(), false); + S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityDecl(), + DD.getAvailabilityMessage(), DD.Loc, DD.getUnknownObjCClass(), + DD.getObjCProperty(), false); } void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { @@ -6623,8 +6619,7 @@ void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { continue; switch (diag.Kind) { - case DelayedDiagnostic::Deprecation: - case DelayedDiagnostic::Unavailable: + case DelayedDiagnostic::Availability: // Don't bother giving deprecation/unavailable diagnostics if // the decl is invalid. if (!decl->isInvalidDecl()) @@ -6659,8 +6654,7 @@ void Sema::EmitAvailabilityWarning(AvailabilityResult AR, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. - if (DelayedDiagnostics.shouldDelayDiagnostics() && - AR != AR_NotYetIntroduced) { + if (DelayedDiagnostics.shouldDelayDiagnostics()) { DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability( AR, Loc, D, UnknownObjCClass, ObjCProperty, Message, ObjCPropertyAccess)); diff --git a/clang/test/SemaObjC/unguarded-availability.m b/clang/test/SemaObjC/unguarded-availability.m index fe25c8b..4369a0e 100644 --- a/clang/test/SemaObjC/unguarded-availability.m +++ b/clang/test/SemaObjC/unguarded-availability.m @@ -63,7 +63,7 @@ typedef int int_10_11 AVAILABLE_10_11; // expected-note {{'int_10_11' has been e #ifdef OBJCPP // expected-note@+2 {{marked partial here}} #endif -typedef int int_10_12 AVAILABLE_10_12; // expected-note 3 {{'int_10_12' has been explicitly marked partial here}} +typedef int int_10_12 AVAILABLE_10_12; // expected-note 2 {{'int_10_12' has been explicitly marked partial here}} void use_typedef() { int_10_11 x; // expected-warning{{'int_10_11' is only available on macOS 10.11 or newer}} expected-note{{enclose 'int_10_11' in an @available check to silence this warning}} @@ -127,8 +127,7 @@ void test_blocks() { void test_params(int_10_12 x); // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}} -// FIXME: This should be fine! -void test_params2(int_10_12 x) AVAILABLE_10_12; // expected-warning {{'int_10_12' is partial: introduced in macOS 10.12}} expected-note{{redeclare}} +void test_params2(int_10_12 x) AVAILABLE_10_12; // no warn #ifdef OBJCPP -- 2.7.4