From 0e6f7c6c7c8f64327150c973606c1a87d587a3cc Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Dec 2023 17:41:51 +0000 Subject: [PATCH 01/20] Add AsyncFn family of traits --- library/core/src/lib.rs | 1 + library/core/src/ops/async_function.rs | 105 ++++++++++++++++++++++ library/core/src/ops/mod.rs | 4 + tests/ui/async-await/async-fn/simple.rs | 16 ++++ tests/ui/did_you_mean/bad-assoc-ty.stderr | 9 +- 5 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 library/core/src/ops/async_function.rs create mode 100644 tests/ui/async-await/async-fn/simple.rs diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 07720f235989b..1cd0240b87cc6 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -227,6 +227,7 @@ #![feature(fundamental)] #![feature(generic_arg_infer)] #![feature(if_let_guard)] +#![feature(impl_trait_in_assoc_type)] #![feature(inline_const)] #![feature(intra_doc_pointers)] #![feature(intrinsics)] diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs new file mode 100644 index 0000000000000..0e05badd06df8 --- /dev/null +++ b/library/core/src/ops/async_function.rs @@ -0,0 +1,105 @@ +use crate::future::Future; +use crate::marker::Tuple; + +/// An async-aware version of the [`Fn`](crate::ops::Fn) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +pub trait AsyncFn: AsyncFnMut { + /// Future returned by [`AsyncFn::async_call`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallFuture<'a>: Future + where + Self: 'a; + + /// Call the [`AsyncFn`], returning a future which may borrow from the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call(&self, args: Args) -> Self::CallFuture<'_>; +} + +/// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +pub trait AsyncFnMut: AsyncFnOnce { + /// Future returned by [`AsyncFnMut::async_call_mut`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallMutFuture<'a>: Future + where + Self: 'a; + + /// Call the [`AsyncFnMut`], returning a future which may borrow from the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallMutFuture<'_>; +} + +/// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait. +/// +/// All `async fn` and functions returning futures implement this trait. +#[unstable(feature = "async_fn_traits", issue = "none")] +#[rustc_paren_sugar] +#[fundamental] +#[must_use = "async closures are lazy and do nothing unless called"] +pub trait AsyncFnOnce { + /// Future returned by [`AsyncFnOnce::async_call_once`]. + #[unstable(feature = "async_fn_traits", issue = "none")] + type CallOnceFuture: Future; + + /// Output type of the called closure's future. + #[unstable(feature = "async_fn_traits", issue = "none")] + type Output; + + /// Call the [`AsyncFnOnce`], returning a future which may move out of the called closure. + #[unstable(feature = "async_fn_traits", issue = "none")] + extern "rust-call" fn async_call_once(self, args: Args) -> Self::CallOnceFuture; +} + +mod impls { + use super::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + use crate::future::Future; + use crate::marker::Tuple; + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFn for F + where + >::Output: Future, + { + type CallFuture<'a> = impl Future where Self: 'a; + + extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> { + async { self.call(args).await } + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFnMut for F + where + >::Output: Future, + { + type CallMutFuture<'a> = impl Future where Self: 'a; + + extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> { + async { self.call_mut(args).await } + } + } + + #[unstable(feature = "async_fn_traits", issue = "none")] + impl, A: Tuple> AsyncFnOnce for F + where + >::Output: Future, + { + type CallOnceFuture = impl Future; + + type Output = <>::Output as Future>::Output; + + extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { + async { self.call_once(args).await } + } + } +} diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 35654d0b853b7..4289a86f89b06 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -139,6 +139,7 @@ #![stable(feature = "rust1", since = "1.0.0")] mod arith; +mod async_function; mod bit; mod control_flow; mod coroutine; @@ -173,6 +174,9 @@ pub use self::drop::Drop; #[stable(feature = "rust1", since = "1.0.0")] pub use self::function::{Fn, FnMut, FnOnce}; +#[unstable(feature = "async_fn_traits", issue = "none")] +pub use self::async_function::{AsyncFn, AsyncFnMut, AsyncFnOnce}; + #[stable(feature = "rust1", since = "1.0.0")] pub use self::index::{Index, IndexMut}; diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs new file mode 100644 index 0000000000000..36d1a6d71036b --- /dev/null +++ b/tests/ui/async-await/async-fn/simple.rs @@ -0,0 +1,16 @@ +// edition: 2021 +// check-pass + +#![feature(async_fn_traits)] + +use std::ops::AsyncFn; + +async fn foo() {} + +async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 { + f.async_call((1i32,)).await +} + +fn main() { + let fut = call_asyncly(|x| async move { x + 1 }); +} diff --git a/tests/ui/did_you_mean/bad-assoc-ty.stderr b/tests/ui/did_you_mean/bad-assoc-ty.stderr index 5c0c7a0b94ffe..356ddf74bb635 100644 --- a/tests/ui/did_you_mean/bad-assoc-ty.stderr +++ b/tests/ui/did_you_mean/bad-assoc-ty.stderr @@ -191,7 +191,14 @@ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:33:10 | LL | type H = Fn(u8) -> (u8)::Output; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output` + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: use fully-qualified syntax + | +LL | type H = <(dyn Fn(u8) -> u8 + 'static) as AsyncFnOnce>::Output; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +LL | type H = <(dyn Fn(u8) -> u8 + 'static) as IntoFuture>::Output; + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:39:19 From fde86e586dfc9826d0db81d1230aba77eb043bc6 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Dec 2023 17:46:34 +0000 Subject: [PATCH 02/20] We do not need impl_trait_in_assoc_ty --- library/core/src/lib.rs | 1 - library/core/src/ops/async_function.rs | 12 ++++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 1cd0240b87cc6..07720f235989b 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -227,7 +227,6 @@ #![feature(fundamental)] #![feature(generic_arg_infer)] #![feature(if_let_guard)] -#![feature(impl_trait_in_assoc_type)] #![feature(inline_const)] #![feature(intra_doc_pointers)] #![feature(intrinsics)] diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 0e05badd06df8..5e5267ed97abf 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -70,10 +70,10 @@ mod impls { where >::Output: Future, { - type CallFuture<'a> = impl Future where Self: 'a; + type CallFuture<'a> = >::Output where Self: 'a; extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> { - async { self.call(args).await } + self.call(args) } } @@ -82,10 +82,10 @@ mod impls { where >::Output: Future, { - type CallMutFuture<'a> = impl Future where Self: 'a; + type CallMutFuture<'a> = >::Output where Self: 'a; extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> { - async { self.call_mut(args).await } + self.call_mut(args) } } @@ -94,12 +94,12 @@ mod impls { where >::Output: Future, { - type CallOnceFuture = impl Future; + type CallOnceFuture = >::Output; type Output = <>::Output as Future>::Output; extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture { - async { self.call_once(args).await } + self.call_once(args) } } } From 17b433351d6c9ef4fb74dae985291b4eb073c807 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 20 Dec 2023 18:03:21 +0000 Subject: [PATCH 03/20] select AsyncFn traits during overloaded call op --- compiler/rustc_hir/src/lang_items.rs | 4 ++++ compiler/rustc_hir_typeck/src/callee.rs | 11 +++++++++++ compiler/rustc_span/src/symbol.rs | 6 ++++++ library/core/src/ops/async_function.rs | 3 +++ tests/ui/async-await/async-fn/simple.rs | 2 +- 5 files changed, 25 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 3f3b57ba94f98..783a050742df9 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -208,6 +208,10 @@ language_item_table! { FnMut, sym::fn_mut, fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); FnOnce, sym::fn_once, fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFn, sym::async_fn, async_fn_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnMut, sym::async_fn_mut, async_fn_mut_trait, Target::Trait, GenericRequirement::Exact(1); + AsyncFnOnce, sym::async_fn_once, async_fn_once_trait, Target::Trait, GenericRequirement::Exact(1); + FnOnceOutput, sym::fn_once_output, fn_once_output, Target::AssocTy, GenericRequirement::None; Iterator, sym::iterator, iterator_trait, Target::Trait, GenericRequirement::Exact(0); diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 2146effd84f06..e464dd45124d8 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -220,6 +220,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (self.tcx.lang_items().fn_trait(), Ident::with_dummy_span(sym::call), true), (self.tcx.lang_items().fn_mut_trait(), Ident::with_dummy_span(sym::call_mut), true), (self.tcx.lang_items().fn_once_trait(), Ident::with_dummy_span(sym::call_once), false), + (self.tcx.lang_items().async_fn_trait(), Ident::with_dummy_span(sym::async_call), true), + ( + self.tcx.lang_items().async_fn_mut_trait(), + Ident::with_dummy_span(sym::async_call_mut), + true, + ), + ( + self.tcx.lang_items().async_fn_once_trait(), + Ident::with_dummy_span(sym::async_call_once), + false, + ), ] { let Some(trait_def_id) = opt_trait_def_id else { continue }; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 95106cc64c129..a123a95352032 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -423,8 +423,14 @@ symbols! { assume, assume_init, async_await, + async_call, + async_call_mut, + async_call_once, async_closure, + async_fn, async_fn_in_trait, + async_fn_mut, + async_fn_once, async_fn_track_caller, async_for_loop, async_iterator, diff --git a/library/core/src/ops/async_function.rs b/library/core/src/ops/async_function.rs index 5e5267ed97abf..965873f163eff 100644 --- a/library/core/src/ops/async_function.rs +++ b/library/core/src/ops/async_function.rs @@ -8,6 +8,7 @@ use crate::marker::Tuple; #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn")] pub trait AsyncFn: AsyncFnMut { /// Future returned by [`AsyncFn::async_call`]. #[unstable(feature = "async_fn_traits", issue = "none")] @@ -27,6 +28,7 @@ pub trait AsyncFn: AsyncFnMut { #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn_mut")] pub trait AsyncFnMut: AsyncFnOnce { /// Future returned by [`AsyncFnMut::async_call_mut`]. #[unstable(feature = "async_fn_traits", issue = "none")] @@ -46,6 +48,7 @@ pub trait AsyncFnMut: AsyncFnOnce { #[rustc_paren_sugar] #[fundamental] #[must_use = "async closures are lazy and do nothing unless called"] +#[cfg_attr(not(bootstrap), lang = "async_fn_once")] pub trait AsyncFnOnce { /// Future returned by [`AsyncFnOnce::async_call_once`]. #[unstable(feature = "async_fn_traits", issue = "none")] diff --git a/tests/ui/async-await/async-fn/simple.rs b/tests/ui/async-await/async-fn/simple.rs index 36d1a6d71036b..99a5d56a3093b 100644 --- a/tests/ui/async-await/async-fn/simple.rs +++ b/tests/ui/async-await/async-fn/simple.rs @@ -8,7 +8,7 @@ use std::ops::AsyncFn; async fn foo() {} async fn call_asyncly(f: impl AsyncFn(i32) -> i32) -> i32 { - f.async_call((1i32,)).await + f(1).await } fn main() { From 46652dd254bc9c413d14cec637c7f21ac6601e05 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 17 Jan 2024 14:26:26 +0000 Subject: [PATCH 04/20] llvm: simplify data layout check Don't skip the inconsistent data layout check for custom LLVMs. With #118708, all targets will have a simple test that would trigger this check if LLVM's data layouts do change - so data layouts would be corrected during the LLVM upgrade. Therefore, with builtin targets, this check won't trigger with our LLVM because each target will have been confirmed to work. With non-builtin targets, this check is probably useful to have because you can change the data layout in your target and if its wrong then that could lead to bugs. When using a custom LLVM, the same justification makes sense for non-builtin targets as with our LLVM, the user can update their target to match their LLVM and that's probably a good thing to do. However, with a custom LLVM, the user cannot change the builtin target data layouts if they don't match - though given that the compiler's data layout is used for layout computation and a bunch of other things - you could get some bugs because of the mismatch and probably want to know about that. `CFG_LLVM_ROOT` was also always set during local development with `download-ci-llvm` so this bug would never trigger locally. Signed-off-by: David Wood --- compiler/rustc_codegen_llvm/messages.ftl | 3 ++ compiler/rustc_codegen_llvm/src/context.rs | 38 +++++-------------- compiler/rustc_codegen_llvm/src/errors.rs | 9 +++++ src/bootstrap/src/core/build_steps/compile.rs | 5 --- src/tools/tidy/src/ui_tests.rs | 7 ++-- tests/run-make/target-specs/Makefile | 2 +- tests/ui/codegen/mismatched-data-layout.json | 13 +++++++ tests/ui/codegen/mismatched-data-layouts.rs | 14 +++++++ .../ui/codegen/mismatched-data-layouts.stderr | 4 ++ 9 files changed, 57 insertions(+), 38 deletions(-) create mode 100644 tests/ui/codegen/mismatched-data-layout.json create mode 100644 tests/ui/codegen/mismatched-data-layouts.rs create mode 100644 tests/ui/codegen/mismatched-data-layouts.stderr diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index 7a86ddc7556a0..d5bc04f594da1 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -39,6 +39,9 @@ codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdy codegen_llvm_lto_proc_macro = lto cannot be used for `proc-macro` crate type without `-Zdylib-lto` +codegen_llvm_mismatch_data_layout = + data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}` + codegen_llvm_missing_features = add the missing features in a `target_feature` attribute diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 1d1b6e6148dd2..b0f0b650e77f3 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -34,6 +34,7 @@ use rustc_target::spec::{HasTargetSpec, RelocModel, Target, TlsModel}; use smallvec::SmallVec; use libc::c_uint; +use std::borrow::Borrow; use std::cell::{Cell, RefCell}; use std::ffi::CStr; use std::str; @@ -147,8 +148,7 @@ pub unsafe fn create_module<'ll>( } // Ensure the data-layout values hardcoded remain the defaults. - if sess.target.is_builtin { - // tm is disposed by its drop impl + { let tm = crate::back::write::create_informational_target_machine(tcx.sess); llvm::LLVMRustSetDataLayoutFromTargetMachine(llmod, &tm); @@ -156,33 +156,13 @@ pub unsafe fn create_module<'ll>( let llvm_data_layout = str::from_utf8(CStr::from_ptr(llvm_data_layout).to_bytes()) .expect("got a non-UTF8 data-layout from LLVM"); - // Unfortunately LLVM target specs change over time, and right now we - // don't have proper support to work with any more than one - // `data_layout` than the one that is in the rust-lang/rust repo. If - // this compiler is configured against a custom LLVM, we may have a - // differing data layout, even though we should update our own to use - // that one. - // - // As an interim hack, if CFG_LLVM_ROOT is not an empty string then we - // disable this check entirely as we may be configured with something - // that has a different target layout. - // - // Unsure if this will actually cause breakage when rustc is configured - // as such. - // - // FIXME(#34960) - let cfg_llvm_root = option_env!("CFG_LLVM_ROOT").unwrap_or(""); - let custom_llvm_used = !cfg_llvm_root.trim().is_empty(); - - if !custom_llvm_used && target_data_layout != llvm_data_layout { - bug!( - "data-layout for target `{rustc_target}`, `{rustc_layout}`, \ - differs from LLVM target's `{llvm_target}` default layout, `{llvm_layout}`", - rustc_target = sess.opts.target_triple, - rustc_layout = target_data_layout, - llvm_target = sess.target.llvm_target, - llvm_layout = llvm_data_layout - ); + if target_data_layout != llvm_data_layout { + tcx.dcx().emit_err(crate::errors::MismatchedDataLayout { + rustc_target: sess.opts.target_triple.to_string().as_str(), + rustc_layout: target_data_layout.as_str(), + llvm_target: sess.target.llvm_target.borrow(), + llvm_layout: llvm_data_layout, + }); } } diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index 697ce6022984b..d82ff6656f4d3 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -244,3 +244,12 @@ pub(crate) struct CopyBitcode { pub struct UnknownCompression { pub algorithm: &'static str, } + +#[derive(Diagnostic)] +#[diag(codegen_llvm_mismatch_data_layout)] +pub struct MismatchedDataLayout<'a> { + pub rustc_target: &'a str, + pub rustc_layout: &'a str, + pub llvm_target: &'a str, + pub llvm_layout: &'a str, +} diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 190f0fe3cddcf..663ec6fe08645 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -1103,16 +1103,11 @@ pub fn rustc_cargo_env( /// Pass down configuration from the LLVM build into the build of /// rustc_llvm and rustc_codegen_llvm. fn rustc_llvm_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelection) { - let target_config = builder.config.target_config.get(&target); - if builder.is_rust_llvm(target) { cargo.env("LLVM_RUSTLLVM", "1"); } let llvm::LlvmResult { llvm_config, .. } = builder.ensure(llvm::Llvm { target }); cargo.env("LLVM_CONFIG", &llvm_config); - if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { - cargo.env("CFG_LLVM_ROOT", s); - } // Some LLVM linker flags (-L and -l) may be needed to link `rustc_llvm`. Its build script // expects these to be passed via the `LLVM_LINKER_FLAGS` env variable, separated by diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 95cf9f8cb13ad..85553d2e3384a 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -24,9 +24,10 @@ const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ "tests/ui/asm/named-asm-labels.s", // loading an external asm file to test named labels lint - "tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs - "tests/ui/commandline-argfile-badutf8.args", // passing args via a file - "tests/ui/commandline-argfile.args", // passing args via a file + "tests/ui/codegen/mismatched-data-layout.json", // testing mismatched data layout w/ custom targets + "tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs + "tests/ui/commandline-argfile-badutf8.args", // passing args via a file + "tests/ui/commandline-argfile.args", // passing args via a file "tests/ui/crate-loading/auxiliary/libfoo.rlib", // testing loading a manually created rlib "tests/ui/include-macros/data.bin", // testing including data with the include macros "tests/ui/include-macros/file.txt", // testing including data with the include macros diff --git a/tests/run-make/target-specs/Makefile b/tests/run-make/target-specs/Makefile index 62d5365a73d03..161b66021857b 100644 --- a/tests/run-make/target-specs/Makefile +++ b/tests/run-make/target-specs/Makefile @@ -9,4 +9,4 @@ all: $(RUSTC) -Z unstable-options --target=my-awesome-platform.json --print target-spec-json > $(TMPDIR)/test-platform.json && $(RUSTC) -Z unstable-options --target=$(TMPDIR)/test-platform.json --print target-spec-json | diff -q $(TMPDIR)/test-platform.json - $(RUSTC) foo.rs --target=definitely-not-builtin-target 2>&1 | $(CGREP) 'may not set is_builtin' $(RUSTC) foo.rs --target=endianness-mismatch 2>&1 | $(CGREP) '"data-layout" claims architecture is little-endian' - $(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib + $(RUSTC) foo.rs --target=mismatching-data-layout --crate-type=lib 2>&1 | $(CGREP) 'data-layout for target' diff --git a/tests/ui/codegen/mismatched-data-layout.json b/tests/ui/codegen/mismatched-data-layout.json new file mode 100644 index 0000000000000..4cb0602dc75b5 --- /dev/null +++ b/tests/ui/codegen/mismatched-data-layout.json @@ -0,0 +1,13 @@ +{ + "llvm-target": "x86_64-unknown-none-gnu", + "data-layout": "e-m:e-i64:64-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": "64", + "target-c-int-width": "32", + "os": "unknown", + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "executables": true +} + diff --git a/tests/ui/codegen/mismatched-data-layouts.rs b/tests/ui/codegen/mismatched-data-layouts.rs new file mode 100644 index 0000000000000..047ec155fdca6 --- /dev/null +++ b/tests/ui/codegen/mismatched-data-layouts.rs @@ -0,0 +1,14 @@ +// This test checks that data layout mismatches emit an error. +// +// build-fail +// needs-llvm-components: x86 +// compile-flags: --crate-type=lib --target={{src-base}}/codegen/mismatched-data-layout.json -Z unstable-options +// error-pattern: differs from LLVM target's +// normalize-stderr-test: "`, `[A-Za-z0-9-:]*`" -> "`, `normalized data layout`" +// normalize-stderr-test: "layout, `[A-Za-z0-9-:]*`" -> "layout, `normalized data layout`" + +#![feature(lang_items, no_core, auto_traits)] +#![no_core] + +#[lang = "sized"] +trait Sized {} diff --git a/tests/ui/codegen/mismatched-data-layouts.stderr b/tests/ui/codegen/mismatched-data-layouts.stderr new file mode 100644 index 0000000000000..1fe242266dff7 --- /dev/null +++ b/tests/ui/codegen/mismatched-data-layouts.stderr @@ -0,0 +1,4 @@ +error: data-layout for target `mismatched-data-layout-7814813422914914169`, `normalized data layout`, differs from LLVM target's `x86_64-unknown-none-gnu` default layout, `normalized data layout` + +error: aborting due to 1 previous error + From 2c2f3ed2c4a99d6d2bc4c1a45890146c7b0c8561 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 Dec 2023 19:09:04 +0000 Subject: [PATCH 05/20] Provide more context on recursive `impl` evaluation overflow When an associated type `Self::Assoc` is part of a `where` clause, we end up unable to evaluate the requirement and emit a E0275. We now point at the associated type if specified in the `impl`. If so, we also suggest using that type instead of `Self::Assoc`. Otherwise, we explain that these are not allowed. ``` error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` --> $DIR/impl-wf-cycle-1.rs:15:1 | LL | / impl Grault for (T,) LL | | LL | | where LL | | Self::A: Baz, LL | | Self::B: Fiz, | |_________________^ LL | { LL | type A = (); | ------ associated type `<(T,) as Grault>::A` is specified here | note: required for `(T,)` to implement `Grault` --> $DIR/impl-wf-cycle-1.rs:15:17 | LL | impl Grault for (T,) | ^^^^^^ ^^^^ ... LL | Self::A: Baz, | --- unsatisfied trait bound introduced here = note: 1 redundant requirement hidden = note: required for `(T,)` to implement `Grault` help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound | LL - Self::A: Baz, LL + , | ``` ``` error[E0275]: overflow evaluating the requirement `::Type == ::Type` --> $DIR/impl-wf-cycle-3.rs:7:1 | LL | / impl B for T LL | | where LL | | T: A, | |_____________________^ LL | { LL | type Type = bool; | --------- associated type `::Type` is specified here | note: required for `T` to implement `B` --> $DIR/impl-wf-cycle-3.rs:7:9 | LL | impl B for T | ^ ^ LL | where LL | T: A, | ------------- unsatisfied trait bound introduced here help: replace the associated type with the type specified in this `impl` | LL | T: A, | ~~~~ ``` ``` error[E0275]: overflow evaluating the requirement `::ToMatch == ::ToMatch` --> $DIR/impl-wf-cycle-4.rs:5:1 | LL | / impl Filter for T LL | | where LL | | T: Fn(Self::ToMatch), | |_________________________^ | note: required for `T` to implement `Filter` --> $DIR/impl-wf-cycle-4.rs:5:9 | LL | impl Filter for T | ^^^^^^ ^ LL | where LL | T: Fn(Self::ToMatch), | ----------------- unsatisfied trait bound introduced here note: associated types for the current `impl` cannot be restricted in `where` clauses --> $DIR/impl-wf-cycle-4.rs:7:11 | LL | T: Fn(Self::ToMatch), | ^^^^^^^^^^^^^ ``` Fix #116925 --- .../src/traits/error_reporting/suggestions.rs | 201 ++++++++++++++---- .../associated-types/impl-wf-cycle-1.stderr | 8 + .../associated-types/impl-wf-cycle-2.stderr | 8 + tests/ui/associated-types/impl-wf-cycle-3.rs | 13 ++ .../associated-types/impl-wf-cycle-3.stderr | 27 +++ tests/ui/associated-types/impl-wf-cycle-4.rs | 15 ++ .../associated-types/impl-wf-cycle-4.stderr | 25 +++ 7 files changed, 252 insertions(+), 45 deletions(-) create mode 100644 tests/ui/associated-types/impl-wf-cycle-3.rs create mode 100644 tests/ui/associated-types/impl-wf-cycle-3.stderr create mode 100644 tests/ui/associated-types/impl-wf-cycle-4.rs create mode 100644 tests/ui/associated-types/impl-wf-cycle-4.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 0e33e9cd790d0..f96392899222c 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -7,7 +7,7 @@ use super::{ use crate::errors; use crate::infer::InferCtxt; -use crate::traits::{NormalizeExt, ObligationCtxt}; +use crate::traits::{ImplDerivedObligationCause, NormalizeExt, ObligationCtxt}; use hir::def::CtorOf; use rustc_data_structures::fx::FxHashSet; @@ -2973,7 +2973,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ObjectTypeBound(..) => {} ObligationCauseCode::RustCall => { if let Some(pred) = predicate.to_opt_poly_trait_pred() - && Some(pred.def_id()) == self.tcx.lang_items().sized_trait() + && Some(pred.def_id()) == tcx.lang_items().sized_trait() { err.note("argument required to be sized due to `extern \"rust-call\"` ABI"); } @@ -3022,15 +3022,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { let def_id = trait_pred.def_id(); let visible_item = if let Some(local) = def_id.as_local() { // Check for local traits being reachable. - let vis = &self.tcx.resolutions(()).effective_visibilities; + let vis = &tcx.resolutions(()).effective_visibilities; // Account for non-`pub` traits in the root of the local crate. - let is_locally_reachable = self.tcx.parent(def_id).is_crate_root(); + let is_locally_reachable = tcx.parent(def_id).is_crate_root(); vis.is_reachable(local) || is_locally_reachable } else { // Check for foreign traits being reachable. - self.tcx.visible_parent_map(()).get(&def_id).is_some() + tcx.visible_parent_map(()).get(&def_id).is_some() }; - if Some(def_id) == self.tcx.lang_items().sized_trait() + if Some(def_id) == tcx.lang_items().sized_trait() && let Some(hir::Node::TraitItem(hir::TraitItem { ident, kind: hir::TraitItemKind::Type(bounds, None), @@ -3039,7 +3039,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Do not suggest relaxing if there is an explicit `Sized` obligation. && !bounds.iter() .filter_map(|bound| bound.trait_ref()) - .any(|tr| tr.trait_def_id() == self.tcx.lang_items().sized_trait()) + .any(|tr| tr.trait_def_id() == tcx.lang_items().sized_trait()) { let (span, separator) = if let [.., last] = bounds { (last.span().shrink_to_hi(), " +") @@ -3102,10 +3102,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } ObligationCauseCode::Coercion { source, target } => { let mut file = None; - let source = - self.tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file); - let target = - self.tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file); + let source = tcx.short_ty_string(self.resolve_vars_if_possible(source), &mut file); + let target = tcx.short_ty_string(self.resolve_vars_if_possible(target), &mut file); err.note(with_forced_trimmed_paths!(format!( "required for the cast from `{source}` to `{target}`", ))); @@ -3154,7 +3152,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } - if self.tcx.sess.is_nightly_build() + if tcx.sess.is_nightly_build() && matches!(is_constable, IsConstable::Fn | IsConstable::Ctor) { err.help( @@ -3164,8 +3162,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } ObligationCauseCode::VariableType(hir_id) => { - let parent_node = self.tcx.hir().parent_id(hir_id); - match self.tcx.opt_hir_node(parent_node) { + let parent_node = tcx.hir().parent_id(hir_id); + match tcx.opt_hir_node(parent_node) { Some(Node::Local(hir::Local { ty: Some(ty), .. })) => { err.span_suggestion_verbose( ty.span.shrink_to_lo(), @@ -3203,7 +3201,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note("all local variables must have a statically known size"); } } - if !self.tcx.features().unsized_locals { + if !tcx.features().unsized_locals { err.help("unsized locals are gated as an unstable feature"); } } @@ -3285,7 +3283,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note("all function arguments must have a statically known size"); } if tcx.sess.opts.unstable_features.is_nightly_build() - && !self.tcx.features().unsized_fn_params + && !tcx.features().unsized_fn_params { err.help("unsized fn params are gated as an unstable feature"); } @@ -3354,7 +3352,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "all values captured by value by a closure must have a statically known size", ); let hir::ExprKind::Closure(closure) = - self.tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind + tcx.hir_node_by_def_id(closure_def_id).expect_expr().kind else { bug!("expected closure in SizedClosureCapture obligation"); }; @@ -3365,7 +3363,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } ObligationCauseCode::SizedCoroutineInterior(coroutine_def_id) => { - let what = match self.tcx.coroutine_kind(coroutine_def_id) { + let what = match tcx.coroutine_kind(coroutine_def_id) { None | Some(hir::CoroutineKind::Coroutine(_)) | Some(hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Gen, _)) => { @@ -3416,10 +3414,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { 'print: { if !is_upvar_tys_infer_tuple { let mut file = None; - let ty_str = self.tcx.short_ty_string(ty, &mut file); + let ty_str = tcx.short_ty_string(ty, &mut file); let msg = format!("required because it appears within the type `{ty_str}`"); match ty.kind() { - ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) { + ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { Some(ident) => err.span_note(ident.span, msg), None => err.note(msg), }, @@ -3442,7 +3440,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { { break 'print; } - err.span_note(self.tcx.def_span(def_id), msg) + err.span_note(tcx.def_span(def_id), msg) } ty::CoroutineWitness(def_id, args) => { use std::fmt::Write; @@ -3459,7 +3457,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.note(msg.trim_end_matches(", ").to_string()) } ty::Coroutine(def_id, _) => { - let sp = self.tcx.def_span(def_id); + let sp = tcx.def_span(def_id); // Special-case this to say "async block" instead of `[static coroutine]`. let kind = tcx.coroutine_kind(def_id).unwrap(); @@ -3471,7 +3469,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ) } ty::Closure(def_id, _) => err.span_note( - self.tcx.def_span(def_id), + tcx.def_span(def_id), "required because it's used within this closure", ), ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"), @@ -3515,14 +3513,12 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); let mut file = None; - let self_ty = - self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); - let msg = format!( - "required for `{self_ty}` to implement `{}`", - parent_trait_pred.print_modifiers_and_trait_path() - ); + let self_ty_str = + tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); + let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); + let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`"); let mut is_auto_trait = false; - match self.tcx.hir().get_if_local(data.impl_or_alias_def_id) { + match tcx.hir().get_if_local(data.impl_or_alias_def_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Trait(is_auto, ..), ident, @@ -3534,7 +3530,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_note(ident.span, msg); } Some(Node::Item(hir::Item { - kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }), + kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, generics, .. }), .. })) => { let mut spans = Vec::with_capacity(2); @@ -3561,6 +3557,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); } err.span_note(spans, msg); + point_at_assoc_type_restriction( + tcx, + err, + &self_ty_str, + &trait_name, + predicate, + &generics, + &data, + ); } _ => { err.note(msg); @@ -3614,9 +3619,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { pluralize!(count) )); let mut file = None; - let self_ty = self - .tcx - .short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); + let self_ty = + tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), &mut file); err.note(format!( "required for `{self_ty}` to implement `{}`", parent_trait_pred.print_modifiers_and_trait_path() @@ -3674,10 +3678,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { multispan.push_span_label(span, "required by this bound"); err.span_note( multispan, - format!( - "required by a bound on the type alias `{}`", - self.infcx.tcx.item_name(def_id) - ), + format!("required by a bound on the type alias `{}`", tcx.item_name(def_id)), ); } ObligationCauseCode::FunctionArgumentObligation { @@ -3708,25 +3709,23 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }); } ObligationCauseCode::CompareImplItemObligation { trait_item_def_id, kind, .. } => { - let item_name = self.tcx.item_name(trait_item_def_id); + let item_name = tcx.item_name(trait_item_def_id); let msg = format!( "the requirement `{predicate}` appears on the `impl`'s {kind} \ `{item_name}` but not on the corresponding trait's {kind}", ); - let sp = self - .tcx + let sp = tcx .opt_item_ident(trait_item_def_id) .map(|i| i.span) - .unwrap_or_else(|| self.tcx.def_span(trait_item_def_id)); + .unwrap_or_else(|| tcx.def_span(trait_item_def_id)); let mut assoc_span: MultiSpan = sp.into(); assoc_span.push_span_label( sp, format!("this trait's {kind} doesn't have the requirement `{predicate}`"), ); - if let Some(ident) = self - .tcx + if let Some(ident) = tcx .opt_associated_item(trait_item_def_id) - .and_then(|i| self.tcx.opt_item_ident(i.container_id(self.tcx))) + .and_then(|i| tcx.opt_item_ident(i.container_id(tcx))) { assoc_span.push_span_label(ident.span, "in this trait"); } @@ -4816,6 +4815,29 @@ fn hint_missing_borrow<'tcx>( } } +/// Collect all the paths that reference `Self`. +/// Used to suggest replacing associated types with an explicit type in `where` clauses. +#[derive(Debug)] +pub struct SelfVisitor<'v> { + pub paths: Vec<&'v hir::Ty<'v>>, + pub name: Option, +} + +impl<'v> Visitor<'v> for SelfVisitor<'v> { + fn visit_ty(&mut self, ty: &'v hir::Ty<'v>) { + if let hir::TyKind::Path(path) = ty.kind + && let hir::QPath::TypeRelative(inner_ty, segment) = path + && (Some(segment.ident.name) == self.name || self.name.is_none()) + && let hir::TyKind::Path(inner_path) = inner_ty.kind + && let hir::QPath::Resolved(None, inner_path) = inner_path + && let Res::SelfTyAlias { .. } = inner_path.res + { + self.paths.push(ty); + } + hir::intravisit::walk_ty(self, ty); + } +} + /// Collect all the returned expressions within the input expression. /// Used to point at the return spans when we want to suggest some change to them. #[derive(Default)] @@ -5060,6 +5082,95 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>( Some(sugg) } +/// On `impl` evaluation cycles, look for `Self::AssocTy` restrictions in `where` clauses, explain +/// they are not allowed and if possible suggest alternatives. +fn point_at_assoc_type_restriction( + tcx: TyCtxt<'_>, + err: &mut Diagnostic, + self_ty_str: &str, + trait_name: &str, + predicate: ty::Predicate<'_>, + generics: &hir::Generics<'_>, + data: &ImplDerivedObligationCause<'_>, +) { + let ty::PredicateKind::Clause(clause) = predicate.kind().skip_binder() else { + return; + }; + let ty::ClauseKind::Projection(proj) = clause else { + return; + }; + let name = tcx.item_name(proj.projection_ty.def_id); + for pred in generics.predicates { + let hir::WherePredicate::BoundPredicate(pred) = pred else { + continue; + }; + for bound in pred.bounds { + let Some(trait_ref) = bound.trait_ref() else { + continue; + }; + if bound.span() != data.span { + continue; + } + if let hir::TyKind::Path(path) = pred.bounded_ty.kind + && let hir::QPath::TypeRelative(ty, segment) = path + && segment.ident.name == name + && let hir::TyKind::Path(inner_path) = ty.kind + && let hir::QPath::Resolved(None, inner_path) = inner_path + && let Res::SelfTyAlias { .. } = inner_path.res + { + err.span_suggestion_verbose( + pred.span, // FIXME: include the trailing comma. + "associated type for the current `impl` cannot be restricted in `where` \ + clauses, remove this bound", + "", + Applicability::MaybeIncorrect, + ); + } + if let Some(new) = + tcx.associated_items(data.impl_or_alias_def_id).find_by_name_and_kind( + tcx, + Ident::with_dummy_span(name), + ty::AssocKind::Type, + data.impl_or_alias_def_id, + ) + { + // The associated type is specified in the `impl` we're + // looking at. Point at it. + let span = tcx.def_span(new.def_id); + err.span_label( + span, + format!( + "associated type `<{self_ty_str} as {trait_name}>::{name}` is specified \ + here", + ), + ); + // Search for the associated type `Self::{name}`, get + // its type and suggest replacing the bound with it. + let mut visitor = SelfVisitor { paths: vec![], name: Some(name) }; + visitor.visit_trait_ref(trait_ref); + for path in visitor.paths { + err.span_suggestion_verbose( + path.span, + "replace the associated type with the type specified in this `impl`", + format!("{}", tcx.type_of(new.def_id).skip_binder(),), + Applicability::MachineApplicable, + ); + } + } else { + let mut visitor = SelfVisitor { paths: vec![], name: None }; + visitor.visit_trait_ref(trait_ref); + let span: MultiSpan = + visitor.paths.iter().map(|p| p.span).collect::>().into(); + err.span_note( + span, + "associated types for the current `impl` cannot be restricted in `where` \ + clauses", + ); + } + } + } +} + fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec) { let mut refs = vec![]; diff --git a/tests/ui/associated-types/impl-wf-cycle-1.stderr b/tests/ui/associated-types/impl-wf-cycle-1.stderr index 5fa36733f6677..b4fc73fc8cfd9 100644 --- a/tests/ui/associated-types/impl-wf-cycle-1.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-1.stderr @@ -7,6 +7,9 @@ LL | | where LL | | Self::A: Baz, LL | | Self::B: Fiz, | |_________________^ +LL | { +LL | type A = (); + | ------ associated type `<(T,) as Grault>::A` is specified here | note: required for `(T,)` to implement `Grault` --> $DIR/impl-wf-cycle-1.rs:15:17 @@ -18,6 +21,11 @@ LL | Self::A: Baz, | --- unsatisfied trait bound introduced here = note: 1 redundant requirement hidden = note: required for `(T,)` to implement `Grault` +help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound + | +LL - Self::A: Baz, +LL + , + | error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/impl-wf-cycle-2.stderr b/tests/ui/associated-types/impl-wf-cycle-2.stderr index 17a96bbd93430..b5ece55c1c9ad 100644 --- a/tests/ui/associated-types/impl-wf-cycle-2.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-2.stderr @@ -6,6 +6,9 @@ LL | | LL | | where LL | | Self::A: Copy, | |__________________^ +LL | { +LL | type A = (); + | ------ associated type `<(T,) as Grault>::A` is specified here | note: required for `(T,)` to implement `Grault` --> $DIR/impl-wf-cycle-2.rs:7:17 @@ -15,6 +18,11 @@ LL | impl Grault for (T,) ... LL | Self::A: Copy, | ---- unsatisfied trait bound introduced here +help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound + | +LL - Self::A: Copy, +LL + , + | error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/impl-wf-cycle-3.rs b/tests/ui/associated-types/impl-wf-cycle-3.rs new file mode 100644 index 0000000000000..044033c5e8ab1 --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-3.rs @@ -0,0 +1,13 @@ +trait A {} + +trait B { + type Type; +} + +impl B for T //~ ERROR overflow evaluating the requirement +where + T: A, +{ + type Type = bool; +} +fn main() {} diff --git a/tests/ui/associated-types/impl-wf-cycle-3.stderr b/tests/ui/associated-types/impl-wf-cycle-3.stderr new file mode 100644 index 0000000000000..d3ca06f890b34 --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-3.stderr @@ -0,0 +1,27 @@ +error[E0275]: overflow evaluating the requirement `::Type == ::Type` + --> $DIR/impl-wf-cycle-3.rs:7:1 + | +LL | / impl B for T +LL | | where +LL | | T: A, + | |_____________________^ +LL | { +LL | type Type = bool; + | --------- associated type `::Type` is specified here + | +note: required for `T` to implement `B` + --> $DIR/impl-wf-cycle-3.rs:7:9 + | +LL | impl B for T + | ^ ^ +LL | where +LL | T: A, + | ------------- unsatisfied trait bound introduced here +help: replace the associated type with the type specified in this `impl` + | +LL | T: A, + | ~~~~ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/associated-types/impl-wf-cycle-4.rs b/tests/ui/associated-types/impl-wf-cycle-4.rs new file mode 100644 index 0000000000000..bfa8adc71a11d --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-4.rs @@ -0,0 +1,15 @@ +trait Filter { + type ToMatch; +} + +impl Filter for T //~ ERROR overflow evaluating the requirement +where + T: Fn(Self::ToMatch), +{ +} + +struct JustFilter { + filter: F, +} + +fn main() {} diff --git a/tests/ui/associated-types/impl-wf-cycle-4.stderr b/tests/ui/associated-types/impl-wf-cycle-4.stderr new file mode 100644 index 0000000000000..cdbac267d34dc --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-4.stderr @@ -0,0 +1,25 @@ +error[E0275]: overflow evaluating the requirement `::ToMatch == ::ToMatch` + --> $DIR/impl-wf-cycle-4.rs:5:1 + | +LL | / impl Filter for T +LL | | where +LL | | T: Fn(Self::ToMatch), + | |_________________________^ + | +note: required for `T` to implement `Filter` + --> $DIR/impl-wf-cycle-4.rs:5:9 + | +LL | impl Filter for T + | ^^^^^^ ^ +LL | where +LL | T: Fn(Self::ToMatch), + | ----------------- unsatisfied trait bound introduced here +note: associated types for the current `impl` cannot be restricted in `where` clauses + --> $DIR/impl-wf-cycle-4.rs:7:11 + | +LL | T: Fn(Self::ToMatch), + | ^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. From c85bb274f6376c0e8b1289d6cb8f187b011b8fd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 28 Dec 2023 22:26:37 +0000 Subject: [PATCH 06/20] Account for trailing comma in removal suggestion --- .../src/traits/error_reporting/suggestions.rs | 29 +++++++++++++++-- .../associated-types/impl-wf-cycle-1.stderr | 1 - .../associated-types/impl-wf-cycle-2.stderr | 2 +- .../ui/associated-types/impl-wf-cycle-5.fixed | 31 ++++++++++++++++++ tests/ui/associated-types/impl-wf-cycle-5.rs | 32 +++++++++++++++++++ .../associated-types/impl-wf-cycle-5.stderr | 31 ++++++++++++++++++ .../ui/associated-types/impl-wf-cycle-6.fixed | 31 ++++++++++++++++++ tests/ui/associated-types/impl-wf-cycle-6.rs | 31 ++++++++++++++++++ .../associated-types/impl-wf-cycle-6.stderr | 29 +++++++++++++++++ 9 files changed, 212 insertions(+), 5 deletions(-) create mode 100644 tests/ui/associated-types/impl-wf-cycle-5.fixed create mode 100644 tests/ui/associated-types/impl-wf-cycle-5.rs create mode 100644 tests/ui/associated-types/impl-wf-cycle-5.stderr create mode 100644 tests/ui/associated-types/impl-wf-cycle-6.fixed create mode 100644 tests/ui/associated-types/impl-wf-cycle-6.rs create mode 100644 tests/ui/associated-types/impl-wf-cycle-6.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 f96392899222c..acfe886db9c4a 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -5100,11 +5100,14 @@ fn point_at_assoc_type_restriction( return; }; let name = tcx.item_name(proj.projection_ty.def_id); - for pred in generics.predicates { + let mut predicates = generics.predicates.iter().peekable(); + let mut prev: Option<&hir::WhereBoundPredicate<'_>> = None; + while let Some(pred) = predicates.next() { let hir::WherePredicate::BoundPredicate(pred) = pred else { continue; }; - for bound in pred.bounds { + let mut bounds = pred.bounds.iter().peekable(); + while let Some(bound) = bounds.next() { let Some(trait_ref) = bound.trait_ref() else { continue; }; @@ -5118,8 +5121,27 @@ fn point_at_assoc_type_restriction( && let hir::QPath::Resolved(None, inner_path) = inner_path && let Res::SelfTyAlias { .. } = inner_path.res { + // The following block is to determine the right span to delete for this bound + // that will leave valid code after the suggestion is applied. + let span = if let Some(hir::WherePredicate::BoundPredicate(next)) = + predicates.peek() + && pred.origin == next.origin + { + // There's another bound, include the comma for the current one. + pred.span.until(next.span) + } else if let Some(prev) = prev + && pred.origin == prev.origin + { + // Last bound, try to remove the previous comma. + prev.span.shrink_to_hi().to(pred.span) + } else if pred.origin == hir::PredicateOrigin::WhereClause { + pred.span.with_hi(generics.where_clause_span.hi()) + } else { + pred.span + }; + err.span_suggestion_verbose( - pred.span, // FIXME: include the trailing comma. + span, "associated type for the current `impl` cannot be restricted in `where` \ clauses, remove this bound", "", @@ -5168,6 +5190,7 @@ fn point_at_assoc_type_restriction( ); } } + prev = Some(pred); } } diff --git a/tests/ui/associated-types/impl-wf-cycle-1.stderr b/tests/ui/associated-types/impl-wf-cycle-1.stderr index b4fc73fc8cfd9..d642f9f0e36a7 100644 --- a/tests/ui/associated-types/impl-wf-cycle-1.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-1.stderr @@ -24,7 +24,6 @@ LL | Self::A: Baz, help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound | LL - Self::A: Baz, -LL + , | error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/impl-wf-cycle-2.stderr b/tests/ui/associated-types/impl-wf-cycle-2.stderr index b5ece55c1c9ad..15d3f7579ea5a 100644 --- a/tests/ui/associated-types/impl-wf-cycle-2.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-2.stderr @@ -21,7 +21,7 @@ LL | Self::A: Copy, help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound | LL - Self::A: Copy, -LL + , +LL + | error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/impl-wf-cycle-5.fixed b/tests/ui/associated-types/impl-wf-cycle-5.fixed new file mode 100644 index 0000000000000..bff6ca90975d2 --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-5.fixed @@ -0,0 +1,31 @@ +// run-rustfix + +trait Baz {} +impl Baz for () {} +impl Baz for (T,) {} + +trait Fiz {} +impl Fiz for bool {} + +trait Grault { + type A; + type B; +} + +impl Grault for () { + type A = (); + type B = bool; +} + +impl Grault for (T,) +//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +where + T: Grault, +{ + type A = (); + type B = bool; +} + +fn main() { + let _: <((),) as Grault>::A = (); +} diff --git a/tests/ui/associated-types/impl-wf-cycle-5.rs b/tests/ui/associated-types/impl-wf-cycle-5.rs new file mode 100644 index 0000000000000..a822e1fb0081b --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-5.rs @@ -0,0 +1,32 @@ +// run-rustfix + +trait Baz {} +impl Baz for () {} +impl Baz for (T,) {} + +trait Fiz {} +impl Fiz for bool {} + +trait Grault { + type A; + type B; +} + +impl Grault for () { + type A = (); + type B = bool; +} + +impl Grault for (T,) +//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +where + T: Grault, + Self::A: Baz, +{ + type A = (); + type B = bool; +} + +fn main() { + let _: <((),) as Grault>::A = (); +} diff --git a/tests/ui/associated-types/impl-wf-cycle-5.stderr b/tests/ui/associated-types/impl-wf-cycle-5.stderr new file mode 100644 index 0000000000000..284a50bb9a3be --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-5.stderr @@ -0,0 +1,31 @@ +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-5.rs:20:1 + | +LL | / impl Grault for (T,) +LL | | +LL | | where +LL | | T: Grault, +LL | | Self::A: Baz, + | |_________________^ +LL | { +LL | type A = (); + | ------ associated type `<(T,) as Grault>::A` is specified here + | +note: required for `(T,)` to implement `Grault` + --> $DIR/impl-wf-cycle-5.rs:20:9 + | +LL | impl Grault for (T,) + | ^^^^^^ ^^^^ +... +LL | Self::A: Baz, + | --- unsatisfied trait bound introduced here +help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound + | +LL - T: Grault, +LL - Self::A: Baz, +LL + T: Grault, + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/associated-types/impl-wf-cycle-6.fixed b/tests/ui/associated-types/impl-wf-cycle-6.fixed new file mode 100644 index 0000000000000..f98ae8523efcc --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-6.fixed @@ -0,0 +1,31 @@ +// run-rustfix + +trait Baz {} +impl Baz for () {} +impl Baz for (T,) {} + +trait Fiz {} +impl Fiz for bool {} + +trait Grault { + type A; + type B; +} + +impl Grault for () { + type A = (); + type B = bool; +} + +impl Grault for (T,) +//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +where + +{ + type A = (); + type B = bool; +} + +fn main() { + let _: <((),) as Grault>::A = (); +} diff --git a/tests/ui/associated-types/impl-wf-cycle-6.rs b/tests/ui/associated-types/impl-wf-cycle-6.rs new file mode 100644 index 0000000000000..20d635cac5d6f --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-6.rs @@ -0,0 +1,31 @@ +// run-rustfix + +trait Baz {} +impl Baz for () {} +impl Baz for (T,) {} + +trait Fiz {} +impl Fiz for bool {} + +trait Grault { + type A; + type B; +} + +impl Grault for () { + type A = (); + type B = bool; +} + +impl Grault for (T,) +//~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` +where + Self::A: Baz, +{ + type A = (); + type B = bool; +} + +fn main() { + let _: <((),) as Grault>::A = (); +} diff --git a/tests/ui/associated-types/impl-wf-cycle-6.stderr b/tests/ui/associated-types/impl-wf-cycle-6.stderr new file mode 100644 index 0000000000000..074671585ffec --- /dev/null +++ b/tests/ui/associated-types/impl-wf-cycle-6.stderr @@ -0,0 +1,29 @@ +error[E0275]: overflow evaluating the requirement `<(T,) as Grault>::A == _` + --> $DIR/impl-wf-cycle-6.rs:20:1 + | +LL | / impl Grault for (T,) +LL | | +LL | | where +LL | | Self::A: Baz, + | |_________________^ +LL | { +LL | type A = (); + | ------ associated type `<(T,) as Grault>::A` is specified here + | +note: required for `(T,)` to implement `Grault` + --> $DIR/impl-wf-cycle-6.rs:20:17 + | +LL | impl Grault for (T,) + | ^^^^^^ ^^^^ +... +LL | Self::A: Baz, + | --- unsatisfied trait bound introduced here +help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound + | +LL - Self::A: Baz, +LL + + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0275`. From 56bc5525b301bcbde05f464493cdf368e9997104 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sun, 21 Jan 2024 17:16:26 +0000 Subject: [PATCH 07/20] Bump `object` version --- Cargo.lock | 34 +++++++--------------------------- src/tools/tidy/src/deps.rs | 2 -- 2 files changed, 7 insertions(+), 29 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ef5811c6901d4..2f759bf85231e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -373,9 +373,9 @@ dependencies = [ [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -2588,9 +2588,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.1" +version = "0.32.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" dependencies = [ "compiler_builtins", "crc32fast", @@ -4789,12 +4789,12 @@ checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" [[package]] name = "ruzstd" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3ffab8f9715a0d455df4bbb9d21e91135aab3cd3ca187af0cd0c3c3f868fdc" +checksum = "58c4eb8a81997cf040a091d1f7e1938aeab6749d3a0dfa73af43cdc32393483d" dependencies = [ "byteorder", - "thiserror-core", + "derive_more", "twox-hash", ] @@ -5357,26 +5357,6 @@ dependencies = [ "thiserror-impl", ] -[[package]] -name = "thiserror-core" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d97345f6437bb2004cd58819d8a9ef8e36cdd7661c2abc4bbde0a7c40d9f497" -dependencies = [ - "thiserror-core-impl", -] - -[[package]] -name = "thiserror-core-impl" -version = "1.0.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10ac1c5050e43014d16b2f94d0d2ce79e65ffdd8b38d8048f9c8f6a8a6da62ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "thiserror-impl" version = "1.0.47" diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index b03811e5efda5..b06c072a2b0fd 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -340,8 +340,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "termize", "thin-vec", "thiserror", - "thiserror-core", - "thiserror-core-impl", "thiserror-impl", "thorin-dwp", "thread_local", From b50b333a0f17fd674ae487f7bd2baf0395b2dd15 Mon Sep 17 00:00:00 2001 From: clubby789 Date: Sun, 21 Jan 2024 17:17:34 +0000 Subject: [PATCH 08/20] Bump `uniq-langid` version --- Cargo.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 2f759bf85231e..a8543eceb22d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5729,9 +5729,9 @@ dependencies = [ [[package]] name = "unic-langid" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "398f9ad7239db44fd0f80fe068d12ff22d78354080332a5077dc6f52f14dcf2f" +checksum = "238722e6d794ed130f91f4ea33e01fcff4f188d92337a21297892521c72df516" dependencies = [ "unic-langid-impl", "unic-langid-macros", @@ -5739,18 +5739,18 @@ dependencies = [ [[package]] name = "unic-langid-impl" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35bfd2f2b8796545b55d7d3fd3e89a0613f68a0d1c8bc28cb7ff96b411a35ff" +checksum = "4bd55a2063fdea4ef1f8633243a7b0524cbeef1905ae04c31a1c9b9775c55bc6" dependencies = [ "tinystr", ] [[package]] name = "unic-langid-macros" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055e618bf694161ffff0466d95cef3e1a5edc59f6ba1888e97801f2b4ebdc4fe" +checksum = "5c854cefb82ff2816410ce606acbad1b3af065140907b29be9229040752b83ec" dependencies = [ "proc-macro-hack", "tinystr", @@ -5760,13 +5760,13 @@ dependencies = [ [[package]] name = "unic-langid-macros-impl" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f5cdec05b907f4e2f6843f4354f4ce6a5bebe1a56df320a49134944477ce4d8" +checksum = "fea2a4c80deb4fb3ca51f66b5e2dd91e3642bbce52234bcf22e41668281208e4" dependencies = [ "proc-macro-hack", "quote", - "syn 1.0.109", + "syn 2.0.32", "unic-langid-impl", ] From 29bdf9ea512e8bb74455410416473644b708f45d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Thu, 4 Jan 2024 00:39:56 +0000 Subject: [PATCH 09/20] Account for single `where` bound being removed --- .../src/traits/error_reporting/suggestions.rs | 22 ++++++++++++++++--- .../associated-types/impl-wf-cycle-2.stderr | 2 +- .../ui/associated-types/impl-wf-cycle-6.fixed | 3 +-- .../associated-types/impl-wf-cycle-6.stderr | 2 +- 4 files changed, 22 insertions(+), 7 deletions(-) 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 acfe886db9c4a..959aa1359ca03 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -5123,8 +5123,24 @@ fn point_at_assoc_type_restriction( { // The following block is to determine the right span to delete for this bound // that will leave valid code after the suggestion is applied. - let span = if let Some(hir::WherePredicate::BoundPredicate(next)) = - predicates.peek() + let span = if pred.origin == hir::PredicateOrigin::WhereClause + && generics + .predicates + .iter() + .filter(|p| { + matches!( + p, + hir::WherePredicate::BoundPredicate(p) + if hir::PredicateOrigin::WhereClause == p.origin + ) + }) + .count() + == 1 + { + // There's only one `where` bound, that needs to be removed. Remove the whole + // `where` clause. + generics.where_clause_span + } else if let Some(hir::WherePredicate::BoundPredicate(next)) = predicates.peek() && pred.origin == next.origin { // There's another bound, include the comma for the current one. @@ -5174,7 +5190,7 @@ fn point_at_assoc_type_restriction( err.span_suggestion_verbose( path.span, "replace the associated type with the type specified in this `impl`", - format!("{}", tcx.type_of(new.def_id).skip_binder(),), + tcx.type_of(new.def_id).skip_binder().to_string(), Applicability::MachineApplicable, ); } diff --git a/tests/ui/associated-types/impl-wf-cycle-2.stderr b/tests/ui/associated-types/impl-wf-cycle-2.stderr index 15d3f7579ea5a..9454d1d669792 100644 --- a/tests/ui/associated-types/impl-wf-cycle-2.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-2.stderr @@ -20,8 +20,8 @@ LL | Self::A: Copy, | ---- unsatisfied trait bound introduced here help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound | +LL - where LL - Self::A: Copy, -LL + | error: aborting due to 1 previous error diff --git a/tests/ui/associated-types/impl-wf-cycle-6.fixed b/tests/ui/associated-types/impl-wf-cycle-6.fixed index f98ae8523efcc..73ed64f7ce381 100644 --- a/tests/ui/associated-types/impl-wf-cycle-6.fixed +++ b/tests/ui/associated-types/impl-wf-cycle-6.fixed @@ -19,8 +19,7 @@ impl Grault for () { impl Grault for (T,) //~^ ERROR overflow evaluating the requirement `<(T,) as Grault>::A == _` -where - + { type A = (); type B = bool; diff --git a/tests/ui/associated-types/impl-wf-cycle-6.stderr b/tests/ui/associated-types/impl-wf-cycle-6.stderr index 074671585ffec..c9b5d8060be68 100644 --- a/tests/ui/associated-types/impl-wf-cycle-6.stderr +++ b/tests/ui/associated-types/impl-wf-cycle-6.stderr @@ -20,8 +20,8 @@ LL | Self::A: Baz, | --- unsatisfied trait bound introduced here help: associated type for the current `impl` cannot be restricted in `where` clauses, remove this bound | +LL - where LL - Self::A: Baz, -LL + | error: aborting due to 1 previous error From 849d884141530c1e5b04a7cd66a0332fe9dd1d7a Mon Sep 17 00:00:00 2001 From: David Koloski Date: Tue, 23 Jan 2024 19:10:17 +0000 Subject: [PATCH 10/20] Remove --fatal-warnings on wasm targets These were added with good intentions, but a recent change in LLVM 18 emits a warning while examining .rmeta sections in .rlib files. Since this flag is a nice-to-have and users can update their LLVM linker independently of rustc's LLVM version, we can just omit the flag. --- compiler/rustc_target/src/spec/base/wasm.rs | 3 --- .../src/spec/targets/wasm32_unknown_emscripten.rs | 5 +---- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/wasm.rs b/compiler/rustc_target/src/spec/base/wasm.rs index 87ade9e58cf45..4b4d2aca26e4a 100644 --- a/compiler/rustc_target/src/spec/base/wasm.rs +++ b/compiler/rustc_target/src/spec/base/wasm.rs @@ -38,9 +38,6 @@ pub fn options() -> TargetOptions { // supposed to be imported and have all other symbols generate errors if // they remain undefined. concat!($prefix, "--allow-undefined"), - // Rust code should never have warnings, and warnings are often - // indicative of bugs, let's prevent them. - concat!($prefix, "--fatal-warnings"), // LLD only implements C++-like demangling, which doesn't match our own // mangling scheme. Tell LLD to not demangle anything and leave it up to // us to demangle these symbols later. Currently rustc does not perform diff --git a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs index 394f02ecac495..e9e874297d39b 100644 --- a/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/targets/wasm32_unknown_emscripten.rs @@ -5,10 +5,7 @@ use crate::spec::{ pub fn target() -> Target { // Reset flags for non-Em flavors back to empty to satisfy sanity checking tests. let pre_link_args = LinkArgs::new(); - let post_link_args = TargetOptions::link_args( - LinkerFlavor::EmCc, - &["-sABORTING_MALLOC=0", "-Wl,--fatal-warnings"], - ); + let post_link_args = TargetOptions::link_args(LinkerFlavor::EmCc, &["-sABORTING_MALLOC=0"]); let opts = TargetOptions { os: "emscripten".into(), From 50501c6fbaea5db4d9fed7e2df83b25c264f57a9 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 17 Jan 2024 23:14:14 +0300 Subject: [PATCH 11/20] linker: Refactor APIs for linking dynamic libraries Rename `link_(dylib,framework)`, remove `link_rust_dylib`. --- compiler/rustc_codegen_ssa/src/back/link.rs | 17 ++- compiler/rustc_codegen_ssa/src/back/linker.rs | 109 ++++-------------- 2 files changed, 33 insertions(+), 93 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 959653c932653..411f727a9f87b 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1265,7 +1265,7 @@ fn link_sanitizer_runtime( 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.link_dylib(&filename, false, true); + 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. @@ -2526,7 +2526,7 @@ fn add_native_libs_from_crate( } NativeLibKind::Dylib { as_needed } => { if link_dynamic { - cmd.link_dylib(name, verbatim, as_needed.unwrap_or(true)) + cmd.link_dylib_by_name(name, verbatim, as_needed.unwrap_or(true)) } } NativeLibKind::Unspecified => { @@ -2538,13 +2538,13 @@ fn add_native_libs_from_crate( } } else { if link_dynamic { - cmd.link_dylib(name, verbatim, true); + cmd.link_dylib_by_name(name, verbatim, true); } } } NativeLibKind::Framework { as_needed } => { if link_dynamic { - cmd.link_framework(name, as_needed.unwrap_or(true)) + cmd.link_framework_by_name(name, verbatim, as_needed.unwrap_or(true)) } } NativeLibKind::RawDylib => { @@ -2859,13 +2859,20 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { // Just need to tell the linker about where the library lives and // what its name is let parent = cratepath.parent(); + // When producing a dll, the MSVC linker may not actually emit a + // `foo.lib` file if the dll doesn't actually export any symbols, so we + // check to see if the file is there and just omit linking to it if it's + // not present. + if sess.target.is_like_msvc && !cratepath.with_extension("dll.lib").exists() { + return; + } if let Some(dir) = parent { cmd.include_path(&rehome_sysroot_lib_dir(sess, dir)); } let stem = cratepath.file_stem().unwrap().to_str().unwrap(); // Convert library file-stem into a cc -l argument. let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 }; - cmd.link_rust_dylib(&stem[prefix..], parent.unwrap_or_else(|| Path::new(""))); + cmd.link_dylib_by_name(&stem[prefix..], false, true); } fn relevant_lib(sess: &Session, lib: &NativeLib) -> bool { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 90f5027c26494..9a854bb7101dd 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -166,9 +166,10 @@ pub fn get_linker<'a>( pub trait Linker { fn cmd(&mut self) -> &mut Command; fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path); - fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool); - fn link_rust_dylib(&mut self, lib: &str, path: &Path); - fn link_framework(&mut self, framework: &str, as_needed: bool); + 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) { + bug!("framework linked with unsupported linker") + } fn link_staticlib(&mut self, lib: &str, verbatim: bool); fn link_rlib(&mut self, lib: &Path); fn link_whole_rlib(&mut self, lib: &Path); @@ -432,8 +433,8 @@ impl<'a> Linker for GccLinker<'a> { } } - fn link_dylib(&mut self, lib: &str, verbatim: bool, as_needed: bool) { - if self.sess.target.os == "illumos" && lib == "c" { + fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, as_needed: bool) { + if self.sess.target.os == "illumos" && name == "c" { // libc will be added via late_link_args on illumos so that it will // appear last in the library search order. // FIXME: This should be replaced by a more complete and generic @@ -454,7 +455,7 @@ impl<'a> Linker for GccLinker<'a> { } } self.hint_dynamic(); - self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },)); + self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); if !as_needed { if self.sess.target.is_like_osx { // See above FIXME comment @@ -493,20 +494,15 @@ impl<'a> Linker for GccLinker<'a> { self.linker_args(&["-z", "norelro"]); } - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { - self.hint_dynamic(); - self.cmd.arg(format!("-l{lib}")); - } - - fn link_framework(&mut self, framework: &str, as_needed: bool) { + fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) { self.hint_dynamic(); 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(framework); + // self.cmd.arg("-needed_framework").arg(name); self.sess.dcx().emit_warn(errors::Ld64UnimplementedModifier); } - self.cmd.arg("-framework").arg(framework); + self.cmd.arg("-framework").arg(name); } // Here we explicitly ask that the entire archive is included into the @@ -845,19 +841,8 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/OPT:NOREF,NOICF"); } - fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) { - self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); - } - - fn link_rust_dylib(&mut self, lib: &str, path: &Path) { - // When producing a dll, the MSVC linker may not actually emit a - // `foo.lib` file if the dll doesn't actually export any symbols, so we - // check to see if the file is there and just omit linking to it if it's - // not present. - let name = format!("{lib}.dll.lib"); - if path.join(&name).exists() { - self.cmd.arg(name); - } + fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { + self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); } fn link_staticlib(&mut self, lib: &str, verbatim: bool) { @@ -899,9 +884,6 @@ impl<'a> Linker for MsvcLinker<'a> { fn framework_path(&mut self, _path: &Path) { bug!("frameworks are not supported on windows") } - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - bug!("frameworks are not supported on windows") - } fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) { self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" })); @@ -1073,9 +1055,9 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.arg(path); } - fn link_dylib(&mut self, lib: &str, verbatim: bool, _as_needed: bool) { + fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { // Emscripten always links statically - self.link_staticlib(lib, verbatim); + self.link_staticlib(name, verbatim); } fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) { @@ -1088,10 +1070,6 @@ impl<'a> Linker for EmLinker<'a> { self.link_rlib(lib); } - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { - self.link_dylib(lib, false, true); - } - fn link_rlib(&mut self, lib: &Path) { self.add_object(lib); } @@ -1112,10 +1090,6 @@ impl<'a> Linker for EmLinker<'a> { bug!("frameworks are not supported on Emscripten") } - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - bug!("frameworks are not supported on Emscripten") - } - fn gc_sections(&mut self, _keep_metadata: bool) { // noop } @@ -1249,8 +1223,8 @@ impl<'a> Linker for WasmLd<'a> { } } - fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) { - self.cmd.arg("-l").arg(lib); + fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { + self.cmd.arg("-l").arg(name); } fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { @@ -1283,14 +1257,6 @@ impl<'a> Linker for WasmLd<'a> { fn no_relro(&mut self) {} - fn link_rust_dylib(&mut self, lib: &str, _path: &Path) { - self.cmd.arg("-l").arg(lib); - } - - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - panic!("frameworks not supported") - } - fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { self.cmd.arg("--whole-archive").arg("-l").arg(lib).arg("--no-whole-archive"); } @@ -1398,7 +1364,7 @@ pub struct L4Bender<'a> { } impl<'a> Linker for L4Bender<'a> { - fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { + fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { bug!("dylibs are not supported on L4Re"); } fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { @@ -1442,14 +1408,6 @@ impl<'a> Linker for L4Bender<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_rust_dylib(&mut self, _: &str, _: &Path) { - panic!("Rust dylibs not supported"); - } - - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - bug!("frameworks not supported on L4Re"); - } - fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { self.hint_static(); self.cmd.arg("--whole-archive").arg(format!("-l{lib}")); @@ -1571,9 +1529,9 @@ impl<'a> AixLinker<'a> { } impl<'a> Linker for AixLinker<'a> { - fn link_dylib(&mut self, lib: &str, _verbatim: bool, _as_needed: bool) { + fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { self.hint_dynamic(); - self.cmd.arg(format!("-l{lib}")); + self.cmd.arg(format!("-l{name}")); } fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { @@ -1626,15 +1584,6 @@ impl<'a> Linker for AixLinker<'a> { } } - fn link_rust_dylib(&mut self, lib: &str, _: &Path) { - self.hint_dynamic(); - self.cmd.arg(format!("-l{lib}")); - } - - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - bug!("frameworks not supported on AIX"); - } - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) { self.hint_static(); let lib = find_native_static_library(lib, verbatim, search_path, self.sess); @@ -1844,11 +1793,7 @@ impl<'a> Linker for PtxLinker<'a> { self.cmd.arg("-o").arg(path); } - fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - - fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) { + fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { panic!("external dylibs not supported") } @@ -1864,10 +1809,6 @@ impl<'a> Linker for PtxLinker<'a> { panic!("frameworks not supported") } - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} @@ -1942,11 +1883,7 @@ impl<'a> Linker for BpfLinker<'a> { self.cmd.arg("-o").arg(path); } - fn link_dylib(&mut self, _lib: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - - fn link_rust_dylib(&mut self, _lib: &str, _path: &Path) { + fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { panic!("external dylibs not supported") } @@ -1962,10 +1899,6 @@ impl<'a> Linker for BpfLinker<'a> { panic!("frameworks not supported") } - fn link_framework(&mut self, _framework: &str, _as_needed: bool) { - panic!("frameworks not supported") - } - fn full_relro(&mut self) {} fn partial_relro(&mut self) {} From 0e38a65612570bb0cabcf77a55d6f171c42413a5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Jan 2024 00:28:56 +0300 Subject: [PATCH 12/20] linker: Refactor APIs for linking static libraries Rename `link(_whole)(staticlib,rlib)` to something more suitable. --- compiler/rustc_codegen_ssa/src/back/link.rs | 14 +- compiler/rustc_codegen_ssa/src/back/linker.rs | 169 +++++++++++------- 2 files changed, 114 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 411f727a9f87b..18fa8a41c4622 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1273,7 +1273,7 @@ fn link_sanitizer_runtime( } else { let filename = format!("librustc{channel}_rt.{name}.a"); let path = find_sanitizer_runtime(sess, &filename).join(&filename); - linker.link_whole_rlib(&path); + linker.link_whole_staticlib_by_path(&path); } } @@ -2506,20 +2506,20 @@ fn add_native_libs_from_crate( // If rlib contains native libs as archives, they are unpacked to tmpdir. let path = tmpdir.join(filename.as_str()); if whole_archive { - cmd.link_whole_rlib(&path); + cmd.link_whole_staticlib_by_path(&path); } else { - cmd.link_rlib(&path); + cmd.link_staticlib_by_path(&path); } } } else { if whole_archive { - cmd.link_whole_staticlib( + cmd.link_whole_staticlib_by_name( name, verbatim, search_paths.get_or_init(|| archive_search_paths(sess)), ); } else { - cmd.link_staticlib(name, verbatim) + cmd.link_staticlib_by_name(name, verbatim) } } } @@ -2534,7 +2534,7 @@ fn add_native_libs_from_crate( // link kind is unspecified. if !link_output_kind.can_link_dylib() && !sess.target.crt_static_allows_dylibs { if link_static { - cmd.link_staticlib(name, verbatim) + cmd.link_staticlib_by_name(name, verbatim) } } else { if link_dynamic { @@ -2791,7 +2791,7 @@ fn add_static_crate<'a>( } else { fix_windows_verbatim_for_gcc(path) }; - cmd.link_rlib(&rlib_path); + cmd.link_staticlib_by_path(&rlib_path); }; if !are_upstream_rust_objects_already_included(sess) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 9a854bb7101dd..4360c10edc30a 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -170,10 +170,15 @@ pub trait Linker { fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { bug!("framework linked with unsupported linker") } - fn link_staticlib(&mut self, lib: &str, verbatim: bool); - fn link_rlib(&mut self, lib: &Path); - fn link_whole_rlib(&mut self, lib: &Path); - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]); + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool); + fn link_staticlib_by_path(&mut self, path: &Path); + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + search_paths: &[PathBuf], + ); + fn link_whole_staticlib_by_path(&mut self, path: &Path); fn include_path(&mut self, path: &Path); fn framework_path(&mut self, path: &Path); fn output_filename(&mut self, path: &Path); @@ -464,13 +469,13 @@ impl<'a> Linker for GccLinker<'a> { } } } - fn link_staticlib(&mut self, lib: &str, verbatim: bool) { + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool) { self.hint_static(); - self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },)); + self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); } - fn link_rlib(&mut self, lib: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path) { self.hint_static(); - self.cmd.arg(lib); + self.cmd.arg(path); } fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); @@ -511,29 +516,34 @@ impl<'a> Linker for GccLinker<'a> { // don't otherwise explicitly reference them. This can occur for // libraries which are just providing bindings, libraries with generic // functions, etc. - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) { + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + search_paths: &[PathBuf], + ) { self.hint_static(); let target = &self.sess.target; if !target.is_like_osx { self.linker_arg("--whole-archive"); - self.cmd.arg(format!("-l{}{lib}", if verbatim && self.is_gnu { ":" } else { "" },)); + self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" })); self.linker_arg("--no-whole-archive"); } else { // -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"); - let lib = find_native_static_library(lib, verbatim, search_path, self.sess); + let lib = find_native_static_library(name, verbatim, search_paths, self.sess); self.linker_arg(&lib); } } - fn link_whole_rlib(&mut self, lib: &Path) { + fn link_whole_staticlib_by_path(&mut self, path: &Path) { self.hint_static(); if self.sess.target.is_like_osx { self.linker_arg("-force_load"); - self.linker_arg(&lib); + self.linker_arg(&path); } else { - self.linker_args(&[OsString::from("--whole-archive"), lib.into()]); + self.linker_args(&[OsString::from("--whole-archive"), path.into()]); self.linker_arg("--no-whole-archive"); } } @@ -817,8 +827,8 @@ impl<'a> Linker for MsvcLinker<'a> { } } - fn link_rlib(&mut self, lib: &Path) { - self.cmd.arg(lib); + fn link_staticlib_by_path(&mut self, path: &Path) { + self.cmd.arg(path); } fn add_object(&mut self, path: &Path) { self.cmd.arg(path); @@ -845,8 +855,8 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); } - fn link_staticlib(&mut self, lib: &str, verbatim: bool) { - self.cmd.arg(format!("{}{}", lib, if verbatim { "" } else { ".lib" })); + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool) { + self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); } fn full_relro(&mut self) { @@ -885,10 +895,15 @@ impl<'a> Linker for MsvcLinker<'a> { bug!("frameworks are not supported on windows") } - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) { - self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", lib, if verbatim { "" } else { ".lib" })); + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + _search_paths: &[PathBuf], + ) { + self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", name, if verbatim { "" } else { ".lib" })); } - fn link_whole_rlib(&mut self, path: &Path) { + fn link_whole_staticlib_by_path(&mut self, path: &Path) { let mut arg = OsString::from("/WHOLEARCHIVE:"); arg.push(path); self.cmd.arg(arg); @@ -1043,8 +1058,8 @@ impl<'a> Linker for EmLinker<'a> { self.cmd.arg("-L").arg(path); } - fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { - self.cmd.arg("-l").arg(lib); + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool) { + self.cmd.arg("-l").arg(name); } fn output_filename(&mut self, path: &Path) { @@ -1057,21 +1072,26 @@ impl<'a> Linker for EmLinker<'a> { fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { // Emscripten always links statically - self.link_staticlib(name, verbatim); + self.link_staticlib_by_name(name, verbatim); } - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, _search_path: &[PathBuf]) { + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + _search_paths: &[PathBuf], + ) { // not supported? - self.link_staticlib(lib, verbatim); + self.link_staticlib_by_name(name, verbatim); } - fn link_whole_rlib(&mut self, lib: &Path) { + fn link_whole_staticlib_by_path(&mut self, path: &Path) { // not supported? - self.link_rlib(lib); + self.link_staticlib_by_path(path); } - fn link_rlib(&mut self, lib: &Path) { - self.add_object(lib); + fn link_staticlib_by_path(&mut self, path: &Path) { + self.add_object(path); } fn full_relro(&mut self) { @@ -1227,12 +1247,12 @@ impl<'a> Linker for WasmLd<'a> { self.cmd.arg("-l").arg(name); } - fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { - self.cmd.arg("-l").arg(lib); + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool) { + self.cmd.arg("-l").arg(name); } - fn link_rlib(&mut self, lib: &Path) { - self.cmd.arg(lib); + fn link_staticlib_by_path(&mut self, path: &Path) { + self.cmd.arg(path); } fn include_path(&mut self, path: &Path) { @@ -1257,12 +1277,17 @@ impl<'a> Linker for WasmLd<'a> { fn no_relro(&mut self) {} - fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { - self.cmd.arg("--whole-archive").arg("-l").arg(lib).arg("--no-whole-archive"); + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + _verbatim: bool, + _search_paths: &[PathBuf], + ) { + self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); } - fn link_whole_rlib(&mut self, lib: &Path) { - self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive"); + fn link_whole_staticlib_by_path(&mut self, path: &Path) { + self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); } fn gc_sections(&mut self, _keep_metadata: bool) { @@ -1367,13 +1392,13 @@ impl<'a> Linker for L4Bender<'a> { fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { bug!("dylibs are not supported on L4Re"); } - fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool) { self.hint_static(); - self.cmd.arg(format!("-PC{lib}")); + self.cmd.arg(format!("-PC{name}")); } - fn link_rlib(&mut self, lib: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path) { self.hint_static(); - self.cmd.arg(lib); + self.cmd.arg(path); } fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); @@ -1408,15 +1433,20 @@ impl<'a> Linker for L4Bender<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_whole_staticlib(&mut self, lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + _verbatim: bool, + _search_paths: &[PathBuf], + ) { self.hint_static(); - self.cmd.arg("--whole-archive").arg(format!("-l{lib}")); + self.cmd.arg("--whole-archive").arg(format!("-l{name}")); self.cmd.arg("--no-whole-archive"); } - fn link_whole_rlib(&mut self, lib: &Path) { + fn link_whole_staticlib_by_path(&mut self, path: &Path) { self.hint_static(); - self.cmd.arg("--whole-archive").arg(lib).arg("--no-whole-archive"); + self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); } fn gc_sections(&mut self, keep_metadata: bool) { @@ -1534,14 +1564,14 @@ impl<'a> Linker for AixLinker<'a> { self.cmd.arg(format!("-l{name}")); } - fn link_staticlib(&mut self, lib: &str, _verbatim: bool) { + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool) { self.hint_static(); - self.cmd.arg(format!("-l{lib}")); + self.cmd.arg(format!("-l{name}")); } - fn link_rlib(&mut self, lib: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path) { self.hint_static(); - self.cmd.arg(lib); + self.cmd.arg(path); } fn include_path(&mut self, path: &Path) { @@ -1584,15 +1614,20 @@ impl<'a> Linker for AixLinker<'a> { } } - fn link_whole_staticlib(&mut self, lib: &str, verbatim: bool, search_path: &[PathBuf]) { + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + search_paths: &[PathBuf], + ) { self.hint_static(); - let lib = find_native_static_library(lib, verbatim, search_path, self.sess); + let lib = find_native_static_library(name, verbatim, search_paths, self.sess); self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); } - fn link_whole_rlib(&mut self, lib: &Path) { + fn link_whole_staticlib_by_path(&mut self, path: &Path) { self.hint_static(); - self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); + self.cmd.arg(format!("-bkeepfile:{}", path.to_str().unwrap())); } fn gc_sections(&mut self, _keep_metadata: bool) { @@ -1759,11 +1794,11 @@ impl<'a> Linker for PtxLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_rlib(&mut self, path: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path) { self.cmd.arg("--rlib").arg(path); } - fn link_whole_rlib(&mut self, path: &Path) { + fn link_whole_staticlib_by_path(&mut self, path: &Path) { self.cmd.arg("--rlib").arg(path); } @@ -1797,11 +1832,16 @@ impl<'a> Linker for PtxLinker<'a> { panic!("external dylibs not supported") } - fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) { + fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool) { panic!("staticlibs not supported") } - fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { + fn link_whole_staticlib_by_name( + &mut self, + _name: &str, + _verbatim: bool, + _search_paths: &[PathBuf], + ) { panic!("staticlibs not supported") } @@ -1848,11 +1888,11 @@ impl<'a> Linker for BpfLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn link_rlib(&mut self, path: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path) { self.cmd.arg(path); } - fn link_whole_rlib(&mut self, path: &Path) { + fn link_whole_staticlib_by_path(&mut self, path: &Path) { self.cmd.arg(path); } @@ -1887,11 +1927,16 @@ impl<'a> Linker for BpfLinker<'a> { panic!("external dylibs not supported") } - fn link_staticlib(&mut self, _lib: &str, _verbatim: bool) { + fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool) { panic!("staticlibs not supported") } - fn link_whole_staticlib(&mut self, _lib: &str, _verbatim: bool, _search_path: &[PathBuf]) { + fn link_whole_staticlib_by_name( + &mut self, + _name: &str, + _verbatim: bool, + _search_paths: &[PathBuf], + ) { panic!("staticlibs not supported") } From 14cd3fd6f909c2c75edd333f41a1e6c69558d4e6 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Jan 2024 15:47:41 +0300 Subject: [PATCH 13/20] linker: Group library linking methods together and sort them consistently --- compiler/rustc_codegen_ssa/src/back/linker.rs | 351 +++++++++--------- 1 file changed, 180 insertions(+), 171 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 4360c10edc30a..2bddd473702e8 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -171,13 +171,13 @@ pub trait Linker { bug!("framework linked with unsupported linker") } fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool); - fn link_staticlib_by_path(&mut self, path: &Path); fn link_whole_staticlib_by_name( &mut self, name: &str, verbatim: bool, search_paths: &[PathBuf], ); + fn link_staticlib_by_path(&mut self, path: &Path); fn link_whole_staticlib_by_path(&mut self, path: &Path); fn include_path(&mut self, path: &Path); fn framework_path(&mut self, path: &Path); @@ -469,35 +469,6 @@ impl<'a> Linker for GccLinker<'a> { } } } - fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool) { - self.hint_static(); - self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); - } - fn link_staticlib_by_path(&mut self, path: &Path) { - self.hint_static(); - self.cmd.arg(path); - } - 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); - } - fn full_relro(&mut self) { - self.linker_args(&["-z", "relro", "-z", "now"]); - } - fn partial_relro(&mut self) { - self.linker_args(&["-z", "relro"]); - } - fn no_relro(&mut self) { - self.linker_args(&["-z", "norelro"]); - } fn link_framework_by_name(&mut self, name: &str, _verbatim: bool, as_needed: bool) { self.hint_dynamic(); @@ -510,6 +481,11 @@ impl<'a> Linker for GccLinker<'a> { self.cmd.arg("-framework").arg(name); } + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool) { + self.hint_static(); + self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); + } + // Here we explicitly ask that the entire archive is included into the // result artifact. For more details see #15460, but the gist is that // the linker will strip away any unused objects in the archive if we @@ -537,6 +513,11 @@ impl<'a> Linker for GccLinker<'a> { } } + fn link_staticlib_by_path(&mut self, path: &Path) { + self.hint_static(); + self.cmd.arg(path); + } + fn link_whole_staticlib_by_path(&mut self, path: &Path) { self.hint_static(); if self.sess.target.is_like_osx { @@ -548,6 +529,28 @@ impl<'a> Linker for GccLinker<'a> { } } + 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); + } + fn full_relro(&mut self) { + self.linker_args(&["-z", "relro", "-z", "now"]); + } + fn partial_relro(&mut self) { + self.linker_args(&["-z", "relro"]); + } + fn no_relro(&mut self) { + self.linker_args(&["-z", "norelro"]); + } + fn gc_sections(&mut self, keep_metadata: bool) { // The dead_strip option to the linker specifies that functions and data // unreachable by the entry point will be removed. This is quite useful @@ -827,9 +830,33 @@ 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" })); + } + + fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool) { + self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + } + + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + _search_paths: &[PathBuf], + ) { + self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", name, if verbatim { "" } else { ".lib" })); + } + fn link_staticlib_by_path(&mut self, path: &Path) { self.cmd.arg(path); } + + fn link_whole_staticlib_by_path(&mut self, path: &Path) { + let mut arg = OsString::from("/WHOLEARCHIVE:"); + arg.push(path); + self.cmd.arg(arg); + } + fn add_object(&mut self, path: &Path) { self.cmd.arg(path); } @@ -851,14 +878,6 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg("/OPT:NOREF,NOICF"); } - fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { - self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); - } - - fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool) { - self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); - } - fn full_relro(&mut self) { // noop } @@ -895,19 +914,6 @@ impl<'a> Linker for MsvcLinker<'a> { bug!("frameworks are not supported on windows") } - fn link_whole_staticlib_by_name( - &mut self, - name: &str, - verbatim: bool, - _search_paths: &[PathBuf], - ) { - self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", name, if verbatim { "" } else { ".lib" })); - } - fn link_whole_staticlib_by_path(&mut self, path: &Path) { - let mut arg = OsString::from("/WHOLEARCHIVE:"); - arg.push(path); - self.cmd.arg(arg); - } fn optimize(&mut self) { // Needs more investigation of `/OPT` arguments } @@ -1054,27 +1060,15 @@ impl<'a> Linker for EmLinker<'a> { fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - fn include_path(&mut self, path: &Path) { - self.cmd.arg("-L").arg(path); + fn link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { + // Emscripten always links statically + self.link_staticlib_by_name(name, verbatim); } fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool) { self.cmd.arg("-l").arg(name); } - 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 link_dylib_by_name(&mut self, name: &str, verbatim: bool, _as_needed: bool) { - // Emscripten always links statically - self.link_staticlib_by_name(name, verbatim); - } - fn link_whole_staticlib_by_name( &mut self, name: &str, @@ -1085,13 +1079,25 @@ impl<'a> Linker for EmLinker<'a> { self.link_staticlib_by_name(name, verbatim); } + fn link_staticlib_by_path(&mut self, path: &Path) { + self.add_object(path); + } + fn link_whole_staticlib_by_path(&mut self, path: &Path) { // not supported? self.link_staticlib_by_path(path); } - fn link_staticlib_by_path(&mut self, path: &Path) { - self.add_object(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); } fn full_relro(&mut self) { @@ -1251,10 +1257,23 @@ impl<'a> Linker for WasmLd<'a> { self.cmd.arg("-l").arg(name); } + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + _verbatim: bool, + _search_paths: &[PathBuf], + ) { + self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); + } + fn link_staticlib_by_path(&mut self, path: &Path) { self.cmd.arg(path); } + fn link_whole_staticlib_by_path(&mut self, path: &Path) { + self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + } + fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } @@ -1277,19 +1296,6 @@ impl<'a> Linker for WasmLd<'a> { fn no_relro(&mut self) {} - fn link_whole_staticlib_by_name( - &mut self, - name: &str, - _verbatim: bool, - _search_paths: &[PathBuf], - ) { - self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); - } - - fn link_whole_staticlib_by_path(&mut self, path: &Path) { - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); - } - fn gc_sections(&mut self, _keep_metadata: bool) { self.cmd.arg("--gc-sections"); } @@ -1389,17 +1395,42 @@ pub struct L4Bender<'a> { } impl<'a> Linker for L4Bender<'a> { + fn cmd(&mut self) -> &mut Command { + &mut self.cmd + } + + 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) { bug!("dylibs are not supported on L4Re"); } + fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool) { self.hint_static(); self.cmd.arg(format!("-PC{name}")); } + + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + _verbatim: bool, + _search_paths: &[PathBuf], + ) { + self.hint_static(); + self.cmd.arg("--whole-archive").arg(format!("-l{name}")); + self.cmd.arg("--no-whole-archive"); + } + fn link_staticlib_by_path(&mut self, path: &Path) { self.hint_static(); self.cmd.arg(path); } + + fn link_whole_staticlib_by_path(&mut self, path: &Path) { + self.hint_static(); + self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + } + fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } @@ -1427,28 +1458,6 @@ impl<'a> Linker for L4Bender<'a> { self.cmd.arg("-z").arg("norelro"); } - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, _output_kind: LinkOutputKind, _out_filename: &Path) {} - - fn link_whole_staticlib_by_name( - &mut self, - name: &str, - _verbatim: bool, - _search_paths: &[PathBuf], - ) { - self.hint_static(); - self.cmd.arg("--whole-archive").arg(format!("-l{name}")); - self.cmd.arg("--no-whole-archive"); - } - - fn link_whole_staticlib_by_path(&mut self, path: &Path) { - self.hint_static(); - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); - } - fn gc_sections(&mut self, keep_metadata: bool) { if !keep_metadata { self.cmd.arg("--gc-sections"); @@ -1559,6 +1568,24 @@ impl<'a> AixLinker<'a> { } impl<'a> Linker for AixLinker<'a> { + fn cmd(&mut self) -> &mut Command { + &mut self.cmd + } + + fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { + match output_kind { + LinkOutputKind::DynamicDylib => { + self.hint_dynamic(); + self.build_dylib(out_filename); + } + LinkOutputKind::StaticDylib => { + self.hint_static(); + self.build_dylib(out_filename); + } + _ => {} + } + } + fn link_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { self.hint_dynamic(); self.cmd.arg(format!("-l{name}")); @@ -1569,11 +1596,27 @@ impl<'a> Linker for AixLinker<'a> { self.cmd.arg(format!("-l{name}")); } + fn link_whole_staticlib_by_name( + &mut self, + name: &str, + verbatim: bool, + search_paths: &[PathBuf], + ) { + self.hint_static(); + let lib = find_native_static_library(name, verbatim, search_paths, self.sess); + self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); + } + fn link_staticlib_by_path(&mut self, path: &Path) { self.hint_static(); self.cmd.arg(path); } + fn link_whole_staticlib_by_path(&mut self, path: &Path) { + self.hint_static(); + self.cmd.arg(format!("-bkeepfile:{}", path.to_str().unwrap())); + } + fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } @@ -1596,40 +1639,6 @@ impl<'a> Linker for AixLinker<'a> { fn no_relro(&mut self) {} - fn cmd(&mut self) -> &mut Command { - &mut self.cmd - } - - fn set_output_kind(&mut self, output_kind: LinkOutputKind, out_filename: &Path) { - match output_kind { - LinkOutputKind::DynamicDylib => { - self.hint_dynamic(); - self.build_dylib(out_filename); - } - LinkOutputKind::StaticDylib => { - self.hint_static(); - self.build_dylib(out_filename); - } - _ => {} - } - } - - fn link_whole_staticlib_by_name( - &mut self, - name: &str, - verbatim: bool, - search_paths: &[PathBuf], - ) { - self.hint_static(); - let lib = find_native_static_library(name, verbatim, search_paths, self.sess); - self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); - } - - fn link_whole_staticlib_by_path(&mut self, path: &Path) { - self.hint_static(); - self.cmd.arg(format!("-bkeepfile:{}", path.to_str().unwrap())); - } - fn gc_sections(&mut self, _keep_metadata: bool) { self.cmd.arg("-bgc"); } @@ -1794,6 +1803,23 @@ impl<'a> Linker for PtxLinker<'a> { 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) { + panic!("external dylibs not supported") + } + + fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool) { + panic!("staticlibs not supported") + } + + fn link_whole_staticlib_by_name( + &mut self, + _name: &str, + _verbatim: bool, + _search_paths: &[PathBuf], + ) { + panic!("staticlibs not supported") + } + fn link_staticlib_by_path(&mut self, path: &Path) { self.cmd.arg("--rlib").arg(path); } @@ -1828,23 +1854,6 @@ impl<'a> Linker for PtxLinker<'a> { self.cmd.arg("-o").arg(path); } - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool) { - panic!("staticlibs not supported") - } - - fn link_whole_staticlib_by_name( - &mut self, - _name: &str, - _verbatim: bool, - _search_paths: &[PathBuf], - ) { - panic!("staticlibs not supported") - } - fn framework_path(&mut self, _path: &Path) { panic!("frameworks not supported") } @@ -1888,6 +1897,23 @@ impl<'a> Linker for BpfLinker<'a> { 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) { + panic!("external dylibs not supported") + } + + fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool) { + panic!("staticlibs not supported") + } + + fn link_whole_staticlib_by_name( + &mut self, + _name: &str, + _verbatim: bool, + _search_paths: &[PathBuf], + ) { + panic!("staticlibs not supported") + } + fn link_staticlib_by_path(&mut self, path: &Path) { self.cmd.arg(path); } @@ -1923,23 +1949,6 @@ impl<'a> Linker for BpfLinker<'a> { self.cmd.arg("-o").arg(path); } - fn link_dylib_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { - panic!("external dylibs not supported") - } - - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool) { - panic!("staticlibs not supported") - } - - fn link_whole_staticlib_by_name( - &mut self, - _name: &str, - _verbatim: bool, - _search_paths: &[PathBuf], - ) { - panic!("staticlibs not supported") - } - fn framework_path(&mut self, _path: &Path) { panic!("frameworks not supported") } From 859f37ae869bcfe059b1f6ecdf10174d9d87d5b5 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Jan 2024 16:13:13 +0300 Subject: [PATCH 14/20] linker: Do not collect search paths unless necessary --- compiler/rustc_codegen_ssa/src/back/link.rs | 25 +++++++++++-------- compiler/rustc_codegen_ssa/src/back/linker.rs | 25 +++++++++++-------- 2 files changed, 29 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 18fa8a41c4622..5507f04fea1f7 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -52,6 +52,15 @@ use std::path::{Path, PathBuf}; use std::process::{ExitStatus, Output, Stdio}; use std::{env, fmt, fs, io, mem, str}; +#[derive(Default)] +pub struct SearchPaths(OnceCell>); + +impl SearchPaths { + pub(super) fn get(&self, sess: &Session) -> &[PathBuf] { + self.0.get_or_init(|| archive_search_paths(sess)) + } +} + pub fn ensure_removed(dcx: &DiagCtxt, path: &Path) { if let Err(e) = fs::remove_file(path) { if e.kind() != io::ErrorKind::NotFound { @@ -2445,7 +2454,7 @@ fn add_native_libs_from_crate( archive_builder_builder: &dyn ArchiveBuilderBuilder, codegen_results: &CodegenResults, tmpdir: &Path, - search_paths: &OnceCell>, + search_paths: &SearchPaths, bundled_libs: &FxHashSet, cnum: CrateNum, link_static: bool, @@ -2513,11 +2522,7 @@ fn add_native_libs_from_crate( } } else { if whole_archive { - cmd.link_whole_staticlib_by_name( - name, - verbatim, - search_paths.get_or_init(|| archive_search_paths(sess)), - ); + cmd.link_whole_staticlib_by_name(name, verbatim, search_paths); } else { cmd.link_staticlib_by_name(name, verbatim) } @@ -2581,7 +2586,7 @@ fn add_local_native_libraries( } } - let search_paths = OnceCell::new(); + let search_paths = SearchPaths::default(); // All static and dynamic native library dependencies are linked to the local crate. let link_static = true; let link_dynamic = true; @@ -2623,7 +2628,7 @@ fn add_upstream_rust_crates<'a>( .find(|(ty, _)| *ty == crate_type) .expect("failed to find crate type in dependency format list"); - let search_paths = OnceCell::new(); + let search_paths = SearchPaths::default(); for &cnum in &codegen_results.crate_info.used_crates { // We may not pass all crates through to the linker. Some crates may appear statically in // an existing dylib, meaning we'll pick up all the symbols from the dylib. @@ -2698,7 +2703,7 @@ fn add_upstream_native_libraries( tmpdir: &Path, link_output_kind: LinkOutputKind, ) { - let search_path = OnceCell::new(); + let search_paths = SearchPaths::default(); for &cnum in &codegen_results.crate_info.used_crates { // Static libraries are not linked here, they are linked in `add_upstream_rust_crates`. // FIXME: Merge this function to `add_upstream_rust_crates` so that all native libraries @@ -2720,7 +2725,7 @@ fn add_upstream_native_libraries( archive_builder_builder, codegen_results, tmpdir, - &search_path, + &search_paths, &Default::default(), cnum, link_static, diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 2bddd473702e8..4b38be6f1889a 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -1,5 +1,6 @@ use super::command::Command; use super::symbol_export; +use crate::back::link::SearchPaths; use crate::errors; use rustc_span::symbol::sym; @@ -175,7 +176,7 @@ pub trait Linker { &mut self, name: &str, verbatim: bool, - search_paths: &[PathBuf], + search_paths: &SearchPaths, ); fn link_staticlib_by_path(&mut self, path: &Path); fn link_whole_staticlib_by_path(&mut self, path: &Path); @@ -496,7 +497,7 @@ impl<'a> Linker for GccLinker<'a> { &mut self, name: &str, verbatim: bool, - search_paths: &[PathBuf], + search_paths: &SearchPaths, ) { self.hint_static(); let target = &self.sess.target; @@ -508,7 +509,8 @@ impl<'a> Linker for GccLinker<'a> { // -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"); - let lib = find_native_static_library(name, verbatim, search_paths, self.sess); + let lib = + find_native_static_library(name, verbatim, search_paths.get(self.sess), self.sess); self.linker_arg(&lib); } } @@ -842,7 +844,7 @@ impl<'a> Linker for MsvcLinker<'a> { &mut self, name: &str, verbatim: bool, - _search_paths: &[PathBuf], + _search_paths: &SearchPaths, ) { self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", name, if verbatim { "" } else { ".lib" })); } @@ -1073,7 +1075,7 @@ impl<'a> Linker for EmLinker<'a> { &mut self, name: &str, verbatim: bool, - _search_paths: &[PathBuf], + _search_paths: &SearchPaths, ) { // not supported? self.link_staticlib_by_name(name, verbatim); @@ -1261,7 +1263,7 @@ impl<'a> Linker for WasmLd<'a> { &mut self, name: &str, _verbatim: bool, - _search_paths: &[PathBuf], + _search_paths: &SearchPaths, ) { self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); } @@ -1414,7 +1416,7 @@ impl<'a> Linker for L4Bender<'a> { &mut self, name: &str, _verbatim: bool, - _search_paths: &[PathBuf], + _search_paths: &SearchPaths, ) { self.hint_static(); self.cmd.arg("--whole-archive").arg(format!("-l{name}")); @@ -1600,10 +1602,11 @@ impl<'a> Linker for AixLinker<'a> { &mut self, name: &str, verbatim: bool, - search_paths: &[PathBuf], + search_paths: &SearchPaths, ) { self.hint_static(); - let lib = find_native_static_library(name, verbatim, search_paths, self.sess); + let lib = + find_native_static_library(name, verbatim, search_paths.get(self.sess), self.sess); self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); } @@ -1815,7 +1818,7 @@ impl<'a> Linker for PtxLinker<'a> { &mut self, _name: &str, _verbatim: bool, - _search_paths: &[PathBuf], + _search_paths: &SearchPaths, ) { panic!("staticlibs not supported") } @@ -1909,7 +1912,7 @@ impl<'a> Linker for BpfLinker<'a> { &mut self, _name: &str, _verbatim: bool, - _search_paths: &[PathBuf], + _search_paths: &SearchPaths, ) { panic!("staticlibs not supported") } From d15db6b26071b4d9550c2237283ba602bb4c1a53 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Jan 2024 17:41:18 +0300 Subject: [PATCH 15/20] linker: Merge `link_staticlib_*` and `link_whole_staticlib_*` --- compiler/rustc_codegen_ssa/src/back/link.rs | 18 +- compiler/rustc_codegen_ssa/src/back/linker.rs | 198 +++++++----------- 2 files changed, 86 insertions(+), 130 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 5507f04fea1f7..e3b4189b3f5a3 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1282,7 +1282,7 @@ fn link_sanitizer_runtime( } else { let filename = format!("librustc{channel}_rt.{name}.a"); let path = find_sanitizer_runtime(sess, &filename).join(&filename); - linker.link_whole_staticlib_by_path(&path); + linker.link_staticlib_by_path(&path, true); } } @@ -2514,18 +2514,10 @@ fn add_native_libs_from_crate( if let Some(filename) = lib.filename { // If rlib contains native libs as archives, they are unpacked to tmpdir. let path = tmpdir.join(filename.as_str()); - if whole_archive { - cmd.link_whole_staticlib_by_path(&path); - } else { - cmd.link_staticlib_by_path(&path); - } + cmd.link_staticlib_by_path(&path, whole_archive); } } else { - if whole_archive { - cmd.link_whole_staticlib_by_name(name, verbatim, search_paths); - } else { - cmd.link_staticlib_by_name(name, verbatim) - } + cmd.link_staticlib_by_name(name, verbatim, whole_archive, search_paths); } } } @@ -2539,7 +2531,7 @@ fn add_native_libs_from_crate( // link kind is unspecified. if !link_output_kind.can_link_dylib() && !sess.target.crt_static_allows_dylibs { if link_static { - cmd.link_staticlib_by_name(name, verbatim) + cmd.link_staticlib_by_name(name, verbatim, false, search_paths); } } else { if link_dynamic { @@ -2796,7 +2788,7 @@ fn add_static_crate<'a>( } else { fix_windows_verbatim_for_gcc(path) }; - cmd.link_staticlib_by_path(&rlib_path); + cmd.link_staticlib_by_path(&rlib_path, false); }; if !are_upstream_rust_objects_already_included(sess) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 4b38be6f1889a..092b66e386867 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -171,15 +171,14 @@ pub trait Linker { fn link_framework_by_name(&mut self, _name: &str, _verbatim: bool, _as_needed: bool) { bug!("framework linked with unsupported linker") } - fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool); - fn link_whole_staticlib_by_name( + fn link_staticlib_by_name( &mut self, name: &str, verbatim: bool, + whole_archive: bool, search_paths: &SearchPaths, ); - fn link_staticlib_by_path(&mut self, path: &Path); - fn link_whole_staticlib_by_path(&mut self, path: &Path); + 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); @@ -482,26 +481,17 @@ impl<'a> Linker for GccLinker<'a> { self.cmd.arg("-framework").arg(name); } - fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool) { - self.hint_static(); - self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" },)); - } - - // Here we explicitly ask that the entire archive is included into the - // result artifact. For more details see #15460, but the gist is that - // the linker will strip away any unused objects in the archive if we - // don't otherwise explicitly reference them. This can occur for - // libraries which are just providing bindings, libraries with generic - // functions, etc. - fn link_whole_staticlib_by_name( + fn link_staticlib_by_name( &mut self, name: &str, verbatim: bool, + whole_archive: bool, search_paths: &SearchPaths, ) { self.hint_static(); - let target = &self.sess.target; - if !target.is_like_osx { + if !whole_archive { + self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" })); + } else if !self.sess.target.is_like_osx { self.linker_arg("--whole-archive"); self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" })); self.linker_arg("--no-whole-archive"); @@ -515,14 +505,11 @@ impl<'a> Linker for GccLinker<'a> { } } - fn link_staticlib_by_path(&mut self, path: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); - self.cmd.arg(path); - } - - fn link_whole_staticlib_by_path(&mut self, path: &Path) { - self.hint_static(); - if self.sess.target.is_like_osx { + if !whole_archive { + self.cmd.arg(path); + } else if self.sess.target.is_like_osx { self.linker_arg("-force_load"); self.linker_arg(&path); } else { @@ -836,27 +823,28 @@ impl<'a> Linker for MsvcLinker<'a> { self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); } - fn link_staticlib_by_name(&mut self, name: &str, verbatim: bool) { - self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); - } - - fn link_whole_staticlib_by_name( + fn link_staticlib_by_name( &mut self, name: &str, verbatim: bool, + whole_archive: bool, _search_paths: &SearchPaths, ) { - self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", name, if verbatim { "" } else { ".lib" })); - } - - fn link_staticlib_by_path(&mut self, path: &Path) { - self.cmd.arg(path); + if !whole_archive { + self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); + } else { + self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", name, if verbatim { "" } else { ".lib" })); + } } - fn link_whole_staticlib_by_path(&mut self, path: &Path) { - let mut arg = OsString::from("/WHOLEARCHIVE:"); - arg.push(path); - self.cmd.arg(arg); + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { + if !whole_archive { + self.cmd.arg(path); + } else { + let mut arg = OsString::from("/WHOLEARCHIVE:"); + arg.push(path); + self.cmd.arg(arg); + } } fn add_object(&mut self, path: &Path) { @@ -1062,34 +1050,25 @@ impl<'a> Linker for EmLinker<'a> { 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_dylib_by_name(&mut self, name: &str, _verbatim: bool, _as_needed: bool) { // Emscripten always links statically - self.link_staticlib_by_name(name, verbatim); - } - - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool) { self.cmd.arg("-l").arg(name); } - fn link_whole_staticlib_by_name( + fn link_staticlib_by_name( &mut self, name: &str, - verbatim: bool, + _verbatim: bool, + _whole_archive: bool, _search_paths: &SearchPaths, ) { - // not supported? - self.link_staticlib_by_name(name, verbatim); + self.cmd.arg("-l").arg(name); } - fn link_staticlib_by_path(&mut self, path: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { self.add_object(path); } - fn link_whole_staticlib_by_path(&mut self, path: &Path) { - // not supported? - self.link_staticlib_by_path(path); - } - fn include_path(&mut self, path: &Path) { self.cmd.arg("-L").arg(path); } @@ -1255,25 +1234,26 @@ impl<'a> Linker for WasmLd<'a> { self.cmd.arg("-l").arg(name); } - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool) { - self.cmd.arg("-l").arg(name); - } - - fn link_whole_staticlib_by_name( + fn link_staticlib_by_name( &mut self, name: &str, _verbatim: bool, + whole_archive: bool, _search_paths: &SearchPaths, ) { - self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); - } - - fn link_staticlib_by_path(&mut self, path: &Path) { - self.cmd.arg(path); + if !whole_archive { + self.cmd.arg("-l").arg(name); + } else { + self.cmd.arg("--whole-archive").arg("-l").arg(name).arg("--no-whole-archive"); + } } - fn link_whole_staticlib_by_path(&mut self, path: &Path) { - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { + if !whole_archive { + self.cmd.arg(path); + } else { + self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + } } fn include_path(&mut self, path: &Path) { @@ -1407,30 +1387,29 @@ impl<'a> Linker for L4Bender<'a> { bug!("dylibs are not supported on L4Re"); } - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool) { - self.hint_static(); - self.cmd.arg(format!("-PC{name}")); - } - - fn link_whole_staticlib_by_name( + fn link_staticlib_by_name( &mut self, name: &str, _verbatim: bool, + whole_archive: bool, _search_paths: &SearchPaths, ) { self.hint_static(); - self.cmd.arg("--whole-archive").arg(format!("-l{name}")); - self.cmd.arg("--no-whole-archive"); - } - - fn link_staticlib_by_path(&mut self, path: &Path) { - self.hint_static(); - self.cmd.arg(path); + if !whole_archive { + self.cmd.arg(format!("-PC{name}")); + } else { + self.cmd.arg("--whole-archive").arg(format!("-l{name}")); + self.cmd.arg("--no-whole-archive"); + } } - fn link_whole_staticlib_by_path(&mut self, path: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); - self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + if !whole_archive { + self.cmd.arg(path); + } else { + self.cmd.arg("--whole-archive").arg(path).arg("--no-whole-archive"); + } } fn include_path(&mut self, path: &Path) { @@ -1593,31 +1572,30 @@ impl<'a> Linker for AixLinker<'a> { self.cmd.arg(format!("-l{name}")); } - fn link_staticlib_by_name(&mut self, name: &str, _verbatim: bool) { - self.hint_static(); - self.cmd.arg(format!("-l{name}")); - } - - fn link_whole_staticlib_by_name( + fn link_staticlib_by_name( &mut self, name: &str, verbatim: bool, + whole_archive: bool, search_paths: &SearchPaths, ) { self.hint_static(); - let lib = - find_native_static_library(name, verbatim, search_paths.get(self.sess), self.sess); - self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); - } - - fn link_staticlib_by_path(&mut self, path: &Path) { - self.hint_static(); - self.cmd.arg(path); + if !whole_archive { + self.cmd.arg(format!("-l{name}")); + } else { + let lib = + find_native_static_library(name, verbatim, search_paths.get(self.sess), self.sess); + self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); + } } - fn link_whole_staticlib_by_path(&mut self, path: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { self.hint_static(); - self.cmd.arg(format!("-bkeepfile:{}", path.to_str().unwrap())); + if !whole_archive { + self.cmd.arg(path); + } else { + self.cmd.arg(format!("-bkeepfile:{}", path.to_str().unwrap())); + } } fn include_path(&mut self, path: &Path) { @@ -1810,24 +1788,17 @@ impl<'a> Linker for PtxLinker<'a> { panic!("external dylibs not supported") } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool) { - panic!("staticlibs not supported") - } - - fn link_whole_staticlib_by_name( + fn link_staticlib_by_name( &mut self, _name: &str, _verbatim: bool, + _whole_archive: bool, _search_paths: &SearchPaths, ) { panic!("staticlibs not supported") } - fn link_staticlib_by_path(&mut self, path: &Path) { - self.cmd.arg("--rlib").arg(path); - } - - fn link_whole_staticlib_by_path(&mut self, path: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { self.cmd.arg("--rlib").arg(path); } @@ -1904,24 +1875,17 @@ impl<'a> Linker for BpfLinker<'a> { panic!("external dylibs not supported") } - fn link_staticlib_by_name(&mut self, _name: &str, _verbatim: bool) { - panic!("staticlibs not supported") - } - - fn link_whole_staticlib_by_name( + fn link_staticlib_by_name( &mut self, _name: &str, _verbatim: bool, + _whole_archive: bool, _search_paths: &SearchPaths, ) { panic!("staticlibs not supported") } - fn link_staticlib_by_path(&mut self, path: &Path) { - self.cmd.arg(path); - } - - fn link_whole_staticlib_by_path(&mut self, path: &Path) { + fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { self.cmd.arg(path); } From 1b8e871f1c3b2aca174ac1a4d46613355a956fcc Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Thu, 18 Jan 2024 18:09:59 +0300 Subject: [PATCH 16/20] linker: Cleanup implementations of `link_staticlib_*` --- compiler/rustc_codegen_ssa/src/back/linker.rs | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 092b66e386867..9f06f398288f2 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -489,19 +489,19 @@ impl<'a> Linker for GccLinker<'a> { search_paths: &SearchPaths, ) { self.hint_static(); + let colon = if verbatim && self.is_gnu { ":" } else { "" }; if !whole_archive { - self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" })); - } else if !self.sess.target.is_like_osx { - self.linker_arg("--whole-archive"); - self.cmd.arg(format!("-l{}{name}", if verbatim && self.is_gnu { ":" } else { "" })); - self.linker_arg("--no-whole-archive"); - } else { + self.cmd.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"); - let lib = - find_native_static_library(name, verbatim, search_paths.get(self.sess), self.sess); - self.linker_arg(&lib); + let search_paths = search_paths.get(self.sess); + self.linker_arg(find_native_static_library(name, verbatim, search_paths, self.sess)); + } else { + self.linker_arg("--whole-archive"); + self.cmd.arg(format!("-l{colon}{name}")); + self.linker_arg("--no-whole-archive"); } } @@ -511,9 +511,10 @@ impl<'a> Linker for GccLinker<'a> { self.cmd.arg(path); } else if self.sess.target.is_like_osx { self.linker_arg("-force_load"); - self.linker_arg(&path); + self.linker_arg(path); } else { - self.linker_args(&[OsString::from("--whole-archive"), path.into()]); + self.linker_arg("--whole-archive"); + self.linker_arg(path); self.linker_arg("--no-whole-archive"); } } @@ -830,11 +831,9 @@ impl<'a> Linker for MsvcLinker<'a> { whole_archive: bool, _search_paths: &SearchPaths, ) { - if !whole_archive { - self.cmd.arg(format!("{}{}", name, if verbatim { "" } else { ".lib" })); - } else { - self.cmd.arg(format!("/WHOLEARCHIVE:{}{}", name, if verbatim { "" } else { ".lib" })); - } + let prefix = if whole_archive { "/WHOLEARCHIVE:" } else { "" }; + let suffix = if verbatim { "" } else { ".lib" }; + self.cmd.arg(format!("{prefix}{name}{suffix}")); } fn link_staticlib_by_path(&mut self, path: &Path, whole_archive: bool) { @@ -1066,7 +1065,7 @@ impl<'a> Linker for EmLinker<'a> { } fn link_staticlib_by_path(&mut self, path: &Path, _whole_archive: bool) { - self.add_object(path); + self.cmd.arg(path); } fn include_path(&mut self, path: &Path) { @@ -1398,8 +1397,7 @@ impl<'a> Linker for L4Bender<'a> { if !whole_archive { self.cmd.arg(format!("-PC{name}")); } else { - self.cmd.arg("--whole-archive").arg(format!("-l{name}")); - self.cmd.arg("--no-whole-archive"); + self.cmd.arg("--whole-archive").arg(format!("-l{name}")).arg("--no-whole-archive"); } } @@ -1583,9 +1581,10 @@ impl<'a> Linker for AixLinker<'a> { if !whole_archive { self.cmd.arg(format!("-l{name}")); } else { - let lib = - find_native_static_library(name, verbatim, search_paths.get(self.sess), self.sess); - self.cmd.arg(format!("-bkeepfile:{}", lib.to_str().unwrap())); + let mut arg = OsString::from("-bkeepfile:"); + let search_path = search_paths.get(self.sess); + arg.push(find_native_static_library(name, verbatim, search_path, self.sess)); + self.cmd.arg(arg); } } @@ -1594,7 +1593,9 @@ impl<'a> Linker for AixLinker<'a> { if !whole_archive { self.cmd.arg(path); } else { - self.cmd.arg(format!("-bkeepfile:{}", path.to_str().unwrap())); + let mut arg = OsString::from("-bkeepfile:"); + arg.push(path); + self.cmd.arg(arg); } } From 03f23c1a2fd36b33820750ddf41246ad322baef7 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Wed, 24 Jan 2024 01:50:04 +0300 Subject: [PATCH 17/20] linker: Fix Rust dylib crate extension on windows-msvc --- compiler/rustc_codegen_ssa/src/back/link.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e3b4189b3f5a3..f098fc9cb5970 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -2866,7 +2866,11 @@ fn add_dynamic_crate(cmd: &mut dyn Linker, sess: &Session, cratepath: &Path) { if let Some(dir) = parent { cmd.include_path(&rehome_sysroot_lib_dir(sess, dir)); } - let stem = cratepath.file_stem().unwrap().to_str().unwrap(); + // "/name.dll -> name.dll" on windows-msvc + // "/name.dll -> name" on windows-gnu + // "/libname. -> name" elsewhere + let stem = if sess.target.is_like_msvc { cratepath.file_name() } else { cratepath.file_stem() }; + let stem = stem.unwrap().to_str().unwrap(); // Convert library file-stem into a cc -l argument. let prefix = if stem.starts_with("lib") && !sess.target.is_like_windows { 3 } else { 0 }; cmd.link_dylib_by_name(&stem[prefix..], false, true); From 83ef18cd6cdcf80b7075424625123f878bda8722 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 24 Jan 2024 12:57:11 +1100 Subject: [PATCH 18/20] coverage: Dismantle `Instrumentor` into ordinary functions --- .../rustc_mir_transform/src/coverage/mod.rs | 265 +++++++++--------- 1 file changed, 126 insertions(+), 139 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index a11d224e8f1b5..d40b625be88a2 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -59,167 +59,154 @@ impl<'tcx> MirPass<'tcx> for InstrumentCoverage { _ => {} } - trace!("InstrumentCoverage starting for {def_id:?}"); - Instrumentor::new(tcx, mir_body).inject_counters(); - trace!("InstrumentCoverage done for {def_id:?}"); + instrument_function_for_coverage(tcx, mir_body); } } -struct Instrumentor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - mir_body: &'a mut mir::Body<'tcx>, - hir_info: ExtractedHirInfo, - basic_coverage_blocks: CoverageGraph, -} - -impl<'a, 'tcx> Instrumentor<'a, 'tcx> { - fn new(tcx: TyCtxt<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { - let hir_info = extract_hir_info(tcx, mir_body.source.def_id().expect_local()); +fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir::Body<'tcx>) { + let def_id = mir_body.source.def_id(); + let _span = debug_span!("instrument_function_for_coverage", ?def_id).entered(); - debug!(?hir_info, "instrumenting {:?}", mir_body.source.def_id()); + let hir_info = extract_hir_info(tcx, def_id.expect_local()); + let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); - let basic_coverage_blocks = CoverageGraph::from_mir(mir_body); + //////////////////////////////////////////////////// + // Compute coverage spans from the `CoverageGraph`. + let Some(coverage_spans) = + CoverageSpans::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks) + else { + // No relevant spans were found in MIR, so skip instrumenting this function. + return; + }; - Self { tcx, mir_body, hir_info, basic_coverage_blocks } + //////////////////////////////////////////////////// + // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure + // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` + // and all `Expression` dependencies (operands) are also generated, for any other + // `BasicCoverageBlock`s not already associated with a coverage span. + let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); + let coverage_counters = + CoverageCounters::make_bcb_counters(&basic_coverage_blocks, bcb_has_coverage_spans); + + let mappings = create_mappings(tcx, &hir_info, &coverage_spans, &coverage_counters); + if mappings.is_empty() { + // No spans could be converted into valid mappings, so skip this function. + debug!("no spans could be converted into valid mappings; skipping"); + return; } - fn inject_counters(&'a mut self) { - //////////////////////////////////////////////////// - // Compute coverage spans from the `CoverageGraph`. - let Some(coverage_spans) = CoverageSpans::generate_coverage_spans( - self.mir_body, - &self.hir_info, - &self.basic_coverage_blocks, - ) else { - // No relevant spans were found in MIR, so skip instrumenting this function. - return; - }; - - //////////////////////////////////////////////////// - // Create an optimized mix of `Counter`s and `Expression`s for the `CoverageGraph`. Ensure - // every coverage span has a `Counter` or `Expression` assigned to its `BasicCoverageBlock` - // and all `Expression` dependencies (operands) are also generated, for any other - // `BasicCoverageBlock`s not already associated with a coverage span. - let bcb_has_coverage_spans = |bcb| coverage_spans.bcb_has_coverage_spans(bcb); - let coverage_counters = CoverageCounters::make_bcb_counters( - &self.basic_coverage_blocks, - bcb_has_coverage_spans, - ); + inject_coverage_statements( + mir_body, + &basic_coverage_blocks, + bcb_has_coverage_spans, + &coverage_counters, + ); - let mappings = self.create_mappings(&coverage_spans, &coverage_counters); - if mappings.is_empty() { - // No spans could be converted into valid mappings, so skip this function. - debug!("no spans could be converted into valid mappings; skipping"); - return; - } + mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { + function_source_hash: hir_info.function_source_hash, + num_counters: coverage_counters.num_counters(), + expressions: coverage_counters.into_expressions(), + mappings, + })); +} - self.inject_coverage_statements(bcb_has_coverage_spans, &coverage_counters); +/// For each coverage span extracted from MIR, create a corresponding +/// mapping. +/// +/// Precondition: All BCBs corresponding to those spans have been given +/// coverage counters. +fn create_mappings<'tcx>( + tcx: TyCtxt<'tcx>, + hir_info: &ExtractedHirInfo, + coverage_spans: &CoverageSpans, + coverage_counters: &CoverageCounters, +) -> Vec { + let source_map = tcx.sess.source_map(); + let body_span = hir_info.body_span; + + let source_file = source_map.lookup_source_file(body_span.lo()); + use rustc_session::RemapFileNameExt; + let file_name = Symbol::intern(&source_file.name.for_codegen(tcx.sess).to_string_lossy()); + + let term_for_bcb = |bcb| { + coverage_counters + .bcb_counter(bcb) + .expect("all BCBs with spans were given counters") + .as_term() + }; - self.mir_body.function_coverage_info = Some(Box::new(FunctionCoverageInfo { - function_source_hash: self.hir_info.function_source_hash, - num_counters: coverage_counters.num_counters(), - expressions: coverage_counters.into_expressions(), - mappings, - })); - } + coverage_spans + .all_bcb_mappings() + .filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| { + let kind = match bcb_mapping_kind { + BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)), + }; + let code_region = make_code_region(source_map, file_name, span, body_span)?; + Some(Mapping { kind, code_region }) + }) + .collect::>() +} - /// For each coverage span extracted from MIR, create a corresponding - /// mapping. - /// - /// Precondition: All BCBs corresponding to those spans have been given - /// coverage counters. - fn create_mappings( - &self, - coverage_spans: &CoverageSpans, - coverage_counters: &CoverageCounters, - ) -> Vec { - let source_map = self.tcx.sess.source_map(); - let body_span = self.hir_info.body_span; - - let source_file = source_map.lookup_source_file(body_span.lo()); - use rustc_session::RemapFileNameExt; - let file_name = - Symbol::intern(&source_file.name.for_codegen(self.tcx.sess).to_string_lossy()); - - let term_for_bcb = |bcb| { - coverage_counters - .bcb_counter(bcb) - .expect("all BCBs with spans were given counters") - .as_term() +/// For each BCB node or BCB edge that has an associated coverage counter, +/// inject any necessary coverage statements into MIR. +fn inject_coverage_statements<'tcx>( + mir_body: &mut mir::Body<'tcx>, + basic_coverage_blocks: &CoverageGraph, + bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, + coverage_counters: &CoverageCounters, +) { + // Process the counters associated with BCB nodes. + for (bcb, counter_kind) in coverage_counters.bcb_node_counters() { + let do_inject = match counter_kind { + // Counter-increment statements always need to be injected. + BcbCounter::Counter { .. } => true, + // The only purpose of expression-used statements is to detect + // when a mapping is unreachable, so we only inject them for + // expressions with one or more mappings. + BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb), }; - - coverage_spans - .all_bcb_mappings() - .filter_map(|&BcbMapping { kind: bcb_mapping_kind, span }| { - let kind = match bcb_mapping_kind { - BcbMappingKind::Code(bcb) => MappingKind::Code(term_for_bcb(bcb)), - }; - let code_region = make_code_region(source_map, file_name, span, body_span)?; - Some(Mapping { kind, code_region }) - }) - .collect::>() + if do_inject { + inject_statement( + mir_body, + make_mir_coverage_kind(counter_kind), + basic_coverage_blocks[bcb].leader_bb(), + ); + } } - /// For each BCB node or BCB edge that has an associated coverage counter, - /// inject any necessary coverage statements into MIR. - fn inject_coverage_statements( - &mut self, - bcb_has_coverage_spans: impl Fn(BasicCoverageBlock) -> bool, - coverage_counters: &CoverageCounters, - ) { - // Process the counters associated with BCB nodes. - for (bcb, counter_kind) in coverage_counters.bcb_node_counters() { - let do_inject = match counter_kind { - // Counter-increment statements always need to be injected. - BcbCounter::Counter { .. } => true, - // The only purpose of expression-used statements is to detect - // when a mapping is unreachable, so we only inject them for - // expressions with one or more mappings. - BcbCounter::Expression { .. } => bcb_has_coverage_spans(bcb), - }; - if do_inject { - inject_statement( - self.mir_body, - self.make_mir_coverage_kind(counter_kind), - self.basic_coverage_blocks[bcb].leader_bb(), - ); - } + // Process the counters associated with BCB edges. + for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() { + let do_inject = match counter_kind { + // Counter-increment statements always need to be injected. + BcbCounter::Counter { .. } => true, + // BCB-edge expressions never have mappings, so they never need + // a corresponding statement. + BcbCounter::Expression { .. } => false, + }; + if !do_inject { + continue; } - // Process the counters associated with BCB edges. - for (from_bcb, to_bcb, counter_kind) in coverage_counters.bcb_edge_counters() { - let do_inject = match counter_kind { - // Counter-increment statements always need to be injected. - BcbCounter::Counter { .. } => true, - // BCB-edge expressions never have mappings, so they never need - // a corresponding statement. - BcbCounter::Expression { .. } => false, - }; - if !do_inject { - continue; - } + // We need to inject a coverage statement into a new BB between the + // last BB of `from_bcb` and the first BB of `to_bcb`. + let from_bb = basic_coverage_blocks[from_bcb].last_bb(); + let to_bb = basic_coverage_blocks[to_bcb].leader_bb(); - // We need to inject a coverage statement into a new BB between the - // last BB of `from_bcb` and the first BB of `to_bcb`. - let from_bb = self.basic_coverage_blocks[from_bcb].last_bb(); - let to_bb = self.basic_coverage_blocks[to_bcb].leader_bb(); - - let new_bb = inject_edge_counter_basic_block(self.mir_body, from_bb, to_bb); - debug!( - "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \ + let new_bb = inject_edge_counter_basic_block(mir_body, from_bb, to_bb); + debug!( + "Edge {from_bcb:?} (last {from_bb:?}) -> {to_bcb:?} (leader {to_bb:?}) \ requires a new MIR BasicBlock {new_bb:?} for edge counter {counter_kind:?}", - ); + ); - // Inject a counter into the newly-created BB. - inject_statement(self.mir_body, self.make_mir_coverage_kind(counter_kind), new_bb); - } + // Inject a counter into the newly-created BB. + inject_statement(mir_body, make_mir_coverage_kind(counter_kind), new_bb); } +} - fn make_mir_coverage_kind(&self, counter_kind: &BcbCounter) -> CoverageKind { - match *counter_kind { - BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id }, - BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id }, - } +fn make_mir_coverage_kind(counter_kind: &BcbCounter) -> CoverageKind { + match *counter_kind { + BcbCounter::Counter { id } => CoverageKind::CounterIncrement { id }, + BcbCounter::Expression { id } => CoverageKind::ExpressionUsed { id }, } } From 572d7e9e69ca85c7a11e8730d9e4921d59691800 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 24 Jan 2024 12:40:31 +1100 Subject: [PATCH 19/20] coverage: Flatten the functions for extracting/refining coverage spans Consolidating this code into flatter functions reduces the amount of pointer-chasing required to read and modify it. --- .../rustc_mir_transform/src/coverage/mod.rs | 2 +- .../rustc_mir_transform/src/coverage/spans.rs | 119 +++++++----------- .../src/coverage/spans/from_mir.rs | 6 + 3 files changed, 53 insertions(+), 74 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs index d40b625be88a2..59a83e8d3568d 100644 --- a/compiler/rustc_mir_transform/src/coverage/mod.rs +++ b/compiler/rustc_mir_transform/src/coverage/mod.rs @@ -73,7 +73,7 @@ fn instrument_function_for_coverage<'tcx>(tcx: TyCtxt<'tcx>, mir_body: &mut mir: //////////////////////////////////////////////////// // Compute coverage spans from the `CoverageGraph`. let Some(coverage_spans) = - CoverageSpans::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks) + spans::generate_coverage_spans(mir_body, &hir_info, &basic_coverage_blocks) else { // No relevant spans were found in MIR, so skip instrumenting this function. return; diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 81f6c8312061b..dee6a3b7143f5 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -26,45 +26,6 @@ pub(super) struct CoverageSpans { } impl CoverageSpans { - /// Extracts coverage-relevant spans from MIR, and associates them with - /// their corresponding BCBs. - /// - /// Returns `None` if no coverage-relevant spans could be extracted. - pub(super) fn generate_coverage_spans( - mir_body: &mir::Body<'_>, - hir_info: &ExtractedHirInfo, - basic_coverage_blocks: &CoverageGraph, - ) -> Option { - let mut mappings = vec![]; - - let coverage_spans = CoverageSpansGenerator::generate_coverage_spans( - mir_body, - hir_info, - basic_coverage_blocks, - ); - mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| { - // Each span produced by the generator represents an ordinary code region. - BcbMapping { kind: BcbMappingKind::Code(bcb), span } - })); - - if mappings.is_empty() { - return None; - } - - // Identify which BCBs have one or more mappings. - let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - let mut insert = |bcb| { - bcb_has_mappings.insert(bcb); - }; - for &BcbMapping { kind, span: _ } in &mappings { - match kind { - BcbMappingKind::Code(bcb) => insert(bcb), - } - } - - Some(Self { bcb_has_mappings, mappings }) - } - pub(super) fn bcb_has_coverage_spans(&self, bcb: BasicCoverageBlock) -> bool { self.bcb_has_mappings.contains(bcb) } @@ -74,6 +35,43 @@ impl CoverageSpans { } } +/// Extracts coverage-relevant spans from MIR, and associates them with +/// their corresponding BCBs. +/// +/// Returns `None` if no coverage-relevant spans could be extracted. +pub(super) fn generate_coverage_spans( + mir_body: &mir::Body<'_>, + hir_info: &ExtractedHirInfo, + basic_coverage_blocks: &CoverageGraph, +) -> Option { + let mut mappings = vec![]; + + let sorted_spans = + from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks); + let coverage_spans = SpansRefiner::refine_sorted_spans(basic_coverage_blocks, sorted_spans); + mappings.extend(coverage_spans.into_iter().map(|CoverageSpan { bcb, span, .. }| { + // Each span produced by the generator represents an ordinary code region. + BcbMapping { kind: BcbMappingKind::Code(bcb), span } + })); + + if mappings.is_empty() { + return None; + } + + // Identify which BCBs have one or more mappings. + let mut bcb_has_mappings = BitSet::new_empty(basic_coverage_blocks.num_nodes()); + let mut insert = |bcb| { + bcb_has_mappings.insert(bcb); + }; + for &BcbMapping { kind, span: _ } in &mappings { + match kind { + BcbMappingKind::Code(bcb) => insert(bcb), + } + } + + Some(CoverageSpans { bcb_has_mappings, mappings }) +} + /// A BCB is deconstructed into one or more `Span`s. Each `Span` maps to a `CoverageSpan` that /// references the originating BCB and one or more MIR `Statement`s and/or `Terminator`s. /// Initially, the `Span`s come from the `Statement`s and `Terminator`s, but subsequent @@ -130,7 +128,7 @@ impl CoverageSpan { /// * Merge spans that represent continuous (both in source code and control flow), non-branching /// execution /// * Carve out (leave uncovered) any span that will be counted by another MIR (notably, closures) -struct CoverageSpansGenerator<'a> { +struct SpansRefiner<'a> { /// The BasicCoverageBlock Control Flow Graph (BCB CFG). basic_coverage_blocks: &'a CoverageGraph, @@ -173,40 +171,15 @@ struct CoverageSpansGenerator<'a> { refined_spans: Vec, } -impl<'a> CoverageSpansGenerator<'a> { - /// Generate a minimal set of `CoverageSpan`s, each representing a contiguous code region to be - /// counted. - /// - /// The basic steps are: - /// - /// 1. Extract an initial set of spans from the `Statement`s and `Terminator`s of each - /// `BasicCoverageBlockData`. - /// 2. Sort the spans by span.lo() (starting position). Spans that start at the same position - /// are sorted with longer spans before shorter spans; and equal spans are sorted - /// (deterministically) based on "dominator" relationship (if any). - /// 3. Traverse the spans in sorted order to identify spans that can be dropped (for instance, - /// if another span or spans are already counting the same code region), or should be merged - /// into a broader combined span (because it represents a contiguous, non-branching, and - /// uninterrupted region of source code). - /// - /// Closures are exposed in their enclosing functions as `Assign` `Rvalue`s, and since - /// closures have their own MIR, their `Span` in their enclosing function should be left - /// "uncovered". - /// - /// Note the resulting vector of `CoverageSpan`s may not be fully sorted (and does not need - /// to be). - pub(super) fn generate_coverage_spans( - mir_body: &mir::Body<'_>, - hir_info: &ExtractedHirInfo, +impl<'a> SpansRefiner<'a> { + /// Takes the initial list of (sorted) spans extracted from MIR, and "refines" + /// them by merging compatible adjacent spans, removing redundant spans, + /// and carving holes in spans when they overlap in unwanted ways. + fn refine_sorted_spans( basic_coverage_blocks: &'a CoverageGraph, + sorted_spans: Vec, ) -> Vec { - let sorted_spans = from_mir::mir_to_initial_sorted_coverage_spans( - mir_body, - hir_info, - basic_coverage_blocks, - ); - - let coverage_spans = Self { + let this = Self { basic_coverage_blocks, sorted_spans_iter: sorted_spans.into_iter(), some_curr: None, @@ -217,7 +190,7 @@ impl<'a> CoverageSpansGenerator<'a> { refined_spans: Vec::with_capacity(basic_coverage_blocks.num_nodes() * 2), }; - coverage_spans.to_refined_spans() + this.to_refined_spans() } /// Iterate through the sorted `CoverageSpan`s, and return the refined list of merged and diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 1b6dfccd57495..8d8e8e6132743 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -12,6 +12,12 @@ use crate::coverage::graph::{ use crate::coverage::spans::CoverageSpan; use crate::coverage::ExtractedHirInfo; +/// Traverses the MIR body to produce an initial collection of coverage-relevant +/// spans, each associated with a node in the coverage graph (BCB) and possibly +/// other metadata. +/// +/// The returned spans are sorted in a specific order that is expected by the +/// subsequent span-refinement step. pub(super) fn mir_to_initial_sorted_coverage_spans( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, From 64f590a50d0fed4a7267076d73bf9f3dcd71aff2 Mon Sep 17 00:00:00 2001 From: Urgau Date: Mon, 22 Jan 2024 12:08:48 +0100 Subject: [PATCH 20/20] Assert that a single scope is passed to `for_scope` --- compiler/rustc_session/src/session.rs | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index cba6ce0d235ea..c26a8467b6adb 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1523,16 +1523,25 @@ pub trait RemapFileNameExt { where Self: 'a; - fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_>; + /// Returns a possibly remapped filename based on the passed scope and remap cli options. + /// + /// One and only one scope should be passed to this method. For anything related to + /// "codegen" see the [`RemapFileNameExt::for_codegen`] method. + fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_>; + /// Return a possibly remapped filename, to be used in "codegen" related parts. fn for_codegen(&self, sess: &Session) -> Self::Output<'_>; } impl RemapFileNameExt for rustc_span::FileName { type Output<'a> = rustc_span::FileNameDisplay<'a>; - fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_> { - if sess.opts.unstable_opts.remap_path_scope.contains(scopes) { + fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_> { + assert!( + scope.bits().count_ones() == 1, + "one and only one scope should be passed to for_scope" + ); + if sess.opts.unstable_opts.remap_path_scope.contains(scope) { self.prefer_remapped_unconditionaly() } else { self.prefer_local() @@ -1551,8 +1560,12 @@ impl RemapFileNameExt for rustc_span::FileName { impl RemapFileNameExt for rustc_span::RealFileName { type Output<'a> = &'a Path; - fn for_scope(&self, sess: &Session, scopes: RemapPathScopeComponents) -> Self::Output<'_> { - if sess.opts.unstable_opts.remap_path_scope.contains(scopes) { + fn for_scope(&self, sess: &Session, scope: RemapPathScopeComponents) -> Self::Output<'_> { + assert!( + scope.bits().count_ones() == 1, + "one and only one scope should be passed to for_scope" + ); + if sess.opts.unstable_opts.remap_path_scope.contains(scope) { self.remapped_path_if_available() } else { self.local_path_if_available()