https://github.com/DataCorrupted updated https://github.com/llvm/llvm-project/pull/170616
>From 76489044b1150f846af5fe86f07d8d8f32e56179 Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Wed, 3 Dec 2025 22:18:02 -0800 Subject: [PATCH 01/10] [ExposeObjCDirect] Adding a flag to allow new objc direct ABI 1. Add a flag 2. Clean up and set up helper functions to implement later Signed-off-by: Peter Rong <[email protected]> --- clang/include/clang/AST/DeclObjC.h | 6 ++++ clang/include/clang/Basic/CodeGenOptions.def | 2 ++ clang/include/clang/Options/Options.td | 5 +++ clang/lib/CodeGen/CGObjCRuntime.cpp | 26 +++++++++------ clang/lib/CodeGen/CGObjCRuntime.h | 35 ++++++++++++++++++-- clang/lib/CodeGen/CodeGenModule.h | 26 +++++++++++++++ clang/lib/Driver/ToolChains/Clang.cpp | 4 +++ 7 files changed, 90 insertions(+), 14 deletions(-) diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 2541edba83855..e2292cbdea042 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -482,6 +482,12 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext { /// True if the method is tagged as objc_direct bool isDirectMethod() const; + /// Check if this direct method can move nil-check to thunk. + /// Variadic functions cannot use thunks (musttail incompatible with va_arg) + bool canHaveNilCheckThunk() const { + return isDirectMethod() && !isVariadic(); + } + /// True if the method has a parameter that's destroyed in the callee. bool hasParamDestroyedInCallee() const; diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index 76a6463881c6f..a7e8564c9e83c 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -210,6 +210,8 @@ ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy, Benign) /// Replace certain message sends with calls to ObjC runtime entrypoints CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1, Benign) CODEGENOPT(ObjCAvoidHeapifyLocalBlocks, 1, 0, Benign) +/// Expose objc_direct method symbols publicly and optimize nil checks. +CODEGENOPT(ObjCExposeDirectMethods, 1, 0, Benign) // The optimization options affect frontend options, which in turn do affect the AST. diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 756d6deed7130..ddc04b30cbaa2 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -3775,6 +3775,11 @@ defm objc_avoid_heapify_local_blocks : BoolFOption<"objc-avoid-heapify-local-blo PosFlag<SetTrue, [], [ClangOption], "Try">, NegFlag<SetFalse, [], [ClangOption], "Don't try">, BothFlags<[], [CC1Option], " to avoid heapifying local blocks">>; +defm objc_expose_direct_methods : BoolFOption<"objc-expose-direct-methods", + CodeGenOpts<"ObjCExposeDirectMethods">, DefaultFalse, + PosFlag<SetTrue, [], [ClangOption, CC1Option], + "Expose direct method symbols and move nil checks to caller-side thunks">, + NegFlag<SetFalse>>; defm disable_block_signature_string : BoolFOption<"disable-block-signature-string", CodeGenOpts<"DisableBlockSignatureString">, DefaultFalse, PosFlag<SetTrue, [], [ClangOption], "Disable">, diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp index 76e0054f4c9da..38efd4d865284 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -382,11 +382,9 @@ CGObjCRuntime::getMessageSendInfo(const ObjCMethodDecl *method, return MessageSendInfo(argsInfo, signatureType); } -bool CGObjCRuntime::canMessageReceiverBeNull(CodeGenFunction &CGF, - const ObjCMethodDecl *method, - bool isSuper, - const ObjCInterfaceDecl *classReceiver, - llvm::Value *receiver) { +bool CGObjCRuntime::canMessageReceiverBeNull( + CodeGenFunction &CGF, const ObjCMethodDecl *method, bool isSuper, + const ObjCInterfaceDecl *classReceiver, llvm::Value *receiver) { // Super dispatch assumes that self is non-null; even the messenger // doesn't have a null check internally. if (isSuper) @@ -399,8 +397,7 @@ bool CGObjCRuntime::canMessageReceiverBeNull(CodeGenFunction &CGF, // If we're emitting a method, and self is const (meaning just ARC, for now), // and the receiver is a load of self, then self is a valid object. - if (auto curMethod = - dyn_cast_or_null<ObjCMethodDecl>(CGF.CurCodeDecl)) { + if (auto curMethod = dyn_cast_or_null<ObjCMethodDecl>(CGF.CurCodeDecl)) { auto self = curMethod->getSelfDecl(); if (self->getType().isConstQualified()) { if (auto LI = dyn_cast<llvm::LoadInst>(receiver->stripPointerCasts())) { @@ -416,6 +413,13 @@ bool CGObjCRuntime::canMessageReceiverBeNull(CodeGenFunction &CGF, return true; } +bool CGObjCRuntime::canClassObjectBeUnrealized( + const ObjCInterfaceDecl *CalleeClassDecl, CodeGenFunction &CGF) const { + + // Otherwise, assume it can be unrealized. + return true; +} + bool CGObjCRuntime::isWeakLinkedClass(const ObjCInterfaceDecl *ID) { do { if (ID->isWeakImported()) @@ -466,11 +470,11 @@ clang::CodeGen::emitObjCProtocolObject(CodeGenModule &CGM, } std::string CGObjCRuntime::getSymbolNameForMethod(const ObjCMethodDecl *OMD, - bool includeCategoryName) { + bool includeCategoryName, + bool includePrefixByte) { std::string buffer; llvm::raw_string_ostream out(buffer); - CGM.getCXXABI().getMangleContext().mangleObjCMethodName(OMD, out, - /*includePrefixByte=*/true, - includeCategoryName); + CGM.getCXXABI().getMangleContext().mangleObjCMethodName( + OMD, out, includePrefixByte, includeCategoryName); return buffer; } diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h index 72997bf6348ae..1ee3b85e8a779 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -117,7 +117,8 @@ class CGObjCRuntime { virtual ~CGObjCRuntime(); std::string getSymbolNameForMethod(const ObjCMethodDecl *method, - bool includeCategoryName = true); + bool includeCategoryName = true, + bool includePrefixByte = true); /// Generate the function required to register all Objective-C components in /// this compilation unit with the runtime library. @@ -322,10 +323,38 @@ class CGObjCRuntime { MessageSendInfo getMessageSendInfo(const ObjCMethodDecl *method, QualType resultType, CallArgList &callArgs); - bool canMessageReceiverBeNull(CodeGenFunction &CGF, - const ObjCMethodDecl *method, bool isSuper, + + /// Check if the receiver of an ObjC message send can be null. + /// Returns true if the receiver may be null, false if provably non-null. + /// + /// This can be overridden by subclasses to add runtime-specific heuristics. + /// Base implementation checks: + /// - Super dispatch (always non-null) + /// - Self in const-qualified methods (ARC) + /// - Weak-linked classes + /// + /// Future enhancements in CGObjCCommonMac override: + /// - _Nonnull attributes + /// - Results of alloc, new, ObjC literals + virtual bool canMessageReceiverBeNull(CodeGenFunction &CGF, + const ObjCMethodDecl *method, + bool isSuper, const ObjCInterfaceDecl *classReceiver, llvm::Value *receiver); + + /// Check if a class object can be unrealized (not yet initialized). + /// Returns true if the class may be unrealized, false if provably realized. + /// + /// STUB IMPLEMENTATION: Base class always returns true (conservative). + /// Subclasses can override to add runtime-specific dominating-call analysis. + /// + /// Future: Returns false if: + /// - An instance method on the same class was called in a dominating path + /// - The class was explicitly realized earlier in control flow + /// - Note: [Parent foo] does NOT realize Child (inheritance care needed) + virtual bool canClassObjectBeUnrealized(const ObjCInterfaceDecl *ClassDecl, + CodeGenFunction &CGF) const; + static bool isWeakLinkedClass(const ObjCInterfaceDecl *cls); /// Destroy the callee-destroyed arguments of the given method, diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index a253bcda2d06c..f65739de10957 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -717,6 +717,32 @@ class CodeGenModule : public CodeGenTypeCache { /// Return true iff an Objective-C runtime has been configured. bool hasObjCRuntime() { return !!ObjCRuntime; } + /// Check if a direct method should have its symbol exposed (no \01 prefix). + /// This applies to ALL direct methods (including variadic). + /// Returns false if OMD is null or not a direct method. + bool shouldExposeSymbol(const ObjCMethodDecl *OMD) const { + return OMD && OMD->isDirectMethod() && + getLangOpts().ObjCRuntime.isNeXTFamily() && + getCodeGenOpts().ObjCExposeDirectMethods; + } + + /// Check if a direct method should use nil-check thunks at call sites. + /// This applies only to non-variadic direct methods. + /// Variadic methods cannot use thunks (musttail incompatible with va_arg). + /// Returns false if OMD is null or not eligible for thunks. + bool shouldHaveNilCheckThunk(const ObjCMethodDecl *OMD) const { + return OMD && shouldExposeSymbol(OMD) && OMD->canHaveNilCheckThunk(); + } + + /// Check if a direct method should have inline nil checks at call sites. + /// This applies to direct methods that cannot use thunks (e.g., variadic + /// methods). These methods get exposed symbols but need inline nil checks + /// instead of thunks. Returns false if OMD is null or not eligible for inline + /// nil checks. + bool shouldHaveNilCheckInline(const ObjCMethodDecl *OMD) const { + return OMD && shouldExposeSymbol(OMD) && !OMD->canHaveNilCheckThunk(); + } + const std::string &getModuleNameHash() const { return ModuleNameHash; } /// Return a reference to the configured OpenCL runtime. diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 0380568412e62..2c3beb94f2ef8 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4096,6 +4096,10 @@ static void RenderObjCOptions(const ToolChain &TC, const Driver &D, } } + // Forward -fobjc-expose-direct-methods to cc1 + if (Args.hasArg(options::OPT_fobjc_expose_direct_methods)) + CmdArgs.push_back("-fobjc-expose-direct-methods"); + // When ObjectiveC legacy runtime is in effect on MacOSX, turn on the option // to do Array/Dictionary subscripting by default. if (Arch == llvm::Triple::x86 && T.isMacOSX() && >From b5fd161368aafff8323866990bd351a2d08e2dc6 Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Wed, 3 Dec 2025 23:15:45 -0800 Subject: [PATCH 02/10] format --- clang/lib/CodeGen/CGObjCRuntime.cpp | 2 +- clang/lib/CodeGen/CGObjCRuntime.h | 22 +++------------------- 2 files changed, 4 insertions(+), 20 deletions(-) diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp index 38efd4d865284..a4b4460fdc49c 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -415,7 +415,7 @@ bool CGObjCRuntime::canMessageReceiverBeNull( bool CGObjCRuntime::canClassObjectBeUnrealized( const ObjCInterfaceDecl *CalleeClassDecl, CodeGenFunction &CGF) const { - + // TODO // Otherwise, assume it can be unrealized. return true; } diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h index 1ee3b85e8a779..0f0cc6ba09200 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -324,31 +324,15 @@ class CGObjCRuntime { QualType resultType, CallArgList &callArgs); - /// Check if the receiver of an ObjC message send can be null. - /// Returns true if the receiver may be null, false if provably non-null. - /// - /// This can be overridden by subclasses to add runtime-specific heuristics. - /// Base implementation checks: - /// - Super dispatch (always non-null) - /// - Self in const-qualified methods (ARC) - /// - Weak-linked classes - /// - /// Future enhancements in CGObjCCommonMac override: - /// - _Nonnull attributes - /// - Results of alloc, new, ObjC literals - virtual bool canMessageReceiverBeNull(CodeGenFunction &CGF, - const ObjCMethodDecl *method, - bool isSuper, + bool canMessageReceiverBeNull(CodeGenFunction &CGF, + const ObjCMethodDecl *method, bool isSuper, const ObjCInterfaceDecl *classReceiver, llvm::Value *receiver); /// Check if a class object can be unrealized (not yet initialized). /// Returns true if the class may be unrealized, false if provably realized. /// - /// STUB IMPLEMENTATION: Base class always returns true (conservative). - /// Subclasses can override to add runtime-specific dominating-call analysis. - /// - /// Future: Returns false if: + /// TODO: Returns false if: /// - An instance method on the same class was called in a dominating path /// - The class was explicitly realized earlier in control flow /// - Note: [Parent foo] does NOT realize Child (inheritance care needed) >From 488ebbc2d444bc02aafe434166b2c23fe45a381d Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Tue, 9 Dec 2025 14:10:18 -0800 Subject: [PATCH 03/10] update driver behavior and a test --- clang/lib/Driver/ToolChains/Clang.cpp | 3 ++- clang/test/Driver/clang_f_opts.c | 8 ++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 2c3beb94f2ef8..193a756cc5f86 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4097,7 +4097,8 @@ static void RenderObjCOptions(const ToolChain &TC, const Driver &D, } // Forward -fobjc-expose-direct-methods to cc1 - if (Args.hasArg(options::OPT_fobjc_expose_direct_methods)) + if (Args.hasFlag(options::OPT_fobjc_expose_direct_methods, + options::OPT_fno_objc_expose_direct_methods, false)) CmdArgs.push_back("-fobjc-expose-direct-methods"); // When ObjectiveC legacy runtime is in effect on MacOSX, turn on the option diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index 765f9d6ae3212..2088ceaa3e8f0 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -599,6 +599,14 @@ // CHECK_DISABLE_DIRECT: -fobjc-disable-direct-methods-for-testing // CHECK_NO_DISABLE_DIRECT-NOT: -fobjc-disable-direct-methods-for-testing +// RUN: %clang -### -xobjective-c -fobjc-expose-direct-methods %s 2>&1 | FileCheck -check-prefix=CHECK_EXPOSE_DIRECT %s +// RUN: %clang -### -xobjective-c -fno-objc-expose-direct-methods %s 2>&1 | FileCheck -check-prefix=CHECK_NO_EXPOSE_DIRECT %s +// RUN: %clang -### -xobjective-c -fobjc-expose-direct-methods -fno-objc-expose-direct-methods %s 2>&1 | FileCheck -check-prefix=CHECK_NO_EXPOSE_DIRECT %s +// RUN: %clang -### -xobjective-c -fno-objc-expose-direct-methods -fobjc-expose-direct-methods %s 2>&1 | FileCheck -check-prefix=CHECK_EXPOSE_DIRECT %s +// RUN: %clang -### -xobjective-c %s 2>&1 | FileCheck -check-prefix=CHECK_NO_EXPOSE_DIRECT %s +// CHECK_EXPOSE_DIRECT: "-fobjc-expose-direct-methods" +// CHECK_NO_EXPOSE_DIRECT-NOT: -fobjc-expose-direct-methods + // RUN: %clang -### -S -fjmc --target=x86_64-unknown-linux %s 2>&1 | FileCheck -check-prefixes=CHECK_JMC_WARN,CHECK_NOJMC %s // RUN: %clang -### -S -fjmc --target=x86_64-pc-windows-msvc %s 2>&1 | FileCheck -check-prefixes=CHECK_JMC_WARN,CHECK_NOJMC %s // RUN: %clang -### -S -fjmc -g --target=x86_64-pc-windows-msvc %s 2>&1 | FileCheck -check-prefix=CHECK_JMC %s >From 465314d87ab9c2661e9c3aef2a1a4f8d371dd7de Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Sat, 13 Dec 2025 00:35:20 -0800 Subject: [PATCH 04/10] Rename to precondition thunk --- clang/include/clang/AST/DeclObjC.h | 4 +-- clang/include/clang/Basic/CodeGenOptions.def | 4 +-- clang/include/clang/Options/Options.td | 6 ++-- clang/lib/CodeGen/CodeGenModule.h | 30 ++++++++++---------- clang/lib/Driver/ToolChains/Clang.cpp | 8 +++--- clang/test/Driver/clang_f_opts.c | 14 ++++----- 6 files changed, 33 insertions(+), 33 deletions(-) diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index e2292cbdea042..96c22bfeab735 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -482,9 +482,9 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext { /// True if the method is tagged as objc_direct bool isDirectMethod() const; - /// Check if this direct method can move nil-check to thunk. + /// Check if this direct method can move precondition-check to thunk. /// Variadic functions cannot use thunks (musttail incompatible with va_arg) - bool canHaveNilCheckThunk() const { + bool canHavePreconditionThunk() const { return isDirectMethod() && !isVariadic(); } diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index a7e8564c9e83c..cde7589a3167e 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -210,8 +210,8 @@ ENUM_CODEGENOPT(ObjCDispatchMethod, ObjCDispatchMethodKind, 2, Legacy, Benign) /// Replace certain message sends with calls to ObjC runtime entrypoints CODEGENOPT(ObjCConvertMessagesToRuntimeCalls , 1, 1, Benign) CODEGENOPT(ObjCAvoidHeapifyLocalBlocks, 1, 0, Benign) -/// Expose objc_direct method symbols publicly and optimize nil checks. -CODEGENOPT(ObjCExposeDirectMethods, 1, 0, Benign) +/// Generate direct method precondition thunks to expose symbols and optimize nil checks. +CODEGENOPT(ObjCDirectPreconditionThunk, 1, 0, Benign) // The optimization options affect frontend options, which in turn do affect the AST. diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index ddc04b30cbaa2..bab2b98f694b0 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -3775,10 +3775,10 @@ defm objc_avoid_heapify_local_blocks : BoolFOption<"objc-avoid-heapify-local-blo PosFlag<SetTrue, [], [ClangOption], "Try">, NegFlag<SetFalse, [], [ClangOption], "Don't try">, BothFlags<[], [CC1Option], " to avoid heapifying local blocks">>; -defm objc_expose_direct_methods : BoolFOption<"objc-expose-direct-methods", - CodeGenOpts<"ObjCExposeDirectMethods">, DefaultFalse, +defm objc_direct_precondition_thunk : BoolFOption<"objc-direct-precondition-thunk", + CodeGenOpts<"ObjCDirectPreconditionThunk">, DefaultFalse, PosFlag<SetTrue, [], [ClangOption, CC1Option], - "Expose direct method symbols and move nil checks to caller-side thunks">, + "Move direct methods' precondition checks to thunks">, NegFlag<SetFalse>>; defm disable_block_signature_string : BoolFOption<"disable-block-signature-string", CodeGenOpts<"DisableBlockSignatureString">, DefaultFalse, diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index f65739de10957..1126bba5eef14 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -717,30 +717,30 @@ class CodeGenModule : public CodeGenTypeCache { /// Return true iff an Objective-C runtime has been configured. bool hasObjCRuntime() { return !!ObjCRuntime; } - /// Check if a direct method should have its symbol exposed (no \01 prefix). + /// Check if a direct method should use precondition thunks (exposed symbols). /// This applies to ALL direct methods (including variadic). /// Returns false if OMD is null or not a direct method. - bool shouldExposeSymbol(const ObjCMethodDecl *OMD) const { + bool usePreconditionThunk(const ObjCMethodDecl *OMD) const { return OMD && OMD->isDirectMethod() && getLangOpts().ObjCRuntime.isNeXTFamily() && - getCodeGenOpts().ObjCExposeDirectMethods; + getCodeGenOpts().ObjCDirectPreconditionThunk; } - /// Check if a direct method should use nil-check thunks at call sites. + /// Check if a direct method should use precondition thunks at call sites. /// This applies only to non-variadic direct methods. - /// Variadic methods cannot use thunks (musttail incompatible with va_arg). - /// Returns false if OMD is null or not eligible for thunks. - bool shouldHaveNilCheckThunk(const ObjCMethodDecl *OMD) const { - return OMD && shouldExposeSymbol(OMD) && OMD->canHaveNilCheckThunk(); + /// Returns false if OMD is null or not eligible for thunks (e.g. variadic + /// methods). + bool shouldHavePreconditionThunk(const ObjCMethodDecl *OMD) const { + return OMD && usePreconditionThunk(OMD) && OMD->canHavePreconditionThunk(); } - /// Check if a direct method should have inline nil checks at call sites. - /// This applies to direct methods that cannot use thunks (e.g., variadic - /// methods). These methods get exposed symbols but need inline nil checks - /// instead of thunks. Returns false if OMD is null or not eligible for inline - /// nil checks. - bool shouldHaveNilCheckInline(const ObjCMethodDecl *OMD) const { - return OMD && shouldExposeSymbol(OMD) && !OMD->canHaveNilCheckThunk(); + /// Check if a direct method should have inline precondition checks at call + /// sites. This applies to direct methods that cannot use thunks (e.g., + /// variadic methods). These methods get exposed symbols but need inline + /// precondition checks instead of thunks. + /// Returns false if OMD is null or not eligible. + bool shouldHavePreconditionInline(const ObjCMethodDecl *OMD) const { + return OMD && usePreconditionThunk(OMD) && !OMD->canHavePreconditionThunk(); } const std::string &getModuleNameHash() const { return ModuleNameHash; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 193a756cc5f86..59353f0a81b0c 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4096,10 +4096,10 @@ static void RenderObjCOptions(const ToolChain &TC, const Driver &D, } } - // Forward -fobjc-expose-direct-methods to cc1 - if (Args.hasFlag(options::OPT_fobjc_expose_direct_methods, - options::OPT_fno_objc_expose_direct_methods, false)) - CmdArgs.push_back("-fobjc-expose-direct-methods"); + // Forward -fobjc-direct-precondition-thunk to cc1 + if (Args.hasFlag(options::OPT_fobjc_direct_precondition_thunk, + options::OPT_fno_objc_direct_precondition_thunk, false)) + CmdArgs.push_back("-fobjc-direct-precondition-thunk"); // When ObjectiveC legacy runtime is in effect on MacOSX, turn on the option // to do Array/Dictionary subscripting by default. diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index 2088ceaa3e8f0..1c401f75defd2 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -599,13 +599,13 @@ // CHECK_DISABLE_DIRECT: -fobjc-disable-direct-methods-for-testing // CHECK_NO_DISABLE_DIRECT-NOT: -fobjc-disable-direct-methods-for-testing -// RUN: %clang -### -xobjective-c -fobjc-expose-direct-methods %s 2>&1 | FileCheck -check-prefix=CHECK_EXPOSE_DIRECT %s -// RUN: %clang -### -xobjective-c -fno-objc-expose-direct-methods %s 2>&1 | FileCheck -check-prefix=CHECK_NO_EXPOSE_DIRECT %s -// RUN: %clang -### -xobjective-c -fobjc-expose-direct-methods -fno-objc-expose-direct-methods %s 2>&1 | FileCheck -check-prefix=CHECK_NO_EXPOSE_DIRECT %s -// RUN: %clang -### -xobjective-c -fno-objc-expose-direct-methods -fobjc-expose-direct-methods %s 2>&1 | FileCheck -check-prefix=CHECK_EXPOSE_DIRECT %s -// RUN: %clang -### -xobjective-c %s 2>&1 | FileCheck -check-prefix=CHECK_NO_EXPOSE_DIRECT %s -// CHECK_EXPOSE_DIRECT: "-fobjc-expose-direct-methods" -// CHECK_NO_EXPOSE_DIRECT-NOT: -fobjc-expose-direct-methods +// RUN: %clang -### -xobjective-c -fobjc-direct-precondition-thunk %s 2>&1 | FileCheck -check-prefix=CHECK_DIRECT_PRECONDITION_THUNK %s +// RUN: %clang -### -xobjective-c -fno-objc-direct-precondition-thunk %s 2>&1 | FileCheck -check-prefix=CHECK_NO_DIRECT_PRECONDITION_THUNK %s +// RUN: %clang -### -xobjective-c -fobjc-direct-precondition-thunk -fno-objc-direct-precondition-thunk %s 2>&1 | FileCheck -check-prefix=CHECK_NO_DIRECT_PRECONDITION_THUNK %s +// RUN: %clang -### -xobjective-c -fno-objc-direct-precondition-thunk -fobjc-direct-precondition-thunk %s 2>&1 | FileCheck -check-prefix=CHECK_DIRECT_PRECONDITION_THUNK %s +// RUN: %clang -### -xobjective-c %s 2>&1 | FileCheck -check-prefix=CHECK_NO_DIRECT_PRECONDITION_THUNK %s +// CHECK_DIRECT_PRECONDITION_THUNK: "-fobjc-direct-precondition-thunk" +// CHECK_NO_DIRECT_PRECONDITION_THUNK-NOT: -fobjc-direct-precondition-thunk // RUN: %clang -### -S -fjmc --target=x86_64-unknown-linux %s 2>&1 | FileCheck -check-prefixes=CHECK_JMC_WARN,CHECK_NOJMC %s // RUN: %clang -### -S -fjmc --target=x86_64-pc-windows-msvc %s 2>&1 | FileCheck -check-prefixes=CHECK_JMC_WARN,CHECK_NOJMC %s >From 4d57eab46254dcb9a837da01971fb12ab8feea73 Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Mon, 15 Dec 2025 22:06:08 -0800 Subject: [PATCH 05/10] update comment --- clang/lib/Driver/ToolChains/Clang.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 59353f0a81b0c..c5d334b5d62fb 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4097,6 +4097,8 @@ static void RenderObjCOptions(const ToolChain &TC, const Driver &D, } // Forward -fobjc-direct-precondition-thunk to cc1 + // Defaults to false and needs explict turn on for now + // TODO: switch to default true and needs explict turn off in the future. if (Args.hasFlag(options::OPT_fobjc_direct_precondition_thunk, options::OPT_fno_objc_direct_precondition_thunk, false)) CmdArgs.push_back("-fobjc-direct-precondition-thunk"); >From 0e6213ecdc54715f80334916fb33d017123483e6 Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Tue, 16 Dec 2025 22:32:38 -1000 Subject: [PATCH 06/10] Update clang/include/clang/Options/Options.td Co-authored-by: Kyungwoo Lee <[email protected]> --- clang/include/clang/Options/Options.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index bab2b98f694b0..f92e2cd3947b0 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -3778,7 +3778,7 @@ defm objc_avoid_heapify_local_blocks : BoolFOption<"objc-avoid-heapify-local-blo defm objc_direct_precondition_thunk : BoolFOption<"objc-direct-precondition-thunk", CodeGenOpts<"ObjCDirectPreconditionThunk">, DefaultFalse, PosFlag<SetTrue, [], [ClangOption, CC1Option], - "Move direct methods' precondition checks to thunks">, + "Move precondition checks for direct methods into thunks">, NegFlag<SetFalse>>; defm disable_block_signature_string : BoolFOption<"disable-block-signature-string", CodeGenOpts<"DisableBlockSignatureString">, DefaultFalse, >From 9b90f395d6c2a78e502ab510744a4c13970ea3ea Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Wed, 17 Dec 2025 00:37:47 -0800 Subject: [PATCH 07/10] update comments --- clang/lib/CodeGen/CodeGenModule.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 1126bba5eef14..b03347043c455 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -720,6 +720,9 @@ class CodeGenModule : public CodeGenTypeCache { /// Check if a direct method should use precondition thunks (exposed symbols). /// This applies to ALL direct methods (including variadic). /// Returns false if OMD is null or not a direct method. + /// + /// Also checks the runtime family, as the attribute objc_direct is only + /// respected in the NeXT runtime right now. bool usePreconditionThunk(const ObjCMethodDecl *OMD) const { return OMD && OMD->isDirectMethod() && getLangOpts().ObjCRuntime.isNeXTFamily() && >From 4f31b461fb92383a8e898f656c2e3b280130cdec Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Wed, 17 Dec 2025 00:42:23 -0800 Subject: [PATCH 08/10] comment --- clang/include/clang/AST/DeclObjC.h | 6 ------ clang/lib/CodeGen/CodeGenModule.h | 13 ++++++------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/AST/DeclObjC.h b/clang/include/clang/AST/DeclObjC.h index 96c22bfeab735..2541edba83855 100644 --- a/clang/include/clang/AST/DeclObjC.h +++ b/clang/include/clang/AST/DeclObjC.h @@ -482,12 +482,6 @@ class ObjCMethodDecl : public NamedDecl, public DeclContext { /// True if the method is tagged as objc_direct bool isDirectMethod() const; - /// Check if this direct method can move precondition-check to thunk. - /// Variadic functions cannot use thunks (musttail incompatible with va_arg) - bool canHavePreconditionThunk() const { - return isDirectMethod() && !isVariadic(); - } - /// True if the method has a parameter that's destroyed in the callee. bool hasParamDestroyedInCallee() const; diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index b03347043c455..e54d34f951025 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -731,19 +731,18 @@ class CodeGenModule : public CodeGenTypeCache { /// Check if a direct method should use precondition thunks at call sites. /// This applies only to non-variadic direct methods. - /// Returns false if OMD is null or not eligible for thunks (e.g. variadic + /// Returns false if OMD is null or not eligible for thunks (variadic /// methods). bool shouldHavePreconditionThunk(const ObjCMethodDecl *OMD) const { - return OMD && usePreconditionThunk(OMD) && OMD->canHavePreconditionThunk(); + return OMD && usePreconditionThunk(OMD) && !OMD->isVariadic(); } /// Check if a direct method should have inline precondition checks at call - /// sites. This applies to direct methods that cannot use thunks (e.g., - /// variadic methods). These methods get exposed symbols but need inline - /// precondition checks instead of thunks. - /// Returns false if OMD is null or not eligible. + /// sites. This applies to direct methods that cannot use thunks (variadic + /// methods). These methods get exposed symbols but need inline precondition + /// checks instead of thunks. Returns false if OMD is null or not eligible. bool shouldHavePreconditionInline(const ObjCMethodDecl *OMD) const { - return OMD && usePreconditionThunk(OMD) && !OMD->canHavePreconditionThunk(); + return OMD && usePreconditionThunk(OMD) && OMD->isVariadic(); } const std::string &getModuleNameHash() const { return ModuleNameHash; } >From 1cf22070010a1ac6136aecf537ff15af17dcf9d1 Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Wed, 17 Dec 2025 00:42:35 -0800 Subject: [PATCH 09/10] remove one helper --- clang/lib/CodeGen/CGObjCRuntime.cpp | 7 ------- clang/lib/CodeGen/CGObjCRuntime.h | 10 ---------- 2 files changed, 17 deletions(-) diff --git a/clang/lib/CodeGen/CGObjCRuntime.cpp b/clang/lib/CodeGen/CGObjCRuntime.cpp index a4b4460fdc49c..3d47dc9560c65 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.cpp +++ b/clang/lib/CodeGen/CGObjCRuntime.cpp @@ -413,13 +413,6 @@ bool CGObjCRuntime::canMessageReceiverBeNull( return true; } -bool CGObjCRuntime::canClassObjectBeUnrealized( - const ObjCInterfaceDecl *CalleeClassDecl, CodeGenFunction &CGF) const { - // TODO - // Otherwise, assume it can be unrealized. - return true; -} - bool CGObjCRuntime::isWeakLinkedClass(const ObjCInterfaceDecl *ID) { do { if (ID->isWeakImported()) diff --git a/clang/lib/CodeGen/CGObjCRuntime.h b/clang/lib/CodeGen/CGObjCRuntime.h index 0f0cc6ba09200..8cd75b19c4d8d 100644 --- a/clang/lib/CodeGen/CGObjCRuntime.h +++ b/clang/lib/CodeGen/CGObjCRuntime.h @@ -329,16 +329,6 @@ class CGObjCRuntime { const ObjCInterfaceDecl *classReceiver, llvm::Value *receiver); - /// Check if a class object can be unrealized (not yet initialized). - /// Returns true if the class may be unrealized, false if provably realized. - /// - /// TODO: Returns false if: - /// - An instance method on the same class was called in a dominating path - /// - The class was explicitly realized earlier in control flow - /// - Note: [Parent foo] does NOT realize Child (inheritance care needed) - virtual bool canClassObjectBeUnrealized(const ObjCInterfaceDecl *ClassDecl, - CodeGenFunction &CGF) const; - static bool isWeakLinkedClass(const ObjCInterfaceDecl *cls); /// Destroy the callee-destroyed arguments of the given method, >From 24e8ee411a41f234a9203b19185d3abbd65b7be5 Mon Sep 17 00:00:00 2001 From: Peter Rong <[email protected]> Date: Wed, 17 Dec 2025 12:09:27 -0800 Subject: [PATCH 10/10] comment and warning about other runtimes --- clang/include/clang/Basic/DiagnosticDriverKinds.td | 3 +++ clang/lib/CodeGen/CodeGenModule.h | 5 +++-- clang/lib/Driver/ToolChains/Clang.cpp | 12 +++++++++--- clang/test/Driver/clang_f_opts.c | 9 +++++++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td index aeffe96e806bd..340b7ef879017 100644 --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -155,6 +155,9 @@ def warn_drv_unsupported_diag_option_for_flang : Warning< def warn_drv_unsupported_option_for_processor : Warning< "ignoring '%0' option as it is not currently supported for processor '%1'">, InGroup<OptionIgnored>; +def warn_drv_unsupported_option_for_runtime : Warning< + "ignoring '%0' option as it is not currently supported for runtime '%1'">, + InGroup<OptionIgnored>; def warn_drv_unsupported_openmp_library : Warning< "the library '%0=%1' is not supported, OpenMP will not be enabled">, InGroup<OptionIgnored>; diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index e54d34f951025..b4411e8355b93 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -721,10 +721,11 @@ class CodeGenModule : public CodeGenTypeCache { /// This applies to ALL direct methods (including variadic). /// Returns false if OMD is null or not a direct method. /// - /// Also checks the runtime family, as the attribute objc_direct is only - /// respected in the NeXT runtime right now. + /// Also checks the runtime family, currently we only support NeXT. + /// TODO: Add support for GNUStep as well. bool usePreconditionThunk(const ObjCMethodDecl *OMD) const { return OMD && OMD->isDirectMethod() && + getLangOpts().ObjCRuntime.allowsDirectDispatch() && getLangOpts().ObjCRuntime.isNeXTFamily() && getCodeGenOpts().ObjCDirectPreconditionThunk; } diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index c5d334b5d62fb..693b95726a6ec 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -4099,10 +4099,16 @@ static void RenderObjCOptions(const ToolChain &TC, const Driver &D, // Forward -fobjc-direct-precondition-thunk to cc1 // Defaults to false and needs explict turn on for now // TODO: switch to default true and needs explict turn off in the future. + // TODO: add support for other runtimes if (Args.hasFlag(options::OPT_fobjc_direct_precondition_thunk, - options::OPT_fno_objc_direct_precondition_thunk, false)) - CmdArgs.push_back("-fobjc-direct-precondition-thunk"); - + options::OPT_fno_objc_direct_precondition_thunk, false)) { + if (Runtime.isNeXTFamily()) { + CmdArgs.push_back("-fobjc-direct-precondition-thunk"); + } else { + D.Diag(diag::warn_drv_unsupported_option_for_runtime) + << "-fobjc-direct-precondition-thunk" << Runtime.getAsString(); + } + } // When ObjectiveC legacy runtime is in effect on MacOSX, turn on the option // to do Array/Dictionary subscripting by default. if (Arch == llvm::Triple::x86 && T.isMacOSX() && diff --git a/clang/test/Driver/clang_f_opts.c b/clang/test/Driver/clang_f_opts.c index 1c401f75defd2..b13f122a4ab75 100644 --- a/clang/test/Driver/clang_f_opts.c +++ b/clang/test/Driver/clang_f_opts.c @@ -607,6 +607,15 @@ // CHECK_DIRECT_PRECONDITION_THUNK: "-fobjc-direct-precondition-thunk" // CHECK_NO_DIRECT_PRECONDITION_THUNK-NOT: -fobjc-direct-precondition-thunk +// Test that -fobjc-direct-precondition-thunk emits a warning when used with GNU runtime +// and that the flag is not passed to cc1. +// RUN: %clang --target=x86_64-linux-gnu -fobjc-runtime=gnustep-2.0 -fobjc-direct-precondition-thunk -### -c -xobjective-c %s 2>&1 | FileCheck -check-prefix=CHECK_GNUSTEP_WARN %s +// CHECK_GNUSTEP_WARN: warning: ignoring '-fobjc-direct-precondition-thunk' option as it is not currently supported for runtime 'gnustep-2.0' [-Woption-ignored] +// CHECK_GNUSTEP_WARN-NOT: "-fobjc-direct-precondition-thunk" +// RUN: %clang --target=x86_64-linux-gnu -fobjc-runtime=gcc -fobjc-direct-precondition-thunk -### -c -xobjective-c %s 2>&1 | FileCheck -check-prefix=CHECK_GCC_WARN %s +// CHECK_GCC_WARN: warning: ignoring '-fobjc-direct-precondition-thunk' option as it is not currently supported for runtime 'gcc' [-Woption-ignored] +// CHECK_GCC_WARN-NOT: "-fobjc-direct-precondition-thunk" + // RUN: %clang -### -S -fjmc --target=x86_64-unknown-linux %s 2>&1 | FileCheck -check-prefixes=CHECK_JMC_WARN,CHECK_NOJMC %s // RUN: %clang -### -S -fjmc --target=x86_64-pc-windows-msvc %s 2>&1 | FileCheck -check-prefixes=CHECK_JMC_WARN,CHECK_NOJMC %s // RUN: %clang -### -S -fjmc -g --target=x86_64-pc-windows-msvc %s 2>&1 | FileCheck -check-prefix=CHECK_JMC %s _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
