From d58d52a39759960009ca2817f7edcdf22d8722df Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Thu, 11 Nov 2021 18:28:19 -0500 Subject: [PATCH 1/6] Fix handling of substitutions and binders when deciding whether to suggest references When suggesting references, substitutions were being forgotten and some types were misused. This led to at least one ICE and other incorrectly emitted diagnostics. This has been fixed; in some cases this leads to diagnostics changing, and tests have been adjusted. --- .../src/traits/error_reporting/suggestions.rs | 59 +++++++------------ src/test/ui/derives/deriving-copyclone.stderr | 6 +- .../negated-auto-traits-error.stderr | 12 +--- ...ue-90804-incorrect-reference-suggestion.rs | 11 ++++ ...0804-incorrect-reference-suggestion.stderr | 17 ++++++ 5 files changed, 55 insertions(+), 50 deletions(-) create mode 100644 src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.rs create mode 100644 src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.stderr diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index b21936a00b04f..89aa507061af0 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -706,36 +706,29 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } let param_env = obligation.param_env; - let trait_ref = poly_trait_ref.skip_binder(); - - let found_ty = trait_ref.self_ty(); - let found_ty_str = found_ty.to_string(); - let imm_borrowed_found_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, found_ty); - let imm_substs = self.tcx.mk_substs_trait(imm_borrowed_found_ty, &[]); - let mut_borrowed_found_ty = self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, found_ty); - let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]); // Try to apply the original trait binding obligation by borrowing. - let mut try_borrowing = |new_imm_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - new_mut_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, - expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, + let mut try_borrowing = |old_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>, blacklist: &[DefId]| -> bool { - if blacklist.contains(&expected_trait_ref.def_id()) { + if blacklist.contains(&old_ref.def_id()) { return false; } - let imm_result = self.predicate_must_hold_modulo_regions(&Obligation::new( - ObligationCause::dummy(), - param_env, - new_imm_trait_ref.without_const().to_predicate(self.tcx), - )); - - let mut_result = self.predicate_must_hold_modulo_regions(&Obligation::new( - ObligationCause::dummy(), - param_env, - new_mut_trait_ref.without_const().to_predicate(self.tcx), - )); + let orig_ty = old_ref.self_ty().skip_binder(); + let mk_result = |new_ty| { + let new_ref = old_ref.rebind(ty::TraitRef::new( + old_ref.def_id(), + self.tcx.mk_substs_trait(new_ty, &old_ref.skip_binder().substs[1..]), + )); + self.predicate_must_hold_modulo_regions(&Obligation::new( + ObligationCause::dummy(), + param_env, + new_ref.without_const().to_predicate(self.tcx), + )) + }; + let imm_result = mk_result(self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, orig_ty)); + let mut_result = mk_result(self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, orig_ty)); if imm_result || mut_result { if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) { @@ -747,8 +740,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let msg = format!( "the trait bound `{}: {}` is not satisfied", - found_ty_str, - expected_trait_ref.print_only_trait_path(), + orig_ty.to_string(), + old_ref.print_only_trait_path(), ); if has_custom_message { err.note(&msg); @@ -764,7 +757,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span, &format!( "expected an implementor of trait `{}`", - expected_trait_ref.print_only_trait_path(), + old_ref.print_only_trait_path(), ), ); @@ -807,21 +800,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; if let ObligationCauseCode::ImplDerivedObligation(obligation) = &*code { - let expected_trait_ref = obligation.parent_trait_ref; - let new_imm_trait_ref = poly_trait_ref - .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs)); - let new_mut_trait_ref = poly_trait_ref - .rebind(ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs)); - return try_borrowing(new_imm_trait_ref, new_mut_trait_ref, expected_trait_ref, &[]); + try_borrowing(obligation.parent_trait_ref, &[]) } else if let ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ItemObligation(_) = &*code { - return try_borrowing( - poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, imm_substs)), - poly_trait_ref.rebind(ty::TraitRef::new(trait_ref.def_id, mut_substs)), - *poly_trait_ref, - &never_suggest_borrow[..], - ); + try_borrowing(*poly_trait_ref, &never_suggest_borrow[..]) } else { false } diff --git a/src/test/ui/derives/deriving-copyclone.stderr b/src/test/ui/derives/deriving-copyclone.stderr index 1d0554ad0477f..13097edf0adf9 100644 --- a/src/test/ui/derives/deriving-copyclone.stderr +++ b/src/test/ui/derives/deriving-copyclone.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `C: Copy` is not satisfied +error[E0277]: the trait bound `B: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:31:13 | LL | is_copy(B { a: 1, b: C }); @@ -22,7 +22,7 @@ help: consider borrowing here LL | is_copy(&B { a: 1, b: C }); | + -error[E0277]: the trait bound `C: Clone` is not satisfied +error[E0277]: the trait bound `B: Clone` is not satisfied --> $DIR/deriving-copyclone.rs:32:14 | LL | is_clone(B { a: 1, b: C }); @@ -46,7 +46,7 @@ help: consider borrowing here LL | is_clone(&B { a: 1, b: C }); | + -error[E0277]: the trait bound `D: Copy` is not satisfied +error[E0277]: the trait bound `B: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:35:13 | LL | is_copy(B { a: 1, b: D }); diff --git a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr index 1cf73fcdebd0b..1ab130e0ab143 100644 --- a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr +++ b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -65,7 +65,7 @@ LL | is_send(Box::new(TestType)); | | | required by a bound introduced by this call | - = note: the trait bound `dummy2::TestType: Send` is not satisfied + = note: the trait bound `Unique: Send` is not satisfied = note: required because of the requirements on the impl of `Send` for `Unique` = note: required because it appears within the type `Box` note: required by a bound in `is_send` @@ -104,11 +104,11 @@ error[E0277]: `main::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:66:13 | LL | is_sync(Outer2(TestType)); - | ------- ^^^^^^^^^^^^^^^^ expected an implementor of trait `Sync` + | ------- ^^^^^^^^^^^^^^^^ `main::TestType` cannot be sent between threads safely | | | required by a bound introduced by this call | - = note: the trait bound `main::TestType: Sync` is not satisfied + = help: the trait `Send` is not implemented for `main::TestType` note: required because of the requirements on the impl of `Sync` for `Outer2` --> $DIR/negated-auto-traits-error.rs:14:22 | @@ -119,12 +119,6 @@ note: required by a bound in `is_sync` | LL | fn is_sync(_: T) {} | ^^^^ required by this bound in `is_sync` -help: consider borrowing here - | -LL | is_sync(&Outer2(TestType)); - | + -LL | is_sync(&mut Outer2(TestType)); - | ++++ error: aborting due to 7 previous errors diff --git a/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.rs b/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.rs new file mode 100644 index 0000000000000..f891a42fc2af0 --- /dev/null +++ b/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.rs @@ -0,0 +1,11 @@ +// Do not suggest referencing the parameter to `check` + +trait Marker {} + +impl Marker for T {} + +pub fn check>(_: T) {} + +pub fn main() { + check::<()>(()); //~ ERROR [E0277] +} diff --git a/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.stderr b/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.stderr new file mode 100644 index 0000000000000..08eab0253701e --- /dev/null +++ b/src/test/ui/typeck/issue-90804-incorrect-reference-suggestion.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `(): Marker` is not satisfied + --> $DIR/issue-90804-incorrect-reference-suggestion.rs:10:17 + | +LL | check::<()>(()); + | ----------- ^^ the trait `Marker` is not implemented for `()` + | | + | required by a bound introduced by this call + | +note: required by a bound in `check` + --> $DIR/issue-90804-incorrect-reference-suggestion.rs:7:17 + | +LL | pub fn check>(_: T) {} + | ^^^^^^^^^^^ required by this bound in `check` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. From 845c25d1b445f76cd4a2c69a6ac61b85f0327626 Mon Sep 17 00:00:00 2001 From: pierwill Date: Fri, 12 Nov 2021 13:35:42 -0600 Subject: [PATCH 2/6] Generate documentation in rustc `rustc_index::newtype_index` macro The macro now documents all generated items. Documentation notes possible panics and unsafety. --- compiler/rustc_index/src/vec.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 45639bad24313..55ccfd0ad2380 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -118,32 +118,54 @@ macro_rules! newtype_index { } impl $type { + /// Maximum value the index can take, as a `u32`. $v const MAX_AS_U32: u32 = $max; + /// Maximum value the index can take. $v const MAX: Self = Self::from_u32($max); + /// Creates a new index from a given `usize`. + /// + /// # Panics + /// + /// Will panic if `value` exceeds `MAX`. #[inline] $v const fn from_usize(value: usize) -> Self { assert!(value <= ($max as usize)); + // SAFETY: We just checked that `value <= max`. unsafe { Self::from_u32_unchecked(value as u32) } } + /// Creates a new index from a given `u32`. + /// + /// # Panics + /// + /// Will panic if `value` exceeds `MAX`. #[inline] $v const fn from_u32(value: u32) -> Self { assert!(value <= $max); + // SAFETY: We just checked that `value <= max`. unsafe { Self::from_u32_unchecked(value) } } + /// Creates a new index from a given `u32`. + /// + /// # Safety + /// + /// The provided value must be less than or equal to the maximum value for the newtype. + /// Providing a value outside this range is undefined due to layout restrictions. + /// + /// Prefer using `from_u32`. #[inline] $v const unsafe fn from_u32_unchecked(value: u32) -> Self { Self { private: value } } - /// Extracts the value of this index as an integer. + /// Extracts the value of this index as a `usize`. #[inline] $v const fn index(self) -> usize { self.as_usize() From 94ca0b392df7c0f551c136394bf3456bee041357 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Nov 2021 20:55:33 -0500 Subject: [PATCH 3/6] fix ICE on Miri/CTFE copy of half a pointer --- .../rustc_const_eval/src/interpret/memory.rs | 13 +++++----- src/test/ui/consts/issue-miri-1910.rs | 12 +++++++++ src/test/ui/consts/issue-miri-1910.stderr | 26 +++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/consts/issue-miri-1910.rs create mode 100644 src/test/ui/consts/issue-miri-1910.stderr diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index b8b6ff93753f0..4aa3c83cc0243 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1057,20 +1057,19 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Some(dest_ptr) => dest_ptr, }; + // This checks relocation edges on the src, which needs to happen before + // `prepare_relocation_copy`. + let src_bytes = src_alloc + .get_bytes_with_uninit_and_ptr(&tcx, src_range) + .map_err(|e| e.to_interp_error(src_alloc_id))? + .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation // first copy the relocations to a temporary buffer, because // `get_bytes_mut` will clear the relocations, which is correct, // since we don't want to keep any relocations at the target. - // (`get_bytes_with_uninit_and_ptr` below checks that there are no - // relocations overlapping the edges; those would not be handled correctly). let relocations = src_alloc.prepare_relocation_copy(self, src_range, dest_offset, num_copies); // Prepare a copy of the initialization mask. let compressed = src_alloc.compress_uninit_range(src_range); - // This checks relocation edges on the src. - let src_bytes = src_alloc - .get_bytes_with_uninit_and_ptr(&tcx, src_range) - .map_err(|e| e.to_interp_error(src_alloc_id))? - .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation // Destination alloc preparations and access hooks. let (dest_alloc, extra) = self.get_raw_mut(dest_alloc_id)?; diff --git a/src/test/ui/consts/issue-miri-1910.rs b/src/test/ui/consts/issue-miri-1910.rs new file mode 100644 index 0000000000000..20efa145dbe1e --- /dev/null +++ b/src/test/ui/consts/issue-miri-1910.rs @@ -0,0 +1,12 @@ +// error-pattern unable to turn pointer into raw bytes +#![feature(const_ptr_read)] +#![feature(const_ptr_offset)] + +const C: () = unsafe { + let foo = Some(&42 as *const i32); + let one_and_a_half_pointers = std::mem::size_of::<*const i32>()/2*3; + (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); +}; + +fn main() { +} diff --git a/src/test/ui/consts/issue-miri-1910.stderr b/src/test/ui/consts/issue-miri-1910.stderr new file mode 100644 index 0000000000000..e2f4ef635887c --- /dev/null +++ b/src/test/ui/consts/issue-miri-1910.stderr @@ -0,0 +1,26 @@ +error: any use of this value will cause an error + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | unable to turn pointer into raw bytes + | inside `std::ptr::read::` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | inside `ptr::const_ptr::::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `C` at $DIR/issue-miri-1910.rs:8:5 + | + ::: $DIR/issue-miri-1910.rs:5:1 + | +LL | / const C: () = unsafe { +LL | | let foo = Some(&42 as *const i32); +LL | | let one_and_a_half_pointers = std::mem::size_of::<*const i32>()/2*3; +LL | | (&foo as *const _ as *const u8).add(one_and_a_half_pointers).read(); +LL | | }; + | |__- + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + +error: aborting due to previous error + From 9bbc9cb597a37385f423c49e0bbf8ddafb128bbf Mon Sep 17 00:00:00 2001 From: kit Date: Mon, 8 Nov 2021 20:45:04 +1100 Subject: [PATCH 4/6] Add a helper method for linker arguments Linker arguments must transformed when Rust is interacting with the linker through a compiler. This commit introduces a helper function that abstracts away details of this transformation. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 39 +++++++++++++------ 1 file changed, 28 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 429dc45d6a4c4..1e29c3085a3fd 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -219,19 +219,36 @@ pub struct GccLinker<'a> { } impl<'a> GccLinker<'a> { - /// Argument that must be passed *directly* to the linker + /// Passes an argument directly to the linker. /// - /// These arguments need to be prepended with `-Wl`, when a GCC-style linker is used. - fn linker_arg(&mut self, arg: S) -> &mut Self - where - S: AsRef, - { - if !self.is_ld { - let mut os = OsString::from("-Wl,"); - os.push(arg.as_ref()); - self.cmd.arg(os); + /// When the linker is not ld-like such as when using a compiler as a linker, the argument is + /// prepended by `-Wl,`. + fn linker_arg(&mut self, arg: impl AsRef) -> &mut Self { + self.linker_args(&[arg]); + self + } + + /// 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: &[impl AsRef]) -> &mut Self { + if self.is_ld { + args.into_iter().for_each(|a| { + self.cmd.arg(a); + }); } else { - self.cmd.arg(arg); + if !args.is_empty() { + let mut s = OsString::from("-Wl"); + for a in args { + s.push(","); + s.push(a); + } + self.cmd.arg(s); + } } self } From 32ddd0206c9bd1956f7629c8c76191369f19023f Mon Sep 17 00:00:00 2001 From: kit Date: Tue, 9 Nov 2021 10:36:47 +1100 Subject: [PATCH 5/6] Refactor linker argument generation This commit refactors linker argument generation to leverage a helper function that abstracts away details governing how these arguments are transformed and provided to the linker. This fixes the misuse of the `-exported_symbols_list` when an ld-like linker is used rather than a compiler. A compiler would expect `-Wl,-exported_symbols_list,path` but ld would expect `-exported_symbols_list` and `path` as two seperate arguments. Prior to this change, an ld-like linker was given `-exported_symbols_list,path`. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 48 +++++++------------ 1 file changed, 18 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 1e29c3085a3fd..f8f88bf607aac 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -306,8 +306,10 @@ impl<'a> GccLinker<'a> { if let Some(path) = &self.sess.opts.debugging_opts.profile_sample_use { self.linker_arg(&format!("-plugin-opt=sample-profile={}", path.display())); }; - self.linker_arg(&format!("-plugin-opt={}", opt_level)); - self.linker_arg(&format!("-plugin-opt=mcpu={}", self.target_cpu)); + self.linker_args(&[ + &format!("-plugin-opt={}", opt_level), + &format!("-plugin-opt=mcpu={}", self.target_cpu), + ]); } fn build_dylib(&mut self, out_filename: &Path) { @@ -321,10 +323,9 @@ impl<'a> GccLinker<'a> { // principled solution at some point to force the compiler to pass // the right `-Wl,-install_name` with an `@rpath` in it. if self.sess.opts.cg.rpath || self.sess.opts.debugging_opts.osx_rpath_install_name { - self.linker_arg("-install_name"); - let mut v = OsString::from("@rpath/"); - v.push(out_filename.file_name().unwrap()); - self.linker_arg(&v); + let mut rpath = OsString::from("@rpath/"); + rpath.push(out_filename.file_name().unwrap()); + self.linker_args(&[OsString::from("-install_name"), rpath]); } } else { self.cmd.arg("-shared"); @@ -398,8 +399,7 @@ impl<'a> Linker for GccLinker<'a> { self.build_dylib(out_filename); } LinkOutputKind::WasiReactorExe => { - self.linker_arg("--entry"); - self.linker_arg("_initialize"); + self.linker_args(&["--entry", "_initialize"]); } } // VxWorks compiler driver introduced `--static-crt` flag specifically for rustc, @@ -471,8 +471,7 @@ impl<'a> Linker for GccLinker<'a> { self.cmd.arg(path); } fn full_relro(&mut self) { - self.linker_arg("-zrelro"); - self.linker_arg("-znow"); + self.linker_args(&["-zrelro", "-znow"]); } fn partial_relro(&mut self) { self.linker_arg("-zrelro"); @@ -656,7 +655,6 @@ impl<'a> Linker for GccLinker<'a> { } let is_windows = self.sess.target.is_like_windows; - let mut arg = OsString::new(); let path = tmpdir.join(if is_windows { "list.def" } else { "list" }); debug!("EXPORTED SYMBOLS:"); @@ -708,27 +706,18 @@ impl<'a> Linker for GccLinker<'a> { } if self.sess.target.is_like_osx { - if !self.is_ld { - arg.push("-Wl,") - } - arg.push("-exported_symbols_list,"); + self.linker_args(&[OsString::from("-exported_symbols_list"), path.into()]); } else if self.sess.target.is_like_solaris { - if !self.is_ld { - arg.push("-Wl,") - } - arg.push("-M,"); + self.linker_args(&[OsString::from("-M"), path.into()]); } else { - if !self.is_ld { - arg.push("-Wl,") - } - // Both LD and LLD accept export list in *.def file form, there are no flags required - if !is_windows { - arg.push("--version-script=") + if is_windows { + self.linker_arg(path); + } else { + let mut arg = OsString::from("--version-script="); + arg.push(path); + self.linker_arg(arg); } } - - arg.push(&path); - self.cmd.arg(arg); } fn subsystem(&mut self, subsystem: &str) { @@ -786,8 +775,7 @@ impl<'a> Linker for GccLinker<'a> { self.linker_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_arg("-z"); - self.linker_arg("ignore"); + self.linker_args(&["-z", "ignore"]); } } } From f44fa6348f48403a79b506823286444b453267cb Mon Sep 17 00:00:00 2001 From: kit Date: Tue, 9 Nov 2021 10:44:49 +1100 Subject: [PATCH 6/6] Only use the -dynamiclib flag when the linker is not ld This is not a valid flag for ld64. When the ld64 linker is explicitly provided through `config.toml`, rustc will not successfully compile. --- compiler/rustc_codegen_ssa/src/back/linker.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index f8f88bf607aac..15d16e7d3d61a 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -315,7 +315,10 @@ impl<'a> GccLinker<'a> { fn build_dylib(&mut self, out_filename: &Path) { // On mac we need to tell the linker to let this library be rpathed if self.sess.target.is_like_osx { - self.cmd.arg("-dynamiclib"); + if !self.is_ld { + self.cmd.arg("-dynamiclib"); + } + self.linker_arg("-dylib"); // Note that the `osx_rpath_install_name` option here is a hack