diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -3012,7 +3012,11 @@ << Method->getDeclName(); } - if (ReceiverType->isObjCClassType() && !isImplicit) { + // Under ARC, self can't be assigned, and doing a direct call to `self` + // when it's a Class is hence safe. For other cases, we can't trust `self` + // is what we think it is, so we reject it. + if (ReceiverType->isObjCClassType() && !isImplicit && + (!Receiver->isObjCSelfExpr() || !getLangOpts().ObjCAutoRefCount)) { Diag(Receiver->getExprLoc(), diag::err_messaging_class_with_direct_method); Diag(Method->getLocation(), diag::note_direct_method_declared_at) diff --git a/clang/test/SemaObjC/method-direct-arc.m b/clang/test/SemaObjC/method-direct-arc.m new file mode 100644 --- /dev/null +++ b/clang/test/SemaObjC/method-direct-arc.m @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -fobjc-arc -fsyntax-only -verify -Wselector-type-mismatch %s + +extern Class object_getClass(id); + +__attribute__((objc_root_class)) +@interface Root +- (Class)class; ++ (void)directMethod1 __attribute__((objc_direct)); // expected-note {{direct method 'directMethod1' declared here}} ++ (void)directMethod2 __attribute__((objc_direct)); +@end + +@implementation Root +- (Class)class +{ + return object_getClass(self); +} ++ (void)directMethod1 { +} ++ (void)directMethod2 { + [self directMethod1]; // this should not warn +} ++ (void)regularMethod { + [self directMethod1]; // this should not warn + [self directMethod2]; // this should not warn +} +- (void)regularInstanceMethod { + [[self class] directMethod1]; // expected-error {{messaging a Class with a method that is possibly direct}} +} +@end