r350768 - [ObjC] Allow the use of implemented unavailable methods from within
Alex Lorenz via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 9 14:31:37 PST 2019
Author: arphaman
Date: Wed Jan 9 14:31:37 2019
New Revision: 350768
URL: http://llvm.org/viewvc/llvm-project?rev=350768&view=rev
Log:
[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
Added:
cfe/trunk/test/SemaObjC/call-unavailable-init-in-self.m
Modified:
cfe/trunk/lib/Sema/SemaDeclAttr.cpp
Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=350768&r1=350767&r2=350768&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed Jan 9 14:31:37 2019
@@ -7269,9 +7269,10 @@ ShouldDiagnoseAvailabilityOfDecl(Sema &S
/// 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 ShouldDiagnoseAvailabilityIn
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(Se
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::Diag
// 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
Added: cfe/trunk/test/SemaObjC/call-unavailable-init-in-self.m
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaObjC/call-unavailable-init-in-self.m?rev=350768&view=auto
==============================================================================
--- cfe/trunk/test/SemaObjC/call-unavailable-init-in-self.m (added)
+++ cfe/trunk/test/SemaObjC/call-unavailable-init-in-self.m Wed Jan 9 14:31:37 2019
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -x objective-c -verify -fobjc-arc %s
+
+ at interface NSObject
+
++ (instancetype)new;
++ (instancetype)alloc;
+
+ at end
+
+ at interface Sub: NSObject
+
+- (instancetype)init __attribute__((unavailable)); // expected-note 4 {{'init' has been explicitly marked unavailable here}}
+
+- (void)notImplemented __attribute__((unavailable)); // expected-note {{'notImplemented' has been explicitly marked unavailable here}}
+
+ at end
+
+ at implementation Sub
+
++ (Sub *)create {
+ return [[self alloc] init];
+}
+
++ (Sub *)create2 {
+ return [self new];
+}
+
++ (Sub *)create3 {
+ return [Sub new];
+}
+
+- (instancetype) init {
+ return self;
+}
+
+- (void)reportUseOfUnimplemented {
+ [self notImplemented]; // expected-error {{'notImplemented' is unavailable}}
+}
+
+ at end
+
+ at interface SubClassContext: Sub
+ at end
+
+ at implementation SubClassContext
+
+- (void)subClassContext {
+ (void)[[Sub alloc] init]; // expected-error {{'init' is unavailable}}
+ (void)[Sub new]; // expected-error {{'new' is unavailable}}
+}
+
+ at end
+
+void unrelatedContext() {
+ (void)[[Sub alloc] init]; // expected-error {{'init' is unavailable}}
+ (void)[Sub new]; // expected-error {{'new' is unavailable}}
+}
+
+ at interface X @end
+
+ at interface X (Foo)
+-(void)meth __attribute__((unavailable));
+ at end
+
+ at implementation X (Foo)
+-(void)meth {}
+-(void)call_it { [self meth]; }
+ at end
More information about the cfe-commits
mailing list