[clang] a976856 - [Objective-C][WebAssembly] Always emit nil-check for indirect calls (#215920)

via cfe-commits cfe-commits at lists.llvm.org
Tue Aug 25 04:51:37 PDT 2026


Author: Hendrik Hübner
Date: 2026-08-25T13:51:31+02:00
New Revision: a976856deff93f6e41b0b55e464a2f94da09a30c

URL: https://github.com/llvm/llvm-project/commit/a976856deff93f6e41b0b55e464a2f94da09a30c
DIFF: https://github.com/llvm/llvm-project/commit/a976856deff93f6e41b0b55e464a2f94da09a30c.diff

LOG: [Objective-C][WebAssembly] Always emit nil-check for indirect calls (#215920)

We cannot use the nil-IMP stubs in libobjc2 because WebAssembly requires
exact function signature matches for indirect calls. On native platforms
such as x86 and arm this is fine, since the native calling conventions
typically allow for additional arguments to be passed without issue. For
WebAssembly, we may run into RuntimeErrors without this change.

Added: 
    clang/test/CodeGenObjC/gnustep2-wasm32-nil.m

Modified: 
    clang/lib/CodeGen/CGObjCGNU.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index 44b182ad487fb..e2fc2eca7523a 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -2974,6 +2974,15 @@ CGObjCGNU::GenerateMessageSend(CodeGenFunction &CGF,
       hasParamDestroyedInCallee = true;
     }
 
+    // WebAssembly indirect calls require an exact function type match.
+    // Therfore, we cannot use libobjc2's nil-IMP stubs for WebAssembly
+    // and must always emit a null check and optionally zero the result.
+    if (CGM.getTriple().isWasm() && !isDirect) {
+      requiresExplicitZeroResult =
+          !Return.isUnused() && !ResultType->isVoidType();
+      return true;
+    }
+
     // If the return value isn't flagged as unused, and the result
     // type isn't in our narrow set where we assume compatibility,
     // we need a nil check to ensure a nil value.

diff  --git a/clang/test/CodeGenObjC/gnustep2-wasm32-nil.m b/clang/test/CodeGenObjC/gnustep2-wasm32-nil.m
new file mode 100644
index 0000000000000..ae66f3ffbf9a9
--- /dev/null
+++ b/clang/test/CodeGenObjC/gnustep2-wasm32-nil.m
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 -triple wasm32-unknown-emscripten -emit-llvm -fobjc-runtime=gnustep-2.2 -o - %s | FileCheck %s
+
+
+typedef struct {
+  int x;
+  int y;
+  int z;
+} S;
+
+ at interface Object
+- (int)value;
+- (S)s;
+ at end
+
+// We expect generated nil-checks and zeroing of the result for WASM.
+
+int sendToPossiblyNil(Object *object) {
+  // CHECK-LABEL: define{{.*}} i32 @sendToPossiblyNil
+  // CHECK: icmp eq ptr %{{.*}}, null
+  // CHECK: br i1 %{{.*}}, label %[[CONTINUE:.*]], label %[[SEND:.*]]
+  // CHECK: [[SEND]]:
+  // CHECK: call ptr @objc_msg_lookup_sender
+  // CHECK: br label %[[CONTINUE]]
+  // CHECK: [[CONTINUE]]:
+  // CHECK: phi i32 [ %{{.*}}, %[[SEND]] ], [ 0, %{{.*}} ]
+  return [object value];
+}
+
+S sendStructToPossiblyNil(Object *object) {
+  // CHECK-LABEL: define{{.*}} void @sendStructToPossiblyNil
+  // CHECK: [[ISNIL:%.*]] = icmp eq ptr %{{.*}}, null
+  // CHECK: br i1 [[ISNIL]], label %[[NIL_CLEANUP:.*]], label %[[STRUCT_SEND:.*]]
+  // CHECK: [[STRUCT_SEND]]:
+  // CHECK: call ptr @objc_msg_lookup_sender
+  // CHECK: call void %{{.*}}(ptr{{.*}} sret(%struct.S){{.*}}
+  // CHECK: br label %[[STRUCT_CONTINUE:.*]]
+  // CHECK: [[NIL_CLEANUP]]:
+  // CHECK-NEXT: call void @llvm.memset.p0.i32(ptr align 4 %agg.result, i8 0, i32 12, i1 false)
+  // CHECK-NEXT: br label %[[STRUCT_CONTINUE]]
+  // CHECK: [[STRUCT_CONTINUE]]:
+  // CHECK: ret void
+  return [object s];
+}


        


More information about the cfe-commits mailing list