Index: lib/CodeGen/CGObjC.cpp =================================================================== --- lib/CodeGen/CGObjC.cpp +++ lib/CodeGen/CGObjC.cpp @@ -372,7 +372,8 @@ llvm::Value *Receiver, const CallArgList& Args, Selector Sel, const ObjCMethodDecl *method, - bool isClassMessage) { + bool isClassMessage, + bool isSelfReceiverInClassMethod) { auto &CGM = CGF.CGM; if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls) return None; @@ -380,13 +381,15 @@ auto &Runtime = CGM.getLangOpts().ObjCRuntime; switch (Sel.getMethodFamily()) { case OMF_alloc: - if (isClassMessage && + if ((isClassMessage || isSelfReceiverInClassMethod) && Runtime.shouldUseRuntimeFunctionsForAlloc() && ResultType->isObjCObjectPointerType()) { - // [Foo alloc] -> objc_alloc(Foo) + // [Foo alloc] -> objc_alloc(Foo) or + // [self alloc] -> objc_alloc(self) if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc") return CGF.EmitObjCAlloc(Receiver, CGF.ConvertType(ResultType)); - // [Foo allocWithZone:nil] -> objc_allocWithZone(Foo) + // [Foo allocWithZone:nil] -> objc_allocWithZone(Foo) or + // [self allocWithZone:nil] -> objc_allocWithZone(self) if (Sel.isKeywordSelector() && Sel.getNumArgs() == 1 && Args.size() == 1 && Args.front().getType()->isPointerType() && Sel.getNameForSlot(0) == "allocWithZone") { @@ -444,22 +447,38 @@ Sel.getNameForSlot(0) != "init") return None; - // Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]'. + // Okay, this is '[receiver init]', check if 'receiver' is '[cls alloc]' or + // we are in an ObjC class method and 'receiver' is '[self alloc]'. auto *SubOME = - dyn_cast(OME->getInstanceReceiver()->IgnoreParens()); + dyn_cast(OME->getInstanceReceiver()->IgnoreParenCasts()); if (!SubOME) return None; Selector SubSel = SubOME->getSelector(); - if (SubOME->getReceiverKind() != ObjCMessageExpr::Class || - !SubOME->getType()->isObjCObjectPointerType() || + + // Check if we are in an ObjC class method and the receiver expression is + // 'self'. + const Expr *SelfInClassMethod = nullptr; + if (const auto *CurMD = dyn_cast(CGF.CurFuncDecl)) + if (CurMD->isClassMethod()) + if ((SelfInClassMethod = SubOME->getInstanceReceiver())) + if (!SelfInClassMethod->isObjCSelfExpr()) + SelfInClassMethod = nullptr; + + if ((SubOME->getReceiverKind() != ObjCMessageExpr::Class && + !SelfInClassMethod) || !SubOME->getType()->isObjCObjectPointerType() || !SubSel.isUnarySelector() || SubSel.getNameForSlot(0) != "alloc") return None; - QualType ReceiverType = SubOME->getClassReceiver(); - const ObjCObjectType *ObjTy = ReceiverType->getAs(); - const ObjCInterfaceDecl *ID = ObjTy->getInterface(); - assert(ID && "null interface should be impossible here"); - llvm::Value *Receiver = CGF.CGM.getObjCRuntime().GetClass(CGF, ID); + llvm::Value *Receiver; + if (SelfInClassMethod) { + Receiver = CGF.EmitScalarExpr(SelfInClassMethod); + } else { + QualType ReceiverType = SubOME->getClassReceiver(); + const ObjCObjectType *ObjTy = ReceiverType->getAs(); + const ObjCInterfaceDecl *ID = ObjTy->getInterface(); + assert(ID && "null interface should be impossible here"); + Receiver = CGF.CGM.getObjCRuntime().GetClass(CGF, ID); + } return CGF.EmitObjCAllocInit(Receiver, CGF.ConvertType(OME->getType())); } @@ -500,6 +519,7 @@ CGObjCRuntime &Runtime = CGM.getObjCRuntime(); bool isSuperMessage = false; bool isClassMessage = false; + bool isSelfReceiverInClassMethod = false; ObjCInterfaceDecl *OID = nullptr; // Find the receiver QualType ReceiverType; @@ -507,6 +527,10 @@ switch (E->getReceiverKind()) { case ObjCMessageExpr::Instance: ReceiverType = E->getInstanceReceiver()->getType(); + if (auto *OMD = dyn_cast(CurFuncDecl)) + if (OMD->isClassMethod()) + if (E->getInstanceReceiver()->isObjCSelfExpr()) + isSelfReceiverInClassMethod = true; if (retainSelf) { TryEmitResult ter = tryEmitARCRetainScalarExpr(*this, E->getInstanceReceiver()); @@ -592,7 +616,8 @@ if (Optional SpecializedResult = tryGenerateSpecializedMessageSend(*this, ResultType, Receiver, Args, E->getSelector(), method, - isClassMessage)) { + isClassMessage, + isSelfReceiverInClassMethod)) { result = RValue::get(SpecializedResult.getValue()); } else { result = Runtime.GenerateMessageSend(*this, Return, ResultType, Index: test/CodeGenObjC/convert-messages-to-runtime-calls.m =================================================================== --- test/CodeGenObjC/convert-messages-to-runtime-calls.m +++ test/CodeGenObjC/convert-messages-to-runtime-calls.m @@ -150,6 +150,34 @@ return [c retain]; } +@interface TestSelf ++ (instancetype)alloc; ++ (instancetype)allocWithZone:(void*)zone; ++ (id)classMeth; +- (id)instanceMeth; +@end + +@implementation TestSelf +// CHECK-LABEL: define internal i8* @"\01+[TestSelf classMeth]"( ++ (id)classMeth { + // MSGS: {{call.*@objc_msgSend}} + // MSGS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_allocWithZone\(}} + // CALLS: {{call.*@objc_alloc\(}} + [self allocWithZone:nil]; + return [self alloc]; +} +// CHECK-LABEL: define internal i8* @"\01-[TestSelf instanceMeth]"( +- (id)instanceMeth { + // MSGS: {{call.*@objc_msgSend}} + // MSGS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_msgSend}} + // CALLS: {{call.*@objc_msgSend}} + [self allocWithZone:nil]; + return [self alloc]; +} +@end + @interface NSString : NSObject + (void)retain_self; - (void)retain_super; Index: test/CodeGenObjC/objc-alloc-init.m =================================================================== --- test/CodeGenObjC/objc-alloc-init.m +++ test/CodeGenObjC/objc-alloc-init.m @@ -23,14 +23,20 @@ @interface Y : X +(void)meth; +-(void)instanceMeth; @end @implementation Y +(void)meth { [[self alloc] init]; + // OPTIMIZED: call i8* @objc_alloc_init( + // NOT_OPTIMIZED: call i8* @objc_alloc( +} +-(void)instanceMeth { // EITHER-NOT: call i8* @objc_alloc // EITHER: call {{.*}} @objc_msgSend // EITHER: call {{.*}} @objc_msgSend + [[self alloc] init]; } @end