diff options
author | Alex Lorenz <arphaman@gmail.com> | 2019-01-09 22:31:37 +0000 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2019-01-09 22:31:37 +0000 |
commit | b01820327c555b8e32787e728892d4b89288e700 (patch) | |
tree | d465993019702f72d0dec9dfd5cda0b2fa4fcb30 /lib/Sema/SemaDeclAttr.cpp | |
parent | 05d16b5603d658446d6b5e1e31af924959d00026 (diff) | |
download | clang-b01820327c555b8e32787e728892d4b89288e700.tar.gz |
[ObjC] Allow the use of implemented unavailable methods from within
the @implementation context
In Objective-C, it's common for some frameworks to mark some methods like init
as unavailable in the @interface to prohibit their usage. However, these
frameworks then often implemented said method and refer to it in another method
that acts as a factory for that object. The recent change to how messages to
self are type checked in clang (r349841) introduced a regression which started
to prohibit this pattern with an X is unavailable error. This commit addresses
the aforementioned regression.
rdar://47134898
Differential Revision: https://reviews.llvm.org/D56469
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@350768 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaDeclAttr.cpp')
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index d1db71838f..864c930136 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -7269,9 +7269,10 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, /// 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) { +static bool +ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, + VersionTuple DeclVersion, Decl *Ctx, + const NamedDecl *OffendingDecl) { assert(K != AR_Available && "Expected an unavailable declaration here!"); // Checks if we should emit the availability diagnostic in the context of C. @@ -7280,9 +7281,22 @@ static bool ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C)) if (AA->getIntroduced() >= DeclVersion) return true; - } else if (K == AR_Deprecated) + } else if (K == AR_Deprecated) { if (C->isDeprecated()) return true; + } else if (K == AR_Unavailable) { + // It is perfectly fine to refer to an 'unavailable' Objective-C method + // when it's actually defined and is referenced from within the + // @implementation itself. In this context, we interpret unavailable as a + // form of access control. + if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) { + if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) { + if (MD->getClassInterface() == Impl->getClassInterface() && + MD->isDefined()) + return true; + } + } + } if (C->isUnavailable()) return true; @@ -7471,7 +7485,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl)) DeclVersion = AA->getIntroduced(); - if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) + if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx, + OffendingDecl)) return; SourceLocation Loc = Locs.front(); @@ -7955,7 +7970,8 @@ void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( // If the context of this function is less available than D, we should not // emit a diagnostic. - if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx)) + if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx, + OffendingDecl)) return; // We would like to emit the diagnostic even if -Wunguarded-availability is |