Index: lib/Sema/SemaExprObjC.cpp =================================================================== --- lib/Sema/SemaExprObjC.cpp +++ lib/Sema/SemaExprObjC.cpp @@ -1320,9 +1320,11 @@ } } - // - if the receiver is the name of a class U, T is a pointer to U + // - if the receiver is the name of a class U, T is a pointer to U. U should + // be desugared to avoid 'decltype(self)' propagation. if (ReceiverType->getAsObjCInterfaceType()) - return transferNullability(Context.getObjCObjectPointerType(ReceiverType)); + return transferNullability(Context.getObjCObjectPointerType( + ReceiverType.getDesugaredType(Context))); // - if the receiver is of type Class or qualified Class type, // T is the declared return type of the method. if (ReceiverType->isObjCClassType() || @@ -2738,10 +2740,31 @@ } else if (ReceiverType->isObjCClassOrClassKindOfType() || ReceiverType->isObjCQualifiedClassType()) { // Handle messages to Class. + // Treat messages to 'self' in class methods as class messages when ARC + // is enabled (because self can't be reassigned when ARC is on). + if (Receiver->isObjCSelfExpr() && getLangOpts().ObjCAutoRefCount) { + assert(ReceiverType->isObjCClassType() && "expected a Class self"); + const ObjCMethodDecl *MD = cast( + cast( + cast(Receiver->IgnoreParenImpCasts())->getDecl()) + ->getDeclContext()); + assert(MD->isClassMethod() && "expected a class method"); + QualType ReceiverType = + Context.getObjCInterfaceType(MD->getClassInterface()); + // Use a pseudo-decltype type to keep the expression in the AST. + assert(!Receiver->isInstantiationDependent() && + "unexpected dependent expr"); + ReceiverType = Context.getDecltypeType(Receiver, ReceiverType); + return BuildClassMessage( + Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc), + ReceiverType, + /*SuperLoc=*/SourceLocation(), Sel, + /*Method=*/nullptr, LBracLoc, SelectorLocs, RBracLoc, ArgsIn); + } // We allow sending a message to a qualified Class ("Class"), which // is ok as long as one of the protocols implements the selector (if not, // warn). - if (!ReceiverType->isObjCClassOrClassKindOfType()) { + else if (!ReceiverType->isObjCClassOrClassKindOfType()) { const ObjCObjectPointerType *QClassTy = ReceiverType->getAsObjCQualifiedClassType(); // Search protocols for class methods. Index: test/SemaObjC/multiple-method-names-class-self.m =================================================================== --- /dev/null +++ test/SemaObjC/multiple-method-names-class-self.m @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -Wobjc-multiple-method-names -x objective-c -verify %s +// RUN: %clang_cc1 -Wobjc-multiple-method-names -x objective-c -verify -fobjc-arc -DARC %s +#ifdef ARC +// expected-no-diagnostics +#endif + +@interface NSObj + ++ (instancetype) alloc; + +@end + +@interface SelfAllocReturn: NSObj + +- (instancetype)initWithFoo:(int)x; +#ifndef ARC +// expected-note@-2 {{using}} +#endif + +@end + +@interface SelfAllocReturn2: NSObj + +- (instancetype)initWithFoo:(SelfAllocReturn *)x; +#ifndef ARC +// expected-note@-2 {{also found}} +#endif + +@end + +@implementation SelfAllocReturn + +- (instancetype)initWithFoo:(int)x { + return self; +} + ++ (instancetype) thingWithFoo:(int)x { + return [[self alloc] initWithFoo: x]; +#ifndef ARC +// expected-warning@-2 {{multiple methods named 'initWithFoo:' found}} +#endif +} + +@end