From e9ea57814768cdae0b36065a731009afa7e36f31 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Mar 2024 12:01:57 +0000 Subject: Move vcall_visibility_metadata optimization hint out of a debuginfo generation method --- compiler/rustc_codegen_ssa/src/meth.rs | 1 + compiler/rustc_codegen_ssa/src/traits/misc.rs | 7 +++++++ 2 files changed, 8 insertions(+) (limited to 'compiler/rustc_codegen_ssa/src') diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs index ddc6797388e..febc8ee2be2 100644 --- a/compiler/rustc_codegen_ssa/src/meth.rs +++ b/compiler/rustc_codegen_ssa/src/meth.rs @@ -133,6 +133,7 @@ pub fn get_vtable<'tcx, Cx: CodegenMethods<'tcx>>( let align = cx.data_layout().pointer_align.abi; let vtable = cx.static_addr_of(vtable_const, align, Some("vtable")); + cx.apply_vcall_visibility_metadata(ty, trait_ref, vtable); cx.create_vtable_debuginfo(ty, trait_ref, vtable); cx.vtables().borrow_mut().insert((ty, trait_ref), vtable); vtable diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index 04e2b8796c4..af3a9989604 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -9,6 +9,13 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn vtables( &self, ) -> &RefCell, Option>), Self::Value>>; + fn apply_vcall_visibility_metadata( + &self, + _ty: Ty<'tcx>, + _poly_trait_ref: Option>, + _vtable: Self::Value, + ) { + } fn check_overflow(&self) -> bool; fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function; fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value; -- cgit 1.4.1-3-g733a5 From 7f445329ec3330f4334431b68b26325922391e5c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Mar 2024 13:19:58 +0000 Subject: Remove PrintBackendInfo trait It is only implemented for a single type. Directly passing this type is simpler and avoids overhead from indirect calls. --- compiler/rustc_codegen_llvm/src/lib.rs | 24 ++++++++++--------- compiler/rustc_codegen_llvm/src/llvm_util.rs | 30 +++++++++++++----------- compiler/rustc_codegen_ssa/src/traits/backend.rs | 20 +--------------- compiler/rustc_codegen_ssa/src/traits/mod.rs | 4 +--- 4 files changed, 31 insertions(+), 47 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src') diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 4b7a2643007..ed0989a0ba4 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -274,10 +274,11 @@ impl CodegenBackend for LlvmCodegenBackend { |tcx, ()| llvm_util::global_llvm_features(tcx.sess, true) } - fn print(&self, req: &PrintRequest, out: &mut dyn PrintBackendInfo, sess: &Session) { + fn print(&self, req: &PrintRequest, out: &mut String, sess: &Session) { + use std::fmt::Write; match req.kind { PrintKind::RelocationModels => { - writeln!(out, "Available relocation models:"); + writeln!(out, "Available relocation models:").unwrap(); for name in &[ "static", "pic", @@ -288,25 +289,25 @@ impl CodegenBackend for LlvmCodegenBackend { "ropi-rwpi", "default", ] { - writeln!(out, " {name}"); + writeln!(out, " {name}").unwrap(); } - writeln!(out); + writeln!(out).unwrap(); } PrintKind::CodeModels => { - writeln!(out, "Available code models:"); + writeln!(out, "Available code models:").unwrap(); for name in &["tiny", "small", "kernel", "medium", "large"] { - writeln!(out, " {name}"); + writeln!(out, " {name}").unwrap(); } - writeln!(out); + writeln!(out).unwrap(); } PrintKind::TlsModels => { - writeln!(out, "Available TLS models:"); + writeln!(out, "Available TLS models:").unwrap(); for name in &["global-dynamic", "local-dynamic", "initial-exec", "local-exec", "emulated"] { - writeln!(out, " {name}"); + writeln!(out, " {name}").unwrap(); } - writeln!(out); + writeln!(out).unwrap(); } PrintKind::StackProtectorStrategies => { writeln!( @@ -332,7 +333,8 @@ impl CodegenBackend for LlvmCodegenBackend { none Do not generate stack canaries. "# - ); + ) + .unwrap(); } _other => llvm_util::print(req, out, sess), } diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 7e0f264a4ae..0e89e66be49 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -6,7 +6,6 @@ use crate::errors::{ use crate::llvm; use libc::c_int; use rustc_codegen_ssa::base::wants_wasm_eh; -use rustc_codegen_ssa::traits::PrintBackendInfo; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::small_c_str::SmallCStr; use rustc_fs_util::path_to_c_string; @@ -18,6 +17,7 @@ use rustc_target::spec::{MergeFunctions, PanicStrategy}; use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES; use std::ffi::{c_char, c_void, CStr, CString}; +use std::fmt::Write; use std::path::Path; use std::ptr; use std::slice; @@ -372,7 +372,7 @@ fn llvm_target_features(tm: &llvm::TargetMachine) -> Vec<(&str, &str)> { ret } -fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &llvm::TargetMachine) { +fn print_target_features(out: &mut String, sess: &Session, tm: &llvm::TargetMachine) { let mut llvm_target_features = llvm_target_features(tm); let mut known_llvm_target_features = FxHashSet::<&'static str>::default(); let mut rustc_target_features = sess @@ -412,24 +412,26 @@ fn print_target_features(out: &mut dyn PrintBackendInfo, sess: &Session, tm: &ll .max() .unwrap_or(0); - writeln!(out, "Features supported by rustc for this target:"); + writeln!(out, "Features supported by rustc for this target:").unwrap(); for (feature, desc) in &rustc_target_features { - writeln!(out, " {feature:max_feature_len$} - {desc}."); + writeln!(out, " {feature:max_feature_len$} - {desc}.").unwrap(); } - writeln!(out, "\nCode-generation features supported by LLVM for this target:"); + writeln!(out, "\nCode-generation features supported by LLVM for this target:").unwrap(); for (feature, desc) in &llvm_target_features { - writeln!(out, " {feature:max_feature_len$} - {desc}."); + writeln!(out, " {feature:max_feature_len$} - {desc}.").unwrap(); } if llvm_target_features.is_empty() { - writeln!(out, " Target features listing is not supported by this LLVM version."); + writeln!(out, " Target features listing is not supported by this LLVM version.") + .unwrap(); } - writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it."); - writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n"); - writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],"); - writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n"); + writeln!(out, "\nUse +feature to enable a feature, or -feature to disable it.").unwrap(); + writeln!(out, "For example, rustc -C target-cpu=mycpu -C target-feature=+feature1,-feature2\n") + .unwrap(); + writeln!(out, "Code-generation features cannot be used in cfg or #[target_feature],").unwrap(); + writeln!(out, "and may be renamed or removed in a future version of LLVM or rustc.\n").unwrap(); } -pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess: &Session) { +pub(crate) fn print(req: &PrintRequest, mut out: &mut String, sess: &Session) { require_inited(); let tm = create_informational_target_machine(sess); match req.kind { @@ -440,9 +442,9 @@ pub(crate) fn print(req: &PrintRequest, mut out: &mut dyn PrintBackendInfo, sess let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref())) .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e)); unsafe extern "C" fn callback(out: *mut c_void, string: *const c_char, len: usize) { - let out = &mut *(out as *mut &mut dyn PrintBackendInfo); + let out = &mut *(out as *mut &mut String); let bytes = slice::from_raw_parts(string as *const u8, len); - write!(out, "{}", String::from_utf8_lossy(bytes)); + write!(out, "{}", String::from_utf8_lossy(bytes)).unwrap(); } unsafe { llvm::LLVMRustPrintTargetCPUs( diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index e8b9490d401..3770bd11cf9 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -22,8 +22,6 @@ use rustc_session::{ use rustc_span::symbol::Symbol; use rustc_target::abi::call::FnAbi; -use std::fmt; - pub trait BackendTypes { type Value: CodegenObject; type Function: CodegenObject; @@ -62,7 +60,7 @@ pub trait CodegenBackend { fn locale_resource(&self) -> &'static str; fn init(&self, _sess: &Session) {} - fn print(&self, _req: &PrintRequest, _out: &mut dyn PrintBackendInfo, _sess: &Session) {} + fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} fn target_features(&self, _sess: &Session, _allow_unstable: bool) -> Vec { vec![] } @@ -150,19 +148,3 @@ pub trait ExtraBackendMethods: std::thread::Builder::new().name(name).spawn(f) } } - -pub trait PrintBackendInfo { - fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>); -} - -impl PrintBackendInfo for String { - fn infallible_write_fmt(&mut self, args: fmt::Arguments<'_>) { - fmt::Write::write_fmt(self, args).unwrap(); - } -} - -impl dyn PrintBackendInfo + '_ { - pub fn write_fmt(&mut self, args: fmt::Arguments<'_>) { - self.infallible_write_fmt(args); - } -} diff --git a/compiler/rustc_codegen_ssa/src/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs index 728c2bc8c49..8cb58bd4c70 100644 --- a/compiler/rustc_codegen_ssa/src/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -30,9 +30,7 @@ mod write; pub use self::abi::AbiBuilderMethods; pub use self::asm::{AsmBuilderMethods, AsmMethods, GlobalAsmOperandRef, InlineAsmOperandRef}; -pub use self::backend::{ - Backend, BackendTypes, CodegenBackend, ExtraBackendMethods, PrintBackendInfo, -}; +pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods}; pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; pub use self::coverageinfo::CoverageInfoBuilderMethods; -- cgit 1.4.1-3-g733a5 From 98e8601ac3426c395c017f110e2ff8b05733a163 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Mar 2024 13:32:05 +0000 Subject: Remove const_bitcast from ConstMethods --- compiler/rustc_codegen_gcc/src/common.rs | 26 ++++++++++++------------- compiler/rustc_codegen_llvm/src/common.rs | 4 ---- compiler/rustc_codegen_ssa/src/traits/consts.rs | 1 - 3 files changed, 13 insertions(+), 18 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src') diff --git a/compiler/rustc_codegen_gcc/src/common.rs b/compiler/rustc_codegen_gcc/src/common.rs index 548c23cc794..230fe4f5871 100644 --- a/compiler/rustc_codegen_gcc/src/common.rs +++ b/compiler/rustc_codegen_gcc/src/common.rs @@ -28,6 +28,19 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { global // TODO(antoyo): set linkage. } + + pub fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { + if value.get_type() == self.bool_type.make_pointer() { + if let Some(pointee) = typ.get_pointee() { + if pointee.dyncast_vector().is_some() { + panic!() + } + } + } + // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some + // SIMD builtins require a constant value. + self.bitcast_if_needed(value, typ) + } } pub fn bytes_in_context<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, bytes: &[u8]) -> RValue<'gcc> { @@ -239,19 +252,6 @@ impl<'gcc, 'tcx> ConstMethods<'tcx> for CodegenCx<'gcc, 'tcx> { const_alloc_to_gcc(self, alloc) } - fn const_bitcast(&self, value: RValue<'gcc>, typ: Type<'gcc>) -> RValue<'gcc> { - if value.get_type() == self.bool_type.make_pointer() { - if let Some(pointee) = typ.get_pointee() { - if pointee.dyncast_vector().is_some() { - panic!() - } - } - } - // NOTE: since bitcast makes a value non-constant, don't bitcast if not necessary as some - // SIMD builtins require a constant value. - self.bitcast_if_needed(value, typ) - } - fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { self.context .new_array_access(None, base_addr, self.const_usize(offset.bytes())) diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 4ffc92eb633..d42c6ed827a 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -329,10 +329,6 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> { const_alloc_to_llvm(self, alloc, /*static*/ false) } - fn const_bitcast(&self, val: &'ll Value, ty: &'ll Type) -> &'ll Value { - self.const_bitcast(val, ty) - } - fn const_ptr_byte_offset(&self, base_addr: Self::Value, offset: abi::Size) -> Self::Value { unsafe { llvm::LLVMConstInBoundsGEP2( diff --git a/compiler/rustc_codegen_ssa/src/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs index 8cb17a5b37a..3da732602c5 100644 --- a/compiler/rustc_codegen_ssa/src/traits/consts.rs +++ b/compiler/rustc_codegen_ssa/src/traits/consts.rs @@ -37,6 +37,5 @@ pub trait ConstMethods<'tcx>: BackendTypes { fn scalar_to_backend(&self, cv: Scalar, layout: abi::Scalar, llty: Self::Type) -> Self::Value; - fn const_bitcast(&self, val: Self::Value, ty: Self::Type) -> Self::Value; fn const_ptr_byte_offset(&self, val: Self::Value, offset: abi::Size) -> Self::Value; } -- cgit 1.4.1-3-g733a5 From e32eb4c9e933d98455205348706620c51f25b69d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Mar 2024 13:53:52 +0000 Subject: Dedup some intrinsic handling code for caller_location --- compiler/rustc_codegen_ssa/src/mir/block.rs | 37 ++++++++++------------------- 1 file changed, 12 insertions(+), 25 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src') diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 57138d3b9db..57a5393da25 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -902,31 +902,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // The arguments we'll be passing. Plus one to account for outptr, if used. let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; - if matches!(intrinsic, Some(ty::IntrinsicDef { name: sym::caller_location, .. })) { - return if let Some(target) = target { - let location = - self.get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); - - let mut llargs = Vec::with_capacity(arg_count); - let ret_dest = self.make_return_dest( - bx, - destination, - &fn_abi.ret, - &mut llargs, - intrinsic, - Some(target), - ); - assert_eq!(llargs, []); - if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { - location.val.store(bx, tmp); - } - self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); - helper.funclet_br(self, bx, target, mergeable_succ) - } else { - MergingSucc::False - }; - } - let instance = match intrinsic { None => instance, Some(intrinsic) => { @@ -971,6 +946,18 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) .collect(); + if matches!(intrinsic, ty::IntrinsicDef { name: sym::caller_location, .. }) { + let location = self + .get_caller_location(bx, mir::SourceInfo { span: fn_span, ..source_info }); + + assert_eq!(llargs, []); + if let ReturnDest::IndirectOperand(tmp, _) = ret_dest { + location.val.store(bx, tmp); + } + self.store_return(bx, ret_dest, &fn_abi.ret, location.immediate()); + return helper.funclet_br(self, bx, target.unwrap(), mergeable_succ); + } + let instance = *instance.as_ref().unwrap(); match Self::codegen_intrinsic_call(bx, instance, fn_abi, &args, dest, span) { Ok(()) => { -- cgit 1.4.1-3-g733a5 From 22b32432ca3e8296a7649ef8c3711c0310f8f426 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Mar 2024 13:58:06 +0000 Subject: Move all intrinsic handling code in codegen_call_terminators together --- compiler/rustc_codegen_ssa/src/mir/block.rs | 44 +++++++++++++---------------- 1 file changed, 19 insertions(+), 25 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src') diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 57a5393da25..1eec1841a37 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -751,7 +751,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { &mut self, helper: &TerminatorCodegenHelper<'tcx>, bx: &mut Bx, - intrinsic: Option, + intrinsic: ty::IntrinsicDef, instance: Option>, source_info: mir::SourceInfo, target: Option, @@ -761,8 +761,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Emit a panic or a no-op for `assert_*` intrinsics. // These are intrinsics that compile to panics so that we can get a message // which mentions the offending type, even from a const context. - let panic_intrinsic = intrinsic.and_then(|i| ValidityRequirement::from_intrinsic(i.name)); - if let Some(requirement) = panic_intrinsic { + if let Some(requirement) = ValidityRequirement::from_intrinsic(intrinsic.name) { let ty = instance.unwrap().args.type_at(0); let do_panic = !bx @@ -869,12 +868,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let sig = callee.layout.ty.fn_sig(bx.tcx()); let abi = sig.abi(); - // Handle intrinsics old codegen wants Expr's for, ourselves. - let intrinsic = match def { - Some(ty::InstanceKind::Intrinsic(def_id)) => Some(bx.tcx().intrinsic(def_id).unwrap()), - _ => None, - }; - let extra_args = &args[sig.inputs().skip_binder().len()..]; let extra_args = bx.tcx().mk_type_list_from_iter(extra_args.iter().map(|op_arg| { let op_ty = op_arg.node.ty(self.mir, bx.tcx()); @@ -886,25 +879,25 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { None => bx.fn_abi_of_fn_ptr(sig, extra_args), }; - if let Some(merging_succ) = self.codegen_panic_intrinsic( - &helper, - bx, - intrinsic, - instance, - source_info, - target, - unwind, - mergeable_succ, - ) { - return merging_succ; - } - // The arguments we'll be passing. Plus one to account for outptr, if used. let arg_count = fn_abi.args.len() + fn_abi.ret.is_indirect() as usize; - let instance = match intrinsic { - None => instance, - Some(intrinsic) => { + let instance = match def { + Some(ty::InstanceKind::Intrinsic(def_id)) => { + let intrinsic = bx.tcx().intrinsic(def_id).unwrap(); + if let Some(merging_succ) = self.codegen_panic_intrinsic( + &helper, + bx, + intrinsic, + instance, + source_info, + target, + unwind, + mergeable_succ, + ) { + return merging_succ; + } + let mut llargs = Vec::with_capacity(1); let ret_dest = self.make_return_dest( bx, @@ -984,6 +977,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } } + _ => instance, }; let mut llargs = Vec::with_capacity(arg_count); -- cgit 1.4.1-3-g733a5 From aacdce38f7f2298c5779446ffe17cae0068ccd37 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Mar 2024 14:25:13 +0000 Subject: Remove check_overflow method from MiscMethods It can be retrieved from the Session too. --- compiler/rustc_codegen_gcc/src/context.rs | 8 -------- compiler/rustc_codegen_llvm/src/context.rs | 8 -------- compiler/rustc_codegen_ssa/src/mir/block.rs | 2 +- compiler/rustc_codegen_ssa/src/traits/misc.rs | 1 - 4 files changed, 1 insertion(+), 18 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src') diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 4a1f5188a80..6231b09552c 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -27,7 +27,6 @@ use crate::callee::get_fn; use crate::common::SignType; pub struct CodegenCx<'gcc, 'tcx> { - pub check_overflow: bool, pub codegen_unit: &'tcx CodegenUnit<'tcx>, pub context: &'gcc Context<'gcc>, @@ -134,8 +133,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { tcx: TyCtxt<'tcx>, supports_128bit_integers: bool, ) -> Self { - let check_overflow = tcx.sess.overflow_checks(); - let create_type = |ctype, rust_type| { let layout = tcx.layout_of(ParamEnv::reveal_all().and(rust_type)).unwrap(); let align = layout.align.abi.bytes(); @@ -271,7 +268,6 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { } let mut cx = Self { - check_overflow, codegen_unit, context, current_func: RefCell::new(None), @@ -511,10 +507,6 @@ impl<'gcc, 'tcx> MiscMethods<'tcx> for CodegenCx<'gcc, 'tcx> { &self.tcx.sess } - fn check_overflow(&self) -> bool { - self.check_overflow - } - fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { self.codegen_unit } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 57682d1cc8c..1a8e8efdae5 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -44,7 +44,6 @@ use std::str; /// All other LLVM data structures in the `CodegenCx` are tied to that `llvm::Context`. pub struct CodegenCx<'ll, 'tcx> { pub tcx: TyCtxt<'tcx>, - pub check_overflow: bool, pub use_dll_storage_attrs: bool, pub tls_model: llvm::ThreadLocalMode, @@ -442,8 +441,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { // start) and then strongly recommending static linkage on Windows! let use_dll_storage_attrs = tcx.sess.target.is_like_windows; - let check_overflow = tcx.sess.overflow_checks(); - let tls_model = to_llvm_tls_model(tcx.sess.tls_model()); let (llcx, llmod) = (&*llvm_module.llcx, llvm_module.llmod()); @@ -467,7 +464,6 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { CodegenCx { tcx, - check_overflow, use_dll_storage_attrs, tls_model, llmod, @@ -606,10 +602,6 @@ impl<'ll, 'tcx> MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { self.tcx.sess } - fn check_overflow(&self) -> bool { - self.check_overflow - } - fn codegen_unit(&self) -> &'tcx CodegenUnit<'tcx> { self.codegen_unit } diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 1eec1841a37..b1c22faf1ae 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -658,7 +658,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // with #[rustc_inherit_overflow_checks] and inlined from // another crate (mostly core::num generic/#[inline] fns), // while the current crate doesn't use overflow checks. - if !bx.cx().check_overflow() && msg.is_optional_overflow_check() { + if !bx.sess().overflow_checks() && msg.is_optional_overflow_check() { const_cond = Some(expected); } diff --git a/compiler/rustc_codegen_ssa/src/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs index af3a9989604..0ace28ed3ba 100644 --- a/compiler/rustc_codegen_ssa/src/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -16,7 +16,6 @@ pub trait MiscMethods<'tcx>: BackendTypes { _vtable: Self::Value, ) { } - fn check_overflow(&self) -> bool; fn get_fn(&self, instance: Instance<'tcx>) -> Self::Function; fn get_fn_addr(&self, instance: Instance<'tcx>) -> Self::Value; fn eh_personality(&self) -> Self::Value; -- cgit 1.4.1-3-g733a5 From 887f57ff0bd0664bfb901321048302f0879e1be2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Mar 2024 14:36:14 +0000 Subject: Remove type_i1 and type_struct from cg_ssa They are not representable by Cranelift --- compiler/rustc_codegen_gcc/src/type_.rs | 50 +++++++++++++------------- compiler/rustc_codegen_llvm/src/type_.rs | 28 +++++++-------- compiler/rustc_codegen_ssa/src/traits/type_.rs | 2 -- 3 files changed, 39 insertions(+), 41 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src') diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs index 68471b028be..4caff2e6310 100644 --- a/compiler/rustc_codegen_gcc/src/type_.rs +++ b/compiler/rustc_codegen_gcc/src/type_.rs @@ -89,13 +89,34 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { ty::FloatTy::F128 => self.type_f128(), } } -} -impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { - fn type_i1(&self) -> Type<'gcc> { + pub fn type_i1(&self) -> Type<'gcc> { self.bool_type } + pub fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> { + let types = fields.to_vec(); + if let Some(typ) = self.struct_types.borrow().get(fields) { + return *typ; + } + let fields: Vec<_> = fields + .iter() + .enumerate() + .map(|(index, field)| { + self.context.new_field(None, *field, format!("field{}_TODO", index)) + }) + .collect(); + let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); + if packed { + #[cfg(feature = "master")] + typ.set_packed(); + } + self.struct_types.borrow_mut().insert(types, typ); + typ + } +} + +impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_i8(&self) -> Type<'gcc> { self.i8_type } @@ -131,7 +152,7 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { fn type_f64(&self) -> Type<'gcc> { self.double_type } - + fn type_f128(&self) -> Type<'gcc> { unimplemented!("f16_f128") } @@ -140,27 +161,6 @@ impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { self.context.new_function_pointer_type(None, return_type, params, false) } - fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> { - let types = fields.to_vec(); - if let Some(typ) = self.struct_types.borrow().get(fields) { - return *typ; - } - let fields: Vec<_> = fields - .iter() - .enumerate() - .map(|(index, field)| { - self.context.new_field(None, *field, format!("field{}_TODO", index)) - }) - .collect(); - let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); - if packed { - #[cfg(feature = "master")] - typ.set_packed(); - } - self.struct_types.borrow_mut().insert(types, typ); - typ - } - fn type_kind(&self, typ: Type<'gcc>) -> TypeKind { if self.is_int_type_or_bool(typ) { TypeKind::Integer diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index a00f09dc40d..f1141c57ced 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -127,13 +127,24 @@ impl<'ll> CodegenCx<'ll, '_> { pub(crate) fn type_variadic_func(&self, args: &[&'ll Type], ret: &'ll Type) -> &'ll Type { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, True) } } -} -impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn type_i1(&self) -> &'ll Type { + pub(crate) fn type_i1(&self) -> &'ll Type { unsafe { llvm::LLVMInt1TypeInContext(self.llcx) } } + pub(crate) fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type { + unsafe { + llvm::LLVMStructTypeInContext( + self.llcx, + els.as_ptr(), + els.len() as c_uint, + packed as Bool, + ) + } + } +} + +impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn type_i8(&self) -> &'ll Type { unsafe { llvm::LLVMInt8TypeInContext(self.llcx) } } @@ -178,17 +189,6 @@ impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMFunctionType(ret, args.as_ptr(), args.len() as c_uint, False) } } - fn type_struct(&self, els: &[&'ll Type], packed: bool) -> &'ll Type { - unsafe { - llvm::LLVMStructTypeInContext( - self.llcx, - els.as_ptr(), - els.len() as c_uint, - packed as Bool, - ) - } - } - fn type_kind(&self, ty: &'ll Type) -> TypeKind { unsafe { llvm::LLVMRustGetTypeKind(ty).to_generic() } } diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index 403f6a73277..e492bba969e 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -12,7 +12,6 @@ use rustc_target::abi::{AddressSpace, Float, Integer}; // This depends on `Backend` and not `BackendTypes`, because consumers will probably want to use // `LayoutOf` or `HasTyCtxt`. This way, they don't have to add a constraint on it themselves. pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { - fn type_i1(&self) -> Self::Type; fn type_i8(&self) -> Self::Type; fn type_i16(&self) -> Self::Type; fn type_i32(&self) -> Self::Type; @@ -27,7 +26,6 @@ pub trait BaseTypeMethods<'tcx>: Backend<'tcx> { fn type_array(&self, ty: Self::Type, len: u64) -> Self::Type; fn type_func(&self, args: &[Self::Type], ret: Self::Type) -> Self::Type; - fn type_struct(&self, els: &[Self::Type], packed: bool) -> Self::Type; fn type_kind(&self, ty: Self::Type) -> TypeKind; fn type_ptr(&self) -> Self::Type; fn type_ptr_ext(&self, address_space: AddressSpace) -> Self::Type; -- cgit 1.4.1-3-g733a5 From 84f45bb0930a0696f8d0bcb8b480bc194da80db1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 30 Mar 2024 17:29:32 +0000 Subject: Fix doc comment --- compiler/rustc_codegen_ssa/src/traits/type_.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src') diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs index e492bba969e..b1bad6cfa6f 100644 --- a/compiler/rustc_codegen_ssa/src/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -113,8 +113,8 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> { /// The backend type used for a rust type when it's in an SSA register. /// /// For nearly all types this is the same as the [`Self::backend_type`], however - /// `bool` (and other `0`-or-`1` values) are kept as [`BaseTypeMethods::type_i1`] - /// in registers but as [`BaseTypeMethods::type_i8`] in memory. + /// `bool` (and other `0`-or-`1` values) are kept as `i1` in registers but as + /// [`BaseTypeMethods::type_i8`] in memory. /// /// Converting values between the two different backend types is done using /// [`from_immediate`](super::BuilderMethods::from_immediate) and -- cgit 1.4.1-3-g733a5 From af31c338fc19c51d61b9dabe7b8e4bc854558907 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Sat, 27 Jan 2024 19:35:55 +0300 Subject: linker: Refactor interface for passing arguments to linker --- compiler/rustc_codegen_ssa/src/back/link.rs | 70 +-- compiler/rustc_codegen_ssa/src/back/linker.rs | 617 ++++++++++++-------------- 2 files changed, 314 insertions(+), 373 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src') diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d509e4ce56d..da7ffdc4911 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -45,7 +45,7 @@ use tempfile::Builder as TempFileBuilder; use itertools::Itertools; use std::collections::BTreeSet; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsString; use std::fs::{read, File, OpenOptions}; use std::io::{BufWriter, Write}; use std::ops::Deref; @@ -1306,12 +1306,12 @@ fn link_sanitizer_runtime( let filename = format!("rustc{channel}_rt.{name}"); let path = find_sanitizer_runtime(sess, &filename); let rpath = path.to_str().expect("non-utf8 component in path"); - linker.args(&["-Wl,-rpath", "-Xlinker", rpath]); + linker.cc_args(&["-Wl,-rpath", "-Xlinker", rpath]); linker.link_dylib_by_name(&filename, false, true); } else if sess.target.is_like_msvc && flavor == LinkerFlavor::Msvc(Lld::No) && name == "asan" { // MSVC provides the `/INFERASANLIBS` argument to automatically find the // compatible ASAN library. - linker.arg("/INFERASANLIBS"); + linker.link_arg("/INFERASANLIBS"); } else { let filename = format!("librustc{channel}_rt.{name}.a"); let path = find_sanitizer_runtime(sess, &filename).join(&filename); @@ -1888,9 +1888,9 @@ fn add_post_link_objects( /// FIXME: Determine where exactly these args need to be inserted. fn add_pre_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let Some(args) = sess.target.pre_link_args.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } - cmd.args(&sess.opts.unstable_opts.pre_link_args); + cmd.verbatim_args(&sess.opts.unstable_opts.pre_link_args); } /// Add a link script embedded in the target, if applicable. @@ -1908,8 +1908,7 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty sess.dcx().emit_fatal(errors::LinkScriptWriteFailure { path, error }); } - cmd.arg("--script"); - cmd.arg(path); + cmd.link_arg("--script").link_arg(path); } _ => {} } @@ -1918,7 +1917,7 @@ fn add_link_script(cmd: &mut dyn Linker, sess: &Session, tmpdir: &Path, crate_ty /// Add arbitrary "user defined" args defined from command line. /// FIXME: Determine where exactly these args need to be inserted. fn add_user_defined_link_args(cmd: &mut dyn Linker, sess: &Session) { - cmd.args(&sess.opts.cg.link_args); + cmd.verbatim_args(&sess.opts.cg.link_args); } /// Add arbitrary "late link" args defined by the target spec. @@ -1936,15 +1935,15 @@ fn add_late_link_args( }); if any_dynamic_crate { if let Some(args) = sess.target.late_link_args_dynamic.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } else { if let Some(args) = sess.target.late_link_args_static.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } if let Some(args) = sess.target.late_link_args.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } @@ -1952,7 +1951,7 @@ fn add_late_link_args( /// FIXME: Determine where exactly these args need to be inserted. fn add_post_link_args(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { if let Some(args) = sess.target.post_link_args.get(&flavor) { - cmd.args(args.iter().map(Deref::deref)); + cmd.verbatim_args(args.iter().map(Deref::deref)); } } @@ -2119,7 +2118,7 @@ fn add_rpath_args( is_like_osx: sess.target.is_like_osx, linker_is_gnu: sess.target.linker_flavor.is_gnu(), }; - cmd.args(&rpath::get_rpath_flags(&rpath_config)); + cmd.cc_args(&rpath::get_rpath_flags(&rpath_config)); } } @@ -2378,7 +2377,7 @@ fn add_order_independent_options( } else { "" }; - cmd.arg(format!("--dynamic-linker={prefix}ld.so.1")); + cmd.link_arg(format!("--dynamic-linker={prefix}ld.so.1")); } if sess.target.eh_frame_header { @@ -2393,8 +2392,7 @@ fn add_order_independent_options( } if sess.target.os == "emscripten" { - cmd.arg("-s"); - cmd.arg(if sess.panic_strategy() == PanicStrategy::Abort { + cmd.cc_arg("-s").cc_arg(if sess.panic_strategy() == PanicStrategy::Abort { "DISABLE_EXCEPTION_CATCHING=1" } else { "DISABLE_EXCEPTION_CATCHING=0" @@ -2402,22 +2400,21 @@ fn add_order_independent_options( } if flavor == LinkerFlavor::Llbc { - cmd.arg("--target"); - cmd.arg(sess.target.llvm_target.as_ref()); - cmd.arg("--target-cpu"); - cmd.arg(&codegen_results.crate_info.target_cpu); + cmd.link_args(&[ + "--target", + sess.target.llvm_target.as_ref(), + "--target-cpu", + &codegen_results.crate_info.target_cpu, + ]); } else if flavor == LinkerFlavor::Ptx { - cmd.arg("--fallback-arch"); - cmd.arg(&codegen_results.crate_info.target_cpu); + cmd.link_args(&["--fallback-arch", &codegen_results.crate_info.target_cpu]); } else if flavor == LinkerFlavor::Bpf { - cmd.arg("--cpu"); - cmd.arg(&codegen_results.crate_info.target_cpu); + cmd.link_args(&["--cpu", &codegen_results.crate_info.target_cpu]); if let Some(feat) = [sess.opts.cg.target_feature.as_str(), &sess.target.options.features] .into_iter() .find(|feat| !feat.is_empty()) { - cmd.arg("--cpu-features"); - cmd.arg(feat); + cmd.link_args(&["--cpu-features", feat]); } } @@ -2618,7 +2615,11 @@ fn add_native_libs_from_crate( NativeLibKind::WasmImportModule => {} NativeLibKind::LinkArg => { if link_static { - cmd.linker_arg(OsStr::new(name), verbatim); + if verbatim { + cmd.verbatim_arg(name); + } else { + cmd.link_arg(name); + } } } } @@ -3012,10 +3013,10 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { // This is admittedly a bit strange, as on most targets // `-isysroot` only applies to include header files, but on Apple // targets this also applies to libraries and frameworks. - cmd.args(&["-isysroot", &sdk_root]); + cmd.cc_args(&["-isysroot", &sdk_root]); } LinkerFlavor::Darwin(Cc::No, _) => { - cmd.args(&["-syslibroot", &sdk_root]); + cmd.link_args(&["-syslibroot", &sdk_root]); } _ => unreachable!(), } @@ -3026,8 +3027,9 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { // search path. // The flags are called `-L` and `-F` both in Clang, ld64 and ldd. - cmd.arg(format!("-L{sdk_root}/System/iOSSupport/usr/lib")); - cmd.arg(format!("-F{sdk_root}/System/iOSSupport/System/Library/Frameworks")); + let sdk_root = Path::new(&sdk_root); + cmd.include_path(&sdk_root.join("System/iOSSupport/usr/lib")); + cmd.framework_path(&sdk_root.join("System/iOSSupport/System/Library/Frameworks")); } } @@ -3142,7 +3144,7 @@ fn add_lld_args( for path in sess.get_tools_search_paths(false) { let linker_path = path.join("gcc-ld"); linker_path_exists |= linker_path.exists(); - cmd.arg({ + cmd.cc_arg({ let mut arg = OsString::from("-B"); arg.push(linker_path); arg @@ -3162,7 +3164,7 @@ fn add_lld_args( // is to use LLD but the `wasm32-wasip2` target relies on a wrapper around // this, `wasm-component-ld`, which is overridden if this option is passed. if !sess.target.is_like_wasm { - cmd.arg("-fuse-ld=lld"); + cmd.cc_arg("-fuse-ld=lld"); } if !flavor.is_gnu() { @@ -3186,7 +3188,7 @@ fn add_lld_args( // targeting a different linker flavor on macOS, and that's also always // the case when targeting WASM. if sess.target.linker_flavor != sess.host.linker_flavor { - cmd.arg(format!("--target={}", sess.target.llvm_target)); + cmd.cc_arg(format!("--target={}", sess.target.llvm_target)); } } } diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index a82478900b1..0f75ece9729 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -8,7 +8,7 @@ use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufWriter}; use std::path::{Path, PathBuf}; -use std::{env, mem, str}; +use std::{env, iter, mem, str}; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; @@ -159,6 +159,102 @@ pub fn get_linker<'a>( } } +// Note: Ideally neither these helper function, nor the macro-generated inherent methods below +// would exist, and these functions would live in `trait Linker`. +// Unfortunately, adding these functions to `trait Linker` make it `dyn`-incompatible. +// If the methods are added to the trait with `where Self: Sized` bounds, then even a separate +// implementation of them for `dyn Linker {}` wouldn't work due to a conflict with those +// uncallable methods in the trait. + +/// Just pass the arguments to the linker as is. +/// It is assumed that they are correctly prepared in advance. +fn verbatim_args( + l: &mut L, + args: impl IntoIterator>, +) -> &mut L { + for arg in args { + l.cmd().arg(arg); + } + l +} +/// Arguments for the underlying linker. +/// Add options to pass them through cc wrapper if `Linker` is a cc wrapper. +fn link_args( + l: &mut L, + args: impl IntoIterator, IntoIter: ExactSizeIterator>, +) -> &mut L { + let args = args.into_iter(); + if !l.is_cc() { + verbatim_args(l, args); + } else if args.len() != 0 { + // FIXME: Support arguments with commas, see `rpaths_to_flags` for the example. + let mut combined_arg = OsString::from("-Wl"); + for arg in args { + combined_arg.push(","); + combined_arg.push(arg); + } + l.cmd().arg(combined_arg); + } + l +} +/// Arguments for the cc wrapper specifically. +/// Check that it's indeed a cc wrapper and pass verbatim. +fn cc_args(l: &mut L, args: impl IntoIterator>) -> &mut L { + assert!(l.is_cc()); + verbatim_args(l, args) +} +/// Arguments supported by both underlying linker and cc wrapper, pass verbatim. +fn link_or_cc_args( + l: &mut L, + args: impl IntoIterator>, +) -> &mut L { + verbatim_args(l, args) +} + +macro_rules! generate_arg_methods { + ($($ty:ty)*) => { $( + impl $ty { + pub fn verbatim_args(&mut self, args: impl IntoIterator>) -> &mut Self { + verbatim_args(self, args) + } + pub fn verbatim_arg(&mut self, arg: impl AsRef) -> &mut Self { + verbatim_args(self, iter::once(arg)) + } + pub fn link_args(&mut self, args: impl IntoIterator, IntoIter: ExactSizeIterator>) -> &mut Self { + link_args(self, args) + } + pub fn link_arg(&mut self, arg: impl AsRef) -> &mut Self { + link_args(self, iter::once(arg)) + } + pub fn cc_args(&mut self, args: impl IntoIterator>) -> &mut Self { + cc_args(self, args) + } + pub fn cc_arg(&mut self, arg: impl AsRef) -> &mut Self { + cc_args(self, iter::once(arg)) + } + pub fn link_or_cc_args(&mut self, args: impl IntoIterator>) -> &mut Self { + link_or_cc_args(self, args) + } + pub fn link_or_cc_arg(&mut self, arg: impl AsRef) -> &mut Self { + link_or_cc_args(self, iter::once(arg)) + } + } + )* } +} + +generate_arg_methods! { + GccLinker<'_> + MsvcLinker<'_> + EmLinker<'_> + WasmLd<'_> + L4Bender<'_> + AixLinker<'_> + LlbcLinker<'_> + PtxLinker<'_> + BpfLinker<'_> + dyn Linker + '_ +} + /// Linker abstraction used by `back::link` to build up the command to invoke a /// linker. /// @@ -168,6 +264,9 @@ pub fn get_linker<'a>( /// MSVC linker (e.g., `link.exe`) is being used. pub trait Linker { fn cmd(&mut self) -> &mut Command; + fn is_cc(&self) -> bool { + false + } fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool); fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { @@ -175,10 +274,18 @@ pub trait Linker { } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool); fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool); - fn include_path(&mut self, path: &Path); - fn framework_path(&mut self, path: &Path); - fn output_filename(&mut self, path: &Path); - fn add_object(&mut self, path: &Path); + fn include_path(&mut self, path: &Path) { + link_or_cc_args(link_or_cc_args(self, &["-L"]), &[path]); + } + fn framework_path(&mut self, _path: &Path) { + bug!("framework path set with unsupported linker") + } + fn output_filename(&mut self, path: &Path) { + link_or_cc_args(link_or_cc_args(self, &["-o"]), &[path]); + } + fn add_object(&mut self, path: &Path) { + link_or_cc_args(self, &[path]); + } fn gc_sections(&mut self, keep_metadata: bool); fn no_gc_sections(&mut self); fn full_relro(&mut self); @@ -198,25 +305,9 @@ pub trait Linker { fn add_no_exec(&mut self) {} fn add_as_needed(&mut self) {} fn reset_per_library_state(&mut self) {} - fn linker_arg(&mut self, arg: &OsStr, verbatim: bool) { - self.linker_args(&[arg], verbatim); - } - fn linker_args(&mut self, args: &[&OsStr], _verbatim: bool) { - args.into_iter().for_each(|a| { - self.cmd().arg(a); - }); - } } impl dyn Linker + '_ { - pub fn arg(&mut self, arg: impl AsRef) { - self.cmd().arg(arg); - } - - pub fn args(&mut self, args: impl IntoIterator>) { - self.cmd().args(args); - } - pub fn take_cmd(&mut self) -> Command { mem::replace(self.cmd(), Command::new("")) } @@ -233,14 +324,6 @@ pub struct GccLinker<'a> { } impl<'a> GccLinker<'a> { - fn linker_arg(&mut self, arg: impl AsRef) { - Linker::linker_arg(self, arg.as_ref(), false); - } - fn linker_args(&mut self, args: &[impl AsRef]) { - let args_vec: Vec<&OsStr> = args.iter().map(|x| x.as_ref()).collect(); - Linker::linker_args(self, &args_vec, false); - } - fn takes_hints(&self) -> bool { // Really this function only returns true if the underlying linker // configured for a compiler is binutils `ld.bfd` and `ld.gold`. We @@ -262,7 +345,7 @@ impl<'a> GccLinker<'a> { return; } if self.hinted_static != Some(true) { - self.linker_arg("-Bstatic"); + self.link_arg("-Bstatic"); self.hinted_static = Some(true); } } @@ -272,7 +355,7 @@ impl<'a> GccLinker<'a> { return; } if self.hinted_static != Some(false) { - self.linker_arg("-Bdynamic"); + self.link_arg("-Bdynamic"); self.hinted_static = Some(false); } } @@ -281,7 +364,7 @@ impl<'a> GccLinker<'a> { if let Some(plugin_path) = plugin_path { let mut arg = OsString::from("-plugin="); arg.push(plugin_path); - self.linker_arg(&arg); + self.link_arg(&arg); } let opt_level = match self.sess.opts.optimize { @@ -292,9 +375,9 @@ impl<'a> GccLinker<'a> { }; if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use { - self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display())); + self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display())); }; - self.linker_args(&[ + self.link_args(&[ &format!("-plugin-opt={opt_level}"), &format!("-plugin-opt=mcpu={}", self.target_cpu), ]); @@ -304,10 +387,10 @@ impl<'a> GccLinker<'a> { // On mac we need to tell the linker to let this library be rpathed if self.sess.target.is_like_osx { if !self.is_ld { - self.cmd.arg("-dynamiclib"); + self.cc_arg("-dynamiclib"); } - self.linker_arg("-dylib"); + self.link_arg("-dylib"); // Note that the `osx_rpath_install_name` option here is a hack // purely to support rustbuild right now, we should get a more @@ -316,10 +399,10 @@ impl<'a> GccLinker<'a> { if self.sess.opts.cg.rpath || self.sess.opts.unstable_opts.osx_rpath_install_name { let mut rpath = OsString::from("@rpath/"); rpath.push(out_filename.file_name().unwrap()); - self.linker_args(&[OsString::from("-install_name"), rpath]); + self.link_arg("-install_name").link_arg(rpath); } } else { - self.cmd.arg("-shared"); + self.link_or_cc_arg("-shared"); if self.sess.target.is_like_windows { // The output filename already contains `dll_suffix` so // the resulting import library will have a name in the @@ -336,7 +419,7 @@ impl<'a> GccLinker<'a> { if let Some(implib_name) = implib_name { let implib = out_filename.parent().map(|dir| dir.join(&implib_name)); if let Some(implib) = implib { - self.linker_arg(&format!("--out-implib={}", (*implib).to_str().unwrap())); + self.link_arg(&format!("--out-implib={}", (*implib).to_str().unwrap())); } } } @@ -345,76 +428,56 @@ impl<'a> GccLinker<'a> { } impl<'a> Linker for GccLinker<'a> { - /// Passes a series of arguments directly to the linker. - /// - /// When the linker is ld-like, the arguments are simply appended to the command. When the - /// linker is not ld-like such as when using a compiler as a linker, the arguments are joined by - /// commas to form an argument that is then prepended with `-Wl`. In this situation, only a - /// single argument is appended to the command to ensure that the order of the arguments is - /// preserved by the compiler. - fn linker_args(&mut self, args: &[&OsStr], verbatim: bool) { - if self.is_ld || verbatim { - args.into_iter().for_each(|a| { - self.cmd.arg(a); - }); - } else { - if !args.is_empty() { - let mut s = OsString::from("-Wl"); - for a in args { - s.push(","); - s.push(a); - } - self.cmd.arg(s); - } - } - } - fn cmd(&mut self) -> &mut Command { &mut self.cmd } + fn is_cc(&self) -> bool { + !self.is_ld + } + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { match output_kind { LinkOutputKind::DynamicNoPicExe => { if !self.is_ld && self.is_gnu { - self.cmd.arg("-no-pie"); + self.cc_arg("-no-pie"); } } LinkOutputKind::DynamicPicExe => { // noop on windows w/ gcc & ld, error w/ lld if !self.sess.target.is_like_windows { // `-pie` works for both gcc wrapper and ld. - self.cmd.arg("-pie"); + self.link_or_cc_arg("-pie"); } } LinkOutputKind::StaticNoPicExe => { // `-static` works for both gcc wrapper and ld. - self.cmd.arg("-static"); + self.link_or_cc_arg("-static"); if !self.is_ld && self.is_gnu { - self.cmd.arg("-no-pie"); + self.cc_arg("-no-pie"); } } LinkOutputKind::StaticPicExe => { if !self.is_ld { // Note that combination `-static -pie` doesn't work as expected // for the gcc wrapper, `-static` in that case suppresses `-pie`. - self.cmd.arg("-static-pie"); + self.cc_arg("-static-pie"); } else { // `--no-dynamic-linker` and `-z text` are not strictly necessary for producing // a static pie, but currently passed because gcc and clang pass them. // The former suppresses the `INTERP` ELF header specifying dynamic linker, // which is otherwise implicitly injected by ld (but not lld). // The latter doesn't change anything, only ensures that everything is pic. - self.cmd.args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); + self.link_args(&["-static", "-pie", "--no-dynamic-linker", "-z", "text"]); } } LinkOutputKind::DynamicDylib => self.build_dylib(out_filename), LinkOutputKind::StaticDylib => { - self.cmd.arg("-static"); + self.link_or_cc_arg("-static"); self.build_dylib(out_filename); } LinkOutputKind::WasiReactorExe => { - self.linker_args(&["--entry", "_initialize"]); + self.link_args(&["--entry", "_initialize"]); } } // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc, @@ -430,7 +493,7 @@ impl<'a> Linker for GccLinker<'a> { | LinkOutputKind::StaticDylib ) { - self.cmd.arg("--static-crt"); + self.cc_arg("--static-crt"); } } @@ -450,18 +513,18 @@ impl<'a> Linker for GccLinker<'a> { // but we have no way to detect that here. self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); } else if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--no-as-needed"); + self.link_arg("--no-as-needed"); } else { self.sess.dcx().emit_warn(errors::LinkerUnsupportedModifier); } } self.hint_dynamic(); - self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); + self.link_or_cc_arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); if !as_needed { if self.sess.target.is_like_osx { // See above FIXME comment } else if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--as-needed"); + self.link_arg("--as-needed"); } } } @@ -471,63 +534,51 @@ impl<'a> Linker for GccLinker<'a> { if !as_needed { // FIXME(81490): ld64 as of macOS 11 supports the -needed_framework // flag but we have no way to detect that here. - // self.cmd.arg("-needed_framework").arg(name); + // self.link_or_cc_arg("-needed_framework").link_or_cc_arg(name); self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); } - self.cmd.arg("-framework").arg(name); + self.link_or_cc_args(&["-framework", name]); } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); let colon = if verbatim && self.is_gnu { ":" } else { "" }; if !whole_archive { - self.cmd.arg(format!("-l{colon}{name}")); + self.link_or_cc_arg(format!("-l{colon}{name}")); } else if self.sess.target.is_like_osx { // -force_load is the macOS equivalent of --whole-archive, but it // involves passing the full path to the library to link. - self.linker_arg("-force_load"); - self.linker_arg(find_native_static_library(name, verbatim, self.sess)); + self.link_arg("-force_load"); + self.link_arg(find_native_static_library(name, verbatim, self.sess)); } else { - self.linker_arg("--whole-archive"); - self.cmd.arg(format!("-l{colon}{name}")); - self.linker_arg("--no-whole-archive"); + self.link_arg("--whole-archive") + .link_or_cc_arg(format!("-l{colon}{name}")) + .link_arg("--no-whole-archive"); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else if self.sess.target.is_like_osx { - self.linker_arg("-force_load"); - self.linker_arg(path); + self.link_arg("-force_load").link_arg(path); } else { - self.linker_arg("--whole-archive"); - self.linker_arg(path); - self.linker_arg("--no-whole-archive"); + self.link_arg("--whole-archive").link_arg(path).link_arg("--no-whole-archive"); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } fn framework_path(&mut self, path: &Path) { - self.cmd.arg("-F").arg(path); - } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_or_cc_arg("-F").link_or_cc_arg(path); } fn full_relro(&mut self) { - self.linker_args(&["-z", "relro", "-z", "now"]); + self.link_args(&["-z", "relro", "-z", "now"]); } fn partial_relro(&mut self) { - self.linker_args(&["-z", "relro"]); + self.link_args(&["-z", "relro"]); } fn no_relro(&mut self) { - self.linker_args(&["-z", "norelro"]); + self.link_args(&["-z", "norelro"]); } fn gc_sections(&mut self, keep_metadata: bool) { @@ -546,7 +597,7 @@ impl<'a> Linker for GccLinker<'a> { // for partial linking when using multiple codegen units (-r). So we // insert it here. if self.sess.target.is_like_osx { - self.linker_arg("-dead_strip"); + self.link_arg("-dead_strip"); // If we're building a dylib, we don't use --gc-sections because LLVM // has already done the best it can do, and we also don't want to @@ -554,13 +605,13 @@ impl<'a> Linker for GccLinker<'a> { // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% // reduction. } else if (self.is_gnu || self.sess.target.is_like_wasm) && !keep_metadata { - self.linker_arg("--gc-sections"); + self.link_arg("--gc-sections"); } } fn no_gc_sections(&mut self) { if self.is_gnu || self.sess.target.is_like_wasm { - self.linker_arg("--no-gc-sections"); + self.link_arg("--no-gc-sections"); } } @@ -574,7 +625,7 @@ impl<'a> Linker for GccLinker<'a> { if self.sess.opts.optimize == config::OptLevel::Default || self.sess.opts.optimize == config::OptLevel::Aggressive { - self.linker_arg("-O1"); + self.link_arg("-O1"); } } @@ -594,8 +645,7 @@ impl<'a> Linker for GccLinker<'a> { // // Though it may be worth to try to revert those changes upstream, since // the overhead of the initialization should be minor. - self.cmd.arg("-u"); - self.cmd.arg("__llvm_profile_runtime"); + self.link_or_cc_args(&["-u", "__llvm_profile_runtime"]); } fn control_flow_guard(&mut self) {} @@ -616,33 +666,33 @@ impl<'a> Linker for GccLinker<'a> { // The --strip-debug case is handled by running an external // `strip` utility as a separate step after linking. if !self.sess.target.is_like_solaris { - self.linker_arg("--strip-debug"); + self.link_arg("--strip-debug"); } } Strip::Symbols => { - self.linker_arg("--strip-all"); + self.link_arg("--strip-all"); } } match self.sess.opts.unstable_opts.debuginfo_compression { config::DebugInfoCompression::None => {} config::DebugInfoCompression::Zlib => { - self.linker_arg("--compress-debug-sections=zlib"); + self.link_arg("--compress-debug-sections=zlib"); } config::DebugInfoCompression::Zstd => { - self.linker_arg("--compress-debug-sections=zstd"); + self.link_arg("--compress-debug-sections=zstd"); } } } fn no_crt_objects(&mut self) { if !self.is_ld { - self.cmd.arg("-nostartfiles"); + self.cc_arg("-nostartfiles"); } } fn no_default_libraries(&mut self) { if !self.is_ld { - self.cmd.arg("-nodefaultlibs"); + self.cc_arg("-nodefaultlibs"); } } @@ -718,24 +768,22 @@ impl<'a> Linker for GccLinker<'a> { } if self.sess.target.is_like_osx { - self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]); + self.link_arg("-exported_symbols_list").link_arg(path); } else if self.sess.target.is_like_solaris { - self.linker_args(&[OsString::from("-M"), path.into()]); + self.link_arg("-M").link_arg(path); } else { if is_windows { - self.linker_arg(path); + self.link_arg(path); } else { let mut arg = OsString::from("--version-script="); arg.push(path); - self.linker_arg(arg); - self.linker_arg("--no-undefined-version"); + self.link_arg(arg).link_arg("--no-undefined-version"); } } } fn subsystem(&mut self, subsystem: &str) { - self.linker_arg("--subsystem"); - self.linker_arg(&subsystem); + self.link_args(&["--subsystem", subsystem]); } fn reset_per_library_state(&mut self) { @@ -760,23 +808,23 @@ impl<'a> Linker for GccLinker<'a> { // Some versions of `gcc` add it implicitly, some (e.g. `musl-gcc`) don't, // so we just always add it. fn add_eh_frame_header(&mut self) { - self.linker_arg("--eh-frame-hdr"); + self.link_arg("--eh-frame-hdr"); } fn add_no_exec(&mut self) { if self.sess.target.is_like_windows { - self.linker_arg("--nxcompat"); + self.link_arg("--nxcompat"); } else if self.is_gnu { - self.linker_args(&["-z", "noexecstack"]); + self.link_args(&["-z", "noexecstack"]); } } fn add_as_needed(&mut self) { if self.is_gnu && !self.sess.target.is_like_windows { - self.linker_arg("--as-needed"); + self.link_arg("--as-needed"); } else if self.sess.target.is_like_solaris { // -z ignore is the Solaris equivalent to the GNU ld --as-needed option - self.linker_args(&["-z", "ignore"]); + self.link_args(&["-z", "ignore"]); } } } @@ -798,10 +846,10 @@ impl<'a> Linker for MsvcLinker<'a> { | LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {} LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { - self.cmd.arg("/DLL"); + self.link_arg("/DLL"); let mut arg: OsString = "/IMPLIB:".into(); arg.push(out_filename.with_extension("dll.lib")); - self.cmd.arg(arg); + self.link_arg(arg); } LinkOutputKind::WasiReactorExe => { panic!("can't link as reactor on non-wasi target"); @@ -810,44 +858,40 @@ impl<'a> Linker for MsvcLinker<'a> { } fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { - self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + self.link_arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; let suffix = if verbatim { "" } else { ".lib" }; - self.cmd.arg(format!("{prefix}{name}{suffix}")); + self.link_arg(format!("{prefix}{name}{suffix}")); } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { if !whole_archive { - self.cmd.arg(path); + self.link_arg(path); } else { let mut arg = OsString::from("/WHOLEARCHIVE:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn gc_sections(&mut self, _keep_metadata: bool) { // MSVC's ICF (Identical COMDAT Folding) link optimization is // slow for Rust and thus we disable it by default when not in // optimization build. if self.sess.opts.optimize != config::OptLevel::No { - self.cmd.arg("/OPT:REF,ICF"); + self.link_arg("/OPT:REF,ICF"); } else { // It is necessary to specify NOICF here, because /OPT:REF // implies ICF by default. - self.cmd.arg("/OPT:REF,NOICF"); + self.link_arg("/OPT:REF,NOICF"); } } fn no_gc_sections(&mut self) { - self.cmd.arg("/OPT:NOREF,NOICF"); + self.link_arg("/OPT:NOREF,NOICF"); } fn full_relro(&mut self) { @@ -867,23 +911,19 @@ impl<'a> Linker for MsvcLinker<'a> { } fn no_default_libraries(&mut self) { - self.cmd.arg("/NODEFAULTLIB"); + self.link_arg("/NODEFAULTLIB"); } fn include_path(&mut self, path: &Path) { let mut arg = OsString::from("/LIBPATH:"); arg.push(path); - self.cmd.arg(&arg); + self.link_arg(&arg); } fn output_filename(&mut self, path: &Path) { let mut arg = OsString::from("/OUT:"); arg.push(path); - self.cmd.arg(&arg); - } - - fn framework_path(&mut self, _path: &Path) { - bug!("frameworks are not supported on windows") + self.link_arg(&arg); } fn optimize(&mut self) { @@ -895,19 +935,19 @@ impl<'a> Linker for MsvcLinker<'a> { } fn control_flow_guard(&mut self) { - self.cmd.arg("/guard:cf"); + self.link_arg("/guard:cf"); } fn ehcont_guard(&mut self) { if self.sess.target.pointer_width == 64 { - self.cmd.arg("/guard:ehcont"); + self.link_arg("/guard:ehcont"); } } fn debuginfo(&mut self, _strip: Strip, natvis_debugger_visualizers: &[PathBuf]) { // This will cause the Microsoft linker to generate a PDB file // from the CodeView line tables in the object files. - self.cmd.arg("/DEBUG"); + self.link_arg("/DEBUG"); // Default to emitting only the file name of the PDB file into // the binary instead of the full path. Emitting the full path @@ -916,7 +956,7 @@ impl<'a> Linker for MsvcLinker<'a> { // // This default behavior can be overridden by explicitly passing // `-Clink-arg=/PDBALTPATH:...` to rustc. - self.cmd.arg("/PDBALTPATH:%_PDB%"); + self.link_arg("/PDBALTPATH:%_PDB%"); // This will cause the Microsoft linker to embed .natvis info into the PDB file let natvis_dir_path = self.sess.sysroot.join("lib\\rustlib\\etc"); @@ -928,7 +968,7 @@ impl<'a> Linker for MsvcLinker<'a> { if path.extension() == Some("natvis".as_ref()) { let mut arg = OsString::from("/NATVIS:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } Err(error) => { @@ -942,7 +982,7 @@ impl<'a> Linker for MsvcLinker<'a> { for path in natvis_debugger_visualizers { let mut arg = OsString::from("/NATVIS:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } @@ -986,13 +1026,13 @@ impl<'a> Linker for MsvcLinker<'a> { } let mut arg = OsString::from("/DEF:"); arg.push(path); - self.cmd.arg(&arg); + self.link_arg(&arg); } fn subsystem(&mut self, subsystem: &str) { // Note that previous passes of the compiler validated this subsystem, // so we just blindly pass it to the linker. - self.cmd.arg(&format!("/SUBSYSTEM:{subsystem}")); + self.link_arg(&format!("/SUBSYSTEM:{subsystem}")); // Windows has two subsystems we're interested in right now, the console // and windows subsystems. These both implicitly have different entry @@ -1009,7 +1049,7 @@ impl<'a> Linker for MsvcLinker<'a> { // // For more information see RFC #1665 if subsystem == "windows" { - self.cmd.arg("/ENTRY:mainCRTStartup"); + self.link_arg("/ENTRY:mainCRTStartup"); } } @@ -1018,7 +1058,7 @@ impl<'a> Linker for MsvcLinker<'a> { } fn add_no_exec(&mut self) { - self.cmd.arg("/NXCOMPAT"); + self.link_arg("/NXCOMPAT"); } } @@ -1032,31 +1072,23 @@ impl<'a> Linker for EmLinker<'a> { &mut self.cmd } + fn is_cc(&self) -> bool { + true + } + fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { // Emscripten always links statically - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); } fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, _whole_archive: bool) { - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_or_cc_arg(path); } fn full_relro(&mut self) { @@ -1071,10 +1103,6 @@ impl<'a> Linker for EmLinker<'a> { // noop } - fn framework_path(&mut self, _path: &Path) { - bug!("frameworks are not supported on Emscripten") - } - fn gc_sections(&mut self, _keep_metadata: bool) { // noop } @@ -1085,7 +1113,7 @@ impl<'a> Linker for EmLinker<'a> { fn optimize(&mut self) { // Emscripten performs own optimizations - self.cmd.arg(match self.sess.opts.optimize { + self.cc_arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", OptLevel::Default => "-O2", @@ -1106,7 +1134,7 @@ impl<'a> Linker for EmLinker<'a> { fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { // Preserve names or generate source maps depending on debug info // For more information see https://emscripten.org/docs/tools_reference/emcc.html#emcc-g - self.cmd.arg(match self.sess.opts.debuginfo { + self.cc_arg(match self.sess.opts.debuginfo { DebugInfo::None => "-g0", DebugInfo::Limited | DebugInfo::LineTablesOnly | DebugInfo::LineDirectivesOnly => { "--profiling-funcs" @@ -1118,13 +1146,13 @@ impl<'a> Linker for EmLinker<'a> { fn no_crt_objects(&mut self) {} fn no_default_libraries(&mut self) { - self.cmd.arg("-nodefaultlibs"); + self.cc_arg("-nodefaultlibs"); } fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { debug!("EXPORTED SYMBOLS:"); - self.cmd.arg("-s"); + self.cc_arg("-s"); let mut arg = OsString::from("EXPORTED_FUNCTIONS="); let encoded = serde_json::to_string( @@ -1135,7 +1163,7 @@ impl<'a> Linker for EmLinker<'a> { arg.push(encoded); - self.cmd.arg(arg); + self.cc_arg(arg); } fn subsystem(&mut self, _subsystem: &str) { @@ -1153,7 +1181,7 @@ pub struct WasmLd<'a> { } impl<'a> WasmLd<'a> { - fn new(mut cmd: Command, sess: &'a Session) -> WasmLd<'a> { + fn new(cmd: Command, sess: &'a Session) -> WasmLd<'a> { // If the atomics feature is enabled for wasm then we need a whole bunch // of flags: // @@ -1172,18 +1200,19 @@ impl<'a> WasmLd<'a> { // On wasm32-unknown-unknown, we also export symbols for glue code to use: // * `--export=*tls*` - when `#[thread_local]` symbols are used these // symbols are how the TLS segments are initialized and configured. + let mut wasm_ld = WasmLd { cmd, sess }; if sess.target_features.contains(&sym::atomics) { - cmd.arg("--shared-memory"); - cmd.arg("--max-memory=1073741824"); - cmd.arg("--import-memory"); + wasm_ld.link_args(&["--shared-memory", "--max-memory=1073741824", "--import-memory"]); if sess.target.os == "unknown" { - cmd.arg("--export=__wasm_init_tls"); - cmd.arg("--export=__tls_size"); - cmd.arg("--export=__tls_align"); - cmd.arg("--export=__tls_base"); + wasm_ld.link_args(&[ + "--export=__wasm_init_tls", + "--export=__tls_size", + "--export=__tls_align", + "--export=__tls_base", + ]); } } - WasmLd { cmd, sess } + wasm_ld } } @@ -1199,51 +1228,36 @@ impl<'a> Linker for WasmLd<'a> { | LinkOutputKind::StaticNoPicExe | LinkOutputKind::StaticPicExe => {} LinkOutputKind::DynamicDylib | LinkOutputKind::StaticDylib => { - self.cmd.arg("--no-entry"); + self.link_arg("--no-entry"); } LinkOutputKind::WasiReactorExe => { - self.cmd.arg("--entry"); - self.cmd.arg("_initialize"); + self.link_args(&["--entry", "_initialize"]); } } } fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); } fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { if !whole_archive { - self.cmd.arg("-l").arg(name); + self.link_or_cc_args(&["-l", name]); } else { - self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); + self.link_arg("--whole-archive") + .link_or_cc_args(&["-l", name]) + .link_arg("--no-whole-archive"); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else { - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive"); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1251,17 +1265,17 @@ impl<'a> Linker for WasmLd<'a> { fn no_relro(&mut self) {} fn gc_sections(&mut self, _keep_metadata: bool) { - self.cmd.arg("--gc-sections"); + self.link_arg("--gc-sections"); } fn no_gc_sections(&mut self) { - self.cmd.arg("--no-gc-sections"); + self.link_arg("--no-gc-sections"); } fn optimize(&mut self) { // The -O flag is, as of late 2023, only used for merging of strings and debuginfo, and // only differentiates -O0 and -O1. It does not apply to LTO. - self.cmd.arg(match self.sess.opts.optimize { + self.link_arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", OptLevel::Default => "-O2", @@ -1279,10 +1293,10 @@ impl<'a> Linker for WasmLd<'a> { match strip { Strip::None => {} Strip::Debuginfo => { - self.cmd.arg("--strip-debug"); + self.link_arg("--strip-debug"); } Strip::Symbols => { - self.cmd.arg("--strip-all"); + self.link_arg("--strip-all"); } } } @@ -1297,7 +1311,7 @@ impl<'a> Linker for WasmLd<'a> { fn export_symbols(&mut self, _tmpdir: &Path, _crate_type: CrateType, symbols: &[String]) { for sym in symbols { - self.cmd.arg("--export").arg(&sym); + self.link_args(&["--export", sym]); } // LLD will hide these otherwise-internal symbols since it only exports @@ -1305,8 +1319,7 @@ impl<'a> Linker for WasmLd<'a> { // others. Various bits and pieces of wasm32-unknown-unknown tooling use // this, so be sure these symbols make their way out of the linker as well. if self.sess.target.os == "unknown" { - self.cmd.arg("--export=__heap_base"); - self.cmd.arg("--export=__data_end"); + self.link_args(&["--export=__heap_base", "--export=__data_end"]); } } @@ -1337,7 +1350,7 @@ impl<'a> WasmLd<'a> { // wasm-ld only handles integer LTO opt levels. Use O2 config::OptLevel::Size | config::OptLevel::SizeMin => "O2", }; - self.cmd.arg(&format!("--lto-{opt_level}")); + self.link_arg(&format!("--lto-{opt_level}")); } } @@ -1362,56 +1375,43 @@ impl<'a> Linker for L4Bender<'a> { fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(format!("-PC{name}")); + self.link_arg(format!("-PC{name}")); } else { - self.cmd.arg("--whole-archive").arg(format!("-l{name}")).arg("--no-whole-archive"); + self.link_arg("--whole-archive") + .link_or_cc_arg(format!("-l{name}")) + .link_arg("--no-whole-archive"); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else { - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + self.link_arg("--whole-archive").link_or_cc_arg(path).link_arg("--no-whole-archive"); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - fn framework_path(&mut self, _: &Path) { - bug!("frameworks are not supported on L4Re"); - } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn full_relro(&mut self) { - self.cmd.arg("-z").arg("relro"); - self.cmd.arg("-z").arg("now"); + self.link_args(&["-z", "relro", "-z", "now"]); } fn partial_relro(&mut self) { - self.cmd.arg("-z").arg("relro"); + self.link_args(&["-z", "relro"]); } fn no_relro(&mut self) { - self.cmd.arg("-z").arg("norelro"); + self.link_args(&["-z", "norelro"]); } fn gc_sections(&mut self, keep_metadata: bool) { if !keep_metadata { - self.cmd.arg("--gc-sections"); + self.link_arg("--gc-sections"); } } fn no_gc_sections(&mut self) { - self.cmd.arg("--no-gc-sections"); + self.link_arg("--no-gc-sections"); } fn optimize(&mut self) { @@ -1420,7 +1420,7 @@ impl<'a> Linker for L4Bender<'a> { if self.sess.opts.optimize == config::OptLevel::Default || self.sess.opts.optimize == config::OptLevel::Aggressive { - self.cmd.arg("-O1"); + self.link_arg("-O1"); } } @@ -1430,16 +1430,16 @@ impl<'a> Linker for L4Bender<'a> { match strip { Strip::None => {} Strip::Debuginfo => { - self.cmd().arg("--strip-debug"); + self.link_arg("--strip-debug"); } Strip::Symbols => { - self.cmd().arg("--strip-all"); + self.link_arg("--strip-all"); } } } fn no_default_libraries(&mut self) { - self.cmd.arg("-nostdlib"); + self.cc_arg("-nostdlib"); } fn export_symbols(&mut self, _: &Path, _: CrateType, _: &[String]) { @@ -1449,7 +1449,7 @@ impl<'a> Linker for L4Bender<'a> { } fn subsystem(&mut self, subsystem: &str) { - self.cmd.arg(&format!("--subsystem {subsystem}")); + self.link_arg(&format!("--subsystem {subsystem}")); } fn reset_per_library_state(&mut self) { @@ -1467,12 +1467,12 @@ impl<'a> Linker for L4Bender<'a> { impl<'a> L4Bender<'a> { pub fn new(cmd: Command, sess: &'a Session) -> L4Bender<'a> { - L4Bender { cmd: cmd, sess: sess, hinted_static: false } + L4Bender { cmd, sess: sess, hinted_static: false } } fn hint_static(&mut self) { if !self.hinted_static { - self.cmd.arg("-static"); + self.link_or_cc_arg("-static"); self.hinted_static = true; } } @@ -1487,29 +1487,28 @@ pub struct AixLinker<'a> { impl<'a> AixLinker<'a> { pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> { - AixLinker { cmd: cmd, sess: sess, hinted_static: None } + AixLinker { cmd, sess: sess, hinted_static: None } } fn hint_static(&mut self) { if self.hinted_static != Some(true) { - self.cmd.arg("-bstatic"); + self.link_arg("-bstatic"); self.hinted_static = Some(true); } } fn hint_dynamic(&mut self) { if self.hinted_static != Some(false) { - self.cmd.arg("-bdynamic"); + self.link_arg("-bdynamic"); self.hinted_static = Some(false); } } fn build_dylib(&mut self, _out_filename: &Path) { - self.cmd.arg("-bM:SRE"); - self.cmd.arg("-bnoentry"); + self.link_args(&["-bM:SRE", "-bnoentry"]); // FIXME: Use CreateExportList utility to create export list // and remove -bexpfull. - self.cmd.arg("-bexpfull"); + self.link_arg("-bexpfull"); } } @@ -1534,47 +1533,31 @@ impl<'a> Linker for AixLinker<'a> { fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { self.hint_dynamic(); - self.cmd.arg(format!("-l{name}")); + self.link_or_cc_arg(format!("-l{name}")); } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(format!("-l{name}")); + self.link_or_cc_arg(format!("-l{name}")); } else { let mut arg = OsString::from("-bkeepfile:"); arg.push(find_native_static_library(name, verbatim, self.sess)); - self.cmd.arg(arg); + self.link_or_cc_arg(arg); } } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); if !whole_archive { - self.cmd.arg(path); + self.link_or_cc_arg(path); } else { let mut arg = OsString::from("-bkeepfile:"); arg.push(path); - self.cmd.arg(arg); + self.link_arg(arg); } } - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); - } - - fn framework_path(&mut self, _: &Path) { - bug!("frameworks are not supported on AIX"); - } - - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1582,17 +1565,17 @@ impl<'a> Linker for AixLinker<'a> { fn no_relro(&mut self) {} fn gc_sections(&mut self, _keep_metadata: bool) { - self.cmd.arg("-bgc"); + self.link_arg("-bgc"); } fn no_gc_sections(&mut self) { - self.cmd.arg("-bnogc"); + self.link_arg("-bnogc"); } fn optimize(&mut self) {} fn pgo_gen(&mut self) { - self.cmd.arg("-bdbg:namedsects:ss"); + self.link_arg("-bdbg:namedsects:ss"); } fn control_flow_guard(&mut self) {} @@ -1618,7 +1601,7 @@ impl<'a> Linker for AixLinker<'a> { if let Err(e) = res { self.sess.dcx().fatal(format!("failed to write export file: {e}")); } - self.cmd.arg(format!("-bE:{}", path.to_str().unwrap())); + self.link_arg(format!("-bE:{}", path.to_str().unwrap())); } fn subsystem(&mut self, _subsystem: &str) {} @@ -1747,39 +1730,27 @@ impl<'a> Linker for PtxLinker<'a> { } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg("--rlib").arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); + self.link_arg("--rlib").link_arg(path); } fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); + self.link_arg("--debug"); } fn add_object(&mut self, path: &Path) { - self.cmd.arg("--bitcode").arg(path); + self.link_arg("--bitcode").link_arg(path); } fn optimize(&mut self) { match self.sess.lto() { Lto::Thin | Lto::Fat | Lto::ThinLocal => { - self.cmd.arg("-Olto"); + self.link_arg("-Olto"); } Lto::No => {} } } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1829,19 +1800,11 @@ impl<'a> Linker for LlbcLinker<'a> { } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); + self.link_or_cc_arg(path); } fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_arg("--debug"); } fn optimize(&mut self) { @@ -1855,14 +1818,6 @@ impl<'a> Linker for LlbcLinker<'a> { }; } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1887,7 +1842,7 @@ impl<'a> Linker for LlbcLinker<'a> { match _crate_type { CrateType::Cdylib => { for sym in symbols { - self.cmd.arg("--export-symbol").arg(sym); + self.link_args(&["--export-symbol", sym]); } } _ => (), @@ -1920,23 +1875,15 @@ impl<'a> Linker for BpfLinker<'a> { } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.cmd.arg(path); - } - - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); + self.link_or_cc_arg(path); } fn debuginfo(&mut self, _strip: Strip, _: &[PathBuf]) { - self.cmd.arg("--debug"); - } - - fn add_object(&mut self, path: &Path) { - self.cmd.arg(path); + self.link_arg("--debug"); } fn optimize(&mut self) { - self.cmd.arg(match self.sess.opts.optimize { + self.link_arg(match self.sess.opts.optimize { OptLevel::No => "-O0", OptLevel::Less => "-O1", OptLevel::Default => "-O2", @@ -1946,14 +1893,6 @@ impl<'a> Linker for BpfLinker<'a> { }); } - fn output_filename(&mut self, path: &Path) { - self.cmd.arg("-o").arg(path); - } - - fn framework_path(&mut self, _path: &Path) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1985,7 +1924,7 @@ impl<'a> Linker for BpfLinker<'a> { if let Err(error) = res { self.sess.dcx().emit_fatal(errors::SymbolFileWriteFailure { error }); } else { - self.cmd.arg("--export-symbols").arg(&path); + self.link_arg("--export-symbols").link_arg(&path); } } -- cgit 1.4.1-3-g733a5 From 5f9a0d3844e5a00f2c821c9b1e7d17679b758036 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 1 Jul 2024 13:06:20 +0300 Subject: linker: Bail out of rpath logic early if the target doesn't support rpath --- compiler/rustc_codegen_ssa/src/back/link.rs | 5 ++++- compiler/rustc_codegen_ssa/src/back/rpath.rs | 6 ------ compiler/rustc_codegen_ssa/src/back/rpath/tests.rs | 3 --- 3 files changed, 4 insertions(+), 10 deletions(-) (limited to 'compiler/rustc_codegen_ssa/src') diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index da7ffdc4911..da4fa41e2aa 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2096,6 +2096,10 @@ fn add_rpath_args( codegen_results: &CodegenResults, out_filename: &Path, ) { + if !sess.target.has_rpath { + return; + } + // FIXME (#2397): At some point we want to rpath our guesses as to // where extern libraries might live, based on the // add_lib_search_paths @@ -2114,7 +2118,6 @@ fn add_rpath_args( let rpath_config = RPathConfig { libs: &*libs, out_filename: out_filename.to_path_buf(), - has_rpath: sess.target.has_rpath, is_like_osx: sess.target.is_like_osx, linker_is_gnu: sess.target.linker_flavor.is_gnu(), }; diff --git a/compiler/rustc_codegen_ssa/src/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs index f499bbcf853..82070d4453b 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath.rs @@ -9,16 +9,10 @@ pub struct RPathConfig<'a> { pub libs: &'a [&'a Path], pub out_filename: PathBuf, pub is_like_osx: bool, - pub has_rpath: bool, pub linker_is_gnu: bool, } pub fn get_rpath_flags(config: &RPathConfig<'_>) -> Vec { - // No rpath on windows - if !config.has_rpath { - return Vec::new(); - } - debug!("preparing the RPATH!"); let rpaths = get_rpaths(config); diff --git a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs index 0de90a1036e..c620e92db1f 100644 --- a/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs +++ b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs @@ -37,7 +37,6 @@ fn test_rpath_relative() { if cfg!(target_os = "macos") { let config = &mut RPathConfig { libs: &[], - has_rpath: true, is_like_osx: true, linker_is_gnu: false, out_filename: PathBuf::from("bin/rustc"), @@ -48,7 +47,6 @@ fn test_rpath_relative() { let config = &mut RPathConfig { libs: &[], out_filename: PathBuf::from("bin/rustc"), - has_rpath: true, is_like_osx: false, linker_is_gnu: true, }; @@ -62,7 +60,6 @@ fn test_rpath_relative_issue_119571() { let config = &mut RPathConfig { libs: &[], out_filename: PathBuf::from("rustc"), - has_rpath: true, is_like_osx: false, linker_is_gnu: true, }; -- cgit 1.4.1-3-g733a5