From 8a195efa1e38021dd4a83d884861b5822bb6afc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 7 Jul 2025 23:06:18 +0200 Subject: [PATCH 01/16] Make it possible to attach opaque string metadata to `StepMetadata` --- src/bootstrap/src/core/builder/mod.rs | 9 ++++++++- src/bootstrap/src/core/builder/tests.rs | 5 ++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index b96a988cde3f..72e5728f2c2b 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -146,6 +146,8 @@ pub struct StepMetadata { target: TargetSelection, built_by: Option, stage: Option, + /// Additional opaque string printed in the metadata + metadata: Option, } impl StepMetadata { @@ -170,7 +172,7 @@ pub fn test(name: &'static str, target: TargetSelection) -> Self { } fn new(name: &'static str, target: TargetSelection, kind: Kind) -> Self { - Self { name, kind, target, built_by: None, stage: None } + Self { name, kind, target, built_by: None, stage: None, metadata: None } } pub fn built_by(mut self, compiler: Compiler) -> Self { @@ -183,6 +185,11 @@ pub fn stage(mut self, stage: u32) -> Self { self } + pub fn with_metadata(mut self, metadata: String) -> Self { + self.metadata = Some(metadata); + self + } + pub fn get_stage(&self) -> Option { self.stage.or(self .built_by diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 1d5690a81971..9433e15f6ffa 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1587,7 +1587,7 @@ fn contains_fuzzy(&self, metadata: &StepMetadata) -> bool { } fn fuzzy_metadata_eq(executed: &StepMetadata, to_match: &StepMetadata) -> bool { - let StepMetadata { name, kind, target, built_by: _, stage: _ } = executed; + let StepMetadata { name, kind, target, built_by: _, stage: _, metadata } = executed; *name == to_match.name && *kind == to_match.kind && *target == to_match.target } @@ -1648,6 +1648,9 @@ fn render_metadata(metadata: &StepMetadata) -> String { } let stage = metadata.get_stage().map(|stage| format!("{stage} ")).unwrap_or_default(); write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target)); + if let Some(metadata) = &metadata.metadata { + write!(record, " {metadata}"); + } record } From 8d0c55cb6b39f3c7b1931ccd739dece821a4ced2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 7 Jul 2025 23:08:33 +0200 Subject: [PATCH 02/16] Remove test hack for std crates --- src/bootstrap/src/core/build_steps/compile.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 3e2bdc2d6b5a..6dec950266d4 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -451,11 +451,6 @@ fn copy_self_contained_objects( /// Resolves standard library crates for `Std::run_make` for any build kind (like check, build, clippy, etc.). pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec { - // FIXME: Extend builder tests to cover the `crates` field of `Std` instances. - if cfg!(test) { - return vec![]; - } - let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false); From 5880a3196be4137e2b70bcc5d432dea20155fc13 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 7 Jul 2025 23:11:18 +0200 Subject: [PATCH 03/16] Add `crates` metadata to `doc::Std` step --- src/bootstrap/src/core/build_steps/doc.rs | 6 +++- src/bootstrap/src/core/builder/tests.rs | 38 +++++++++++------------ 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index f7c4c5ad0bbd..48dde4aae68a 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -665,7 +665,11 @@ fn run(self, builder: &Builder<'_>) { } fn metadata(&self) -> Option { - Some(StepMetadata::doc("std", self.target).stage(self.stage)) + Some( + StepMetadata::doc("std", self.target) + .stage(self.stage) + .with_metadata(format!("crates=[{}]", self.crates.join(","))), + ) } } diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 9433e15f6ffa..3d889729f90e 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -942,7 +942,7 @@ fn alias_and_path_for_library() { [build] llvm [build] rustc 0 -> rustc 1 [build] rustdoc 0 - [doc] std 1 + [doc] std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] "); } @@ -991,12 +991,12 @@ fn dist_baseline() { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustdoc 1 - [doc] std 2 + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 0 -> RustInstaller 1 [dist] docs - [doc] std 2 + [doc] std 2 crates=[] [dist] mingw [build] rustc 0 -> GenerateCopyright 1 [dist] rustc @@ -1023,12 +1023,12 @@ fn dist_extended() { [build] rustc 1 -> rustc 2 [build] rustc 1 -> WasmComponentLd 2 [build] rustdoc 1 - [doc] std 2 + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 0 -> RustInstaller 1 [dist] docs - [doc] std 2 + [doc] std 2 crates=[] [dist] mingw [build] rustc 0 -> GenerateCopyright 1 [dist] rustc @@ -1059,15 +1059,15 @@ fn dist_with_targets() { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustdoc 1 - [doc] std 2 - [doc] std 2 + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 0 -> RustInstaller 1 [dist] docs [dist] docs - [doc] std 2 - [doc] std 2 + [doc] std 2 crates=[] + [doc] std 2 crates=[] [dist] mingw [dist] mingw [build] rustc 0 -> GenerateCopyright 1 @@ -1096,14 +1096,14 @@ fn dist_with_hosts() { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustdoc 1 - [doc] std 2 + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 1 -> std 1 [build] rustc 2 -> std 2 [build] rustc 0 -> RustInstaller 1 [dist] docs - [doc] std 2 + [doc] std 2 crates=[] [dist] mingw [build] rustc 0 -> GenerateCopyright 1 [dist] rustc @@ -1133,8 +1133,8 @@ fn dist_with_targets_and_hosts() { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustdoc 1 - [doc] std 2 - [doc] std 2 + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 1 -> std 1 @@ -1142,8 +1142,8 @@ fn dist_with_targets_and_hosts() { [build] rustc 0 -> RustInstaller 1 [dist] docs [dist] docs - [doc] std 2 - [doc] std 2 + [doc] std 2 crates=[] + [doc] std 2 crates=[] [dist] mingw [dist] mingw [build] rustc 0 -> GenerateCopyright 1 @@ -1175,11 +1175,11 @@ fn dist_with_empty_host() { [build] rustc 1 -> std 1 [build] rustc 1 -> rustc 2 [build] rustdoc 1 - [doc] std 2 + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 0 -> RustInstaller 1 [dist] docs - [doc] std 2 + [doc] std 2 crates=[] [dist] mingw [build] rustc 2 -> std 2 [dist] rustc 2 -> std 2 @@ -1207,14 +1207,14 @@ fn dist_all_cross() { [build] rustc 1 -> rustc 2 [build] rustc 1 -> WasmComponentLd 2 [build] rustdoc 1 - [doc] std 2 + [doc] std 2 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] [build] rustc 2 -> std 2 [build] rustc 1 -> std 1 [build] rustc 2 -> std 2 [build] rustc 0 -> LintDocs 1 [build] rustc 0 -> RustInstaller 1 [dist] docs - [doc] std 2 + [doc] std 2 crates=[] [dist] mingw [build] llvm [build] rustc 1 -> rustc 2 From d6bc881afb69047afb32a23664be6ffa75219f1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Mon, 7 Jul 2025 23:31:03 +0200 Subject: [PATCH 04/16] Fix handling of std crates for no_std targets --- src/bootstrap/src/core/build_steps/compile.rs | 25 ++--- src/bootstrap/src/core/builder/tests.rs | 94 +++++++++++++++---- src/bootstrap/src/utils/tests/mod.rs | 28 +++--- 3 files changed, 106 insertions(+), 41 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 6dec950266d4..caf2d83d213f 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -449,21 +449,24 @@ fn copy_self_contained_objects( target_deps } -/// Resolves standard library crates for `Std::run_make` for any build kind (like check, build, clippy, etc.). +/// Resolves standard library crates for `Std::run_make` for any build kind (like check, doc, +/// build, clippy, etc.). pub fn std_crates_for_run_make(run: &RunConfig<'_>) -> Vec { - let has_alias = run.paths.iter().any(|set| set.assert_single_path().path.ends_with("library")); - let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false); + let mut crates = run.make_run_crates(builder::Alias::Library); - // For no_std targets, do not add any additional crates to the compilation other than what `compile::std_cargo` already adds for no_std targets. + // For no_std targets, we only want to check core and alloc + // Regardless of core/alloc being selected explicitly or via the "library" default alias, + // we only want to keep these two crates. + // The set of no_std crates should be kept in sync with what `Builder::std_cargo` does. + // Note: an alternative design would be to return an enum from this function (Default vs Subset) + // of crates. However, several steps currently pass `-p ` even if all crates are + // selected, because Cargo behaves differently in that case. To keep that behavior without + // making further changes, we pre-filter the no-std crates here. + let target_is_no_std = run.builder.no_std(run.target).unwrap_or(false); if target_is_no_std { - vec![] - } - // If the paths include "library", build the entire standard library. - else if has_alias { - run.make_run_crates(builder::Alias::Library) - } else { - run.cargo_crates_in_set() + crates.retain(|c| c == "core" || c == "alloc"); } + crates } /// Tries to find LLVM's `compiler-rt` source directory, for building `library/profiler_builtins`. diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 3d889729f90e..b1e8150a20f8 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -637,8 +637,8 @@ mod snapshot { use crate::core::build_steps::{compile, dist, doc, test, tool}; use crate::core::builder::tests::{ - TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, configure, configure_with_args, first, - host_target, render_steps, run_build, + RenderConfig, TEST_TRIPLE_1, TEST_TRIPLE_2, TEST_TRIPLE_3, configure, configure_with_args, + first, host_target, render_steps, run_build, }; use crate::core::builder::{Builder, Kind, StepDescription, StepMetadata}; use crate::core::config::TargetSelection; @@ -1521,6 +1521,49 @@ fn test_exclude_kind() { steps.assert_contains(StepMetadata::test("CrateLibrustc", host)); steps.assert_contains_fuzzy(StepMetadata::build("rustc", host)); } + + #[test] + fn doc_library() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("doc") + .path("library") + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 0 + [doc] std 1 crates=[alloc,compiler_builtins,core,panic_abort,panic_unwind,proc_macro,std,sysroot,test,unwind] + "); + } + + #[test] + fn doc_core() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("doc") + .path("core") + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 0 + [doc] std 1 crates=[core] + "); + } + + #[test] + fn doc_library_no_std_target() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("doc") + .path("core") + .override_target_no_std(&host_target()) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 0 + [doc] std 1 crates=[core] + "); + } } struct ExecutedSteps { @@ -1529,7 +1572,10 @@ struct ExecutedSteps { impl ExecutedSteps { fn render(&self) -> String { - render_steps(&self.steps) + self.render_with(RenderConfig::default()) + } + fn render_with(&self, config: RenderConfig) -> String { + render_steps(&self.steps, config) } #[track_caller] @@ -1538,7 +1584,7 @@ fn assert_contains>(&self, metadata: M) { if !self.contains(&metadata) { panic!( "Metadata `{}` ({metadata:?}) not found in executed steps:\n{}", - render_metadata(&metadata), + render_metadata(&metadata, &RenderConfig::default()), self.render() ); } @@ -1553,7 +1599,7 @@ fn assert_contains_fuzzy>(&self, metadata: M) { if !self.contains_fuzzy(&metadata) { panic!( "Metadata `{}` ({metadata:?}) not found in executed steps:\n{}", - render_metadata(&metadata), + render_metadata(&metadata, &RenderConfig::default()), self.render() ); } @@ -1565,7 +1611,7 @@ fn assert_not_contains>(&self, metadata: M) { if self.contains(&metadata) { panic!( "Metadata `{}` ({metadata:?}) found in executed steps (it should not be there):\n{}", - render_metadata(&metadata), + render_metadata(&metadata, &RenderConfig::default()), self.render() ); } @@ -1618,6 +1664,16 @@ fn render_steps(self) -> String { } } +struct RenderConfig { + normalize_host: bool, +} + +impl Default for RenderConfig { + fn default() -> Self { + Self { normalize_host: true } + } +} + /// Renders the executed bootstrap steps for usage in snapshot tests with insta. /// Only renders certain important steps. /// Each value in `steps` should be a tuple of (Step, step output). @@ -1625,7 +1681,7 @@ fn render_steps(self) -> String { /// The arrow in the rendered output (`X -> Y`) means `X builds Y`. /// This is similar to the output printed by bootstrap to stdout, but here it is /// generated purely for the purpose of tests. -fn render_steps(steps: &[ExecutedStep]) -> String { +fn render_steps(steps: &[ExecutedStep], config: RenderConfig) -> String { steps .iter() .filter_map(|step| { @@ -1635,35 +1691,35 @@ fn render_steps(steps: &[ExecutedStep]) -> String { return None; }; - Some(render_metadata(&metadata)) + Some(render_metadata(&metadata, &config)) }) .collect::>() .join("\n") } -fn render_metadata(metadata: &StepMetadata) -> String { +fn render_metadata(metadata: &StepMetadata, config: &RenderConfig) -> String { let mut record = format!("[{}] ", metadata.kind.as_str()); if let Some(compiler) = metadata.built_by { - write!(record, "{} -> ", render_compiler(compiler)); + write!(record, "{} -> ", render_compiler(compiler, config)); } let stage = metadata.get_stage().map(|stage| format!("{stage} ")).unwrap_or_default(); - write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target)); + write!(record, "{} {stage}<{}>", metadata.name, normalize_target(metadata.target, config)); if let Some(metadata) = &metadata.metadata { write!(record, " {metadata}"); } record } -fn normalize_target(target: TargetSelection) -> String { - target - .to_string() - .replace(&host_target(), "host") - .replace(TEST_TRIPLE_1, "target1") - .replace(TEST_TRIPLE_2, "target2") +fn normalize_target(target: TargetSelection, config: &RenderConfig) -> String { + let mut target = target.to_string(); + if config.normalize_host { + target = target.replace(&host_target(), "host"); + } + target.replace(TEST_TRIPLE_1, "target1").replace(TEST_TRIPLE_2, "target2") } -fn render_compiler(compiler: Compiler) -> String { - format!("rustc {} <{}>", compiler.stage, normalize_target(compiler.host)) +fn render_compiler(compiler: Compiler, config: &RenderConfig) -> String { + format!("rustc {} <{}>", compiler.stage, normalize_target(compiler.host, config)) } fn host_target() -> String { diff --git a/src/bootstrap/src/utils/tests/mod.rs b/src/bootstrap/src/utils/tests/mod.rs index 59c169b0f2b7..0e516b452685 100644 --- a/src/bootstrap/src/utils/tests/mod.rs +++ b/src/bootstrap/src/utils/tests/mod.rs @@ -48,17 +48,30 @@ fn from_args(args: &[&str], directory: PathBuf) -> Self { } pub fn path(mut self, path: &str) -> Self { - self.args.push(path.to_string()); - self + self.arg(path) } pub fn paths(mut self, paths: &[&str]) -> Self { - for path in paths { - self = self.path(path); + self.args(paths) + } + + pub fn arg(mut self, arg: &str) -> Self { + self.args.push(arg.to_string()); + self + } + + pub fn args(mut self, args: &[&str]) -> Self { + for arg in args { + self = self.arg(arg); } self } + /// Set the specified target to be treated as a no_std target. + pub fn override_target_no_std(mut self, target: &str) -> Self { + self.args(&["--set", &format!("target.{target}.no-std=true")]) + } + pub fn hosts(mut self, targets: &[&str]) -> Self { self.args.push("--host".to_string()); self.args.push(targets.join(",")); @@ -77,13 +90,6 @@ pub fn stage(mut self, stage: u32) -> Self { self } - pub fn args(mut self, args: &[&str]) -> Self { - for arg in args { - self.args.push(arg.to_string()); - } - self - } - pub fn create_config(mut self) -> Config { // Run in dry-check, otherwise the test would be too slow self.args.push("--dry-run".to_string()); From 045557797431bfff807145341efbe8f8fb08817e Mon Sep 17 00:00:00 2001 From: Dillon Amburgey Date: Tue, 8 Jul 2025 06:17:03 -0500 Subject: [PATCH 05/16] fix: correct parameter names in LLVMRustBuildMinNum and LLVMRustBuildMaxNum FFI declarations --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 91ada856d597..b9dd10ff014f 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1980,12 +1980,12 @@ pub(crate) fn LLVMRustBuildVectorReduceFMax<'a>( pub(crate) fn LLVMRustBuildMinNum<'a>( B: &Builder<'a>, LHS: &'a Value, - LHS: &'a Value, + RHS: &'a Value, ) -> &'a Value; pub(crate) fn LLVMRustBuildMaxNum<'a>( B: &Builder<'a>, LHS: &'a Value, - LHS: &'a Value, + RHS: &'a Value, ) -> &'a Value; // Atomic Operations From 543c860ea6c78e77b0a12685e066a74fe26dc301 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 3 Jul 2025 09:14:56 +0000 Subject: [PATCH 06/16] Constify `Fn*` traits --- compiler/rustc_hir_typeck/src/upvar.rs | 6 +- .../src/traits/effects.rs | 54 +++++- library/core/src/ops/function.rs | 34 ++-- tests/ui/consts/fn_trait_refs.stderr | 175 +----------------- .../unstable-const-fn-in-libcore.stderr | 32 +--- .../impl-trait/normalize-tait-in-const.stderr | 32 +--- tests/ui/traits/const-traits/call.rs | 2 +- tests/ui/traits/const-traits/call.stderr | 7 +- .../const-closure-parse-not-item.stderr | 32 +--- .../const-closure-trait-method-fail.stderr | 33 +--- .../const-closure-trait-method.rs | 5 +- .../const-closure-trait-method.stderr | 30 --- .../ui/traits/const-traits/const-closures.rs | 5 +- .../traits/const-traits/const-closures.stderr | 103 ----------- ...nst_closure-const_trait_impl-ice-113381.rs | 5 +- ...closure-const_trait_impl-ice-113381.stderr | 12 +- .../ice-112822-expected-type-for-param.rs | 6 +- .../ice-112822-expected-type-for-param.stderr | 46 +---- .../ice-123664-unexpected-bound-var.rs | 8 - .../ice-123664-unexpected-bound-var.stderr | 21 --- ...-const-op-const-closure-non-const-outer.rs | 2 +- ...st-op-const-closure-non-const-outer.stderr | 10 +- 22 files changed, 128 insertions(+), 532 deletions(-) delete mode 100644 tests/ui/traits/const-traits/const-closure-trait-method.stderr delete mode 100644 tests/ui/traits/const-traits/const-closures.stderr delete mode 100644 tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs delete mode 100644 tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 982cfa2e42be..be774106abf8 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -529,7 +529,11 @@ fn analyze_closure( // process any deferred resolutions. let deferred_call_resolutions = self.remove_deferred_call_resolutions(closure_def_id); for deferred_call_resolution in deferred_call_resolutions { - deferred_call_resolution.resolve(self); + deferred_call_resolution.resolve(&mut FnCtxt::new( + self, + self.param_env, + closure_def_id, + )); } } diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index 176d308de913..d24f861723b5 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -1,7 +1,8 @@ use rustc_hir::{self as hir, LangItem}; use rustc_infer::infer::{BoundRegionConversionTime, DefineOpaqueTypes}; use rustc_infer::traits::{ - ImplDerivedHostCause, ImplSource, Obligation, ObligationCauseCode, PredicateObligation, + ImplDerivedHostCause, ImplSource, Obligation, ObligationCause, ObligationCauseCode, + PredicateObligation, }; use rustc_middle::span_bug; use rustc_middle::traits::query::NoSolution; @@ -303,6 +304,9 @@ fn evaluate_host_effect_from_builtin_impls<'tcx>( ) -> Result>, EvaluationFailure> { match selcx.tcx().as_lang_item(obligation.predicate.def_id()) { Some(LangItem::Destruct) => evaluate_host_effect_for_destruct_goal(selcx, obligation), + Some(LangItem::Fn | LangItem::FnMut | LangItem::FnOnce) => { + evaluate_host_effect_for_fn_goal(selcx, obligation) + } _ => Err(EvaluationFailure::NoSolution), } } @@ -398,6 +402,54 @@ fn evaluate_host_effect_for_destruct_goal<'tcx>( .collect()) } +// NOTE: Keep this in sync with `extract_fn_def_from_const_callable` in the new solver. +fn evaluate_host_effect_for_fn_goal<'tcx>( + selcx: &mut SelectionContext<'_, 'tcx>, + obligation: &HostEffectObligation<'tcx>, +) -> Result>, EvaluationFailure> { + let tcx = selcx.tcx(); + let self_ty = obligation.predicate.self_ty(); + + let (def, args) = match *self_ty.kind() { + ty::FnDef(def, args) => (def, args), + + // We may support function pointers at some point in the future + ty::FnPtr(..) => return Err(EvaluationFailure::NoSolution), + + // Coroutines could implement `[const] Fn`, + // but they don't really need to right now. + ty::Closure(..) + | ty::CoroutineClosure(_, _) + | ty::Coroutine(_, _) + | ty::CoroutineWitness(_, _) => { + return Err(EvaluationFailure::NoSolution); + } + + // Everything else needs explicit impls or cannot have an impl + _ => return Err(EvaluationFailure::NoSolution), + }; + + match tcx.constness(def) { + hir::Constness::Const => Ok(tcx + .const_conditions(def) + .instantiate(tcx, args) + .into_iter() + .map(|(c, span)| { + let code = ObligationCauseCode::WhereClause(def, span); + let cause = + ObligationCause::new(obligation.cause.span, obligation.cause.body_id, code); + Obligation::new( + tcx, + cause, + obligation.param_env, + c.to_host_effect_clause(tcx, obligation.predicate.constness), + ) + }) + .collect()), + hir::Constness::NotConst => Err(EvaluationFailure::NoSolution), + } +} + fn evaluate_host_effect_from_selection_candidate<'tcx>( selcx: &mut SelectionContext<'_, 'tcx>, obligation: &HostEffectObligation<'tcx>, diff --git a/library/core/src/ops/function.rs b/library/core/src/ops/function.rs index df48c104410c..763b60d88e51 100644 --- a/library/core/src/ops/function.rs +++ b/library/core/src/ops/function.rs @@ -72,7 +72,8 @@ )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -// FIXME(const_trait_impl) #[const_trait] +#[const_trait] +#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] pub trait Fn: FnMut { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -159,7 +160,8 @@ pub trait Fn: FnMut { )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -// FIXME(const_trait_impl) #[const_trait] +#[const_trait] +#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] pub trait FnMut: FnOnce { /// Performs the call operation. #[unstable(feature = "fn_traits", issue = "29625")] @@ -238,7 +240,8 @@ pub trait FnMut: FnOnce { )] #[fundamental] // so that regex can rely that `&str: !FnMut` #[must_use = "closures are lazy and do nothing unless called"] -// FIXME(const_trait_impl) #[const_trait] +#[const_trait] +#[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] pub trait FnOnce { /// The returned type after the call operator is used. #[lang = "fn_once_output"] @@ -254,9 +257,10 @@ mod impls { use crate::marker::Tuple; #[stable(feature = "rust1", since = "1.0.0")] - impl Fn for &F + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl const Fn for &F where - F: Fn, + F: ~const Fn, { extern "rust-call" fn call(&self, args: A) -> F::Output { (**self).call(args) @@ -264,9 +268,10 @@ extern "rust-call" fn call(&self, args: A) -> F::Output { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnMut for &F + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl const FnMut for &F where - F: Fn, + F: ~const Fn, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (**self).call(args) @@ -274,9 +279,10 @@ extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnOnce for &F + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl const FnOnce for &F where - F: Fn, + F: ~const Fn, { type Output = F::Output; @@ -286,9 +292,10 @@ extern "rust-call" fn call_once(self, args: A) -> F::Output { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnMut for &mut F + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl const FnMut for &mut F where - F: FnMut, + F: ~const FnMut, { extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { (*self).call_mut(args) @@ -296,9 +303,10 @@ extern "rust-call" fn call_mut(&mut self, args: A) -> F::Output { } #[stable(feature = "rust1", since = "1.0.0")] - impl FnOnce for &mut F + #[rustc_const_unstable(feature = "const_trait_impl", issue = "67792")] + impl const FnOnce for &mut F where - F: FnMut, + F: ~const FnMut, { type Output = F::Output; extern "rust-call" fn call_once(self, args: A) -> F::Output { diff --git a/tests/ui/consts/fn_trait_refs.stderr b/tests/ui/consts/fn_trait_refs.stderr index 445dd75f8249..bbe0714801c4 100644 --- a/tests/ui/consts/fn_trait_refs.stderr +++ b/tests/ui/consts/fn_trait_refs.stderr @@ -4,151 +4,6 @@ error[E0635]: unknown feature `const_fn_trait_ref_impls` LL | #![feature(const_fn_trait_ref_impls)] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:14:8 - | -LL | T: [const] Fn<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:14:8 - | -LL | T: [const] Fn<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:14:8 - | -LL | T: [const] Fn<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:21:8 - | -LL | T: [const] FnMut<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `FnMut` - | -note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:21:8 - | -LL | T: [const] FnMut<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `FnMut` - | -note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:21:8 - | -LL | T: [const] FnMut<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `FnMut` - | -note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:28:8 - | -LL | T: [const] FnOnce<()>, - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:28:8 - | -LL | T: [const] FnOnce<()>, - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:28:8 - | -LL | T: [const] FnOnce<()>, - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:35:8 - | -LL | T: [const] Fn<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:35:8 - | -LL | T: [const] Fn<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:35:8 - | -LL | T: [const] Fn<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:49:8 - | -LL | T: [const] FnMut<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `FnMut` - | -note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:49:8 - | -LL | T: [const] FnMut<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `FnMut` - | -note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/fn_trait_refs.rs:49:8 - | -LL | T: [const] FnMut<()> + [const] Destruct, - | ^^^^^^^ can't be applied to `FnMut` - | -note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0277]: the trait bound `(i32, i32, i32): const PartialEq` is not satisfied --> $DIR/fn_trait_refs.rs:71:17 | @@ -161,31 +16,7 @@ error[E0277]: the trait bound `(i32, i32): const PartialEq` is not satisfied LL | assert!(test_two == (2, 2)); | ^^^^^^^^^^^^^^^^^^ -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/fn_trait_refs.rs:16:5 - | -LL | f() - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error: aborting due to 3 previous errors -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/fn_trait_refs.rs:23:5 - | -LL | f() - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/fn_trait_refs.rs:30:5 - | -LL | f() - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 21 previous errors - -Some errors have detailed explanations: E0015, E0277, E0635. -For more information about an error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0277, E0635. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/consts/unstable-const-fn-in-libcore.stderr b/tests/ui/consts/unstable-const-fn-in-libcore.stderr index 95e48b7b7c80..16db7791cd84 100644 --- a/tests/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/tests/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,30 +1,3 @@ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/unstable-const-fn-in-libcore.rs:19:32 - | -LL | const fn unwrap_or_else T>(self, f: F) -> T { - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/unstable-const-fn-in-libcore.rs:19:32 - | -LL | const fn unwrap_or_else T>(self, f: F) -> T { - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/unstable-const-fn-in-libcore.rs:24:26 - | -LL | Opt::None => f(), - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - error[E0493]: destructor of `F` cannot be evaluated at compile-time --> $DIR/unstable-const-fn-in-libcore.rs:19:61 | @@ -43,7 +16,6 @@ LL | const fn unwrap_or_else T>(self, f: F) -> T { LL | } | - value is dropped here -error: aborting due to 5 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0015, E0493. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0493`. diff --git a/tests/ui/impl-trait/normalize-tait-in-const.stderr b/tests/ui/impl-trait/normalize-tait-in-const.stderr index e17737d1860a..051eb62d9cb8 100644 --- a/tests/ui/impl-trait/normalize-tait-in-const.stderr +++ b/tests/ui/impl-trait/normalize-tait-in-const.stderr @@ -1,22 +1,3 @@ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:27:35 - | -LL | const fn with_positive [const] Fn(&'a Alias<'a>) + [const] Destruct>(fun: F) { - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/normalize-tait-in-const.rs:27:35 - | -LL | const fn with_positive [const] Fn(&'a Alias<'a>) + [const] Destruct>(fun: F) { - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error: unconstrained opaque type --> $DIR/normalize-tait-in-const.rs:14:26 | @@ -44,15 +25,6 @@ note: this item must have a `#[define_opaque(foo::Alias)]` attribute to be able LL | pub const fn filter_positive<'a>() -> &'a Alias<'a> { | ^^^^^^^^^^^^^^^ -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/normalize-tait-in-const.rs:28:5 - | -LL | fun(filter_positive()); - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +error: aborting due to 2 previous errors -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0015, E0308. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/traits/const-traits/call.rs b/tests/ui/traits/const-traits/call.rs index b985e3da3451..b1080fe78bb5 100644 --- a/tests/ui/traits/const-traits/call.rs +++ b/tests/ui/traits/const-traits/call.rs @@ -5,7 +5,7 @@ pub const _: () = { assert!((const || true)()); - //~^ ERROR cannot call non-const closure in constants + //~^ ERROR }: [const] Fn()` is not satisfied }; fn main() {} diff --git a/tests/ui/traits/const-traits/call.stderr b/tests/ui/traits/const-traits/call.stderr index e9bf64092f3b..8e32cab6dfcf 100644 --- a/tests/ui/traits/const-traits/call.stderr +++ b/tests/ui/traits/const-traits/call.stderr @@ -1,12 +1,9 @@ -error[E0015]: cannot call non-const closure in constants +error[E0277]: the trait bound `{closure@$DIR/call.rs:7:14: 7:22}: [const] Fn()` is not satisfied --> $DIR/call.rs:7:13 | LL | assert!((const || true)()); | ^^^^^^^^^^^^^^^^^ - | - = note: closures need an RFC before allowed to be called in constants - = note: calls in constants are limited to constant functions, tuple structs and tuple variants error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr index fdfe3b95d555..1d8d5ff1b4f2 100644 --- a/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr +++ b/tests/ui/traits/const-traits/const-closure-parse-not-item.stderr @@ -1,31 +1,9 @@ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-parse-not-item.rs:7:25 +error[E0277]: the trait bound `{closure@$DIR/const-closure-parse-not-item.rs:8:5: 8:18}: [const] Fn()` is not satisfied + --> $DIR/const-closure-parse-not-item.rs:7:20 | LL | const fn test() -> impl [const] Fn() { - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL + | ^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-parse-not-item.rs:7:25 - | -LL | const fn test() -> impl [const] Fn() { - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-parse-not-item.rs:7:25 - | -LL | const fn test() -> impl [const] Fn() { - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr index 89b202b34381..fddd8d10bccc 100644 --- a/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr +++ b/tests/ui/traits/const-traits/const-closure-trait-method-fail.stderr @@ -1,30 +1,9 @@ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-trait-method-fail.rs:14:32 +error[E0277]: the trait bound `(): const Tr` is not satisfied + --> $DIR/const-closure-trait-method-fail.rs:18:23 | -LL | const fn need_const_closure i32>(x: T) -> i32 { - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL +LL | const _: () = assert!(need_const_closure(Tr::a) == 42); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-trait-method-fail.rs:14:32 - | -LL | const fn need_const_closure i32>(x: T) -> i32 { - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: aborting due to 1 previous error -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closure-trait-method-fail.rs:15:5 - | -LL | x(()) - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.rs b/tests/ui/traits/const-traits/const-closure-trait-method.rs index 831d6e27946d..6477aa63c680 100644 --- a/tests/ui/traits/const-traits/const-closure-trait-method.rs +++ b/tests/ui/traits/const-traits/const-closure-trait-method.rs @@ -1,5 +1,6 @@ -//@ known-bug: #110395 -// FIXME check-pass +//@ check-pass +//@ revisions: next old +//@[next] compile-flags: -Znext-solver #![feature(const_trait_impl)] #[const_trait] diff --git a/tests/ui/traits/const-traits/const-closure-trait-method.stderr b/tests/ui/traits/const-traits/const-closure-trait-method.stderr deleted file mode 100644 index 6de25dc11ef5..000000000000 --- a/tests/ui/traits/const-traits/const-closure-trait-method.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-trait-method.rs:14:32 - | -LL | const fn need_const_closure i32>(x: T) -> i32 { - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closure-trait-method.rs:14:32 - | -LL | const fn need_const_closure i32>(x: T) -> i32 { - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closure-trait-method.rs:15:5 - | -LL | x(()) - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const-closures.rs b/tests/ui/traits/const-traits/const-closures.rs index 2f6f4dc4ba33..8f1c018ca5dd 100644 --- a/tests/ui/traits/const-traits/const-closures.rs +++ b/tests/ui/traits/const-traits/const-closures.rs @@ -1,5 +1,6 @@ -//@ known-bug: #110395 -// FIXME check-pass +//@ check-pass +//@ revisions: next old +//@[next] compile-flags: -Znext-solver #![feature(const_trait_impl)] diff --git a/tests/ui/traits/const-traits/const-closures.stderr b/tests/ui/traits/const-traits/const-closures.stderr deleted file mode 100644 index 19869b470852..000000000000 --- a/tests/ui/traits/const-traits/const-closures.stderr +++ /dev/null @@ -1,103 +0,0 @@ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:8:12 - | -LL | F: [const] FnOnce() -> u8, - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:9:12 - | -LL | F: [const] FnMut() -> u8, - | ^^^^^^^ can't be applied to `FnMut` - | -note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:10:12 - | -LL | F: [const] Fn() -> u8, - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:8:12 - | -LL | F: [const] FnOnce() -> u8, - | ^^^^^^^ can't be applied to `FnOnce` - | -note: `FnOnce` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:9:12 - | -LL | F: [const] FnMut() -> u8, - | ^^^^^^^ can't be applied to `FnMut` - | -note: `FnMut` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:10:12 - | -LL | F: [const] Fn() -> u8, - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:23:20 - | -LL | const fn answer u8>(f: &F) -> u8 { - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/const-closures.rs:23:20 - | -LL | const fn answer u8>(f: &F) -> u8 { - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closures.rs:24:5 - | -LL | f() + f() - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closures.rs:24:11 - | -LL | f() + f() - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error[E0015]: cannot call non-const closure in constant functions - --> $DIR/const-closures.rs:12:5 - | -LL | f() * 7 - | ^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - -error: aborting due to 11 previous errors - -For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs index 92427039b433..30002038f689 100644 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs +++ b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs @@ -1,3 +1,4 @@ +//@ known-bug: #110395 //@ compile-flags: -Znext-solver #![feature(const_closures, const_trait_impl)] #![allow(incomplete_features)] @@ -11,7 +12,7 @@ fn foo(&self) {} } fn main() { - (const || { (()).foo() })(); - //~^ ERROR: cannot call non-const method `<() as Foo>::foo` in constant functions + (const || (()).foo())(); + // ^ ERROR: cannot call non-const method `<() as Foo>::foo` in constant functions // FIXME(const_trait_impl) this should probably say constant closures } diff --git a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr index c08642ba5a31..dab3f14161fa 100644 --- a/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr +++ b/tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.stderr @@ -1,11 +1,9 @@ -error[E0015]: cannot call non-const method `<() as Foo>::foo` in constant functions - --> $DIR/const_closure-const_trait_impl-ice-113381.rs:14:22 +error[E0277]: the trait bound `{closure@$DIR/const_closure-const_trait_impl-ice-113381.rs:15:6: 15:14}: [const] Fn()` is not satisfied + --> $DIR/const_closure-const_trait_impl-ice-113381.rs:15:5 | -LL | (const || { (()).foo() })(); - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants +LL | (const || (()).foo())(); + | ^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs index 026f2c0d6032..8ee3db445d07 100644 --- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs +++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.rs @@ -1,16 +1,14 @@ #![feature(const_trait_impl)] const fn test() -> impl [const] Fn() { - //~^ ERROR `[const]` can only be applied to `#[const_trait]` traits - //~| ERROR `[const]` can only be applied to `#[const_trait]` traits - //~| ERROR `[const]` can only be applied to `#[const_trait]` traits + //~^ ERROR: }: [const] Fn()` is not satisfied const move || { //~ ERROR const closures are experimental let sl: &[u8] = b"foo"; match sl { [first, remainder @ ..] => { assert_eq!(first, &b'f'); - //~^ ERROR cannot call non-const function + // FIXME(const_closures) ^ ERROR cannot call non-const function } [] => panic!(), } diff --git a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr index 78d7b962cc42..abbe0a0070aa 100644 --- a/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr +++ b/tests/ui/traits/const-traits/ice-112822-expected-type-for-param.stderr @@ -1,5 +1,5 @@ error[E0658]: const closures are experimental - --> $DIR/ice-112822-expected-type-for-param.rs:7:5 + --> $DIR/ice-112822-expected-type-for-param.rs:5:5 | LL | const move || { | ^^^^^ @@ -8,45 +8,13 @@ LL | const move || { = help: add `#![feature(const_closures)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/ice-112822-expected-type-for-param.rs:3:25 +error[E0277]: the trait bound `{closure@$DIR/ice-112822-expected-type-for-param.rs:5:5: 5:18}: [const] Fn()` is not satisfied + --> $DIR/ice-112822-expected-type-for-param.rs:3:20 | LL | const fn test() -> impl [const] Fn() { - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL + | ^^^^^^^^^^^^^^^^^ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/ice-112822-expected-type-for-param.rs:3:25 - | -LL | const fn test() -> impl [const] Fn() { - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +error: aborting due to 2 previous errors -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/ice-112822-expected-type-for-param.rs:3:25 - | -LL | const fn test() -> impl [const] Fn() { - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0015]: cannot call non-const function `core::panicking::assert_failed::<&u8, &u8>` in constant functions - --> $DIR/ice-112822-expected-type-for-param.rs:12:17 - | -LL | assert_eq!(first, &b'f'); - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants - = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 5 previous errors - -Some errors have detailed explanations: E0015, E0658. -For more information about an error, try `rustc --explain E0015`. +Some errors have detailed explanations: E0277, E0658. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs deleted file mode 100644 index f1dbd9471617..000000000000 --- a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![allow(incomplete_features)] -#![feature(generic_const_exprs, const_trait_impl)] - -const fn with_positive() {} -//~^ ERROR `[const]` can only be applied to `#[const_trait]` traits -//~| ERROR `[const]` can only be applied to `#[const_trait]` traits - -pub fn main() {} diff --git a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr b/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr deleted file mode 100644 index 1eccb16b46e7..000000000000 --- a/tests/ui/traits/const-traits/ice-123664-unexpected-bound-var.stderr +++ /dev/null @@ -1,21 +0,0 @@ -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/ice-123664-unexpected-bound-var.rs:4:27 - | -LL | const fn with_positive() {} - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - -error: `[const]` can only be applied to `#[const_trait]` traits - --> $DIR/ice-123664-unexpected-bound-var.rs:4:27 - | -LL | const fn with_positive() {} - | ^^^^^^^ can't be applied to `Fn` - | -note: `Fn` can't be used with `[const]` because it isn't annotated with `#[const_trait]` - --> $SRC_DIR/core/src/ops/function.rs:LL:COL - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 2 previous errors - diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs index fa0f78696448..d0470fa34584 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.rs @@ -11,5 +11,5 @@ fn foo(&self) {} fn main() { (const || { (()).foo() })(); - //~^ ERROR: cannot call non-const method + //~^ ERROR: }: [const] Fn()` is not satisfied } diff --git a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr index 2d33406c2224..dcf65ab69408 100644 --- a/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr +++ b/tests/ui/traits/const-traits/non-const-op-const-closure-non-const-outer.stderr @@ -1,11 +1,9 @@ -error[E0015]: cannot call non-const method `<() as Foo>::foo` in constant functions - --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:22 +error[E0277]: the trait bound `{closure@$DIR/non-const-op-const-closure-non-const-outer.rs:13:6: 13:14}: [const] Fn()` is not satisfied + --> $DIR/non-const-op-const-closure-non-const-outer.rs:13:5 | LL | (const || { (()).foo() })(); - | ^^^^^ - | - = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0277`. From 29b75a6b34c966524b81e6137b2f868a1006722f Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 7 Jul 2025 17:02:59 +0200 Subject: [PATCH 07/16] Fix weird rustdoc output when single and glob reexport conflict on a name --- src/librustdoc/clean/inline.rs | 10 ++++-- src/librustdoc/clean/mod.rs | 50 +++++++++++++++----------- src/librustdoc/visit_ast.rs | 64 +++++++++++++++++++++++++--------- 3 files changed, 84 insertions(+), 40 deletions(-) diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 96199cb972a8..37b012d6d0d0 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -152,8 +152,14 @@ pub(crate) fn try_inline( }; cx.inlined.insert(did.into()); - let mut item = - crate::clean::generate_item_with_correct_attrs(cx, kind, did, name, import_def_id, None); + let mut item = crate::clean::generate_item_with_correct_attrs( + cx, + kind, + did, + name, + import_def_id.as_slice(), + None, + ); // The visibility needs to reflect the one from the reexport and not from the "source" DefId. item.inner.inline_stmt_id = import_def_id; ret.push(item); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c2f3da18cd30..e6f7aef02c0e 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -94,12 +94,12 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< // This covers the case where somebody does an import which should pull in an item, // but there's already an item with the same namespace and same name. Rust gives // priority to the not-imported one, so we should, too. - items.extend(doc.items.values().flat_map(|(item, renamed, import_id)| { + items.extend(doc.items.values().flat_map(|(item, renamed, import_ids)| { // First, lower everything other than glob imports. if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { return Vec::new(); } - let v = clean_maybe_renamed_item(cx, item, *renamed, *import_id); + let v = clean_maybe_renamed_item(cx, item, *renamed, import_ids); for item in &v { if let Some(name) = item.name && (cx.render_options.document_hidden || !item.is_doc_hidden()) @@ -162,7 +162,7 @@ pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext< kind, doc.def_id.to_def_id(), doc.name, - doc.import_id, + doc.import_id.as_slice(), doc.renamed, ) } @@ -182,22 +182,29 @@ fn generate_item_with_correct_attrs( kind: ItemKind, def_id: DefId, name: Symbol, - import_id: Option, + import_ids: &[LocalDefId], renamed: Option, ) -> Item { let target_attrs = inline::load_attrs(cx, def_id); - let attrs = if let Some(import_id) = import_id { - // glob reexports are treated the same as `#[doc(inline)]` items. - // - // For glob re-exports the item may or may not exist to be re-exported (potentially the cfgs - // on the path up until the glob can be removed, and only cfgs on the globbed item itself - // matter), for non-inlined re-exports see #85043. - let is_inline = hir_attr_lists(inline::load_attrs(cx, import_id.to_def_id()), sym::doc) - .get_word_attr(sym::inline) - .is_some() - || (is_glob_import(cx.tcx, import_id) - && (cx.render_options.document_hidden || !cx.tcx.is_doc_hidden(def_id))); - let mut attrs = get_all_import_attributes(cx, import_id, def_id, is_inline); + let attrs = if !import_ids.is_empty() { + let mut attrs = Vec::with_capacity(import_ids.len()); + let mut is_inline = false; + + for import_id in import_ids.iter().copied() { + // glob reexports are treated the same as `#[doc(inline)]` items. + // + // For glob re-exports the item may or may not exist to be re-exported (potentially the + // cfgs on the path up until the glob can be removed, and only cfgs on the globbed item + // itself matter), for non-inlined re-exports see #85043. + let import_is_inline = + hir_attr_lists(inline::load_attrs(cx, import_id.to_def_id()), sym::doc) + .get_word_attr(sym::inline) + .is_some() + || (is_glob_import(cx.tcx, import_id) + && (cx.render_options.document_hidden || !cx.tcx.is_doc_hidden(def_id))); + attrs.extend(get_all_import_attributes(cx, import_id, def_id, is_inline)); + is_inline = is_inline || import_is_inline; + } add_without_unwanted_attributes(&mut attrs, target_attrs, is_inline, None); attrs } else { @@ -216,7 +223,8 @@ fn generate_item_with_correct_attrs( let name = renamed.or(Some(name)); let mut item = Item::from_def_id_and_attrs_and_parts(def_id, name, kind, attrs, cfg); - item.inner.inline_stmt_id = import_id; + // FIXME (GuillaumeGomez): Should we also make `inline_stmt_id` a `Vec` instead of an `Option`? + item.inner.inline_stmt_id = import_ids.first().copied(); item } @@ -2754,7 +2762,7 @@ fn clean_maybe_renamed_item<'tcx>( cx: &mut DocContext<'tcx>, item: &hir::Item<'tcx>, renamed: Option, - import_id: Option, + import_ids: &[LocalDefId], ) -> Vec { use hir::ItemKind; fn get_name( @@ -2825,7 +2833,7 @@ fn get_name( })), item.owner_id.def_id.to_def_id(), name, - import_id, + import_ids, renamed, )); return ret; @@ -2880,7 +2888,7 @@ fn get_name( kind, item.owner_id.def_id.to_def_id(), name, - import_id, + import_ids, renamed, )] }) @@ -3151,7 +3159,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( kind, item.owner_id.def_id.to_def_id(), item.ident.name, - import_id, + import_id.as_slice(), renamed, ) }) diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 2889bfae7b00..2784d7c761a8 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -32,11 +32,29 @@ pub(crate) struct Module<'hir> { pub(crate) def_id: LocalDefId, pub(crate) renamed: Option, pub(crate) import_id: Option, - /// The key is the item `ItemId` and the value is: (item, renamed, import_id). + /// The key is the item `ItemId` and the value is: (item, renamed, Vec). /// We use `FxIndexMap` to keep the insert order. + /// + /// `import_id` needs to be a `Vec` because we live in a dark world where you can have code + /// like: + /// + /// ``` + /// mod raw { + /// pub fn foo() {} + /// } + /// + /// /// Foobar + /// pub use raw::foo; + /// + /// pub use raw::*; + /// ``` + /// + /// So in this case, we don't want to have two items but just one with attributes from all + /// non-glob imports to be merged. Glob imports attributes are always ignored, whether they're + /// shadowed or not. pub(crate) items: FxIndexMap< (LocalDefId, Option), - (&'hir hir::Item<'hir>, Option, Option), + (&'hir hir::Item<'hir>, Option, Vec), >, /// (def_id, renamed) -> (res, local_import_id) @@ -154,7 +172,9 @@ pub(crate) fn visit(mut self) -> Module<'tcx> { { let item = self.cx.tcx.hir_expect_item(local_def_id); let (ident, _, _) = item.expect_macro(); - top_level_module.items.insert((local_def_id, Some(ident.name)), (item, None, None)); + top_level_module + .items + .insert((local_def_id, Some(ident.name)), (item, None, Vec::new())); } } @@ -236,7 +256,6 @@ fn maybe_inline_local( ) -> bool { debug!("maybe_inline_local (renamed: {renamed:?}) res: {res:?}"); - let glob = renamed.is_none(); if renamed == Some(kw::Underscore) { // We never inline `_` reexports. return false; @@ -261,6 +280,7 @@ fn maybe_inline_local( return false; } + let is_glob = renamed.is_none(); let is_hidden = !document_hidden && tcx.is_doc_hidden(ori_res_did); let Some(res_did) = ori_res_did.as_local() else { // For cross-crate impl inlining we need to know whether items are @@ -268,7 +288,7 @@ fn maybe_inline_local( // made reachable by cross-crate inlining which we're checking here. // (this is done here because we need to know this upfront). crate::visit_lib::lib_embargo_visit_item(self.cx, ori_res_did); - if is_hidden || glob { + if is_hidden || is_glob { return false; } // We store inlined foreign items otherwise, it'd mean that the `use` item would be kept @@ -316,10 +336,10 @@ fn maybe_inline_local( // Bang macros are handled a bit on their because of how they are handled by the // compiler. If they have `#[doc(hidden)]` and the re-export doesn't have // `#[doc(inline)]`, then we don't inline it. - Node::Item(_) if is_bang_macro && !please_inline && renamed.is_some() && is_hidden => { + Node::Item(_) if is_bang_macro && !please_inline && !is_glob && is_hidden => { return false; } - Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_, m), .. }) if glob => { + Node::Item(&hir::Item { kind: hir::ItemKind::Mod(_, m), .. }) if is_glob => { let prev = mem::replace(&mut self.inlining, true); for &i in m.item_ids { let i = tcx.hir_item(i); @@ -328,13 +348,13 @@ fn maybe_inline_local( self.inlining = prev; true } - Node::Item(it) if !glob => { + Node::Item(it) if !is_glob => { let prev = mem::replace(&mut self.inlining, true); self.visit_item_inner(it, renamed, Some(def_id)); self.inlining = prev; true } - Node::ForeignItem(it) if !glob => { + Node::ForeignItem(it) if !is_glob => { let prev = mem::replace(&mut self.inlining, true); self.visit_foreign_item_inner(it, renamed, Some(def_id)); self.inlining = prev; @@ -378,8 +398,8 @@ fn reexport_public_and_not_hidden( fn add_to_current_mod( &mut self, item: &'tcx hir::Item<'_>, - renamed: Option, - parent_id: Option, + mut renamed: Option, + import_id: Option, ) { if self.is_importable_from_parent // If we're inside an item, only impl blocks and `macro_rules!` with the `macro_export` @@ -392,11 +412,21 @@ fn add_to_current_mod( _ => false, } { - self.modules - .last_mut() - .unwrap() - .items - .insert((item.owner_id.def_id, renamed), (item, renamed, parent_id)); + if renamed == item.kind.ident().map(|ident| ident.name) { + renamed = None; + } + let key = (item.owner_id.def_id, renamed); + if let Some(import_id) = import_id { + self.modules + .last_mut() + .unwrap() + .items + .entry(key) + .and_modify(|v| v.2.push(import_id)) + .or_insert_with(|| (item, renamed, vec![import_id])); + } else { + self.modules.last_mut().unwrap().items.insert(key, (item, renamed, Vec::new())); + } } } @@ -468,7 +498,7 @@ fn visit_item_inner( _ => false, }); let ident = match kind { - hir::UseKind::Single(ident) => Some(renamed.unwrap_or(ident.name)), + hir::UseKind::Single(ident) => Some(ident.name), hir::UseKind::Glob => None, hir::UseKind::ListStem => unreachable!(), }; From b1d45f6b3e672cee544e6ff197a9f21022026871 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 8 Jul 2025 15:41:13 +0000 Subject: [PATCH 08/16] Remove `const_eval_select` hack --- compiler/rustc_hir_typeck/messages.ftl | 7 --- compiler/rustc_hir_typeck/src/callee.rs | 23 -------- compiler/rustc_hir_typeck/src/errors.rs | 18 ------ .../src/traits/effects.rs | 7 +-- library/core/src/intrinsics/mod.rs | 2 +- tests/ui/intrinsics/const-eval-select-bad.rs | 7 +-- .../intrinsics/const-eval-select-bad.stderr | 58 ++++++------------- 7 files changed, 23 insertions(+), 99 deletions(-) diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index c21b16c9f9f0..bac4d70103c3 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -82,13 +82,6 @@ hir_typeck_cast_unknown_pointer = cannot cast {$to -> hir_typeck_const_continue_bad_label = `#[const_continue]` must break to a labeled block that participates in a `#[loop_match]` -hir_typeck_const_select_must_be_const = this argument must be a `const fn` - .help = consult the documentation on `const_eval_select` for more information - -hir_typeck_const_select_must_be_fn = this argument must be a function item - .note = expected a function item, found {$ty} - .help = consult the documentation on `const_eval_select` for more information - hir_typeck_continue_labeled_block = `continue` pointing to a labeled block .label = labeled blocks cannot be `continue`'d diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 7611f8ac3e1a..48bb45de53eb 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -578,29 +578,6 @@ fn confirm_builtin_call( } } - if let Some(def_id) = def_id - && self.tcx.def_kind(def_id) == hir::def::DefKind::Fn - && self.tcx.is_intrinsic(def_id, sym::const_eval_select) - { - let fn_sig = self.resolve_vars_if_possible(fn_sig); - for idx in 0..=1 { - let arg_ty = fn_sig.inputs()[idx + 1]; - let span = arg_exprs.get(idx + 1).map_or(call_expr.span, |arg| arg.span); - // Check that second and third argument of `const_eval_select` must be `FnDef`, and additionally that - // the second argument must be `const fn`. The first argument must be a tuple, but this is already expressed - // in the function signature (`F: FnOnce`), so I did not bother to add another check here. - // - // This check is here because there is currently no way to express a trait bound for `FnDef` types only. - if let ty::FnDef(def_id, _args) = *arg_ty.kind() { - if idx == 0 && !self.tcx.is_const_fn(def_id) { - self.dcx().emit_err(errors::ConstSelectMustBeConst { span }); - } - } else { - self.dcx().emit_err(errors::ConstSelectMustBeFn { span, ty: arg_ty }); - } - } - } - fn_sig.output() } diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index 3606c778fc40..a8bb6956f101 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -605,24 +605,6 @@ fn add_to_diag(self, diag: &mut Diag<'_, G>) { } } -#[derive(Diagnostic)] -#[diag(hir_typeck_const_select_must_be_const)] -#[help] -pub(crate) struct ConstSelectMustBeConst { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(hir_typeck_const_select_must_be_fn)] -#[note] -#[help] -pub(crate) struct ConstSelectMustBeFn<'a> { - #[primary_span] - pub span: Span, - pub ty: Ty<'a>, -} - #[derive(Diagnostic)] #[diag(hir_typeck_union_pat_multiple_fields)] pub(crate) struct UnionPatMultipleFields { diff --git a/compiler/rustc_trait_selection/src/traits/effects.rs b/compiler/rustc_trait_selection/src/traits/effects.rs index d24f861723b5..d694a092853a 100644 --- a/compiler/rustc_trait_selection/src/traits/effects.rs +++ b/compiler/rustc_trait_selection/src/traits/effects.rs @@ -416,12 +416,9 @@ fn evaluate_host_effect_for_fn_goal<'tcx>( // We may support function pointers at some point in the future ty::FnPtr(..) => return Err(EvaluationFailure::NoSolution), - // Coroutines could implement `[const] Fn`, + // Closures could implement `[const] Fn`, // but they don't really need to right now. - ty::Closure(..) - | ty::CoroutineClosure(_, _) - | ty::Coroutine(_, _) - | ty::CoroutineWitness(_, _) => { + ty::Closure(..) | ty::CoroutineClosure(_, _) => { return Err(EvaluationFailure::NoSolution); } diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 791d10eda6d0..1ac0c7ff89b8 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -2279,7 +2279,7 @@ pub const fn const_eval_select( ) -> RET where G: FnOnce, - F: FnOnce; + F: const FnOnce; /// A macro to make it easier to invoke const_eval_select. Use as follows: /// ```rust,ignore (just a macro example) diff --git a/tests/ui/intrinsics/const-eval-select-bad.rs b/tests/ui/intrinsics/const-eval-select-bad.rs index 3365d57af7ce..f40712512992 100644 --- a/tests/ui/intrinsics/const-eval-select-bad.rs +++ b/tests/ui/intrinsics/const-eval-select-bad.rs @@ -5,13 +5,10 @@ const fn not_fn_items() { const_eval_select((), || {}, || {}); - //~^ ERROR this argument must be a function item - //~| ERROR this argument must be a function item + //~^ ERROR const FnOnce()` is not satisfied const_eval_select((), 42, 0xDEADBEEF); //~^ ERROR expected a `FnOnce()` closure //~| ERROR expected a `FnOnce()` closure - //~| ERROR this argument must be a function item - //~| ERROR this argument must be a function item } const fn foo(n: i32) -> i32 { @@ -40,7 +37,7 @@ const fn args_ty_mismatch() { const fn non_const_fn() { const_eval_select((1,), bar, bar); - //~^ ERROR this argument must be a `const fn` + //~^ ERROR the trait bound `fn(i32) -> bool {bar}: const FnOnce(i32)` is not satisfied } fn main() {} diff --git a/tests/ui/intrinsics/const-eval-select-bad.stderr b/tests/ui/intrinsics/const-eval-select-bad.stderr index bb159bed2822..d701f5ea9097 100644 --- a/tests/ui/intrinsics/const-eval-select-bad.stderr +++ b/tests/ui/intrinsics/const-eval-select-bad.stderr @@ -1,23 +1,16 @@ -error: this argument must be a function item +error[E0277]: the trait bound `{closure@$DIR/const-eval-select-bad.rs:7:27: 7:29}: const FnOnce()` is not satisfied --> $DIR/const-eval-select-bad.rs:7:27 | LL | const_eval_select((), || {}, || {}); - | ^^^^^ + | ----------------- ^^^^^ + | | + | required by a bound introduced by this call | - = note: expected a function item, found {closure@$DIR/const-eval-select-bad.rs:7:27: 7:29} - = help: consult the documentation on `const_eval_select` for more information - -error: this argument must be a function item - --> $DIR/const-eval-select-bad.rs:7:34 - | -LL | const_eval_select((), || {}, || {}); - | ^^^^^ - | - = note: expected a function item, found {closure@$DIR/const-eval-select-bad.rs:7:34: 7:36} - = help: consult the documentation on `const_eval_select` for more information +note: required by a bound in `const_eval_select` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL error[E0277]: expected a `FnOnce()` closure, found `{integer}` - --> $DIR/const-eval-select-bad.rs:10:27 + --> $DIR/const-eval-select-bad.rs:9:27 | LL | const_eval_select((), 42, 0xDEADBEEF); | ----------------- ^^ expected an `FnOnce()` closure, found `{integer}` @@ -30,7 +23,7 @@ note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL error[E0277]: expected a `FnOnce()` closure, found `{integer}` - --> $DIR/const-eval-select-bad.rs:10:31 + --> $DIR/const-eval-select-bad.rs:9:31 | LL | const_eval_select((), 42, 0xDEADBEEF); | ----------------- ^^^^^^^^^^ expected an `FnOnce()` closure, found `{integer}` @@ -42,26 +35,8 @@ LL | const_eval_select((), 42, 0xDEADBEEF); note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL -error: this argument must be a function item - --> $DIR/const-eval-select-bad.rs:10:27 - | -LL | const_eval_select((), 42, 0xDEADBEEF); - | ^^ - | - = note: expected a function item, found {integer} - = help: consult the documentation on `const_eval_select` for more information - -error: this argument must be a function item - --> $DIR/const-eval-select-bad.rs:10:31 - | -LL | const_eval_select((), 42, 0xDEADBEEF); - | ^^^^^^^^^^ - | - = note: expected a function item, found {integer} - = help: consult the documentation on `const_eval_select` for more information - error[E0271]: expected `bar` to return `i32`, but it returns `bool` - --> $DIR/const-eval-select-bad.rs:32:34 + --> $DIR/const-eval-select-bad.rs:29:34 | LL | const_eval_select((1,), foo, bar); | ----------------- ^^^ expected `i32`, found `bool` @@ -72,7 +47,7 @@ note: required by a bound in `const_eval_select` --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL error[E0631]: type mismatch in function arguments - --> $DIR/const-eval-select-bad.rs:37:32 + --> $DIR/const-eval-select-bad.rs:34:32 | LL | const fn foo(n: i32) -> i32 { | --------------------------- found signature defined here @@ -91,15 +66,18 @@ help: consider wrapping the function in a closure LL | const_eval_select((true,), |arg0: bool| foo(/* i32 */), baz); | ++++++++++++ +++++++++++ -error: this argument must be a `const fn` - --> $DIR/const-eval-select-bad.rs:42:29 +error[E0277]: the trait bound `fn(i32) -> bool {bar}: const FnOnce(i32)` is not satisfied + --> $DIR/const-eval-select-bad.rs:39:29 | LL | const_eval_select((1,), bar, bar); - | ^^^ + | ----------------- ^^^ + | | + | required by a bound introduced by this call | - = help: consult the documentation on `const_eval_select` for more information +note: required by a bound in `const_eval_select` + --> $SRC_DIR/core/src/intrinsics/mod.rs:LL:COL -error: aborting due to 9 previous errors +error: aborting due to 6 previous errors Some errors have detailed explanations: E0271, E0277, E0631. For more information about an error, try `rustc --explain E0271`. From 96cdbb9ba77b9a840a1637e4dab05bb2cc64fef0 Mon Sep 17 00:00:00 2001 From: George Tokmaji Date: Tue, 8 Jul 2025 21:19:38 +0200 Subject: [PATCH 09/16] Win: Use exceptions with empty data for SEH panic exception copies instead of a new panic For unwinding with SEH, we currently construct a C++ exception with the panic data. Being a regular C++ exception, it interacts with the C++ exception handling machinery and can be retrieved via `std::current_exception`, which needs to copy the exception. We can't support that, so we panic, which throws another exception, which the C++ runtime tries to copy and store into the exception_ptr, which panics again, which causes the C++ runtime to store a `bad_exception` instance. However, this doesn't work because the panics thrown by the copy function will be dropped without being rethrown, and causes unnecessary log spam in stderr. Fix this by directly throwing an exception without data, which doesn't cause log spam and can be dropped without being rethrown. --- library/panic_unwind/src/seh.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 003ac4f0cd37..668e988abff3 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -61,6 +61,7 @@ struct Exception { // and its destructor is executed by the C++ runtime. When we take the Box // out of the exception, we need to leave the exception in a valid state // for its destructor to run without double-dropping the Box. + // We also construct this as None for copies of the exception. data: Option>, } @@ -264,7 +265,11 @@ struct _TypeDescriptor { // runtime under a try/catch block and the panic that we generate here will be // used as the result of the exception copy. This is used by the C++ runtime to // support capturing exceptions with std::exception_ptr, which we can't support -// because Box isn't clonable. +// because Box isn't clonable. Thus we throw an exception without data, +// which the C++ runtime will attempt to copy, which will once again fail, and +// a std::bad_exception instance ends up in the std::exception_ptr instance. +// The lack of data doesn't matter because the exception will never be rethrown +// - it is purely used to signal to the C++ runtime that copying failed. macro_rules! define_cleanup { ($abi:tt $abi2:tt) => { unsafe extern $abi fn exception_cleanup(e: *mut Exception) { @@ -278,7 +283,9 @@ macro_rules! define_cleanup { unsafe extern $abi2 fn exception_copy( _dest: *mut Exception, _src: *mut Exception ) -> *mut Exception { - panic!("Rust panics cannot be copied"); + unsafe { + throw_exception(None); + } } } } @@ -291,6 +298,10 @@ macro_rules! define_cleanup { } pub(crate) unsafe fn panic(data: Box) -> u32 { + unsafe { throw_exception(Some(data)) } +} + +unsafe fn throw_exception(data: Option>) -> ! { use core::intrinsics::{AtomicOrdering, atomic_store}; // _CxxThrowException executes entirely on this stack frame, so there's no @@ -300,8 +311,7 @@ pub(crate) unsafe fn panic(data: Box) -> u32 { // The ManuallyDrop is needed here since we don't want Exception to be // dropped when unwinding. Instead it will be dropped by exception_cleanup // which is invoked by the C++ runtime. - let mut exception = - ManuallyDrop::new(Exception { canary: (&raw const TYPE_DESCRIPTOR), data: Some(data) }); + let mut exception = ManuallyDrop::new(Exception { canary: (&raw const TYPE_DESCRIPTOR), data }); let throw_ptr = (&raw mut exception) as *mut _; // This... may seems surprising, and justifiably so. On 32-bit MSVC the From 6fc5d4edda88d0dd28c45ccba1a1e217ddad11c4 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 7 Jul 2025 19:23:06 +0200 Subject: [PATCH 10/16] emit `.att_syntax` when global/naked asm use that option --- compiler/rustc_codegen_llvm/src/asm.rs | 22 +++++--- tests/assembly/emit-intel-att-syntax.rs | 75 +++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 7 deletions(-) create mode 100644 tests/assembly/emit-intel-att-syntax.rs diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 9ddadcf16aa3..a643a91141e1 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -384,15 +384,19 @@ fn codegen_global_asm( ) { let asm_arch = self.tcx.sess.asm_arch.unwrap(); - // Default to Intel syntax on x86 - let intel_syntax = matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) - && !options.contains(InlineAsmOptions::ATT_SYNTAX); - // Build the template string let mut template_str = String::new(); - if intel_syntax { - template_str.push_str(".intel_syntax\n"); + + // On X86 platforms there are two assembly syntaxes. Rust uses intel by default, + // but AT&T can be specified explicitly. + if matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) { + if options.contains(InlineAsmOptions::ATT_SYNTAX) { + template_str.push_str(".att_syntax\n") + } else { + template_str.push_str(".intel_syntax\n") + } } + for piece in template { match *piece { InlineAsmTemplatePiece::String(ref s) => template_str.push_str(s), @@ -431,7 +435,11 @@ fn codegen_global_asm( } } } - if intel_syntax { + + // Just to play it safe, if intel was used, reset the assembly syntax to att. + if matches!(asm_arch, InlineAsmArch::X86 | InlineAsmArch::X86_64) + && !options.contains(InlineAsmOptions::ATT_SYNTAX) + { template_str.push_str("\n.att_syntax\n"); } diff --git a/tests/assembly/emit-intel-att-syntax.rs b/tests/assembly/emit-intel-att-syntax.rs new file mode 100644 index 000000000000..7b479a0f79ef --- /dev/null +++ b/tests/assembly/emit-intel-att-syntax.rs @@ -0,0 +1,75 @@ +//@ assembly-output: emit-asm +//@ revisions: att intel +//@ [att] compile-flags: -Cllvm-args=-x86-asm-syntax=att +//@ [intel] compile-flags: -Cllvm-args=-x86-asm-syntax=intel +//@ only-x86_64 + +#![crate_type = "lib"] + +// CHECK-LABEL: naked_att: +// intel-CHECK: mov rax, qword ptr [rdi] +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +#[unsafe(naked)] +#[unsafe(no_mangle)] +extern "sysv64" fn naked_att() { + std::arch::naked_asm!( + " + movq (%rdi), %rax + retq + ", + options(att_syntax), + ); +} + +// CHECK-LABEL: naked_intel: +// intel-CHECK: mov rax, rdi +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +#[unsafe(naked)] +#[unsafe(no_mangle)] +extern "sysv64" fn naked_intel() { + std::arch::naked_asm!( + " + mov rax, rdi + ret + ", + options(), + ); +} + +// CHECK-LABEL: global_att: +// intel-CHECK: mov rax, rdi +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +core::arch::global_asm!( + " + .globl global_att + global_att: + movq (%rdi), %rax + retq + ", + options(att_syntax), +); + +// CHECK-LABEL: global_intel: +// intel-CHECK: mov rax, rdi +// intel-CHECK: ret +// att-CHECK: movq (%rdi), %rax +// att-CHECK: retq + +core::arch::global_asm!( + " + .globl global_intel + global_intel: + mov rax, rdi + ret + ", + options(), +); From 87e7539fcdfa45b2aab618c044f888432c5d097d Mon Sep 17 00:00:00 2001 From: Josh Stone Date: Tue, 8 Jul 2025 16:38:35 -0700 Subject: [PATCH 11/16] Disable docs for `compiler-builtins` and `sysroot` Bootstrap already had a manual doc filter for the `sysroot` crate, but other library crates keep themselves out of the public docs by setting `[lib] doc = false` in their manifest. This seems like a better solution to hide `compiler-builtins` docs, and removes the `sysroot` hack too. --- library/compiler-builtins/compiler-builtins/Cargo.toml | 2 ++ library/sysroot/Cargo.toml | 4 ++++ src/bootstrap/src/core/build_steps/doc.rs | 4 ---- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/library/compiler-builtins/compiler-builtins/Cargo.toml b/library/compiler-builtins/compiler-builtins/Cargo.toml index c5446cd76e32..3ccb05f73fb8 100644 --- a/library/compiler-builtins/compiler-builtins/Cargo.toml +++ b/library/compiler-builtins/compiler-builtins/Cargo.toml @@ -19,6 +19,8 @@ links = "compiler-rt" bench = false doctest = false test = false +# make sure this crate isn't included in public standard library docs +doc = false [dependencies] core = { path = "../../core", optional = true } diff --git a/library/sysroot/Cargo.toml b/library/sysroot/Cargo.toml index 3adc02249716..514728887fbc 100644 --- a/library/sysroot/Cargo.toml +++ b/library/sysroot/Cargo.toml @@ -5,6 +5,10 @@ name = "sysroot" version = "0.0.0" edition = "2024" +[lib] +# make sure this crate isn't included in public standard library docs +doc = false + # this is a dummy crate to ensure that all required crates appear in the sysroot [dependencies] proc_macro = { path = "../proc_macro", public = true } diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index f7c4c5ad0bbd..9e839b11c086 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -739,10 +739,6 @@ fn doc_std( } for krate in requested_crates { - if krate == "sysroot" { - // The sysroot crate is an implementation detail, don't include it in public docs. - continue; - } cargo.arg("-p").arg(krate); } From 566dc98d2a614288df7a961009edb992e4d59895 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 9 Jul 2025 09:47:37 +0200 Subject: [PATCH 12/16] Add `doc library` test for a no_std target --- src/bootstrap/src/core/builder/tests.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index b1e8150a20f8..cf0cb3a77b1d 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1551,7 +1551,7 @@ fn doc_core() { } #[test] - fn doc_library_no_std_target() { + fn doc_core_no_std_target() { let ctx = TestCtx::new(); insta::assert_snapshot!( ctx.config("doc") @@ -1564,6 +1564,21 @@ fn doc_library_no_std_target() { [doc] std 1 crates=[core] "); } + + #[test] + fn doc_library_no_std_target() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("doc") + .path("library") + .override_target_no_std(&host_target()) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 0 + [doc] std 1 crates=[alloc,core] + "); + } } struct ExecutedSteps { @@ -1574,6 +1589,7 @@ impl ExecutedSteps { fn render(&self) -> String { self.render_with(RenderConfig::default()) } + fn render_with(&self, config: RenderConfig) -> String { render_steps(&self.steps, config) } From 6c38d389f26faf36a3b674f802c37804f5442c0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Wed, 9 Jul 2025 10:26:36 +0200 Subject: [PATCH 13/16] Add doc cross-compilation test --- src/bootstrap/src/core/builder/tests.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index cf0cb3a77b1d..9ca79131b8da 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -1579,6 +1579,22 @@ fn doc_library_no_std_target() { [doc] std 1 crates=[alloc,core] "); } + + #[test] + fn doc_library_no_std_target_cross_compile() { + let ctx = TestCtx::new(); + insta::assert_snapshot!( + ctx.config("doc") + .path("library") + .targets(&[TEST_TRIPLE_1]) + .override_target_no_std(TEST_TRIPLE_1) + .render_steps(), @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustdoc 0 + [doc] std 1 crates=[alloc,core] + "); + } } struct ExecutedSteps { From bf6d29d55847614e677e6c5d6060d2dc0b1ad47b Mon Sep 17 00:00:00 2001 From: usamoi Date: Sat, 5 Jul 2025 02:07:29 +0800 Subject: [PATCH 14/16] use `--dynamic-list` for exporting executable symbols --- compiler/rustc_codegen_ssa/src/back/linker.rs | 41 +++++++++++-------- tests/ui/linking/export-executable-symbols.rs | 30 ++++++++++++++ 2 files changed, 55 insertions(+), 16 deletions(-) create mode 100644 tests/ui/linking/export-executable-symbols.rs diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 1896f63bd2d6..e0a3ad55be08 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -800,9 +800,7 @@ fn export_symbols( return; } - let is_windows = self.sess.target.is_like_windows; - let path = tmpdir.join(if is_windows { "list.def" } else { "list" }); - + let path = tmpdir.join(if self.sess.target.is_like_windows { "list.def" } else { "list" }); debug!("EXPORTED SYMBOLS:"); if self.sess.target.is_like_darwin { @@ -817,7 +815,8 @@ fn export_symbols( if let Err(error) = res { self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error }); } - } else if is_windows { + self.link_arg("-exported_symbols_list").link_arg(path); + } else if self.sess.target.is_like_windows { let res: io::Result<()> = try { let mut f = File::create_buffered(&path)?; @@ -835,6 +834,21 @@ fn export_symbols( if let Err(error) = res { self.sess.dcx().emit_fatal(errors::LibDefWriteFailure { error }); } + self.link_arg(path); + } else if crate_type == CrateType::Executable && !self.sess.target.is_like_solaris { + let res: io::Result<()> = try { + let mut f = File::create_buffered(&path)?; + writeln!(f, "{{")?; + for (sym, _) in symbols { + debug!(sym); + writeln!(f, " {sym};")?; + } + writeln!(f, "}};")?; + }; + if let Err(error) = res { + self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error }); + } + self.link_arg("--dynamic-list").link_arg(path); } else { // Write an LD version script let res: io::Result<()> = try { @@ -852,18 +866,13 @@ fn export_symbols( if let Err(error) = res { self.sess.dcx().emit_fatal(errors::VersionScriptWriteFailure { error }); } - } - - if self.sess.target.is_like_darwin { - self.link_arg("-exported_symbols_list").link_arg(path); - } else if self.sess.target.is_like_solaris { - self.link_arg("-M").link_arg(path); - } else if is_windows { - self.link_arg(path); - } else { - let mut arg = OsString::from("--version-script="); - arg.push(path); - self.link_arg(arg).link_arg("--no-undefined-version"); + if self.sess.target.is_like_solaris { + self.link_arg("-M").link_arg(path); + } else { + let mut arg = OsString::from("--version-script="); + arg.push(path); + self.link_arg(arg).link_arg("--no-undefined-version"); + } } } diff --git a/tests/ui/linking/export-executable-symbols.rs b/tests/ui/linking/export-executable-symbols.rs new file mode 100644 index 000000000000..aea5527b6a1c --- /dev/null +++ b/tests/ui/linking/export-executable-symbols.rs @@ -0,0 +1,30 @@ +//@ run-pass +//@ only-linux +//@ only-gnu +//@ compile-flags: -Zexport-executable-symbols +//@ edition: 2024 + +// Regression test for . + +#![feature(rustc_private)] + +extern crate libc; + +#[unsafe(no_mangle)] +fn hack() -> u64 { + 998244353 +} + +fn main() { + unsafe { + let handle = libc::dlopen(std::ptr::null(), libc::RTLD_NOW); + let ptr = libc::dlsym(handle, c"hack".as_ptr()); + let ptr: Option u64> = std::mem::transmute(ptr); + if let Some(f) = ptr { + assert!(f() == 998244353); + println!("symbol `hack` is found successfully"); + } else { + panic!("symbol `hack` is not found"); + } + } +} From 27fb02c947a3aec673364ee555c0c24d8215b7c7 Mon Sep 17 00:00:00 2001 From: Predrag Gruevski Date: Wed, 9 Jul 2025 01:32:23 +0000 Subject: [PATCH 15/16] Add rustdoc JSON tests for `#[doc(hidden)]` handling of items. --- .../visibility/doc_hidden_default.rs | 19 +++++++++++++++++++ .../visibility/doc_hidden_documented.rs | 17 +++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/rustdoc-json/visibility/doc_hidden_default.rs create mode 100644 tests/rustdoc-json/visibility/doc_hidden_documented.rs diff --git a/tests/rustdoc-json/visibility/doc_hidden_default.rs b/tests/rustdoc-json/visibility/doc_hidden_default.rs new file mode 100644 index 000000000000..3fa91b3c4ad2 --- /dev/null +++ b/tests/rustdoc-json/visibility/doc_hidden_default.rs @@ -0,0 +1,19 @@ +#![no_std] + +// Without `--document-hidden-items`, +// none of these items are present in rustdoc JSON. + +//@ !has "$.index[?(@.name=='func')]" +#[doc(hidden)] +pub fn func() {} + +//@ !has "$.index[?(@.name=='Unit')]" +#[doc(hidden)] +pub struct Unit; + +//@ !has "$.index[?(@.name=='hidden')]" +#[doc(hidden)] +pub mod hidden { + //@ !has "$.index[?(@.name=='Inner')]" + pub struct Inner; +} diff --git a/tests/rustdoc-json/visibility/doc_hidden_documented.rs b/tests/rustdoc-json/visibility/doc_hidden_documented.rs new file mode 100644 index 000000000000..6e9ef48680be --- /dev/null +++ b/tests/rustdoc-json/visibility/doc_hidden_documented.rs @@ -0,0 +1,17 @@ +//@ compile-flags: --document-hidden-items +#![no_std] + +//@ is "$.index[?(@.name=='func')].attrs" '["#[doc(hidden)]"]' +#[doc(hidden)] +pub fn func() {} + +//@ is "$.index[?(@.name=='Unit')].attrs" '["#[doc(hidden)]"]' +#[doc(hidden)] +pub struct Unit; + +//@ is "$.index[?(@.name=='hidden')].attrs" '["#[doc(hidden)]"]' +#[doc(hidden)] +pub mod hidden { + //@ is "$.index[?(@.name=='Inner')].attrs" '[]' + pub struct Inner; +} From 086b13d170b9207cc7d726048517a8cd5acc096d Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 7 Jul 2025 17:28:19 +0200 Subject: [PATCH 16/16] Add regression test for #143107 --- .../reexport/merge-glob-and-non-glob.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/rustdoc/reexport/merge-glob-and-non-glob.rs diff --git a/tests/rustdoc/reexport/merge-glob-and-non-glob.rs b/tests/rustdoc/reexport/merge-glob-and-non-glob.rs new file mode 100644 index 000000000000..ff67859cb39a --- /dev/null +++ b/tests/rustdoc/reexport/merge-glob-and-non-glob.rs @@ -0,0 +1,41 @@ +// This test ensures that if an item is inlined from two different `use`, +// then it will use attributes from both of them. +// This is a regression test for . + +#![feature(no_core)] +#![no_core] +#![no_std] +#![crate_name = "foo"] + +// First we ensure we only have two items. +//@ has 'foo/index.html' +//@ count - '//dl[@class="item-table"]/dt' 2 +// We should also only have one section (Structs). +//@ count - '//h2[@class="section-header"]' 1 +// We now check the short docs. +//@ has - '//dl[@class="item-table"]/dd' 'Foobar Blob' +//@ has - '//dl[@class="item-table"]/dd' 'Tarte Tatin' + +//@ has 'foo/struct.Foo.html' +//@ has - '//*[@class="docblock"]' 'Foobar Blob' + +//@ has 'foo/struct.Another.html' +//@ has - '//*[@class="docblock"]' 'Tarte Tatin' + +mod raw { + /// Blob + pub struct Foo; + + /// Tatin + pub struct Another; +} + +/// Foobar +pub use raw::Foo; + +// Glob reexport attributes are ignored. +/// Baz +pub use raw::*; + +/// Tarte +pub use raw::Another as Another;