Only convert objc messages to alloc to objc_alloc if the receiver is a class.
authorPete Cooper <peter_cooper@apple.com>
Wed, 2 Jan 2019 17:25:30 +0000 (17:25 +0000)
committerPete Cooper <peter_cooper@apple.com>
Wed, 2 Jan 2019 17:25:30 +0000 (17:25 +0000)
r348687 converted [Foo alloc] to objc_alloc(Foo).  However the objc runtime method only takes a Class, not an arbitrary pointer.

This makes sure we are messaging a class before we convert these messages.

rdar://problem/46943703

llvm-svn: 350224

clang/lib/CodeGen/CGObjC.cpp
clang/test/CodeGenObjC/convert-messages-to-runtime-calls.m

index 8d24b15..9c66ff0 100644 (file)
@@ -370,7 +370,8 @@ static Optional<llvm::Value *>
 tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
                                   llvm::Value *Receiver,
                                   const CallArgList& Args, Selector Sel,
-                                  const ObjCMethodDecl *method) {
+                                  const ObjCMethodDecl *method,
+                                  bool isClassMessage) {
   auto &CGM = CGF.CGM;
   if (!CGM.getCodeGenOpts().ObjCConvertMessagesToRuntimeCalls)
     return None;
@@ -378,7 +379,8 @@ tryGenerateSpecializedMessageSend(CodeGenFunction &CGF, QualType ResultType,
   auto &Runtime = CGM.getLangOpts().ObjCRuntime;
   switch (Sel.getMethodFamily()) {
   case OMF_alloc:
-    if (Runtime.shouldUseRuntimeFunctionsForAlloc() &&
+    if (isClassMessage &&
+        Runtime.shouldUseRuntimeFunctionsForAlloc() &&
         ResultType->isObjCObjectPointerType()) {
         // [Foo alloc] -> objc_alloc(Foo)
         if (Sel.isUnarySelector() && Sel.getNameForSlot(0) == "alloc")
@@ -550,7 +552,8 @@ RValue CodeGenFunction::EmitObjCMessageExpr(const ObjCMessageExpr *E,
     // Call runtime methods directly if we can.
     if (Optional<llvm::Value *> SpecializedResult =
             tryGenerateSpecializedMessageSend(*this, ResultType, Receiver, Args,
-                                              E->getSelector(), method)) {
+                                              E->getSelector(), method,
+                                              isClassMessage)) {
       result = RValue::get(SpecializedResult.getValue());
     } else {
       result = Runtime.GenerateMessageSend(*this, Return, ResultType,
index adbbd4b..8ce024f 100644 (file)
@@ -54,7 +54,9 @@ void test2(void* x) {
 @class A;
 @interface B
 + (A*) alloc;
-+ (A*)allocWithZone:(void*)zone;
++ (A*) allocWithZone:(void*)zone;
+- (A*) alloc;
+- (A*) allocWithZone:(void*)zone;
 - (A*) retain;
 - (A*) autorelease;
 @end
@@ -79,6 +81,19 @@ A* test_allocWithZone_class_ptr() {
   return [B allocWithZone:nil];
 }
 
+// Only call objc_alloc on a Class, not an instance
+// CHECK-LABEL: define {{.*}}void @test_alloc_instance
+void test_alloc_instance(A *a) {
+  // CALLS: {{call.*@objc_alloc}}
+  // CALLS: {{call.*@objc_allocWithZone}}
+  // CALLS: {{call.*@objc_msgSend}}
+  // CALLS: {{call.*@objc_msgSend}}
+  [A alloc];
+  [A allocWithZone:nil];
+  [a alloc];
+  [a allocWithZone:nil];
+}
+
 // Make sure we get a bitcast on the return type as the
 // call will return i8* which we have to cast to A*
 // CHECK-LABEL: define {{.*}}void @test_retain_class_ptr