From c6e490c662c8a13b2ba2fef17c819304a04e45ff Mon Sep 17 00:00:00 2001 From: Jo Bates <29763794+jbatez@users.noreply.github.com> Date: Wed, 4 Jun 2025 19:49:13 -0700 Subject: [PATCH 1/8] initial implementation of the darwin_objc unstable feature --- compiler/rustc_attr_parsing/messages.ftl | 4 + .../src/attributes/codegen_attrs.rs | 62 +++++- compiler/rustc_attr_parsing/src/context.rs | 6 +- .../src/session_diagnostics.rs | 14 ++ compiler/rustc_codegen_llvm/src/base.rs | 32 ++- compiler/rustc_codegen_llvm/src/common.rs | 14 ++ compiler/rustc_codegen_llvm/src/consts.rs | 188 +++++++++++++++++- compiler/rustc_codegen_llvm/src/context.rs | 56 +++++- .../rustc_codegen_ssa/src/codegen_attrs.rs | 6 + compiler/rustc_feature/src/builtin_attrs.rs | 8 + .../rustc_hir/src/attrs/data_structures.rs | 6 + .../rustc_hir/src/attrs/encode_cross_crate.rs | 2 + .../src/middle/codegen_fn_attrs.rs | 6 + compiler/rustc_passes/src/check_attr.rs | 2 + compiler/rustc_span/src/symbol.rs | 2 + library/core/src/lib.rs | 1 + library/core/src/os/darwin/mod.rs | 19 ++ library/core/src/os/darwin/objc.rs | 101 ++++++++++ library/core/src/os/mod.rs | 24 +++ library/std/src/os/darwin/mod.rs | 2 + library/std/src/os/darwin/objc.rs | 13 ++ src/tools/tidy/src/pal.rs | 1 + tests/codegen-llvm/darwin-objc.rs | 148 ++++++++++++++ 23 files changed, 706 insertions(+), 11 deletions(-) create mode 100644 library/core/src/os/darwin/mod.rs create mode 100644 library/core/src/os/darwin/objc.rs create mode 100644 library/core/src/os/mod.rs create mode 100644 library/std/src/os/darwin/objc.rs create mode 100644 tests/codegen-llvm/darwin-objc.rs diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 40e9d597530b7..7829dca27f5f2 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -116,6 +116,10 @@ attr_parsing_null_on_export = `export_name` may not contain null characters attr_parsing_null_on_link_section = `link_section` may not contain null characters +attr_parsing_null_on_objc_class = `rustc_objc_class` may not contain null characters + +attr_parsing_null_on_objc_selector = `rustc_objc_selector` may not contain null characters + attr_parsing_repr_ident = meta item in `repr` must be an identifier diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index b884f8f38328c..aceebc2f34978 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -2,7 +2,9 @@ use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy}; use rustc_session::parse::feature_err; use super::prelude::*; -use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport}; +use crate::session_diagnostics::{ + NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector, +}; pub(crate) struct OptimizeParser; @@ -149,6 +151,64 @@ impl SingleAttributeParser for ExportNameParser { } } +pub(crate) struct ObjcClassParser; + +impl SingleAttributeParser for ObjcClassParser { + const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(classname) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + if classname.as_str().contains('\0') { + // `#[rustc_objc_class = ...]` will be converted to a null-terminated string, + // so it may not contain any null characters. + cx.emit_err(NullOnObjcClass { span: cx.attr_span }); + return None; + } + Some(AttributeKind::ObjcClass { classname, span: cx.attr_span }) + } +} + +pub(crate) struct ObjcSelectorParser; + +impl SingleAttributeParser for ObjcSelectorParser { + const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(methname) = nv.value_as_str() else { + cx.expected_string_literal(nv.value_span, Some(nv.value_as_lit())); + return None; + }; + if methname.as_str().contains('\0') { + // `#[rustc_objc_selector = ...]` will be converted to a null-terminated string, + // so it may not contain any null characters. + cx.emit_err(NullOnObjcSelector { span: cx.attr_span }); + return None; + } + Some(AttributeKind::ObjcSelector { methname, span: cx.attr_span }) + } +} + #[derive(Default)] pub(crate) struct NakedParser { span: Option, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d4b9cfe00add1..7cc3780f3e1a4 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -20,8 +20,8 @@ use crate::attributes::allow_unstable::{ use crate::attributes::body::CoroutineParser; use crate::attributes::codegen_attrs::{ ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser, - NoMangleParser, OptimizeParser, SanitizeParser, TargetFeatureParser, TrackCallerParser, - UsedParser, + NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, SanitizeParser, + TargetFeatureParser, TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::crate_level::CrateNameParser; @@ -179,6 +179,8 @@ attribute_parsers!( Single, Single, Single, + Single, + Single, Single, Single, Single, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 72bee0ddfbfe2..1b25835359978 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -459,6 +459,20 @@ pub(crate) struct NullOnLinkSection { pub span: Span, } +#[derive(Diagnostic)] +#[diag(attr_parsing_null_on_objc_class)] +pub(crate) struct NullOnObjcClass { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_null_on_objc_selector)] +pub(crate) struct NullOnObjcSelector { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd { diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 9cc5d8dbc21cf..e011fc8203db3 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -109,18 +109,35 @@ pub(crate) fn compile_codegen_unit( attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs); } + // Define Objective-C module info for 32-bit x86 macOS. Note, this generates a global + // that gets added to the `llvm.compiler.used` variable, created later. + // + // This is only necessary when we need the linker to do its Objective-C-specific magic. + // We could theoretically do it unconditionally, but at a slight cost to linker + // performance in the common case where it's unnecessary. + let uses_objc = + !cx.objc_classrefs.borrow().is_empty() || !cx.objc_selrefs.borrow().is_empty(); + if uses_objc && cx.tcx.sess.target.arch == "x86" && cx.tcx.sess.target.os == "macos" { + cx.define_objc_module_info(); + } + // Finalize code coverage by injecting the coverage map. Note, the coverage map will // also be added to the `llvm.compiler.used` variable, created next. if cx.sess().instrument_coverage() { cx.coverageinfo_finalize(); } - // Create the llvm.used and llvm.compiler.used variables. + // Create the llvm.used variable. if !cx.used_statics.is_empty() { cx.create_used_variable_impl(c"llvm.used", &cx.used_statics); } - if !cx.compiler_used_statics.is_empty() { - cx.create_used_variable_impl(c"llvm.compiler.used", &cx.compiler_used_statics); + + // Create the llvm.compiler.used variable. + { + let compiler_used_statics = cx.compiler_used_statics.borrow(); + if !compiler_used_statics.is_empty() { + cx.create_used_variable_impl(c"llvm.compiler.used", &compiler_used_statics); + } } // Run replace-all-uses-with for statics that need it. This must @@ -132,6 +149,15 @@ pub(crate) fn compile_codegen_unit( } } + // Add Objective-C module flags. + // + // This is only necessary when we need the linker to do its Objective-C-specific magic. + // We could theoretically do it unconditionally, but at a slight cost to linker + // performance in the common case where it's unnecessary. + if uses_objc { + cx.add_objc_module_flags(); + } + // Finalize debuginfo if cx.sess().opts.debuginfo != DebugInfo::None { cx.debuginfo_finalize(); diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index f29fefb66f0fe..312015f2a3b2a 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -108,6 +108,10 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { bytes_in_context(self.llcx(), bytes) } + pub(crate) fn null_terminate_const_bytes(&self, bytes: &[u8]) -> &'ll Value { + null_terminate_bytes_in_context(self.llcx(), bytes) + } + pub(crate) fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value { unsafe { let idx = c_uint::try_from(idx).expect("LLVMGetAggregateElement index overflow"); @@ -381,6 +385,16 @@ pub(crate) fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> & } } +pub(crate) fn null_terminate_bytes_in_context<'ll>( + llcx: &'ll llvm::Context, + bytes: &[u8], +) -> &'ll Value { + unsafe { + let ptr = bytes.as_ptr() as *const c_char; + llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), False) + } +} + pub(crate) fn named_struct<'ll>(ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value { let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow"); unsafe { llvm::LLVMConstNamedStruct(ty, elts.as_ptr(), len) } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 9ec7b0f80aee7..1060f2872ba84 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -16,6 +16,7 @@ use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; +use rustc_span::Symbol; use tracing::{debug, instrument, trace}; use crate::common::CodegenCx; @@ -331,6 +332,10 @@ impl<'ll> CodegenCx<'ll, '_> { } g + } else if let Some(classname) = fn_attrs.objc_class { + self.get_objc_classref(classname) + } else if let Some(methname) = fn_attrs.objc_selector { + self.get_objc_selref(methname) } else { check_and_apply_linkage(self, fn_attrs, llty, sym, def_id) }; @@ -541,8 +546,187 @@ impl<'ll> CodegenCx<'ll, '_> { /// Add a global value to a list to be stored in the `llvm.compiler.used` variable, /// an array of ptr. - pub(crate) fn add_compiler_used_global(&mut self, global: &'ll Value) { - self.compiler_used_statics.push(global); + pub(crate) fn add_compiler_used_global(&self, global: &'ll Value) { + self.compiler_used_statics.borrow_mut().push(global); + } + + fn define_objc_classname(&self, classname: &str) -> &'ll Value { + // 32-bit x86 macOS only. + assert_eq!(self.tcx.sess.target.arch, "x86"); + assert_eq!(self.tcx.sess.target.os, "macos"); + + let llval = self.null_terminate_const_bytes(classname.as_bytes()); + let llty = self.val_ty(llval); + let sym = self.generate_local_symbol_name("OBJC_CLASS_NAME_"); + let g = self.define_global(&sym, llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + set_global_alignment(self, g, self.tcx.data_layout.i8_align.abi); + llvm::set_initializer(g, llval); + llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); + llvm::set_section(g, c"__TEXT,__cstring,cstring_literals"); + llvm::LLVMSetGlobalConstant(g, llvm::True); + llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); + self.add_compiler_used_global(g); + + g + } + + fn get_objc_class_t(&self) -> &'ll Type { + if let Some(class_t) = self.objc_class_t.get() { + return class_t; + } + + // Darwin-like targets other than 32-bit x86 macOS. + assert!(self.tcx.sess.target.is_like_darwin); + assert!(self.tcx.sess.target.arch != "x86" || self.tcx.sess.target.os != "macos"); + + let class_t = self.type_named_struct("struct._class_t"); + let els = [self.type_ptr(); 5]; + let packed = false; + self.set_struct_body(class_t, &els, packed); + + self.objc_class_t.set(Some(class_t)); + class_t + } + + // We do our best here to match what Clang does when compiling Objective-C natively. We + // deduplicate references within a CGU, but we need a reference definition in each referencing + // CGU. All attempts at using external references to a single reference definition result in + // linker errors. + fn get_objc_classref(&self, classname: Symbol) -> &'ll Value { + let mut classrefs = self.objc_classrefs.borrow_mut(); + if let Some(classref) = classrefs.get(&classname).copied() { + return classref; + } + + let g = if self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos" { + // 32-bit x86 macOS. + let llval = self.define_objc_classname(classname.as_str()); + let llty = self.type_ptr(); + let sym = self.generate_local_symbol_name("OBJC_CLASS_REFERENCES_"); + let g = self.define_global(&sym, llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + llvm::set_initializer(g, llval); + llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); + llvm::set_section(g, c"__OBJC,__cls_refs,literal_pointers"); + self.add_compiler_used_global(g); + g + } else { + // Darwin-like targets other than 32-bit x86 macOS. + assert!(self.tcx.sess.target.is_like_darwin); + let llval = { + let extern_sym = format!("OBJC_CLASS_$_{}", classname.as_str()); + let extern_llty = self.get_objc_class_t(); + self.declare_global(&extern_sym, extern_llty) + }; + let llty = self.type_ptr(); + let sym = self.generate_local_symbol_name("OBJC_CLASSLIST_REFERENCES_$_"); + let g = self.define_global(&sym, llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + llvm::set_initializer(g, llval); + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); + llvm::set_section(g, c"__DATA,__objc_classrefs,regular"); + self.add_compiler_used_global(g); + g + }; + + classrefs.insert(classname, g); + g + } + + // We do our best here to match what Clang does when compiling Objective-C natively. We + // deduplicate references within a CGU, but we need a reference definition in each referencing + // CGU. All attempts at using external references to a single reference definition result in + // linker errors. + fn get_objc_selref(&self, methname: Symbol) -> &'ll Value { + let mut selrefs = self.objc_selrefs.borrow_mut(); + if let Some(selref) = selrefs.get(&methname).copied() { + return selref; + } + + // Darwin-like targets only. + assert!(self.tcx.sess.target.is_like_darwin); + let is_x86_32_macos = + self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos"; + + let methname_llval = self.null_terminate_const_bytes(methname.as_str().as_bytes()); + let methname_llty = self.val_ty(methname_llval); + let methname_sym = self.generate_local_symbol_name("OBJC_METH_VAR_NAME_"); + let methname_g = self.define_global(&methname_sym, methname_llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", methname_sym); + }); + set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align.abi); + llvm::set_initializer(methname_g, methname_llval); + llvm::set_linkage(methname_g, llvm::Linkage::PrivateLinkage); + if is_x86_32_macos { + llvm::set_section(methname_g, c"__TEXT,__cstring,cstring_literals"); + } else { + llvm::set_section(methname_g, c"__TEXT,__objc_methname,cstring_literals"); + } + llvm::LLVMSetGlobalConstant(methname_g, llvm::True); + llvm::LLVMSetUnnamedAddress(methname_g, llvm::UnnamedAddr::Global); + self.add_compiler_used_global(methname_g); + + let selref_llval = methname_g; + let selref_llty = self.type_ptr(); + let selref_sym = self.generate_local_symbol_name("OBJC_SELECTOR_REFERENCES_"); + let selref_g = self.define_global(&selref_sym, selref_llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", selref_sym); + }); + set_global_alignment(self, selref_g, self.tcx.data_layout.pointer_align().abi); + llvm::set_initializer(selref_g, selref_llval); + if is_x86_32_macos { + llvm::set_linkage(selref_g, llvm::Linkage::PrivateLinkage); + llvm::set_section(selref_g, c"__OBJC,__message_refs,literal_pointers"); + } else { + llvm::set_linkage(selref_g, llvm::Linkage::InternalLinkage); + llvm::set_section(selref_g, c"__DATA,__objc_selrefs,literal_pointers"); + } + self.add_compiler_used_global(selref_g); + + selrefs.insert(methname, selref_g); + selref_g + } + + pub(crate) fn define_objc_module_info(&mut self) { + // 32-bit x86 macOS only. + assert_eq!(self.tcx.sess.target.arch, "x86"); + assert_eq!(self.tcx.sess.target.os, "macos"); + + // struct _objc_module { + // long version; // Hardcoded to 7 in Clang. + // long size; // sizeof(struct _objc_module) + // char *name; // Hardcoded to classname "" in Clang. + // struct _objc_symtab* symtab; // Null without class or category definitions. + // } + + let llty = self.type_named_struct("struct._objc_module"); + let i32_llty = self.type_i32(); + let ptr_llty = self.type_ptr(); + let packed = false; + self.set_struct_body(llty, &[i32_llty, i32_llty, ptr_llty, ptr_llty], packed); + + let version = self.const_uint(i32_llty, 7); + let size = self.const_uint(i32_llty, 16); + let name = self.define_objc_classname(""); + let symtab = self.const_null(ptr_llty); + let llval = crate::common::named_struct(llty, &[version, size, name, symtab]); + + let sym = "OBJC_MODULES"; + let g = self.define_global(&sym, llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + llvm::set_initializer(g, llval); + llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); + llvm::set_section(g, c"__OBJC,__module_info,regular,no_dead_strip"); + + self.add_compiler_used_global(g); } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 4a7de7d2e69e2..a7d6d7b59cad6 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -26,7 +26,7 @@ use rustc_session::config::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet, }; use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::{HasTargetSpec, RelocModel, SmallDataThresholdSupport, Target, TlsModel}; use smallvec::SmallVec; @@ -119,7 +119,7 @@ pub(crate) struct FullCx<'ll, 'tcx> { /// Statics that will be placed in the llvm.compiler.used variable /// See for details - pub compiler_used_statics: Vec<&'ll Value>, + pub compiler_used_statics: RefCell>, /// Mapping of non-scalar types to llvm types. pub type_lowering: RefCell, Option), &'ll Type>>, @@ -146,6 +146,15 @@ pub(crate) struct FullCx<'ll, 'tcx> { /// `global_asm!` needs to be able to find this new global so that it can /// compute the correct mangled symbol name to insert into the asm. pub renamed_statics: RefCell>, + + /// Cached Objective-C class type + pub objc_class_t: Cell>, + + /// Cache of Objective-C class references + pub objc_classrefs: RefCell>, + + /// Cache of Objective-C selector references + pub objc_selrefs: RefCell>, } fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode { @@ -640,7 +649,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { const_globals: Default::default(), statics_to_rauw: RefCell::new(Vec::new()), used_statics: Vec::new(), - compiler_used_statics: Vec::new(), + compiler_used_statics: Default::default(), type_lowering: Default::default(), scalar_lltypes: Default::default(), coverage_cx, @@ -651,6 +660,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { intrinsics: Default::default(), local_gen_sym_counter: Cell::new(0), renamed_statics: Default::default(), + objc_class_t: Cell::new(None), + objc_classrefs: Default::default(), + objc_selrefs: Default::default(), }, PhantomData, ) @@ -675,6 +687,44 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { llvm::set_linkage(g, llvm::Linkage::AppendingLinkage); llvm::set_section(g, c"llvm.metadata"); } + + pub(crate) fn add_objc_module_flags(&self) { + assert!(self.tcx.sess.target.is_like_darwin); + + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Objective-C Image Info Version", + 0, + ); + + llvm::add_module_flag_str( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Objective-C Image Info Section", + if self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos" { + "__OBJC,__image_info,regular" + } else { + "__DATA,__objc_imageinfo,regular,no_dead_strip" + }, + ); + + if self.tcx.sess.target.env == "sim" { + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Objective-C Is Simulated", + 1 << 5, + ); + } + + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Objective-C Class Properties", + 1 << 6, + ); + } } impl<'ll> SimpleCx<'ll> { pub(crate) fn get_type_of_global(&self, val: &'ll Value) -> &'ll Type { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 6b0bd64102c65..b83de2074f140 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -296,6 +296,12 @@ fn process_builtin_attrs( AttributeKind::Sanitize { span, .. } => { interesting_spans.sanitize = Some(*span); } + AttributeKind::ObjcClass { classname, .. } => { + codegen_fn_attrs.objc_class = Some(*classname); + } + AttributeKind::ObjcSelector { methname, .. } => { + codegen_fn_attrs.objc_selector = Some(*methname); + } _ => {} } } diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e81003b18972a..852638eb45990 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1056,6 +1056,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, ), + rustc_attr!( + rustc_objc_class, Normal, template!(NameValueStr: "ClassName"), ErrorPreceding, + EncodeCrossCrate::No, + ), + rustc_attr!( + rustc_objc_selector, Normal, template!(NameValueStr: "methodName"), ErrorPreceding, + EncodeCrossCrate::No, + ), // ========================================================================== // Internal attributes, Macro related: diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index 09da5772d2311..06d39b140e0a5 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -467,6 +467,12 @@ pub enum AttributeKind { /// Represents `#[non_exhaustive]` NonExhaustive(Span), + /// Represents `#[rustc_objc_class]` + ObjcClass { classname: Symbol, span: Span }, + + /// Represents `#[rustc_objc_selector]` + ObjcSelector { methname: Symbol, span: Span }, + /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index e5329c104bb57..a7cf4403a6b0b 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -65,6 +65,8 @@ impl AttributeKind { NoImplicitPrelude(..) => No, NoMangle(..) => Yes, // Needed for rustdoc NonExhaustive(..) => Yes, // Needed for rustdoc + ObjcClass { .. } => No, + ObjcSelector { .. } => No, Optimize(..) => No, ParenSugar(..) => No, PassByValue(..) => Yes, diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 78cafe8566b60..f173640298aec 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -70,6 +70,10 @@ pub struct CodegenFnAttrs { /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around /// the function entry. pub patchable_function_entry: Option, + /// The `#[rustc_objc_class = "..."]` attribute. + pub objc_class: Option, + /// The `#[rustc_objc_selector = "..."]` attribute. + pub objc_selector: Option, } #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq, Eq)] @@ -184,6 +188,8 @@ impl CodegenFnAttrs { instruction_set: None, alignment: None, patchable_function_entry: None, + objc_class: None, + objc_selector: None, } } diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7aef60b7b9145..bc9f1906b5a66 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -252,6 +252,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::Linkage(..) | AttributeKind::MustUse { .. } | AttributeKind::CrateName { .. } + | AttributeKind::ObjcClass { .. } + | AttributeKind::ObjcSelector { .. } ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 5d140cc611771..dbde15970a50a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1907,6 +1907,8 @@ symbols! { rustc_no_mir_inline, rustc_nonnull_optimization_guaranteed, rustc_nounwind, + rustc_objc_class, + rustc_objc_selector, rustc_object_lifetime_default, rustc_on_unimplemented, rustc_outlives, diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index f69d6a98592ae..336d6f49156c0 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -343,6 +343,7 @@ pub mod io; pub mod iter; pub mod net; pub mod option; +pub mod os; pub mod panic; pub mod panicking; #[unstable(feature = "pattern_type_macro", issue = "123646")] diff --git a/library/core/src/os/darwin/mod.rs b/library/core/src/os/darwin/mod.rs new file mode 100644 index 0000000000000..8426d82b8ce3e --- /dev/null +++ b/library/core/src/os/darwin/mod.rs @@ -0,0 +1,19 @@ +//! Platform-specific extensions to `core` for Darwin / Apple platforms. +//! +//! This is available on the following operating systems: +//! - macOS +//! - iOS +//! - tvOS +//! - watchOS +//! - visionOS +//! +//! Note: This module is called "Darwin" as that's the name of the underlying +//! core OS of the above operating systems, but it should not be confused with +//! the `-darwin` suffix in the `x86_64-apple-darwin` and +//! `aarch64-apple-darwin` target names, which are mostly named that way for +//! legacy reasons. + +#![unstable(feature = "darwin_objc", issue = "145496")] +#![doc(cfg(target_vendor = "apple"))] + +pub mod objc; diff --git a/library/core/src/os/darwin/objc.rs b/library/core/src/os/darwin/objc.rs new file mode 100644 index 0000000000000..3532e6efaf957 --- /dev/null +++ b/library/core/src/os/darwin/objc.rs @@ -0,0 +1,101 @@ +//! Defines types and macros for Objective-C interoperability. + +#![unstable(feature = "darwin_objc", issue = "145496")] +#![allow(nonstandard_style)] + +use crate::fmt; + +/// Equivalent to Objective-C’s `struct objc_class` type. +#[cfg_attr(not(doc), repr(u8))] // An implementation detail we don't want to show up in rustdoc +pub enum objc_class { + #[unstable( + feature = "objc_class_variant", + reason = "temporary implementation detail", + issue = "none" + )] + #[doc(hidden)] + __variant1, + #[unstable( + feature = "objc_class_variant", + reason = "temporary implementation detail", + issue = "none" + )] + #[doc(hidden)] + __variant2, +} + +impl fmt::Debug for objc_class { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("objc_class").finish() + } +} + +/// Equivalent to Objective-C’s `struct objc_selector` type. +#[cfg_attr(not(doc), repr(u8))] // An implementation detail we don't want to show up in rustdoc +pub enum objc_selector { + #[unstable( + feature = "objc_selector_variant", + reason = "temporary implementation detail", + issue = "none" + )] + #[doc(hidden)] + __variant1, + #[unstable( + feature = "objc_selector_variant", + reason = "temporary implementation detail", + issue = "none" + )] + #[doc(hidden)] + __variant2, +} + +impl fmt::Debug for objc_selector { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("objc_selector").finish() + } +} + +/// Equivalent to Objective-C’s `Class` type. +pub type Class = *mut objc_class; + +/// Equivalent to Objective-C’s `SEL` type. +pub type SEL = *mut objc_selector; + +/// Gets a reference to an Objective-C class. +/// +/// This macro will yield an expression of type [`Class`] for the given class name string literal. +/// +/// # Example +/// +/// ```no_run +/// let string_class = class!("NSString"); +/// ``` +#[allow_internal_unstable(rustc_attrs)] +pub macro class($classname:expr) {{ + unsafe extern "C" { + #[rustc_objc_class = $classname] + safe static VAL: $crate::os::darwin::objc::Class; + } + VAL +}} + +/// Gets a reference to an Objective-C selector. +/// +/// This macro will yield an expression of type [`SEL`] for the given method name string literal. +/// +/// It is similar to Objective-C’s `@selector` directive. +/// +/// # Examples +/// +/// ```no_run +/// let alloc_sel = selector!("alloc"); +/// let init_sel = selector!("initWithCString:encoding:"); +/// ``` +#[allow_internal_unstable(rustc_attrs)] +pub macro selector($methname:expr) {{ + unsafe extern "C" { + #[rustc_objc_selector = $methname] + safe static VAL: $crate::os::darwin::objc::SEL; + } + VAL +}} diff --git a/library/core/src/os/mod.rs b/library/core/src/os/mod.rs new file mode 100644 index 0000000000000..897f59f530ed0 --- /dev/null +++ b/library/core/src/os/mod.rs @@ -0,0 +1,24 @@ +//! OS-specific functionality. + +#![unstable(feature = "darwin_objc", issue = "145496")] + +#[cfg(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +))] +#[unstable(issue = "none", feature = "std_internals")] +pub mod darwin {} + +// darwin +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] +#[cfg(any(target_vendor = "apple", doc))] +pub mod darwin; diff --git a/library/std/src/os/darwin/mod.rs b/library/std/src/os/darwin/mod.rs index 3b1bd974fa313..ff184f477fb0e 100644 --- a/library/std/src/os/darwin/mod.rs +++ b/library/std/src/os/darwin/mod.rs @@ -17,6 +17,8 @@ #![doc(cfg(target_vendor = "apple"))] pub mod fs; +pub mod objc; + // deprecated, but used for public reexport under `std::os::unix::raw`, as // well as `std::os::macos`/`std::os::ios`, because those modules precede the // decision to remove these. diff --git a/library/std/src/os/darwin/objc.rs b/library/std/src/os/darwin/objc.rs new file mode 100644 index 0000000000000..a4b31fee7c582 --- /dev/null +++ b/library/std/src/os/darwin/objc.rs @@ -0,0 +1,13 @@ +//! Defines types and macros for Objective-C interoperability. +//! +//! This module re-exports all the items in [`core::os::darwin::objc`]. +//! +//! [`core::os::darwin::objc`]: ../../../../core/os/darwin/objc/index.html "mod core::os::darwin::objc" + +#![unstable(feature = "darwin_objc", issue = "145496")] + +// We can't generate an intra-doc link for this automatically since `core::os::darwin` isn't +// compiled into `core` on every platform even though it's documented on every platform. +// We just link to it directly in the module documentation above instead. +#[cfg(not(doc))] +pub use core::os::darwin::objc::*; diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 5b8b44429bbc0..991ad55809cc3 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -53,6 +53,7 @@ const EXCEPTION_PATHS: &[&str] = &[ // core::ffi contains platform-specific type and linkage configuration "library/core/src/ffi/mod.rs", "library/core/src/ffi/primitives.rs", + "library/core/src/os", // Platform-specific public interfaces "library/std/src/sys", // Platform-specific code for std lives here. "library/std/src/os", // Platform-specific public interfaces // Temporary `std` exceptions diff --git a/tests/codegen-llvm/darwin-objc.rs b/tests/codegen-llvm/darwin-objc.rs new file mode 100644 index 0000000000000..5527cdcad698b --- /dev/null +++ b/tests/codegen-llvm/darwin-objc.rs @@ -0,0 +1,148 @@ +// ignore-tidy-linelength +//@ add-core-stubs +//@ revisions: i686_apple_darwin +//@ [i686_apple_darwin] compile-flags: --target i686-apple-darwin +//@ [i686_apple_darwin] needs-llvm-components: x86 +//@ revisions: x86_64_apple_darwin +//@ [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin +//@ [x86_64_apple_darwin] needs-llvm-components: x86 +//@ revisions: aarch64_apple_darwin +//@ [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin +//@ [aarch64_apple_darwin] needs-llvm-components: aarch64 +//@ revisions: i386_apple_ios +//@ [i386_apple_ios] compile-flags: --target i386-apple-ios +//@ [i386_apple_ios] needs-llvm-components: x86 +//@ revisions: x86_64_apple_ios +//@ [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios +//@ [x86_64_apple_ios] needs-llvm-components: x86 +//@ revisions: armv7s_apple_ios +//@ [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios +//@ [armv7s_apple_ios] needs-llvm-components: arm +//@ revisions: aarch64_apple_ios +//@ [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios +//@ [aarch64_apple_ios] needs-llvm-components: aarch64 +//@ revisions: aarch64_apple_ios_sim +//@ [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim +//@ [aarch64_apple_ios_sim] needs-llvm-components: aarch64 + +#![crate_type = "lib"] +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn get_class() -> *mut () { + unsafe extern "C" { + #[rustc_objc_class = "MyClass"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_selector() -> *mut () { + unsafe extern "C" { + #[rustc_objc_selector = "myMethod"] + safe static VAL: *mut (); + } + VAL +} + +// i686_apple_darwin: %struct._objc_module = type { i32, i32, ptr, ptr } +// x86_64_apple_darwin: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } +// aarch64_apple_darwin: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } +// i386_apple_ios: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } +// x86_64_apple_ios: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } +// armv7s_apple_ios: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } +// aarch64_apple_ios: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } +// aarch64_apple_ios_sim: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } + +// i686_apple_darwin: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [8 x i8] c"MyClass\00", section "__TEXT,__cstring,cstring_literals", align 1 +// x86_64_apple_darwin: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t +// aarch64_apple_darwin: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t +// i386_apple_ios: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t +// x86_64_apple_ios: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t +// armv7s_apple_ios: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t +// aarch64_apple_ios: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t +// aarch64_apple_ios_sim: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t + +// i686_apple_darwin: @OBJC_CLASS_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, section "__OBJC,__cls_refs,literal_pointers", align 4 +// x86_64_apple_darwin: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 8 +// aarch64_apple_darwin: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 8 +// i386_apple_ios: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 4 +// x86_64_apple_ios: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 8 +// armv7s_apple_ios: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 4 +// aarch64_apple_ios: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 8 +// aarch64_apple_ios_sim: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 8 + +// i686_apple_darwin: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__cstring,cstring_literals", align 1 +// x86_64_apple_darwin: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// aarch64_apple_darwin: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// i386_apple_ios: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// x86_64_apple_ios: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// armv7s_apple_ios: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// aarch64_apple_ios: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// aarch64_apple_ios_sim: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 + +// i686_apple_darwin: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__OBJC,__message_refs,literal_pointers", align 4 +// x86_64_apple_darwin: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 8 +// aarch64_apple_darwin: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 8 +// i386_apple_ios: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 4 +// x86_64_apple_ios: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 8 +// armv7s_apple_ios: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 4 +// aarch64_apple_ios: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 8 +// aarch64_apple_ios_sim: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 8 + +// i686_apple_darwin: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [1 x i8] zeroinitializer, section "__TEXT,__cstring,cstring_literals", align 1 +// i686_apple_darwin: @OBJC_MODULES = private global %struct._objc_module { i32 7, i32 16, ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, ptr null }, section "__OBJC,__module_info,regular,no_dead_strip", align 4 + +// i686_apple_darwin: load ptr, ptr @OBJC_CLASS_REFERENCES_.{{[0-9]+}}, align 4 +// x86_64_apple_darwin: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 +// aarch64_apple_darwin: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 +// i386_apple_ios: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 4 +// x86_64_apple_ios: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 +// armv7s_apple_ios: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 4 +// aarch64_apple_ios: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 +// aarch64_apple_ios_sim: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 + +// i686_apple_darwin: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 4 +// x86_64_apple_darwin: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 +// aarch64_apple_darwin: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 +// i386_apple_ios: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 4 +// x86_64_apple_ios: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 +// armv7s_apple_ios: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 4 +// aarch64_apple_ios: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 +// aarch64_apple_ios_sim: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 + +// i686_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// x86_64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// aarch64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// i386_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// x86_64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// armv7s_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// aarch64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// aarch64_apple_ios_sim: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} + +// i686_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__OBJC,__image_info,regular"} +// x86_64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} +// aarch64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} +// i386_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} +// x86_64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} +// armv7s_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} +// aarch64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} +// aarch64_apple_ios_sim: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} + +// i386_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// x86_64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// aarch64_apple_ios_sim: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} + +// i686_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} +// x86_64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} +// aarch64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} +// i386_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} +// x86_64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} +// armv7s_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} +// aarch64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} +// aarch64_apple_ios_sim: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} From 6685ac5a15669d874086f59fbf9b13a9670ee018 Mon Sep 17 00:00:00 2001 From: Jo Bates <29763794+jbatez@users.noreply.github.com> Date: Sun, 24 Aug 2025 12:38:43 -0700 Subject: [PATCH 2/8] separate darwin-objc-32bit-x86-macos test and use CHECK/-SAME/-NOT to reduce duplication --- .../darwin-objc-32bit-x86-macos.rs | 49 +++++ tests/codegen-llvm/darwin-objc.rs | 192 +++++++----------- 2 files changed, 121 insertions(+), 120 deletions(-) create mode 100644 tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs diff --git a/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs b/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs new file mode 100644 index 0000000000000..c217f84634a0b --- /dev/null +++ b/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs @@ -0,0 +1,49 @@ +// ignore-tidy-linelength +//@ add-core-stubs +//@ revisions: i686_apple_darwin +//@ [i686_apple_darwin] compile-flags: --target i686-apple-darwin +//@ [i686_apple_darwin] needs-llvm-components: x86 + +#![crate_type = "lib"] +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn get_class() -> *mut () { + unsafe extern "C" { + #[rustc_objc_class = "MyClass"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_selector() -> *mut () { + unsafe extern "C" { + #[rustc_objc_selector = "myMethod"] + safe static VAL: *mut (); + } + VAL +} + +// CHECK: %struct._objc_module = type { i32, i32, ptr, ptr } + +// CHECK: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [8 x i8] c"MyClass\00", section "__TEXT,__cstring,cstring_literals", align 1 +// CHECK: @OBJC_CLASS_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, section "__OBJC,__cls_refs,literal_pointers", align 4 + +// CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__cstring,cstring_literals", align 1 +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__OBJC,__message_refs,literal_pointers", align 4 + +// CHECK: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [1 x i8] zeroinitializer, section "__TEXT,__cstring,cstring_literals", align 1 +// CHECK: @OBJC_MODULES = private global %struct._objc_module { i32 7, i32 16, ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, ptr null }, section "__OBJC,__module_info,regular,no_dead_strip", align 4 + +// CHECK: load ptr, ptr @OBJC_CLASS_REFERENCES_.{{[0-9]+}}, align 4 +// CHECK: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 4 + +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__OBJC,__image_info,regular"} +// CHECK-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} diff --git a/tests/codegen-llvm/darwin-objc.rs b/tests/codegen-llvm/darwin-objc.rs index 5527cdcad698b..c47dbde82f991 100644 --- a/tests/codegen-llvm/darwin-objc.rs +++ b/tests/codegen-llvm/darwin-objc.rs @@ -1,29 +1,26 @@ // ignore-tidy-linelength //@ add-core-stubs -//@ revisions: i686_apple_darwin -//@ [i686_apple_darwin] compile-flags: --target i686-apple-darwin -//@ [i686_apple_darwin] needs-llvm-components: x86 -//@ revisions: x86_64_apple_darwin -//@ [x86_64_apple_darwin] compile-flags: --target x86_64-apple-darwin -//@ [x86_64_apple_darwin] needs-llvm-components: x86 -//@ revisions: aarch64_apple_darwin -//@ [aarch64_apple_darwin] compile-flags: --target aarch64-apple-darwin -//@ [aarch64_apple_darwin] needs-llvm-components: aarch64 -//@ revisions: i386_apple_ios -//@ [i386_apple_ios] compile-flags: --target i386-apple-ios -//@ [i386_apple_ios] needs-llvm-components: x86 -//@ revisions: x86_64_apple_ios -//@ [x86_64_apple_ios] compile-flags: --target x86_64-apple-ios -//@ [x86_64_apple_ios] needs-llvm-components: x86 -//@ revisions: armv7s_apple_ios -//@ [armv7s_apple_ios] compile-flags: --target armv7s-apple-ios -//@ [armv7s_apple_ios] needs-llvm-components: arm -//@ revisions: aarch64_apple_ios -//@ [aarch64_apple_ios] compile-flags: --target aarch64-apple-ios -//@ [aarch64_apple_ios] needs-llvm-components: aarch64 -//@ revisions: aarch64_apple_ios_sim -//@ [aarch64_apple_ios_sim] compile-flags: --target aarch64-apple-ios-sim -//@ [aarch64_apple_ios_sim] needs-llvm-components: aarch64 +//@ revisions: x86_64_macos +//@ [x86_64_macos] compile-flags: --target x86_64-apple-darwin +//@ [x86_64_macos] needs-llvm-components: x86 +//@ revisions: aarch64_macos +//@ [aarch64_macos] compile-flags: --target aarch64-apple-darwin +//@ [aarch64_macos] needs-llvm-components: aarch64 +//@ revisions: i386_ios +//@ [i386_ios] compile-flags: --target i386-apple-ios +//@ [i386_ios] needs-llvm-components: x86 +//@ revisions: x86_64_ios +//@ [x86_64_ios] compile-flags: --target x86_64-apple-ios +//@ [x86_64_ios] needs-llvm-components: x86 +//@ revisions: armv7s_ios +//@ [armv7s_ios] compile-flags: --target armv7s-apple-ios +//@ [armv7s_ios] needs-llvm-components: arm +//@ revisions: aarch64_ios +//@ [aarch64_ios] compile-flags: --target aarch64-apple-ios +//@ [aarch64_ios] needs-llvm-components: aarch64 +//@ revisions: aarch64_ios_sim +//@ [aarch64_ios_sim] compile-flags: --target aarch64-apple-ios-sim +//@ [aarch64_ios_sim] needs-llvm-components: aarch64 #![crate_type = "lib"] #![feature(no_core, lang_items, rustc_attrs)] @@ -50,99 +47,54 @@ pub fn get_selector() -> *mut () { VAL } -// i686_apple_darwin: %struct._objc_module = type { i32, i32, ptr, ptr } -// x86_64_apple_darwin: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } -// aarch64_apple_darwin: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } -// i386_apple_ios: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } -// x86_64_apple_ios: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } -// armv7s_apple_ios: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } -// aarch64_apple_ios: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } -// aarch64_apple_ios_sim: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } - -// i686_apple_darwin: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [8 x i8] c"MyClass\00", section "__TEXT,__cstring,cstring_literals", align 1 -// x86_64_apple_darwin: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t -// aarch64_apple_darwin: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t -// i386_apple_ios: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t -// x86_64_apple_ios: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t -// armv7s_apple_ios: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t -// aarch64_apple_ios: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t -// aarch64_apple_ios_sim: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t - -// i686_apple_darwin: @OBJC_CLASS_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, section "__OBJC,__cls_refs,literal_pointers", align 4 -// x86_64_apple_darwin: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 8 -// aarch64_apple_darwin: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 8 -// i386_apple_ios: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 4 -// x86_64_apple_ios: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 8 -// armv7s_apple_ios: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 4 -// aarch64_apple_ios: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 8 -// aarch64_apple_ios_sim: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", align 8 - -// i686_apple_darwin: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__cstring,cstring_literals", align 1 -// x86_64_apple_darwin: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 -// aarch64_apple_darwin: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 -// i386_apple_ios: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 -// x86_64_apple_ios: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 -// armv7s_apple_ios: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 -// aarch64_apple_ios: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 -// aarch64_apple_ios_sim: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 - -// i686_apple_darwin: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__OBJC,__message_refs,literal_pointers", align 4 -// x86_64_apple_darwin: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 8 -// aarch64_apple_darwin: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 8 -// i386_apple_ios: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 4 -// x86_64_apple_ios: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 8 -// armv7s_apple_ios: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 4 -// aarch64_apple_ios: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 8 -// aarch64_apple_ios_sim: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", align 8 - -// i686_apple_darwin: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [1 x i8] zeroinitializer, section "__TEXT,__cstring,cstring_literals", align 1 -// i686_apple_darwin: @OBJC_MODULES = private global %struct._objc_module { i32 7, i32 16, ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, ptr null }, section "__OBJC,__module_info,regular,no_dead_strip", align 4 - -// i686_apple_darwin: load ptr, ptr @OBJC_CLASS_REFERENCES_.{{[0-9]+}}, align 4 -// x86_64_apple_darwin: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 -// aarch64_apple_darwin: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 -// i386_apple_ios: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 4 -// x86_64_apple_ios: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 -// armv7s_apple_ios: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 4 -// aarch64_apple_ios: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 -// aarch64_apple_ios_sim: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 - -// i686_apple_darwin: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 4 -// x86_64_apple_darwin: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 -// aarch64_apple_darwin: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 -// i386_apple_ios: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 4 -// x86_64_apple_ios: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 -// armv7s_apple_ios: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 4 -// aarch64_apple_ios: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 -// aarch64_apple_ios_sim: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 - -// i686_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} -// x86_64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} -// aarch64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} -// i386_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} -// x86_64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} -// armv7s_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} -// aarch64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} -// aarch64_apple_ios_sim: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} - -// i686_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__OBJC,__image_info,regular"} -// x86_64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} -// aarch64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} -// i386_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} -// x86_64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} -// armv7s_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} -// aarch64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} -// aarch64_apple_ios_sim: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} - -// i386_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} -// x86_64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} -// aarch64_apple_ios_sim: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} - -// i686_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} -// x86_64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} -// aarch64_apple_darwin: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} -// i386_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} -// x86_64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} -// armv7s_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} -// aarch64_apple_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} -// aarch64_apple_ios_sim: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} +// CHECK: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } +// CHECK: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t +// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 + +// CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 + +// CHECK: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 + +// CHECK: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 + +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} + +// x86_64_macos-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// aarch64_macos-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// i386_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// x86_64_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// armv7s_ios-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// aarch64_ios-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// aarch64_ios_sim: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} + +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} From dcbf5055c7369e93588c3a5cc6388fe8a74c8e8e Mon Sep 17 00:00:00 2001 From: Jo Bates <29763794+jbatez@users.noreply.github.com> Date: Sun, 24 Aug 2025 12:49:29 -0700 Subject: [PATCH 3/8] add no_dead_strip to OBJC_CLASS_REFERENCES_ and OBJC_SELECTOR_REFERENCES_ --- compiler/rustc_codegen_llvm/src/consts.rs | 8 ++++---- tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs | 4 ++-- tests/codegen-llvm/darwin-objc.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 1060f2872ba84..8179d6e63c98e 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -611,7 +611,7 @@ impl<'ll> CodegenCx<'ll, '_> { set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); llvm::set_initializer(g, llval); llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); - llvm::set_section(g, c"__OBJC,__cls_refs,literal_pointers"); + llvm::set_section(g, c"__OBJC,__cls_refs,literal_pointers,no_dead_strip"); self.add_compiler_used_global(g); g } else { @@ -630,7 +630,7 @@ impl<'ll> CodegenCx<'ll, '_> { set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); llvm::set_initializer(g, llval); llvm::set_linkage(g, llvm::Linkage::InternalLinkage); - llvm::set_section(g, c"__DATA,__objc_classrefs,regular"); + llvm::set_section(g, c"__DATA,__objc_classrefs,regular,no_dead_strip"); self.add_compiler_used_global(g); g }; @@ -682,10 +682,10 @@ impl<'ll> CodegenCx<'ll, '_> { llvm::set_initializer(selref_g, selref_llval); if is_x86_32_macos { llvm::set_linkage(selref_g, llvm::Linkage::PrivateLinkage); - llvm::set_section(selref_g, c"__OBJC,__message_refs,literal_pointers"); + llvm::set_section(selref_g, c"__OBJC,__message_refs,literal_pointers,no_dead_strip"); } else { llvm::set_linkage(selref_g, llvm::Linkage::InternalLinkage); - llvm::set_section(selref_g, c"__DATA,__objc_selrefs,literal_pointers"); + llvm::set_section(selref_g, c"__DATA,__objc_selrefs,literal_pointers,no_dead_strip"); } self.add_compiler_used_global(selref_g); diff --git a/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs b/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs index c217f84634a0b..9440d7b09d58b 100644 --- a/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs +++ b/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs @@ -32,10 +32,10 @@ pub fn get_selector() -> *mut () { // CHECK: %struct._objc_module = type { i32, i32, ptr, ptr } // CHECK: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [8 x i8] c"MyClass\00", section "__TEXT,__cstring,cstring_literals", align 1 -// CHECK: @OBJC_CLASS_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, section "__OBJC,__cls_refs,literal_pointers", align 4 +// CHECK: @OBJC_CLASS_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, section "__OBJC,__cls_refs,literal_pointers,no_dead_strip", align 4 // CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__cstring,cstring_literals", align 1 -// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__OBJC,__message_refs,literal_pointers", align 4 +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__OBJC,__message_refs,literal_pointers,no_dead_strip", align 4 // CHECK: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [1 x i8] zeroinitializer, section "__TEXT,__cstring,cstring_literals", align 1 // CHECK: @OBJC_MODULES = private global %struct._objc_module { i32 7, i32 16, ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, ptr null }, section "__OBJC,__module_info,regular,no_dead_strip", align 4 diff --git a/tests/codegen-llvm/darwin-objc.rs b/tests/codegen-llvm/darwin-objc.rs index c47dbde82f991..21e9e4e4bc5c8 100644 --- a/tests/codegen-llvm/darwin-objc.rs +++ b/tests/codegen-llvm/darwin-objc.rs @@ -49,7 +49,7 @@ pub fn get_selector() -> *mut () { // CHECK: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } // CHECK: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t -// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular", +// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular,no_dead_strip", // x86_64_macos-SAME: align 8 // aarch64_macos-SAME: align 8 // i386_ios-SAME: align 4 @@ -59,7 +59,7 @@ pub fn get_selector() -> *mut () { // aarch64_ios_sim-SAME: align 8 // CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 -// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers", +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", // x86_64_macos-SAME: align 8 // aarch64_macos-SAME: align 8 // i386_ios-SAME: align 4 From c7ba4bb5a69477480000e5d6be5aca9b5a2bf5b0 Mon Sep 17 00:00:00 2001 From: Jo Bates <29763794+jbatez@users.noreply.github.com> Date: Sun, 24 Aug 2025 13:22:18 -0700 Subject: [PATCH 4/8] add externally_initialized to OBJC_SELECTOR_REFERENCES_ --- compiler/rustc_codegen_llvm/src/consts.rs | 1 + compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 1 + compiler/rustc_codegen_llvm/src/llvm/mod.rs | 4 ++++ tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs | 2 +- tests/codegen-llvm/darwin-objc.rs | 2 +- 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 8179d6e63c98e..880cc37a7576f 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -680,6 +680,7 @@ impl<'ll> CodegenCx<'ll, '_> { }); set_global_alignment(self, selref_g, self.tcx.data_layout.pointer_align().abi); llvm::set_initializer(selref_g, selref_llval); + llvm::set_externally_initialized(selref_g, true); if is_x86_32_macos { llvm::set_linkage(selref_g, llvm::Linkage::PrivateLinkage); llvm::set_section(selref_g, c"__OBJC,__message_refs,literal_pointers,no_dead_strip"); diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 2461f70a86e35..ffbf813f9a48f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1189,6 +1189,7 @@ unsafe extern "C" { pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); pub(crate) safe fn LLVMSetTailCallKind(CallInst: &Value, kind: TailCallKind); + pub(crate) safe fn LLVMSetExternallyInitialized(GlobalVar: &Value, IsExtInit: Bool); // Operations on attributes pub(crate) fn LLVMCreateStringAttribute( diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index 7fea7b79a8cfb..df2226bb8e226 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -248,6 +248,10 @@ pub(crate) fn set_alignment(llglobal: &Value, align: Align) { } } +pub(crate) fn set_externally_initialized(llglobal: &Value, is_ext_init: bool) { + LLVMSetExternallyInitialized(llglobal, if is_ext_init { ffi::True } else { ffi::False }); +} + /// Get the `name`d comdat from `llmod` and assign it to `llglobal`. /// /// Inserts the comdat into `llmod` if it does not exist. diff --git a/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs b/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs index 9440d7b09d58b..f875f7b76d014 100644 --- a/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs +++ b/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs @@ -35,7 +35,7 @@ pub fn get_selector() -> *mut () { // CHECK: @OBJC_CLASS_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, section "__OBJC,__cls_refs,literal_pointers,no_dead_strip", align 4 // CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__cstring,cstring_literals", align 1 -// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__OBJC,__message_refs,literal_pointers,no_dead_strip", align 4 +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = private externally_initialized global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__OBJC,__message_refs,literal_pointers,no_dead_strip", align 4 // CHECK: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [1 x i8] zeroinitializer, section "__TEXT,__cstring,cstring_literals", align 1 // CHECK: @OBJC_MODULES = private global %struct._objc_module { i32 7, i32 16, ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, ptr null }, section "__OBJC,__module_info,regular,no_dead_strip", align 4 diff --git a/tests/codegen-llvm/darwin-objc.rs b/tests/codegen-llvm/darwin-objc.rs index 21e9e4e4bc5c8..47597302315b7 100644 --- a/tests/codegen-llvm/darwin-objc.rs +++ b/tests/codegen-llvm/darwin-objc.rs @@ -59,7 +59,7 @@ pub fn get_selector() -> *mut () { // aarch64_ios_sim-SAME: align 8 // CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 -// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal externally_initialized global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", // x86_64_macos-SAME: align 8 // aarch64_macos-SAME: align 8 // i386_ios-SAME: align 4 From fda7bb2df0894ad3925fc770fb7aabed1a53069d Mon Sep 17 00:00:00 2001 From: Jo Bates <29763794+jbatez@users.noreply.github.com> Date: Sun, 24 Aug 2025 13:37:51 -0700 Subject: [PATCH 5/8] add "Objective-C Version" LLVM module flag --- compiler/rustc_codegen_llvm/src/context.rs | 12 +++++++++++- tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs | 1 + tests/codegen-llvm/darwin-objc.rs | 1 + 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index a7d6d7b59cad6..ede047d7edcfe 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -689,7 +689,17 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { } pub(crate) fn add_objc_module_flags(&self) { + // Darwin-like targets only. assert!(self.tcx.sess.target.is_like_darwin); + let is_x86_32_macos = + self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos"; + + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Objective-C Version", + if is_x86_32_macos { 1 } else { 2 }, + ); llvm::add_module_flag_u32( self.llmod, @@ -702,7 +712,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { self.llmod, llvm::ModuleFlagMergeBehavior::Error, "Objective-C Image Info Section", - if self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos" { + if is_x86_32_macos { "__OBJC,__image_info,regular" } else { "__DATA,__objc_imageinfo,regular,no_dead_strip" diff --git a/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs b/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs index f875f7b76d014..a2ee7e57f6d09 100644 --- a/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs +++ b/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs @@ -43,6 +43,7 @@ pub fn get_selector() -> *mut () { // CHECK: load ptr, ptr @OBJC_CLASS_REFERENCES_.{{[0-9]+}}, align 4 // CHECK: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 4 +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Version", i32 1} // CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} // CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__OBJC,__image_info,regular"} // CHECK-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} diff --git a/tests/codegen-llvm/darwin-objc.rs b/tests/codegen-llvm/darwin-objc.rs index 47597302315b7..9a3b9a8a70b83 100644 --- a/tests/codegen-llvm/darwin-objc.rs +++ b/tests/codegen-llvm/darwin-objc.rs @@ -86,6 +86,7 @@ pub fn get_selector() -> *mut () { // aarch64_ios-SAME: align 8 // aarch64_ios_sim-SAME: align 8 +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Version", i32 2} // CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} // CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} From 8de88a2c2b0f34e028dcd1778fbd90df27677159 Mon Sep 17 00:00:00 2001 From: Jo Bates <29763794+jbatez@users.noreply.github.com> Date: Sun, 24 Aug 2025 13:49:03 -0700 Subject: [PATCH 6/8] move add_objc_module_flags call closer to define_objc_module_info --- compiler/rustc_codegen_llvm/src/base.rs | 26 +++++++++---------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index e011fc8203db3..35ee3b313d22b 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -109,16 +109,17 @@ pub(crate) fn compile_codegen_unit( attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs); } - // Define Objective-C module info for 32-bit x86 macOS. Note, this generates a global - // that gets added to the `llvm.compiler.used` variable, created later. + // Define Objective-C module info and module flags. Note, the module info will + // also be added to the `llvm.compiler.used` variable, created later. // - // This is only necessary when we need the linker to do its Objective-C-specific magic. - // We could theoretically do it unconditionally, but at a slight cost to linker + // These are only necessary when we need the linker to do its Objective-C-specific + // magic. We could theoretically do it unconditionally, but at a slight cost to linker // performance in the common case where it's unnecessary. - let uses_objc = - !cx.objc_classrefs.borrow().is_empty() || !cx.objc_selrefs.borrow().is_empty(); - if uses_objc && cx.tcx.sess.target.arch == "x86" && cx.tcx.sess.target.os == "macos" { - cx.define_objc_module_info(); + if !cx.objc_classrefs.borrow().is_empty() || !cx.objc_selrefs.borrow().is_empty() { + if cx.tcx.sess.target.arch == "x86" && cx.tcx.sess.target.os == "macos" { + cx.define_objc_module_info(); + } + cx.add_objc_module_flags(); } // Finalize code coverage by injecting the coverage map. Note, the coverage map will @@ -149,15 +150,6 @@ pub(crate) fn compile_codegen_unit( } } - // Add Objective-C module flags. - // - // This is only necessary when we need the linker to do its Objective-C-specific magic. - // We could theoretically do it unconditionally, but at a slight cost to linker - // performance in the common case where it's unnecessary. - if uses_objc { - cx.add_objc_module_flags(); - } - // Finalize debuginfo if cx.sess().opts.debuginfo != DebugInfo::None { cx.debuginfo_finalize(); From a9521e4cce34961877d96dab7553d26eab4ca40a Mon Sep 17 00:00:00 2001 From: Jo Bates <29763794+jbatez@users.noreply.github.com> Date: Sun, 24 Aug 2025 14:13:43 -0700 Subject: [PATCH 7/8] add CodegenCx::objc_abi_version() to replace scattered target checks --- compiler/rustc_codegen_llvm/src/base.rs | 2 +- compiler/rustc_codegen_llvm/src/consts.rs | 121 +++++++++--------- compiler/rustc_codegen_llvm/src/context.rs | 27 ++-- ...bit-x86-macos.rs => darwin-objc-abi-v1.rs} | 0 .../{darwin-objc.rs => darwin-objc-abi-v2.rs} | 0 5 files changed, 81 insertions(+), 69 deletions(-) rename tests/codegen-llvm/{darwin-objc-32bit-x86-macos.rs => darwin-objc-abi-v1.rs} (100%) rename tests/codegen-llvm/{darwin-objc.rs => darwin-objc-abi-v2.rs} (100%) diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 35ee3b313d22b..978134cc32b1c 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -116,7 +116,7 @@ pub(crate) fn compile_codegen_unit( // magic. We could theoretically do it unconditionally, but at a slight cost to linker // performance in the common case where it's unnecessary. if !cx.objc_classrefs.borrow().is_empty() || !cx.objc_selrefs.borrow().is_empty() { - if cx.tcx.sess.target.arch == "x86" && cx.tcx.sess.target.os == "macos" { + if cx.objc_abi_version() == 1 { cx.define_objc_module_info(); } cx.add_objc_module_flags(); diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 880cc37a7576f..dd29a10d2c4ed 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -551,9 +551,7 @@ impl<'ll> CodegenCx<'ll, '_> { } fn define_objc_classname(&self, classname: &str) -> &'ll Value { - // 32-bit x86 macOS only. - assert_eq!(self.tcx.sess.target.arch, "x86"); - assert_eq!(self.tcx.sess.target.os, "macos"); + assert_eq!(self.objc_abi_version(), 1); let llval = self.null_terminate_const_bytes(classname.as_bytes()); let llty = self.val_ty(llval); @@ -577,9 +575,7 @@ impl<'ll> CodegenCx<'ll, '_> { return class_t; } - // Darwin-like targets other than 32-bit x86 macOS. - assert!(self.tcx.sess.target.is_like_darwin); - assert!(self.tcx.sess.target.arch != "x86" || self.tcx.sess.target.os != "macos"); + assert_eq!(self.objc_abi_version(), 2); let class_t = self.type_named_struct("struct._class_t"); let els = [self.type_ptr(); 5]; @@ -600,39 +596,41 @@ impl<'ll> CodegenCx<'ll, '_> { return classref; } - let g = if self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos" { - // 32-bit x86 macOS. - let llval = self.define_objc_classname(classname.as_str()); - let llty = self.type_ptr(); - let sym = self.generate_local_symbol_name("OBJC_CLASS_REFERENCES_"); - let g = self.define_global(&sym, llty).unwrap_or_else(|| { - bug!("symbol `{}` is already defined", sym); - }); - set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); - llvm::set_initializer(g, llval); - llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); - llvm::set_section(g, c"__OBJC,__cls_refs,literal_pointers,no_dead_strip"); - self.add_compiler_used_global(g); - g - } else { - // Darwin-like targets other than 32-bit x86 macOS. - assert!(self.tcx.sess.target.is_like_darwin); - let llval = { - let extern_sym = format!("OBJC_CLASS_$_{}", classname.as_str()); - let extern_llty = self.get_objc_class_t(); - self.declare_global(&extern_sym, extern_llty) - }; - let llty = self.type_ptr(); - let sym = self.generate_local_symbol_name("OBJC_CLASSLIST_REFERENCES_$_"); - let g = self.define_global(&sym, llty).unwrap_or_else(|| { - bug!("symbol `{}` is already defined", sym); - }); - set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); - llvm::set_initializer(g, llval); - llvm::set_linkage(g, llvm::Linkage::InternalLinkage); - llvm::set_section(g, c"__DATA,__objc_classrefs,regular,no_dead_strip"); - self.add_compiler_used_global(g); - g + let g = match self.objc_abi_version() { + 1 => { + let llval = self.define_objc_classname(classname.as_str()); + let llty = self.type_ptr(); + let sym = self.generate_local_symbol_name("OBJC_CLASS_REFERENCES_"); + let g = self.define_global(&sym, llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + llvm::set_initializer(g, llval); + llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); + llvm::set_section(g, c"__OBJC,__cls_refs,literal_pointers,no_dead_strip"); + self.add_compiler_used_global(g); + g + } + 2 => { + assert!(self.tcx.sess.target.is_like_darwin); + let llval = { + let extern_sym = format!("OBJC_CLASS_$_{}", classname.as_str()); + let extern_llty = self.get_objc_class_t(); + self.declare_global(&extern_sym, extern_llty) + }; + let llty = self.type_ptr(); + let sym = self.generate_local_symbol_name("OBJC_CLASSLIST_REFERENCES_$_"); + let g = self.define_global(&sym, llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + llvm::set_initializer(g, llval); + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); + llvm::set_section(g, c"__DATA,__objc_classrefs,regular,no_dead_strip"); + self.add_compiler_used_global(g); + g + } + _ => unreachable!(), }; classrefs.insert(classname, g); @@ -649,10 +647,7 @@ impl<'ll> CodegenCx<'ll, '_> { return selref; } - // Darwin-like targets only. - assert!(self.tcx.sess.target.is_like_darwin); - let is_x86_32_macos = - self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos"; + let abi_version = self.objc_abi_version(); let methname_llval = self.null_terminate_const_bytes(methname.as_str().as_bytes()); let methname_llty = self.val_ty(methname_llval); @@ -663,11 +658,14 @@ impl<'ll> CodegenCx<'ll, '_> { set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align.abi); llvm::set_initializer(methname_g, methname_llval); llvm::set_linkage(methname_g, llvm::Linkage::PrivateLinkage); - if is_x86_32_macos { - llvm::set_section(methname_g, c"__TEXT,__cstring,cstring_literals"); - } else { - llvm::set_section(methname_g, c"__TEXT,__objc_methname,cstring_literals"); - } + llvm::set_section( + methname_g, + match abi_version { + 1 => c"__TEXT,__cstring,cstring_literals", + 2 => c"__TEXT,__objc_methname,cstring_literals", + _ => unreachable!(), + }, + ); llvm::LLVMSetGlobalConstant(methname_g, llvm::True); llvm::LLVMSetUnnamedAddress(methname_g, llvm::UnnamedAddr::Global); self.add_compiler_used_global(methname_g); @@ -681,13 +679,22 @@ impl<'ll> CodegenCx<'ll, '_> { set_global_alignment(self, selref_g, self.tcx.data_layout.pointer_align().abi); llvm::set_initializer(selref_g, selref_llval); llvm::set_externally_initialized(selref_g, true); - if is_x86_32_macos { - llvm::set_linkage(selref_g, llvm::Linkage::PrivateLinkage); - llvm::set_section(selref_g, c"__OBJC,__message_refs,literal_pointers,no_dead_strip"); - } else { - llvm::set_linkage(selref_g, llvm::Linkage::InternalLinkage); - llvm::set_section(selref_g, c"__DATA,__objc_selrefs,literal_pointers,no_dead_strip"); - } + llvm::set_linkage( + selref_g, + match abi_version { + 1 => llvm::Linkage::PrivateLinkage, + 2 => llvm::Linkage::InternalLinkage, + _ => unreachable!(), + }, + ); + llvm::set_section( + selref_g, + match abi_version { + 1 => c"__OBJC,__message_refs,literal_pointers,no_dead_strip", + 2 => c"__DATA,__objc_selrefs,literal_pointers,no_dead_strip", + _ => unreachable!(), + }, + ); self.add_compiler_used_global(selref_g); selrefs.insert(methname, selref_g); @@ -695,9 +702,7 @@ impl<'ll> CodegenCx<'ll, '_> { } pub(crate) fn define_objc_module_info(&mut self) { - // 32-bit x86 macOS only. - assert_eq!(self.tcx.sess.target.arch, "x86"); - assert_eq!(self.tcx.sess.target.os, "macos"); + assert_eq!(self.objc_abi_version(), 1); // struct _objc_module { // long version; // Hardcoded to 7 in Clang. diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index ede047d7edcfe..5143171609c59 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -688,17 +688,24 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { llvm::set_section(g, c"llvm.metadata"); } - pub(crate) fn add_objc_module_flags(&self) { - // Darwin-like targets only. - assert!(self.tcx.sess.target.is_like_darwin); - let is_x86_32_macos = - self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos"; + pub(crate) fn objc_abi_version(&self) -> u32 { + if self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos" { + // 32-bit x86 macOS uses ABI version 1. + 1 + } else { + // All other Darwin-like targets we support use ABI version 2. + assert!(self.tcx.sess.target.is_like_darwin); + 2 + } + } + pub(crate) fn add_objc_module_flags(&self) { + let abi_version = self.objc_abi_version(); llvm::add_module_flag_u32( self.llmod, llvm::ModuleFlagMergeBehavior::Error, "Objective-C Version", - if is_x86_32_macos { 1 } else { 2 }, + abi_version, ); llvm::add_module_flag_u32( @@ -712,10 +719,10 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { self.llmod, llvm::ModuleFlagMergeBehavior::Error, "Objective-C Image Info Section", - if is_x86_32_macos { - "__OBJC,__image_info,regular" - } else { - "__DATA,__objc_imageinfo,regular,no_dead_strip" + match abi_version { + 1 => "__OBJC,__image_info,regular", + 2 => "__DATA,__objc_imageinfo,regular,no_dead_strip", + _ => unreachable!(), }, ); diff --git a/tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs b/tests/codegen-llvm/darwin-objc-abi-v1.rs similarity index 100% rename from tests/codegen-llvm/darwin-objc-32bit-x86-macos.rs rename to tests/codegen-llvm/darwin-objc-abi-v1.rs diff --git a/tests/codegen-llvm/darwin-objc.rs b/tests/codegen-llvm/darwin-objc-abi-v2.rs similarity index 100% rename from tests/codegen-llvm/darwin-objc.rs rename to tests/codegen-llvm/darwin-objc-abi-v2.rs From 1d4b8660bf1bbd96a9d59407cedbe039d8c1e5b4 Mon Sep 17 00:00:00 2001 From: Jo Bates <29763794+jbatez@users.noreply.github.com> Date: Sun, 24 Aug 2025 14:29:20 -0700 Subject: [PATCH 8/8] comments describing why objc::class!() and objc::selector!() only expose the static value --- library/core/src/os/darwin/objc.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/core/src/os/darwin/objc.rs b/library/core/src/os/darwin/objc.rs index 3532e6efaf957..1b891b251c071 100644 --- a/library/core/src/os/darwin/objc.rs +++ b/library/core/src/os/darwin/objc.rs @@ -72,6 +72,9 @@ pub type SEL = *mut objc_selector; /// ``` #[allow_internal_unstable(rustc_attrs)] pub macro class($classname:expr) {{ + // Since static Objective-C class references actually end up with multiple definitions + // across dylib boundaries, we only expose the value of the static and don't provide a way to + // get the address of or a reference to the static. unsafe extern "C" { #[rustc_objc_class = $classname] safe static VAL: $crate::os::darwin::objc::Class; @@ -93,6 +96,9 @@ pub macro class($classname:expr) {{ /// ``` #[allow_internal_unstable(rustc_attrs)] pub macro selector($methname:expr) {{ + // Since static Objective-C selector references actually end up with multiple definitions + // across dylib boundaries, we only expose the value of the static and don't provide a way to + // get the address of or a reference to the static. unsafe extern "C" { #[rustc_objc_selector = $methname] safe static VAL: $crate::os::darwin::objc::SEL;