[clang] [CodeGen][ObjC] Include all referenced protocols in protocol list (PR #148827)
Hugo Melder via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 15 04:20:18 PDT 2025
https://github.com/hmelder created https://github.com/llvm/llvm-project/pull/148827
When constructing the protocol list in the class metadata generation (`GenerateClass`), only the protocols from the base class are added but not protocols declared in class extensions.
This is fixed by using `all_referenced_protocol_{begin, end}` instead of `protocol_{begin, end}`, matching the behaviour on Apple platforms.
A unit test is included to check if all protocol metadata was emitted and that no duplication occurs in the protocol list.
Fixes https://github.com/gnustep/libobjc2/issues/339
CC: @davidchisnall
>From 6f626d2bab1934331bca0475632f8bcef604e160 Mon Sep 17 00:00:00 2001
From: hmelder <service at hugomelder.com>
Date: Tue, 15 Jul 2025 13:09:28 +0200
Subject: [PATCH] [CodeGen][ObjC] Include all referenced protocols in protocol
list
When constructing the protocol list in the class metadata generation
(`GenerateClass`), only the protocols from the base class are added but
not from class extensions.
This is fixed by using `all_referenced_protocol_{begin, end}` instead of
`protocol_{begin, end}`, matching the behaviour on Apple platforms.
---
clang/lib/CodeGen/CGObjCGNU.cpp | 4 ++--
clang/test/CodeGenObjC/gnustep2-class-exts.m | 25 ++++++++++++++++++++
2 files changed, 27 insertions(+), 2 deletions(-)
create mode 100644 clang/test/CodeGenObjC/gnustep2-class-exts.m
diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index d828702cbb87f..126b46e08df48 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -1942,8 +1942,8 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
// struct objc_class *sibling_class
classFields.addNullPointer(PtrTy);
// struct objc_protocol_list *protocols;
- auto RuntimeProtocols = GetRuntimeProtocolList(classDecl->protocol_begin(),
- classDecl->protocol_end());
+ auto RuntimeProtocols = GetRuntimeProtocolList(classDecl->all_referenced_protocol_begin(),
+ classDecl->all_referenced_protocol_end());
SmallVector<llvm::Constant *, 16> Protocols;
for (const auto *I : RuntimeProtocols)
Protocols.push_back(GenerateProtocolRef(I));
diff --git a/clang/test/CodeGenObjC/gnustep2-class-exts.m b/clang/test/CodeGenObjC/gnustep2-class-exts.m
new file mode 100644
index 0000000000000..b065490a7d8d8
--- /dev/null
+++ b/clang/test/CodeGenObjC/gnustep2-class-exts.m
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -triple aarch64-unknown-linux-gnu -fobjc-runtime=gnustep-2.2 -emit-llvm -o - %s | FileCheck %s
+
+ at protocol BaseProtocol
+ at end
+
+ at protocol ExtendedProtocol
+ at end
+
+ at interface TestClass <BaseProtocol>
+
+-(void) Meth;
+ at end
+
+ at interface TestClass () <BaseProtocol, ExtendedProtocol>
+ at end
+
+ at implementation TestClass
+ at end
+
+// Check that we emit metadata for both protocols
+// CHECK: @._OBJC_PROTOCOL_ExtendedProtocol = global
+// CHECK: @._OBJC_PROTOCOL_BaseProtocol = global
+
+// Check that we deduplicate the protocol list
+// CHECK: @.objc_protocol_list{{\.[0-9]*}} = internal global { ptr, i64, [2 x ptr] }
More information about the cfe-commits
mailing list