From d91025316554f9cff948639ee34bf217ef724947 Mon Sep 17 00:00:00 2001 From: Nathaniel McCallum Date: Sat, 13 Sep 2025 08:51:28 -0400 Subject: [PATCH 01/23] constify Default on Nanoseconds --- library/core/src/num/niche_types.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/core/src/num/niche_types.rs b/library/core/src/num/niche_types.rs index 610d9d8cf92e..9ac0eb72bdcb 100644 --- a/library/core/src/num/niche_types.rs +++ b/library/core/src/num/niche_types.rs @@ -112,7 +112,8 @@ impl Nanoseconds { pub const ZERO: Self = unsafe { Nanoseconds::new_unchecked(0) }; } -impl Default for Nanoseconds { +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for Nanoseconds { #[inline] fn default() -> Self { Self::ZERO From 431ef038a3b20e680687a98c4ad2507ae27a7b0a Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Wed, 24 Sep 2025 15:18:31 +0000 Subject: [PATCH 02/23] impl Ord for params and use unstable sort --- compiler/rustc_hir_analysis/src/constrained_generic_params.rs | 2 +- .../rustc_hir_analysis/src/impl_wf_check/min_specialization.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs index 366b3943a058..2a633810cd70 100644 --- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs +++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs @@ -4,7 +4,7 @@ use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeV use rustc_span::Span; use tracing::debug; -#[derive(Clone, PartialEq, Eq, Hash, Debug)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub(crate) struct Parameter(pub u32); impl From for Parameter { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index b38639ed8c62..13c744ab4613 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -275,7 +275,7 @@ fn check_duplicate_params<'tcx>( span: Span, ) -> Result<(), ErrorGuaranteed> { let mut base_params = cgp::parameters_for(tcx, parent_args, true); - base_params.sort_by_key(|param| param.0); + base_params.sort_unstable(); if let (_, [duplicate, ..]) = base_params.partition_dedup() { let param = impl1_args[duplicate.0 as usize]; return Err(tcx From 77c6acc74ecd44ba7eb5a73c934dffdff7340133 Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Thu, 6 Mar 2025 22:10:42 -0500 Subject: [PATCH 03/23] debuginfo: add an unstable flag to write split DWARF to an explicit directory Bazel requires knowledge of outputs from actions at analysis time, including file or directory name. In order to work around the lack of predictable output name for dwo files, we group the dwo files in a subdirectory of --out-dir as a post-processing step before returning control to bazel. Unfortunately some debugging workflows rely on directly opening the dwo file rather than loading the merged dwp file, and our trick of moving the files breaks those users. We can't just hardlink the file or copy it, because with remote build execution we wouldn't end up with the un-moved file copied back to the developer's workstation. As a fix, we add this unstable flag that causes dwo files to be written to a build-system-controllable location, which then lets bazel hoover up the dwo files, but the objects also have the correct path for the dwo files. --- compiler/rustc_interface/src/util.rs | 2 ++ compiler/rustc_session/src/config.rs | 12 +++++++++++- compiler/rustc_session/src/options.rs | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 76ccd12797e5..58ec72b5b45b 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -542,6 +542,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu stem, None, sess.io.temps_dir.clone(), + sess.opts.unstable_opts.split_dwarf_out_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) @@ -571,6 +572,7 @@ pub fn build_output_filenames(attrs: &[ast::Attribute], sess: &Session) -> Outpu out_filestem, ofile, sess.io.temps_dir.clone(), + sess.opts.unstable_opts.split_dwarf_out_dir.clone(), sess.opts.cg.extra_filename.clone(), sess.opts.output_types.clone(), ) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index ebb6a93b1dd1..93be50f0a26c 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1193,6 +1193,7 @@ pub struct OutputFilenames { filestem: String, pub single_output_file: Option, temps_directory: Option, + explicit_dwo_out_directory: Option, pub outputs: OutputTypes, } @@ -1225,6 +1226,7 @@ impl OutputFilenames { out_filestem: String, single_output_file: Option, temps_directory: Option, + explicit_dwo_out_directory: Option, extra: String, outputs: OutputTypes, ) -> Self { @@ -1232,6 +1234,7 @@ impl OutputFilenames { out_directory, single_output_file, temps_directory, + explicit_dwo_out_directory, outputs, crate_stem: format!("{out_crate_name}{extra}"), filestem: format!("{out_filestem}{extra}"), @@ -1281,7 +1284,14 @@ impl OutputFilenames { codegen_unit_name: &str, invocation_temp: Option<&str>, ) -> PathBuf { - self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp) + let p = self.temp_path_ext_for_cgu(DWARF_OBJECT_EXT, codegen_unit_name, invocation_temp); + if let Some(dwo_out) = &self.explicit_dwo_out_directory { + let mut o = dwo_out.clone(); + o.push(p.file_name().unwrap()); + o + } else { + p + } } /// Like `temp_path`, but also supports things where there is no corresponding diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index b2cc169f12cb..9287e032dc4c 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2633,6 +2633,8 @@ written to standard error output)"), file which is ignored by the linker `single`: sections which do not require relocation are written into object file but ignored by the linker"), + split_dwarf_out_dir : Option = (None, parse_opt_pathbuf, [TRACKED], + "location for writing split DWARF objects (`.dwo`) if enabled"), split_lto_unit: Option = (None, parse_opt_bool, [TRACKED], "enable LTO unit splitting (default: no)"), src_hash_algorithm: Option = (None, parse_src_file_hash, [TRACKED], From eb3fb457f14c419b58fc8b20d72efcea94e06d9f Mon Sep 17 00:00:00 2001 From: Augie Fackler Date: Fri, 26 Sep 2025 15:37:44 -0400 Subject: [PATCH 04/23] split-dwarf: add documentation and test coverage --- .../src/compiler-flags/split-dwarf-out-dir.md | 7 + .../src/external_deps/rustc.rs | 7 + tests/run-make/split-debuginfo/rmake.rs | 148 ++++++++++++++++-- 3 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md diff --git a/src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md b/src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md new file mode 100644 index 000000000000..a2070730b42f --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/split-dwarf-out-dir.md @@ -0,0 +1,7 @@ +# `split-dwarf-out-dir` + +On systems which use DWARF debug info this flag causes `.dwo` files produced +by `-C split-debuginfo` to be written to the specified directory rather than +placed next to the object files. This is mostly useful if you have a build +system which needs to control where to find compile outputs without running the +compiler and have to put your `.dwo` files in a separate directory. diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index b74b1d5e166f..b461a24a0616 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -366,6 +366,13 @@ impl Rustc { self } + pub fn split_dwarf_out_dir(&mut self, out_dir: Option<&str>) -> &mut Self { + if let Some(out_dir) = out_dir { + self.cmd.arg(format!("-Zsplit-dwarf-out-dir={out_dir}")); + } + self + } + /// Pass the `--verbose` flag. pub fn verbose(&mut self) -> &mut Self { self.cmd.arg("--verbose"); diff --git a/tests/run-make/split-debuginfo/rmake.rs b/tests/run-make/split-debuginfo/rmake.rs index e8de5aed1726..e53b71010781 100644 --- a/tests/run-make/split-debuginfo/rmake.rs +++ b/tests/run-make/split-debuginfo/rmake.rs @@ -187,6 +187,25 @@ enum UnstableOptions { Unspecified, } +#[track_caller] +fn dwo_out_filenames(dwo_out: Option<&str>) -> BTreeSet { + let dwo_out = if let Some(d) = dwo_out { + d + } else { + return BTreeSet::new(); + }; + let files = shallow_find_files(dwo_out, |path| { + // Fiilter out source files + !has_extension(path, "rs") + }); + files + .iter() + .map(|p| { + format!("{}/{}", dwo_out, p.file_name().unwrap().to_os_string().into_string().unwrap()) + }) + .collect() +} + #[track_caller] fn cwd_filenames() -> BTreeSet { let files = shallow_find_files(cwd(), |path| { @@ -196,6 +215,17 @@ fn cwd_filenames() -> BTreeSet { files.iter().map(|p| p.file_name().unwrap().to_os_string().into_string().unwrap()).collect() } +#[track_caller] +fn dwo_out_dwo_filenames(dwo_out: &str) -> BTreeSet { + let files = shallow_find_files(dwo_out, |p| has_extension(p, "dwo")); + files + .iter() + .map(|p| { + format!("{}/{}", dwo_out, p.file_name().unwrap().to_os_string().into_string().unwrap()) + }) + .collect() +} + #[track_caller] fn cwd_dwo_filenames() -> BTreeSet { let files = shallow_find_files(cwd(), |path| has_extension(path, "dwo")); @@ -376,17 +406,19 @@ mod shared_linux_other_tests { lto: LinkerPluginLto, remap_path_prefix: RemapPathPrefix, remap_path_scope: RemapPathScope, + split_dwarf_output_directory: Option<&str>, ) { run_in_tmpdir(|| { println!( - "checking: unstable_options={:?} + split_kind={:?} + level={:?} + split_dwarf_kind={:?} + lto={:?} + remap_path_prefix={:?} + remap_path_scope={:?}", + "checking: unstable_options={:?} + split_kind={:?} + level={:?} + split_dwarf_kind={:?} + lto={:?} + remap_path_prefix={:?} + remap_path_scope={:?} + split_dwarf_out_dir={:?}", unstable_options, split_kind, level, split_dwarf_kind, lto, remap_path_prefix, - remap_path_scope + remap_path_scope, + split_dwarf_output_directory, ); match cross_crate_test { @@ -398,6 +430,7 @@ mod shared_linux_other_tests { lto, remap_path_prefix, remap_path_scope, + split_dwarf_output_directory, ), CrossCrateTest::No => simple_split_debuginfo( unstable_options, @@ -407,6 +440,7 @@ mod shared_linux_other_tests { lto, remap_path_prefix, remap_path_scope, + split_dwarf_output_directory, ), } }); @@ -420,7 +454,11 @@ mod shared_linux_other_tests { lto: LinkerPluginLto, remap_path_prefix: RemapPathPrefix, remap_path_scope: RemapPathScope, + split_dwarf_output_directory: Option<&str>, ) { + if let Some(dwo_out) = split_dwarf_output_directory { + run_make_support::rfs::create_dir(dwo_out); + } match (split_kind, level, split_dwarf_kind, lto, remap_path_prefix, remap_path_scope) { // packed-crosscrate-split // - Debuginfo in `.dwo` files @@ -531,13 +569,19 @@ mod shared_linux_other_tests { .input("bar.rs") .crate_type("lib") .split_debuginfo(split_kind.cli_value()) + .split_dwarf_out_dir(split_dwarf_output_directory) .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .run(); - let bar_found_files = cwd_filenames(); + let mut bar_found_files = cwd_filenames(); + bar_found_files.append(&mut dwo_out_filenames(split_dwarf_output_directory)); - let bar_dwo_files = cwd_dwo_filenames(); + let bar_dwo_files = if let Some(dwo_out) = split_dwarf_output_directory { + dwo_out_dwo_filenames(dwo_out) + } else { + cwd_dwo_filenames() + }; assert_eq!(bar_dwo_files.len(), 1); let mut bar_expected_files = BTreeSet::new(); @@ -553,13 +597,19 @@ mod shared_linux_other_tests { .extern_("bar", "libbar.rlib") .input("main.rs") .split_debuginfo(split_kind.cli_value()) + .split_dwarf_out_dir(split_dwarf_output_directory) .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .run(); - let overall_found_files = cwd_filenames(); + let mut overall_found_files = cwd_filenames(); + overall_found_files.append(&mut dwo_out_filenames(split_dwarf_output_directory)); - let overall_dwo_files = cwd_dwo_filenames(); + let overall_dwo_files = if let Some(dwo_out) = split_dwarf_output_directory { + dwo_out_dwo_filenames(dwo_out) + } else { + cwd_dwo_filenames() + }; assert_eq!(overall_dwo_files.len(), 2); let mut overall_expected_files = BTreeSet::new(); @@ -648,7 +698,11 @@ mod shared_linux_other_tests { lto: LinkerPluginLto, remap_path_prefix: RemapPathPrefix, remap_path_scope: RemapPathScope, + split_dwarf_output_directory: Option<&str>, ) { + if let Some(dwo_out) = split_dwarf_output_directory { + run_make_support::rfs::create_dir(dwo_out); + } match (split_kind, level, split_dwarf_kind, lto, remap_path_prefix, remap_path_scope) { // off (unspecified): // - Debuginfo in `.o` files @@ -921,14 +975,19 @@ mod shared_linux_other_tests { rustc(unstable_options) .input("foo.rs") .split_debuginfo(split_kind.cli_value()) + .split_dwarf_out_dir(split_dwarf_output_directory) .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .run(); - let found_files = cwd_filenames(); + let mut found_files = cwd_filenames(); + found_files.append(&mut dwo_out_filenames(split_dwarf_output_directory)); - let dwo_files = cwd_dwo_filenames(); + let dwo_files = if let Some(dwo_dir) = split_dwarf_output_directory { + dwo_out_dwo_filenames(dwo_dir) + } else { + cwd_dwo_filenames() + }; assert_eq!(dwo_files.len(), 1); - let mut expected_files = BTreeSet::new(); expected_files.extend(dwo_files); expected_files.insert("foo".to_string()); @@ -1056,14 +1115,20 @@ mod shared_linux_other_tests { rustc(unstable_options) .input("foo.rs") .split_debuginfo(split_kind.cli_value()) + .split_dwarf_out_dir(split_dwarf_output_directory) .debuginfo(level.cli_value()) .arg(format!("-Zsplit-dwarf-kind={}", split_dwarf_kind.cli_value())) .remap_path_prefix(cwd(), remapped_prefix) .run(); - let found_files = cwd_filenames(); + let mut found_files = cwd_filenames(); + found_files.append(&mut dwo_out_filenames(split_dwarf_output_directory)); - let dwo_files = cwd_dwo_filenames(); + let dwo_files = if let Some(dwo_out) = split_dwarf_output_directory { + dwo_out_dwo_filenames(dwo_out) + } else { + cwd_dwo_filenames() + }; assert_eq!(dwo_files.len(), 1); let mut expected_files = BTreeSet::new(); @@ -1358,6 +1423,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // off @@ -1370,6 +1436,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // packed-split @@ -1382,6 +1449,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // packed-single @@ -1394,6 +1462,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // packed-lto-split @@ -1406,6 +1475,7 @@ fn main() { LinkerPluginLto::Yes, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // packed-lto-single @@ -1418,6 +1488,7 @@ fn main() { LinkerPluginLto::Yes, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // FIXME: the remapping tests probably need to be reworked, see @@ -1433,6 +1504,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Unspecified, + None, ); // packed-remapped-single @@ -1445,6 +1517,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Unspecified, + None, ); // packed-remapped-scope @@ -1457,6 +1530,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Yes("debuginfo"), + None, ); // packed-remapped-wrong-scope @@ -1469,6 +1543,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Yes("macro"), + None, ); // packed-crosscrate-split @@ -1481,6 +1556,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // packed-crosscrate-single @@ -1493,6 +1569,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // unpacked-split @@ -1505,6 +1582,20 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, + ); + + // unpacked-split with split-dwarf-out-dir + shared_linux_other_tests::split_debuginfo( + CrossCrateTest::No, + UnstableOptions::Yes, + SplitDebuginfo::Unpacked, + DebuginfoLevel::Full, + SplitDwarfKind::Split, + LinkerPluginLto::Unspecified, + RemapPathPrefix::Unspecified, + RemapPathScope::Unspecified, + Some("other-dir"), ); // unpacked-single @@ -1517,6 +1608,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // unpacked-lto-split @@ -1529,6 +1621,7 @@ fn main() { LinkerPluginLto::Yes, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // unpacked-lto-single @@ -1541,6 +1634,7 @@ fn main() { LinkerPluginLto::Yes, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); // unpacked-remapped-split @@ -1553,6 +1647,20 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Unspecified, + None, + ); + + // unpacked-remapped-split with split-dwarf-out-dir + shared_linux_other_tests::split_debuginfo( + CrossCrateTest::No, + UnstableOptions::Yes, + SplitDebuginfo::Unpacked, + DebuginfoLevel::Full, + SplitDwarfKind::Split, + LinkerPluginLto::Unspecified, + RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, + RemapPathScope::Unspecified, + Some("other-dir"), ); // unpacked-remapped-single @@ -1565,6 +1673,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Unspecified, + None, ); // unpacked-remapped-scope @@ -1577,6 +1686,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Yes("debuginfo"), + None, ); // unpacked-remapped-wrong-scope @@ -1589,6 +1699,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Yes { remapped_prefix: "/__MY_REMAPPED_PATH__" }, RemapPathScope::Yes("macro"), + None, ); // unpacked-crosscrate-split @@ -1601,6 +1712,20 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, + ); + + // unpacked-crosscrate-split with split-dwarf-out-dir + shared_linux_other_tests::split_debuginfo( + CrossCrateTest::Yes, + UnstableOptions::Yes, + SplitDebuginfo::Unpacked, + DebuginfoLevel::Full, + SplitDwarfKind::Split, + LinkerPluginLto::Unspecified, + RemapPathPrefix::Unspecified, + RemapPathScope::Unspecified, + Some("other-dir"), ); // unpacked-crosscrate-single @@ -1613,6 +1738,7 @@ fn main() { LinkerPluginLto::Unspecified, RemapPathPrefix::Unspecified, RemapPathScope::Unspecified, + None, ); } } From 660a3486fc6da2c3599a167d73d849178f98bc17 Mon Sep 17 00:00:00 2001 From: Noratrieb <48135649+Noratrieb@users.noreply.github.com> Date: Sat, 27 Sep 2025 13:37:29 +0200 Subject: [PATCH 05/23] Skip stack overflow handler for panic=immediate-abort std installs guard pages and a signal handler to ensure that stackoverflows 1) terminate abruptly and 2) print an nice message. Even for panic=immediate-abort, 1) is desirable, we don't want silent data corruption there. But 2) is completely unnecessary, as users deliberately *don't* want nice messages, they want minimum binary size. Therefore, skip the entire guard signal handler setup, which saves a lot of bytes. I tested this with a hello world binary using fat LTO, build-std, panic=immediate-abort, opt-level=s, strip=debuginfo. `size` reports significant savings: ``` text data bss dec hex filename 15252 1032 104 16388 4004 tiny-before 6881 964 48 7893 1ed5 tiny-after2 ``` `nm -U` goes from 71 to 56, getting rid of a bunch of stack overflow related symbols. The disk size goes from `31k` to `24k`. The impact on the error message is minimal, as the message was already missing. before: ``` fish: Job 1, './tiny-so-before' terminated by signal SIGABRT (Abort) ``` after: ``` fish: Job 1, './tiny-so-after' terminated by signal SIGSEGV (Address boundary error) ``` --- library/std/src/sys/pal/unix/stack_overflow.rs | 12 +++++++++++- library/std/src/sys/pal/windows/mod.rs | 3 ++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/unix/stack_overflow.rs b/library/std/src/sys/pal/unix/stack_overflow.rs index 0d2100d66bc0..08a3cee64bab 100644 --- a/library/std/src/sys/pal/unix/stack_overflow.rs +++ b/library/std/src/sys/pal/unix/stack_overflow.rs @@ -148,6 +148,13 @@ mod imp { let mut guard_page_range = unsafe { install_main_guard() }; + // Even for panic=immediate-abort, installing the guard pages is important for soundness. + // That said, we do not care about giving nice stackoverflow messages via our custom + // signal handler, just exit early and let the user enjoy the segfault. + if cfg!(panic = "immediate-abort") { + return; + } + // SAFETY: assuming all platforms define struct sigaction as "zero-initializable" let mut action: sigaction = unsafe { mem::zeroed() }; for &signal in &[SIGSEGV, SIGBUS] { @@ -179,6 +186,9 @@ mod imp { /// Must be called only once #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn cleanup() { + if cfg!(panic = "immediate-abort") { + return; + } // FIXME: I probably cause more bugs than I'm worth! // see https://github.com/rust-lang/rust/issues/111272 unsafe { drop_handler(MAIN_ALTSTACK.load(Ordering::Relaxed)) }; @@ -230,7 +240,7 @@ mod imp { /// Mutates the alternate signal stack #[forbid(unsafe_op_in_unsafe_fn)] pub unsafe fn make_handler(main_thread: bool, thread_name: Option>) -> Handler { - if !NEED_ALTSTACK.load(Ordering::Acquire) { + if cfg!(panic = "immediate-abort") || !NEED_ALTSTACK.load(Ordering::Acquire) { return Handler::null(); } diff --git a/library/std/src/sys/pal/windows/mod.rs b/library/std/src/sys/pal/windows/mod.rs index 3357946b8f71..b7578b01584b 100644 --- a/library/std/src/sys/pal/windows/mod.rs +++ b/library/std/src/sys/pal/windows/mod.rs @@ -22,7 +22,8 @@ pub mod os; pub mod pipe; pub mod time; cfg_select! { - not(target_vendor = "uwp") => { + // We don't care about printing nice error messages for panic=immediate-abort + all(not(target_vendor = "uwp"), not(panic = "immediate-abort")) => { pub mod stack_overflow; } _ => { From b3631e1174e222bf1dadf1549cfd0f717ebf6d64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 16 Sep 2025 11:52:17 -0700 Subject: [PATCH 06/23] improve empty attribute diagnostic --- compiler/rustc_attr_parsing/messages.ftl | 10 +++++++++- compiler/rustc_attr_parsing/src/context.rs | 7 ++++++- compiler/rustc_attr_parsing/src/lints.rs | 18 ++++++++++++------ .../src/session_diagnostics.rs | 3 +++ compiler/rustc_hir/src/lints.rs | 15 ++++++++------- tests/ui/attributes/empty-repr.stderr | 1 + tests/ui/empty/empty-attributes.stderr | 4 ++++ tests/ui/macros/macro-use-all-and-none.stderr | 3 ++- tests/ui/repr/repr-empty-packed.stderr | 1 + 9 files changed, 46 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 81ec17077c13..6c5346e83554 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -8,7 +8,15 @@ attr_parsing_deprecated_item_suggestion = attr_parsing_empty_attribute = unused attribute - .suggestion = remove this attribute + .suggestion = {$valid_without_list -> + [true] remove these parentheses + *[other] remove this attribute + } + .note = {$valid_without_list -> + [true] using `{$attr_path}` with an empty list is equivalent to not using a list at all + *[other] using `{$attr_path}` with an empty list has no effect + } + attr_parsing_invalid_target = `#[{$name}]` attribute cannot be used on {$target} .help = `#[{$name}]` can {$only}be applied to {$applied} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d7ccf3c78069..e8bb4caa4166 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -597,7 +597,12 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { } pub(crate) fn warn_empty_attribute(&mut self, span: Span) { - self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span); + let attr_path = self.attr_path.clone(); + let valid_without_list = self.template.word; + self.emit_lint( + AttributeLintKind::EmptyAttribute { first_span: span, attr_path, valid_without_list }, + span, + ); } } diff --git a/compiler/rustc_attr_parsing/src/lints.rs b/compiler/rustc_attr_parsing/src/lints.rs index ab8ba0daf1f1..3a2a37046696 100644 --- a/compiler/rustc_attr_parsing/src/lints.rs +++ b/compiler/rustc_attr_parsing/src/lints.rs @@ -43,12 +43,18 @@ pub fn emit_attribute_lint(lint: &AttributeLint, lint_emi ), }, ), - AttributeLintKind::EmptyAttribute { first_span } => lint_emitter.emit_node_span_lint( - rustc_session::lint::builtin::UNUSED_ATTRIBUTES, - *id, - *first_span, - session_diagnostics::EmptyAttributeList { attr_span: *first_span }, - ), + AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => { + lint_emitter.emit_node_span_lint( + rustc_session::lint::builtin::UNUSED_ATTRIBUTES, + *id, + *first_span, + session_diagnostics::EmptyAttributeList { + attr_span: *first_span, + attr_path: attr_path.clone(), + valid_without_list: *valid_without_list, + }, + ) + } AttributeLintKind::InvalidTarget { name, target, applied, only } => lint_emitter .emit_node_span_lint( // This check is here because `deprecated` had its own lint group and removing this would be a breaking change diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 2c2b14c8a68b..1194ac5872cb 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -503,9 +503,12 @@ pub(crate) struct EmptyConfusables { #[derive(LintDiagnostic)] #[diag(attr_parsing_empty_attribute)] +#[note] pub(crate) struct EmptyAttributeList { #[suggestion(code = "", applicability = "machine-applicable")] pub attr_span: Span, + pub attr_path: AttrPath, + pub valid_without_list: bool, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_hir/src/lints.rs b/compiler/rustc_hir/src/lints.rs index b7a0a6a0c197..c9de6f6b5d52 100644 --- a/compiler/rustc_hir/src/lints.rs +++ b/compiler/rustc_hir/src/lints.rs @@ -31,6 +31,12 @@ pub struct AttributeLint { #[derive(Clone, Debug, HashStable_Generic)] pub enum AttributeLintKind { + /// Copy of `IllFormedAttributeInput` + /// specifically for the `invalid_macro_export_arguments` lint until that is removed, + /// see + InvalidMacroExportArguments { + suggestions: Vec, + }, UnusedDuplicate { this: Span, other: Span, @@ -41,13 +47,8 @@ pub enum AttributeLintKind { }, EmptyAttribute { first_span: Span, - }, - - /// Copy of `IllFormedAttributeInput` - /// specifically for the `invalid_macro_export_arguments` lint until that is removed, - /// see - InvalidMacroExportArguments { - suggestions: Vec, + attr_path: AttrPath, + valid_without_list: bool, }, InvalidTarget { name: AttrPath, diff --git a/tests/ui/attributes/empty-repr.stderr b/tests/ui/attributes/empty-repr.stderr index 92901fa170c2..6dfa2df75b73 100644 --- a/tests/ui/attributes/empty-repr.stderr +++ b/tests/ui/attributes/empty-repr.stderr @@ -4,6 +4,7 @@ error: unused attribute LL | #[repr()] | ^^^^^^^^^ help: remove this attribute | + = note: using `repr` with an empty list has no effect note: the lint level is defined here --> $DIR/empty-repr.rs:4:9 | diff --git a/tests/ui/empty/empty-attributes.stderr b/tests/ui/empty/empty-attributes.stderr index f0be56ddc6aa..41dc790737dd 100644 --- a/tests/ui/empty/empty-attributes.stderr +++ b/tests/ui/empty/empty-attributes.stderr @@ -56,12 +56,16 @@ error: unused attribute | LL | #[repr()] | ^^^^^^^^^ help: remove this attribute + | + = note: using `repr` with an empty list has no effect error: unused attribute --> $DIR/empty-attributes.rs:12:1 | LL | #[target_feature()] | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute + | + = note: using `target_feature` with an empty list has no effect error: aborting due to 8 previous errors diff --git a/tests/ui/macros/macro-use-all-and-none.stderr b/tests/ui/macros/macro-use-all-and-none.stderr index a5efb065a21b..b4c05adcb33d 100644 --- a/tests/ui/macros/macro-use-all-and-none.stderr +++ b/tests/ui/macros/macro-use-all-and-none.stderr @@ -2,8 +2,9 @@ warning: unused attribute --> $DIR/macro-use-all-and-none.rs:7:12 | LL | #[macro_use()] - | ^^ help: remove this attribute + | ^^ help: remove these parentheses | + = note: using `macro_use` with an empty list is equivalent to not using a list at all note: the lint level is defined here --> $DIR/macro-use-all-and-none.rs:4:9 | diff --git a/tests/ui/repr/repr-empty-packed.stderr b/tests/ui/repr/repr-empty-packed.stderr index 6565b2e8c1dc..adf32c955296 100644 --- a/tests/ui/repr/repr-empty-packed.stderr +++ b/tests/ui/repr/repr-empty-packed.stderr @@ -15,6 +15,7 @@ error: unused attribute LL | #[repr()] | ^^^^^^^^^ help: remove this attribute | + = note: using `repr` with an empty list has no effect note: the lint level is defined here --> $DIR/repr-empty-packed.rs:2:9 | From fa53de656ec9318d9462dcadcfd851685c3dcaf1 Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 27 Sep 2025 19:40:48 +0200 Subject: [PATCH 07/23] tests: Remove ignore-android directive for fixed issue --- tests/ui/test-attrs/test-panic-abort-nocapture.rs | 1 - tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr | 4 ++-- tests/ui/test-attrs/test-panic-abort.rs | 1 - tests/ui/test-attrs/test-panic-abort.run.stdout | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs index 6a1025ea087c..7c78d432fa08 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs @@ -6,7 +6,6 @@ //@ exec-env:RUST_BACKTRACE=0 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ ignore-android #120567 //@ needs-subprocess #![cfg(test)] diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr index 8d7c62f8ec70..d8f65a78261f 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr @@ -1,11 +1,11 @@ -thread 'main' ($TID) panicked at $DIR/test-panic-abort-nocapture.rs:32:5: +thread 'main' ($TID) panicked at $DIR/test-panic-abort-nocapture.rs:31:5: assertion `left == right` failed left: 2 right: 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' ($TID) panicked at $DIR/test-panic-abort-nocapture.rs:26:5: +thread 'main' ($TID) panicked at $DIR/test-panic-abort-nocapture.rs:25:5: assertion `left == right` failed left: 2 right: 4 diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs index 6c9b641fb6fb..13a30223399e 100644 --- a/tests/ui/test-attrs/test-panic-abort.rs +++ b/tests/ui/test-attrs/test-panic-abort.rs @@ -6,7 +6,6 @@ //@ exec-env:RUST_BACKTRACE=0 //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" -//@ ignore-android #120567 //@ needs-subprocess #![cfg(test)] diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout index 4d65c05b9440..ca247f7da418 100644 --- a/tests/ui/test-attrs/test-panic-abort.run.stdout +++ b/tests/ui/test-attrs/test-panic-abort.run.stdout @@ -18,7 +18,7 @@ testing123 ---- it_fails stderr ---- testing321 -thread 'main' ($TID) panicked at $DIR/test-panic-abort.rs:37:5: +thread 'main' ($TID) panicked at $DIR/test-panic-abort.rs:36:5: assertion `left == right` failed left: 2 right: 5 From 0d658fe156c077e0f37068d5788f6c375d555b54 Mon Sep 17 00:00:00 2001 From: Nik Revenco Date: Sun, 28 Sep 2025 00:55:47 +0100 Subject: [PATCH 08/23] test: add `keyword/soup.rs` --- tests/ui/keyword/soup.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/ui/keyword/soup.rs diff --git a/tests/ui/keyword/soup.rs b/tests/ui/keyword/soup.rs new file mode 100644 index 000000000000..c4dbe3fb4834 --- /dev/null +++ b/tests/ui/keyword/soup.rs @@ -0,0 +1,30 @@ +//@ edition:2024 +//@ check-pass + +#![allow(unused_imports)] +#![allow(missing_abi)] +#![allow(unused_macros)] +#![allow(non_camel_case_types)] +#![allow(unreachable_code)] +#![allow(unused_variables)] +#![allow(dead_code)] +#![allow(unused_must_use)] + +// all 48 keywords in 300 characters +mod x { + pub(super) struct X; + use Ok; + impl X { + pub(in crate) async fn x(self: Self, x: &'static &'_ dyn for<> Fn()) where { + unsafe extern { safe fn x(); } + macro_rules! x { () => {}; } + if 'x: loop { + return match while let true = break 'x false { continue } { + ref x => { &raw mut x; async { const { enum A {} } }.await as () }, + }; + } { type x = X; } else { move || { trait x { } union B { x: () } }; } + } + } +} + +fn main() {} From cc7bd291cdd76f1e1ef83223ec7bec4077646ac7 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 28 Sep 2025 17:17:44 +1000 Subject: [PATCH 09/23] Fix change-tracker entry for 147046 --- src/bootstrap/src/utils/change_tracker.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index f311c84bec9b..0123bd6340e5 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -557,7 +557,7 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ summary: "New option `build.windows-rc` that will override which resource compiler on Windows will be used to compile Rust.", }, ChangeInfo { - change_id: 99999, + change_id: 147046, severity: ChangeSeverity::Warning, summary: "The `rust.use-lld` option has been renamed to `rust.bootstrap-override-lld`. Note that it only serves for overriding the linker used when building Rust code in bootstrap to be LLD.", }, From e99364ea357957b33460664fc496a3a8c218494e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 23 Sep 2025 18:12:33 +1000 Subject: [PATCH 10/23] Remove old-output-capture from compiletest --- src/tools/compiletest/src/common.rs | 9 ------- src/tools/compiletest/src/executor.rs | 35 ++++++++------------------- src/tools/compiletest/src/lib.rs | 32 ------------------------ 3 files changed, 10 insertions(+), 66 deletions(-) diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 6da102b1b5f1..6d9599489180 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -661,18 +661,10 @@ pub struct Config { pub builtin_cfg_names: OnceLock>, pub supported_crate_types: OnceLock>, - /// FIXME: this is why we still need to depend on *staged* `std`, it's because we currently rely - /// on `#![feature(internal_output_capture)]` for [`std::io::set_output_capture`] to implement - /// `libtest`-esque `--no-capture`. - /// /// FIXME: rename this to the more canonical `no_capture`, or better, invert this to `capture` /// to avoid `!nocapture` double-negatives. pub nocapture: bool, - /// True if the experimental new output-capture implementation should be - /// used, avoiding the need for `#![feature(internal_output_capture)]`. - pub new_output_capture: bool, - /// Needed both to construct [`build_helper::git::GitConfig`]. pub nightly_branch: String, pub git_merge_commit_email: String, @@ -790,7 +782,6 @@ impl Config { builtin_cfg_names: Default::default(), supported_crate_types: Default::default(), nocapture: Default::default(), - new_output_capture: Default::default(), nightly_branch: Default::default(), git_merge_commit_email: Default::default(), profiler_runtime: Default::default(), diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index c8e13d445738..c7aca6d1c5aa 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -9,8 +9,8 @@ use std::borrow::Cow; use std::collections::HashMap; use std::hash::{BuildHasherDefault, DefaultHasher}; use std::num::NonZero; -use std::sync::{Arc, Mutex, mpsc}; -use std::{env, hint, io, mem, panic, thread}; +use std::sync::{Arc, mpsc}; +use std::{env, hint, mem, panic, thread}; use camino::Utf8PathBuf; @@ -130,10 +130,6 @@ fn run_test_inner( panic_hook::set_capture_buf(Default::default()); } - if let CaptureKind::Old { ref buf } = capture { - io::set_output_capture(Some(Arc::clone(buf))); - } - let stdout = capture.stdout(); let stderr = capture.stderr(); @@ -144,9 +140,6 @@ fn run_test_inner( // Forward any captured panic message to (captured) stderr. write!(stderr, "{panic_buf}"); } - if matches!(capture, CaptureKind::Old { .. }) { - io::set_output_capture(None); - } let outcome = match (should_panic, panic_payload) { (ShouldPanic::No, None) | (ShouldPanic::Yes, Some(_)) => TestOutcome::Succeeded, @@ -167,31 +160,24 @@ enum CaptureKind { /// runners, whose output is always captured.) None, - /// Use the old output-capture implementation, which relies on the unstable - /// library feature `#![feature(internal_output_capture)]`. - Old { buf: Arc>> }, - - /// Use the new output-capture implementation, which only uses stable Rust. - New { buf: output_capture::CaptureBuf }, + /// Capture all console output that would be printed by test runners via + /// their `stdout` and `stderr` trait objects, or via the custom panic hook. + Capture { buf: output_capture::CaptureBuf }, } impl CaptureKind { fn for_config(config: &Config) -> Self { if config.nocapture { Self::None - } else if config.new_output_capture { - Self::New { buf: output_capture::CaptureBuf::new() } } else { - // Create a capure buffer for `io::set_output_capture`. - Self::Old { buf: Default::default() } + Self::Capture { buf: output_capture::CaptureBuf::new() } } } fn should_set_panic_hook(&self) -> bool { match self { Self::None => false, - Self::Old { .. } => true, - Self::New { .. } => true, + Self::Capture { .. } => true, } } @@ -205,16 +191,15 @@ impl CaptureKind { fn capture_buf_or<'a>(&'a self, fallback: &'a dyn ConsoleOut) -> &'a dyn ConsoleOut { match self { - Self::None | Self::Old { .. } => fallback, - Self::New { buf } => buf, + Self::None => fallback, + Self::Capture { buf } => buf, } } fn into_inner(self) -> Option> { match self { Self::None => None, - Self::Old { buf } => Some(buf.lock().unwrap_or_else(|e| e.into_inner()).to_vec()), - Self::New { buf } => Some(buf.into_inner().into()), + Self::Capture { buf } => Some(buf.into_inner().into()), } } } diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index ce2a3d4b5fbb..15e31dadf971 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -1,9 +1,4 @@ #![crate_name = "compiletest"] -// Needed by the "new" test executor that does not depend on libtest. -// FIXME(Zalathar): We should be able to get rid of `internal_output_capture`, -// by having `runtest` manually capture all of its println-like output instead. -// That would result in compiletest being written entirely in stable Rust! -#![feature(internal_output_capture)] #[cfg(test)] mod tests; @@ -178,12 +173,6 @@ pub fn parse_config(args: Vec) -> Config { // FIXME: Temporarily retained so we can point users to `--no-capture` .optflag("", "nocapture", "") .optflag("", "no-capture", "don't capture stdout/stderr of tests") - .optopt( - "N", - "new-output-capture", - "enables or disables the new output-capture implementation", - "off|on", - ) .optflag("", "profiler-runtime", "is the profiler runtime enabled for this target") .optflag("h", "help", "show this message") .reqopt("", "channel", "current Rust channel", "CHANNEL") @@ -480,14 +469,6 @@ pub fn parse_config(args: Vec) -> Config { supported_crate_types: OnceLock::new(), nocapture: matches.opt_present("no-capture"), - new_output_capture: { - let value = matches - .opt_str("new-output-capture") - .or_else(|| env::var("COMPILETEST_NEW_OUTPUT_CAPTURE").ok()) - .unwrap_or_else(|| "on".to_owned()); - parse_bool_option(&value) - .unwrap_or_else(|| panic!("unknown `--new-output-capture` value `{value}` given")) - }, nightly_branch: matches.opt_str("nightly-branch").unwrap(), git_merge_commit_email: matches.opt_str("git-merge-commit-email").unwrap(), @@ -503,19 +484,6 @@ pub fn parse_config(args: Vec) -> Config { } } -/// Parses the same set of boolean values accepted by rustc command-line arguments. -/// -/// Accepting all of these values is more complicated than just picking one -/// pair, but has the advantage that contributors who are used to rustc -/// shouldn't have to think about which values are legal. -fn parse_bool_option(value: &str) -> Option { - match value { - "off" | "no" | "n" | "false" => Some(false), - "on" | "yes" | "y" | "true" => Some(true), - _ => None, - } -} - pub fn opt_str(maybestr: &Option) -> &str { match *maybestr { None => "(none)", From 7b8ae74da119e9ba025baeca60c22376f30d1307 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 23 Sep 2025 21:38:11 +1000 Subject: [PATCH 11/23] Add a bootstrap snapshot test for `x test compiletest` --- src/bootstrap/src/core/builder/tests.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index a3c8380a3c7d..66771fbf41c0 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2145,6 +2145,18 @@ mod snapshot { "); } + #[test] + fn test_compiletest_self_test() { + let ctx = TestCtx::new(); + let steps = ctx.config("test").arg("compiletest").render_steps(); + insta::assert_snapshot!(steps, @r" + [build] llvm + [build] rustc 0 -> rustc 1 + [build] rustc 1 -> std 1 + [build] rustdoc 1 + "); + } + #[test] fn test_compiletest_suites_stage1() { let ctx = TestCtx::new(); From 193f7179cca1c3b01eb7f2587616a95999e51903 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 23 Sep 2025 18:22:56 +1000 Subject: [PATCH 12/23] Build and test compiletest as a stage0 bootstrap tool --- src/bootstrap/src/core/build_steps/check.rs | 11 +++----- src/bootstrap/src/core/build_steps/test.rs | 29 ++++++++++----------- src/bootstrap/src/core/build_steps/tool.rs | 18 +++---------- src/bootstrap/src/core/builder/tests.rs | 18 +------------ src/bootstrap/src/core/config/config.rs | 7 ++--- src/bootstrap/src/core/config/mod.rs | 10 +++++-- src/bootstrap/src/core/config/toml/build.rs | 2 ++ src/bootstrap/src/lib.rs | 4 +-- src/bootstrap/src/utils/change_tracker.rs | 5 ++++ 9 files changed, 40 insertions(+), 64 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 043457f64e57..27f259d42079 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -8,8 +8,8 @@ use crate::core::build_steps::compile::{ }; use crate::core::build_steps::tool; use crate::core::build_steps::tool::{ - COMPILETEST_ALLOW_FEATURES, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode, - get_tool_target_compiler, prepare_tool_cargo, + SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, ToolTargetBuildMode, get_tool_target_compiler, + prepare_tool_cargo, }; use crate::core::builder::{ self, Alias, Builder, Cargo, Kind, RunConfig, ShouldRun, Step, StepMetadata, crate_description, @@ -825,12 +825,7 @@ tool_check_step!(CoverageDump { // so this is mainly for people working on compiletest to run locally. tool_check_step!(Compiletest { path: "src/tools/compiletest", - mode: |builder: &Builder<'_>| if builder.config.compiletest_use_stage0_libtest { - Mode::ToolBootstrap - } else { - Mode::ToolStd - }, - allow_features: COMPILETEST_ALLOW_FEATURES, + mode: |_builder| Mode::ToolBootstrap, default: false, }); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index ca2731819e7e..00aea8feab7d 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -18,8 +18,8 @@ use crate::core::build_steps::llvm::get_llvm_version; use crate::core::build_steps::run::get_completion_paths; use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget; use crate::core::build_steps::tool::{ - self, COMPILETEST_ALLOW_FEATURES, RustcPrivateCompilers, SourceType, - TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool, ToolTargetBuildMode, get_tool_target_compiler, + self, RustcPrivateCompilers, SourceType, TEST_FLOAT_PARSE_ALLOW_FEATURES, Tool, + ToolTargetBuildMode, get_tool_target_compiler, }; use crate::core::build_steps::toolstate::ToolState; use crate::core::build_steps::{compile, dist, llvm}; @@ -36,7 +36,7 @@ use crate::utils::helpers::{ linker_args, linker_flags, t, target_supports_cranelift_backend, up_to_date, }; use crate::utils::render_tests::{add_flags_and_try_run_tests, try_run_tests}; -use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, debug, envify}; +use crate::{CLang, CodegenBackendKind, DocTests, GitRepo, Mode, PathSet, envify}; const ADB_TEST_DIR: &str = "/data/local/tmp/work"; @@ -786,26 +786,26 @@ impl Step for CompiletestTest { fn run(self, builder: &Builder<'_>) { let host = self.host; + // Now that compiletest uses only stable Rust, building it always uses + // the stage 0 compiler. However, some of its unit tests need to be able + // to query information from an in-tree compiler, so we treat `--stage` + // as selecting the stage of that secondary compiler. + if builder.top_stage == 0 && !builder.config.compiletest_allow_stage0 { eprintln!("\ -ERROR: `--stage 0` runs compiletest self-tests against the stage0 (precompiled) compiler, not the in-tree compiler, and will almost always cause tests to fail +ERROR: `--stage 0` causes compiletest to query information from the stage0 (precompiled) compiler, instead of the in-tree compiler, which can cause some tests to fail inappropriately NOTE: if you're sure you want to do this, please open an issue as to why. In the meantime, you can override this with `--set build.compiletest-allow-stage0=true`." ); crate::exit!(1); } - let compiler = builder.compiler(builder.top_stage, host); - debug!(?compiler); + let bootstrap_compiler = builder.compiler(0, host); + let staged_compiler = builder.compiler(builder.top_stage, host); - // We need `ToolStd` for the locally-built sysroot because - // compiletest uses unstable features of the `test` crate. - builder.std(compiler, host); let mut cargo = tool::prepare_tool_cargo( builder, - compiler, - // compiletest uses libtest internals; make it use the in-tree std to make sure it never - // breaks when std sources change. - Mode::ToolStd, + bootstrap_compiler, + Mode::ToolBootstrap, host, Kind::Test, "src/tools/compiletest", @@ -816,9 +816,8 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the // Used for `compiletest` self-tests to have the path to the *staged* compiler. Getting this // right is important, as `compiletest` is intended to only support one target spec JSON // format, namely that of the staged compiler. - cargo.env("TEST_RUSTC", builder.rustc(compiler)); + cargo.env("TEST_RUSTC", builder.rustc(staged_compiler)); - cargo.allow_features(COMPILETEST_ALLOW_FEATURES); run_cargo_test(cargo, &[], &[], "compiletest self test", host, builder); } } diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 4f096d50ea5c..819e903020c8 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -380,7 +380,6 @@ macro_rules! bootstrap_tool { ($( $name:ident, $path:expr, $tool_name:expr $(,is_external_tool = $external:expr)* - $(,is_unstable_tool = $unstable:expr)* $(,allow_features = $allow_features:expr)? $(,submodules = $submodules:expr)? $(,artifact_kind = $artifact_kind:expr)? @@ -438,19 +437,11 @@ macro_rules! bootstrap_tool { } )* - let is_unstable = false $(|| $unstable)*; - let compiletest_wants_stage0 = $tool_name == "compiletest" && builder.config.compiletest_use_stage0_libtest; - builder.ensure(ToolBuild { build_compiler: self.compiler, target: self.target, tool: $tool_name, - mode: if is_unstable && !compiletest_wants_stage0 { - // use in-tree libraries for unstable features - Mode::ToolStd - } else { - Mode::ToolBootstrap - }, + mode: Mode::ToolBootstrap, path: $path, source_type: if false $(|| $external)* { SourceType::Submodule @@ -483,8 +474,6 @@ macro_rules! bootstrap_tool { } } -pub(crate) const COMPILETEST_ALLOW_FEATURES: &str = "internal_output_capture"; - bootstrap_tool!( // This is marked as an external tool because it includes dependencies // from submodules. Trying to keep the lints in sync between all the repos @@ -495,7 +484,7 @@ bootstrap_tool!( Tidy, "src/tools/tidy", "tidy"; Linkchecker, "src/tools/linkchecker", "linkchecker"; CargoTest, "src/tools/cargotest", "cargotest"; - Compiletest, "src/tools/compiletest", "compiletest", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; + Compiletest, "src/tools/compiletest", "compiletest"; BuildManifest, "src/tools/build-manifest", "build-manifest"; RemoteTestClient, "src/tools/remote-test-client", "remote-test-client"; RustInstaller, "src/tools/rust-installer", "rust-installer"; @@ -509,8 +498,7 @@ bootstrap_tool!( CollectLicenseMetadata, "src/tools/collect-license-metadata", "collect-license-metadata"; GenerateCopyright, "src/tools/generate-copyright", "generate-copyright"; GenerateWindowsSys, "src/tools/generate-windows-sys", "generate-windows-sys"; - // rustdoc-gui-test has a crate dependency on compiletest, so it needs the same unstable features. - RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test", is_unstable_tool = true, allow_features = COMPILETEST_ALLOW_FEATURES; + RustdocGUITest, "src/tools/rustdoc-gui-test", "rustdoc-gui-test"; CoverageDump, "src/tools/coverage-dump", "coverage-dump"; UnicodeTableGenerator, "src/tools/unicode-table-generator", "unicode-table-generator"; FeaturesStatusDump, "src/tools/features-status-dump", "features-status-dump"; diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index 66771fbf41c0..88df469e9a09 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2004,21 +2004,6 @@ mod snapshot { .render_steps(), @"[check] rustc 0 -> Compiletest 1 "); } - #[test] - fn check_compiletest_stage1_libtest() { - let ctx = TestCtx::new(); - insta::assert_snapshot!( - ctx.config("check") - .path("compiletest") - .args(&["--set", "build.compiletest-use-stage0-libtest=false"]) - .render_steps(), @r" - [build] llvm - [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [check] rustc 1 -> Compiletest 2 - "); - } - #[test] fn check_codegen() { let ctx = TestCtx::new(); @@ -2152,8 +2137,7 @@ mod snapshot { insta::assert_snapshot!(steps, @r" [build] llvm [build] rustc 0 -> rustc 1 - [build] rustc 1 -> std 1 - [build] rustdoc 1 + [build] rustdoc 0 "); } diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 271ce4cb950b..1fcc1174e856 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -310,9 +310,6 @@ pub struct Config { /// sources. pub compiletest_allow_stage0: bool, - /// Whether to use the precompiled stage0 libtest with compiletest. - pub compiletest_use_stage0_libtest: bool, - /// Default value for `--extra-checks` pub tidy_extra_checks: Option, pub is_running_on_ci: bool, @@ -497,7 +494,8 @@ impl Config { optimized_compiler_builtins: build_optimized_compiler_builtins, jobs: build_jobs, compiletest_diff_tool: build_compiletest_diff_tool, - compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest, + // No longer has any effect; kept (for now) to avoid breaking people's configs. + compiletest_use_stage0_libtest: _, tidy_extra_checks: build_tidy_extra_checks, ccache: build_ccache, exclude: build_exclude, @@ -1197,7 +1195,6 @@ impl Config { compiler_docs: build_compiler_docs.unwrap_or(false), compiletest_allow_stage0: build_compiletest_allow_stage0.unwrap_or(false), compiletest_diff_tool: build_compiletest_diff_tool, - compiletest_use_stage0_libtest: build_compiletest_use_stage0_libtest.unwrap_or(true), config: toml_path, configure_args: build_configure_args.unwrap_or_default(), control_flow_guard: rust_control_flow_guard.unwrap_or(false), diff --git a/src/bootstrap/src/core/config/mod.rs b/src/bootstrap/src/core/config/mod.rs index 56b87823a365..007ed4aaba13 100644 --- a/src/bootstrap/src/core/config/mod.rs +++ b/src/bootstrap/src/core/config/mod.rs @@ -47,11 +47,17 @@ use crate::str::FromStr; #[macro_export] macro_rules! define_config { ($(#[$attr:meta])* struct $name:ident { - $($field:ident: Option<$field_ty:ty> = $field_key:literal,)* + $( + $(#[$field_attr:meta])* + $field:ident: Option<$field_ty:ty> = $field_key:literal, + )* }) => { $(#[$attr])* pub struct $name { - $(pub $field: Option<$field_ty>,)* + $( + $(#[$field_attr])* + pub $field: Option<$field_ty>, + )* } impl Merge for $name { diff --git a/src/bootstrap/src/core/config/toml/build.rs b/src/bootstrap/src/core/config/toml/build.rs index a9d4d3961c9b..c63673dd9808 100644 --- a/src/bootstrap/src/core/config/toml/build.rs +++ b/src/bootstrap/src/core/config/toml/build.rs @@ -70,6 +70,8 @@ define_config! { jobs: Option = "jobs", compiletest_diff_tool: Option = "compiletest-diff-tool", compiletest_allow_stage0: Option = "compiletest-allow-stage0", + /// No longer has any effect; kept (for now) to avoid breaking people's configs. + /// FIXME(#146929): Remove this in 2026. compiletest_use_stage0_libtest: Option = "compiletest-use-stage0-libtest", tidy_extra_checks: Option = "tidy-extra-checks", ccache: Option = "ccache", diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index d798639cc967..dd30f05b7283 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -327,8 +327,8 @@ pub enum Mode { ToolTarget, /// Build a tool which uses the locally built std, placing output in the - /// "stageN-tools" directory. Its usage is quite rare, mainly used by - /// compiletest which needs libtest. + /// "stageN-tools" directory. Its usage is quite rare; historically it was + /// needed by compiletest, but now it is mainly used by `test-float-parse`. ToolStd, /// Build a tool which uses the `rustc_private` mechanism, and thus diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 0123bd6340e5..853fc4e6623e 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -561,4 +561,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Warning, summary: "The `rust.use-lld` option has been renamed to `rust.bootstrap-override-lld`. Note that it only serves for overriding the linker used when building Rust code in bootstrap to be LLD.", }, + ChangeInfo { + change_id: 146929, + severity: ChangeSeverity::Info, + summary: "`compiletest` is now always built with the stage 0 compiler, so `build.compiletest-use-stage0-libtest` has no effect.", + }, ]; From 8b1879864b4487c89ee414fa64abe42440fa922b Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 23 Sep 2025 22:05:12 +1000 Subject: [PATCH 13/23] `tool_check_step!` no longer needs a builder to determine mode --- src/bootstrap/src/core/build_steps/check.rs | 44 +++++++++------------ 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 27f259d42079..20c54a28dda8 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -654,7 +654,7 @@ macro_rules! tool_check_step { // The part of this path after the final '/' is also used as a display name. path: $path:literal $(, alt_path: $alt_path:literal )* - // Closure that returns `Mode` based on the passed `&Builder<'_>` + // `Mode` to use when checking this tool , mode: $mode:expr // Subset of nightly features that are allowed to be used when checking $(, allow_features: $allow_features:expr )? @@ -682,8 +682,7 @@ macro_rules! tool_check_step { fn make_run(run: RunConfig<'_>) { let target = run.target; - let builder = run.builder; - let mode = $mode(builder); + let mode: Mode = $mode; let compiler = prepare_compiler_for_check(run.builder, target, mode); @@ -704,7 +703,7 @@ macro_rules! tool_check_step { _value }; let extra_features: &[&str] = &[$($($enable_features),*)?]; - let mode = $mode(builder); + let mode: Mode = $mode; run_tool_check_step(builder, compiler, target, $path, mode, allow_features, extra_features); } @@ -767,57 +766,50 @@ fn run_tool_check_step( tool_check_step!(Rustdoc { path: "src/tools/rustdoc", alt_path: "src/librustdoc", - mode: |_builder| Mode::ToolRustcPrivate + mode: Mode::ToolRustcPrivate }); // Clippy, miri and Rustfmt are hybrids. They are external tools, but use a git subtree instead // of a submodule. Since the SourceType only drives the deny-warnings // behavior, treat it as in-tree so that any new warnings in clippy will be // rejected. -tool_check_step!(Clippy { path: "src/tools/clippy", mode: |_builder| Mode::ToolRustcPrivate }); -tool_check_step!(Miri { path: "src/tools/miri", mode: |_builder| Mode::ToolRustcPrivate }); -tool_check_step!(CargoMiri { - path: "src/tools/miri/cargo-miri", - mode: |_builder| Mode::ToolRustcPrivate -}); -tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: |_builder| Mode::ToolRustcPrivate }); +tool_check_step!(Clippy { path: "src/tools/clippy", mode: Mode::ToolRustcPrivate }); +tool_check_step!(Miri { path: "src/tools/miri", mode: Mode::ToolRustcPrivate }); +tool_check_step!(CargoMiri { path: "src/tools/miri/cargo-miri", mode: Mode::ToolRustcPrivate }); +tool_check_step!(Rustfmt { path: "src/tools/rustfmt", mode: Mode::ToolRustcPrivate }); tool_check_step!(RustAnalyzer { path: "src/tools/rust-analyzer", - mode: |_builder| Mode::ToolRustcPrivate, + mode: Mode::ToolRustcPrivate, allow_features: tool::RustAnalyzer::ALLOW_FEATURES, enable_features: ["in-rust-tree"], }); tool_check_step!(MiroptTestTools { path: "src/tools/miropt-test-tools", - mode: |_builder| Mode::ToolBootstrap + mode: Mode::ToolBootstrap }); // We want to test the local std tool_check_step!(TestFloatParse { path: "src/tools/test-float-parse", - mode: |_builder| Mode::ToolStd, + mode: Mode::ToolStd, allow_features: TEST_FLOAT_PARSE_ALLOW_FEATURES }); tool_check_step!(FeaturesStatusDump { path: "src/tools/features-status-dump", - mode: |_builder| Mode::ToolBootstrap + mode: Mode::ToolBootstrap }); -tool_check_step!(Bootstrap { - path: "src/bootstrap", - mode: |_builder| Mode::ToolBootstrap, - default: false -}); +tool_check_step!(Bootstrap { path: "src/bootstrap", mode: Mode::ToolBootstrap, default: false }); // `run-make-support` will be built as part of suitable run-make compiletest test steps, but support // check to make it easier to work on. tool_check_step!(RunMakeSupport { path: "src/tools/run-make-support", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false }); tool_check_step!(CoverageDump { path: "src/tools/coverage-dump", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false }); @@ -825,18 +817,18 @@ tool_check_step!(CoverageDump { // so this is mainly for people working on compiletest to run locally. tool_check_step!(Compiletest { path: "src/tools/compiletest", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false, }); tool_check_step!(Linkchecker { path: "src/tools/linkchecker", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false }); tool_check_step!(BumpStage0 { path: "src/tools/bump-stage0", - mode: |_builder| Mode::ToolBootstrap, + mode: Mode::ToolBootstrap, default: false }); From 7a7cb05f11a81e261e22f9ae291755b6343f7095 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sat, 27 Sep 2025 13:28:25 +0000 Subject: [PATCH 14/23] Do not validate MIR if code does not type-check. --- compiler/rustc_interface/src/passes.rs | 26 ++++++++++++++------------ tests/crashes/129095.rs | 13 ------------- tests/crashes/134174.rs | 17 ----------------- tests/crashes/134654.rs | 15 --------------- tests/crashes/135570.rs | 15 --------------- tests/crashes/136381.rs | 18 ------------------ tests/crashes/137190-1.rs | 10 ---------- tests/crashes/137468.rs | 16 ---------------- 8 files changed, 14 insertions(+), 116 deletions(-) delete mode 100644 tests/crashes/129095.rs delete mode 100644 tests/crashes/134174.rs delete mode 100644 tests/crashes/134654.rs delete mode 100644 tests/crashes/135570.rs delete mode 100644 tests/crashes/136381.rs delete mode 100644 tests/crashes/137190-1.rs delete mode 100644 tests/crashes/137468.rs diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 761a5c809182..c1bba0b01975 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -1122,18 +1122,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { sess.time("layout_testing", || layout_test::test_layout(tcx)); sess.time("abi_testing", || abi_test::test_abi(tcx)); - - // If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item - // (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs - // in MIR optimizations that may only be reachable through codegen, or other codepaths - // that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts. - if tcx.sess.opts.unstable_opts.validate_mir { - sess.time("ensuring_final_MIR_is_computable", || { - tcx.par_hir_body_owners(|def_id| { - tcx.instance_mir(ty::InstanceKind::Item(def_id.into())); - }); - }); - } } /// Runs the type-checking, region checking and other miscellaneous analysis @@ -1199,6 +1187,20 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { // we will fail to emit overlap diagnostics. Thus we invoke it here unconditionally. let _ = tcx.all_diagnostic_items(()); }); + + // If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item + // (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs + // in MIR optimizations that may only be reachable through codegen, or other codepaths + // that requires the optimized/ctfe MIR, coroutine bodies, or evaluating consts. + // Nevertheless, wait after type checking is finished, as optimizing code that does not + // type-check is very prone to ICEs. + if tcx.sess.opts.unstable_opts.validate_mir { + sess.time("ensuring_final_MIR_is_computable", || { + tcx.par_hir_body_owners(|def_id| { + tcx.instance_mir(ty::InstanceKind::Item(def_id.into())); + }); + }); + } } /// Runs the codegen backend, after which the AST and analysis can diff --git a/tests/crashes/129095.rs b/tests/crashes/129095.rs deleted file mode 100644 index b1bb74708c2d..000000000000 --- a/tests/crashes/129095.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ known-bug: rust-lang/rust#129095 -//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir - -#![feature(adt_const_params, unsized_const_params)] -#![allow(incomplete_features)] - -pub fn function_with_bytes() -> &'static [u8] { - BYTES -} - -pub fn main() { - assert_eq!(function_with_bytes::(), &[0x41, 0x41, 0x41, 0x41]); -} diff --git a/tests/crashes/134174.rs b/tests/crashes/134174.rs deleted file mode 100644 index 899cdc6faf35..000000000000 --- a/tests/crashes/134174.rs +++ /dev/null @@ -1,17 +0,0 @@ -//@ known-bug: #134175 -//@compile-flags: -Zvalidate-mir -Zinline-mir=yes -use std::vec::IntoIter; - -pub(crate) trait Foo: Iterator::Key> { - type Key; -} - -impl Foo for IntoIter {} - -fn sum_foo>(f: F) -> i32 { - f.fold(0, |a, b| a + b) -} - -fn main() { - let x = sum_foo(vec![11, 10, 1].into_iter()); -} diff --git a/tests/crashes/134654.rs b/tests/crashes/134654.rs deleted file mode 100644 index f2323fe4ecdc..000000000000 --- a/tests/crashes/134654.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #134654 -//@ compile-flags: -Zmir-enable-passes=+GVN -Zmir-enable-passes=+Inline -Zvalidate-mir -//@ only-x86_64 - -#![feature(adt_const_params, unsized_const_params)] -#![allow(incomplete_features)] - -fn function_with_bytes() -> &'static [u8] { - BYTES -} - -fn main() { - function_with_bytes::() == &[]; -} diff --git a/tests/crashes/135570.rs b/tests/crashes/135570.rs deleted file mode 100644 index 7919ceb26d50..000000000000 --- a/tests/crashes/135570.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: #135570 -//@compile-flags: -Zvalidate-mir -Zmir-enable-passes=+Inline -Copt-level=0 -Zmir-enable-passes=+GVN -//@ only-x86_64 - -#![feature(adt_const_params, unsized_const_params)] -#![allow(incomplete_features)] - -fn function_with_bytes( -) -> &'static [u8] { - BYTES -} - -fn main() { - function_with_bytes::() == &[]; -} diff --git a/tests/crashes/136381.rs b/tests/crashes/136381.rs deleted file mode 100644 index 13ccc14a2c5b..000000000000 --- a/tests/crashes/136381.rs +++ /dev/null @@ -1,18 +0,0 @@ -//@ known-bug: #136381 -//@ compile-flags: -Zvalidate-mir -Zmir-enable-passes=+GVN -#![feature(trait_upcasting)] - -trait A {} -trait B: A { - fn c(&self); -} -impl B for i32 { - fn c(self) { - todo!(); - } -} - -fn main() { - let baz: &dyn B = &1; - let bar: &dyn A = baz; -} diff --git a/tests/crashes/137190-1.rs b/tests/crashes/137190-1.rs deleted file mode 100644 index bdfe883b7120..000000000000 --- a/tests/crashes/137190-1.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: #137190 -//@ compile-flags: -Zmir-opt-level=2 -Zvalidate-mir -trait A { - fn b(&self); -} -trait C: A {} -impl C for () {} -fn main() { - (&() as &dyn C as &dyn A).b(); -} diff --git a/tests/crashes/137468.rs b/tests/crashes/137468.rs deleted file mode 100644 index cceb0502bd21..000000000000 --- a/tests/crashes/137468.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@ known-bug: #137468 -//@ compile-flags: -Copt-level=0 -Zmir-enable-passes=+GVN -Zvalidate-mir -trait Supertrait {} - -trait Identity { - type Selff; -} - -trait Trait

: Supertrait<()> + Supertrait<

::Selff> {} - -impl

Trait

for () {} - -fn main() { - let x: &dyn Trait<()> = &(); - let x: &dyn Supertrait<()> = x; -} From 7fcbc5ea465a4e280d3b7a84fc3f781e9a120ed0 Mon Sep 17 00:00:00 2001 From: Antoni Boucher Date: Sun, 28 Sep 2025 12:08:44 -0400 Subject: [PATCH 15/23] Add a leading dash to linker plugin arguments in the gcc codegen --- compiler/rustc_codegen_cranelift/src/lib.rs | 4 ++++ compiler/rustc_codegen_gcc/src/lib.rs | 4 ++++ compiler/rustc_codegen_llvm/src/lib.rs | 13 ++++++++++++- compiler/rustc_codegen_ssa/src/back/link.rs | 6 ++++++ compiler/rustc_codegen_ssa/src/back/linker.rs | 13 +++++++++++-- compiler/rustc_codegen_ssa/src/traits/backend.rs | 11 ++++++++++- .../codegen-backend/auxiliary/the_backend.rs | 4 ++++ 7 files changed, 51 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 8e34436fb5e0..5fd7c4d4f41b 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -165,6 +165,10 @@ impl CodegenBackend for CraneliftCodegenBackend { "" } + fn name(&self) -> &'static str { + "cranelift" + } + fn init(&self, sess: &Session) { use rustc_session::config::{InstrumentCoverage, Lto}; match sess.lto() { diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index f76f933cad4a..ec7eab8489ab 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -184,6 +184,10 @@ impl CodegenBackend for GccCodegenBackend { crate::DEFAULT_LOCALE_RESOURCE } + fn name(&self) -> &'static str { + "gcc" + } + fn init(&self, _sess: &Session) { #[cfg(feature = "master")] { diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 13bdb7cb1a27..e96eb304c50c 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -231,6 +231,10 @@ impl CodegenBackend for LlvmCodegenBackend { crate::DEFAULT_LOCALE_RESOURCE } + fn name(&self) -> &'static str { + "llvm" + } + fn init(&self, sess: &Session) { llvm_util::init(sess); // Make sure llvm is inited } @@ -349,7 +353,14 @@ impl CodegenBackend for LlvmCodegenBackend { // Run the linker on any artifacts that resulted from the LLVM run. // This should produce either a finished executable or library. - link_binary(sess, &LlvmArchiveBuilderBuilder, codegen_results, metadata, outputs); + link_binary( + sess, + &LlvmArchiveBuilderBuilder, + codegen_results, + metadata, + outputs, + self.name(), + ); } } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index d6c304c1b147..db2f2dd65b0b 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -79,6 +79,7 @@ pub fn link_binary( codegen_results: CodegenResults, metadata: EncodedMetadata, outputs: &OutputFilenames, + codegen_backend: &'static str, ) { let _timer = sess.timer("link_binary"); let output_metadata = sess.opts.output_types.contains_key(&OutputType::Metadata); @@ -154,6 +155,7 @@ pub fn link_binary( &codegen_results, &metadata, path.as_ref(), + codegen_backend, ); } } @@ -680,6 +682,7 @@ fn link_natively( codegen_results: &CodegenResults, metadata: &EncodedMetadata, tmpdir: &Path, + codegen_backend: &'static str, ) { info!("preparing {:?} to {:?}", crate_type, out_filename); let (linker_path, flavor) = linker_and_flavor(sess); @@ -705,6 +708,7 @@ fn link_natively( codegen_results, metadata, self_contained_components, + codegen_backend, ); linker::disable_localization(&mut cmd); @@ -2208,6 +2212,7 @@ fn linker_with_args( codegen_results: &CodegenResults, metadata: &EncodedMetadata, self_contained_components: LinkSelfContainedComponents, + codegen_backend: &'static str, ) -> Command { let self_contained_crt_objects = self_contained_components.is_crt_objects_enabled(); let cmd = &mut *super::linker::get_linker( @@ -2216,6 +2221,7 @@ fn linker_with_args( flavor, self_contained_components.are_any_components_enabled(), &codegen_results.crate_info.target_cpu, + codegen_backend, ); let link_output_kind = link_output_kind(sess, crate_type); diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index 624ab1b50848..e644a43f8834 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -52,6 +52,7 @@ pub(crate) fn get_linker<'a>( flavor: LinkerFlavor, self_contained: bool, target_cpu: &'a str, + codegen_backend: &'static str, ) -> Box { let msvc_tool = find_msvc_tools::find_tool(&sess.target.arch, "link.exe"); @@ -154,6 +155,7 @@ pub(crate) fn get_linker<'a>( is_ld: cc == Cc::No, is_gnu: flavor.is_gnu(), uses_lld: flavor.uses_lld(), + codegen_backend, }) as Box, LinkerFlavor::Msvc(..) => Box::new(MsvcLinker { cmd, sess }) as Box, LinkerFlavor::EmCc => Box::new(EmLinker { cmd, sess }) as Box, @@ -367,6 +369,7 @@ struct GccLinker<'a> { is_ld: bool, is_gnu: bool, uses_lld: bool, + codegen_backend: &'static str, } impl<'a> GccLinker<'a> { @@ -423,9 +426,15 @@ impl<'a> GccLinker<'a> { if let Some(path) = &self.sess.opts.unstable_opts.profile_sample_use { self.link_arg(&format!("-plugin-opt=sample-profile={}", path.display())); }; + let prefix = if self.codegen_backend == "gcc" { + // The GCC linker plugin requires a leading dash. + "-" + } else { + "" + }; self.link_args(&[ - &format!("-plugin-opt={opt_level}"), - &format!("-plugin-opt=mcpu={}", self.target_cpu), + &format!("-plugin-opt={prefix}{opt_level}"), + &format!("-plugin-opt={prefix}mcpu={}", self.target_cpu), ]); } diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 29ec7eb1da3b..2400160075e2 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -41,6 +41,8 @@ pub trait CodegenBackend { /// Called before `init` so that all other functions are able to emit translatable diagnostics. fn locale_resource(&self) -> &'static str; + fn name(&self) -> &'static str; + fn init(&self, _sess: &Session) {} fn print(&self, _req: &PrintRequest, _out: &mut String, _sess: &Session) {} @@ -96,7 +98,14 @@ pub trait CodegenBackend { metadata: EncodedMetadata, outputs: &OutputFilenames, ) { - link_binary(sess, &ArArchiveBuilderBuilder, codegen_results, metadata, outputs); + link_binary( + sess, + &ArArchiveBuilderBuilder, + codegen_results, + metadata, + outputs, + self.name(), + ); } } diff --git a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs index 8449479287f0..48f328f4fad3 100644 --- a/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs +++ b/tests/ui-fulldeps/codegen-backend/auxiliary/the_backend.rs @@ -33,6 +33,10 @@ impl CodegenBackend for TheBackend { "" } + fn name(&self) -> &'static str { + "the-backend" + } + fn codegen_crate(&self, tcx: TyCtxt<'_>) -> Box { Box::new(CodegenResults { modules: vec![], From 8f7d61b9efe1f44701f87fe4647eb1f39d20f434 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Mon, 25 Nov 2024 21:52:08 +0000 Subject: [PATCH 16/23] Detect unconstructable re-exported tuple structs When a tuple-struct is re-exported that has inaccessible fields at the `use` scope, the type's constructor cannot be accessed through that re-export. We now account for this case and extend the resulting resolution error. We also check if the constructor would be accessible directly, not through the re-export, and if so, we suggest using the full path instead. ``` error[E0423]: cannot initialize a tuple struct which contains private fields --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:12:33 | LL | let crate::Foo(x) = crate::Foo(42); | ^^^^^^^^^^ | note: the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:3:9 | LL | pub use my_mod::Foo; | ^^^^^^^^^^^ help: the type can be constructed directly, because its fields are available from the current scope | LL | let crate::Foo(x) = crate::my_mod::Foo(42); | ~~~~~~~~~~~~~~~~~~ ``` Fix #133343. --- compiler/rustc_resolve/src/ident.rs | 33 +++++++ .../rustc_resolve/src/late/diagnostics.rs | 99 ++++++++++++------- compiler/rustc_resolve/src/lib.rs | 6 ++ ...ue-to-inaccessible-field-in-reexport.fixed | 20 ++++ ...e-due-to-inaccessible-field-in-reexport.rs | 20 ++++ ...e-to-inaccessible-field-in-reexport.stderr | 36 +++++++ 6 files changed, 181 insertions(+), 33 deletions(-) create mode 100644 tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.fixed create mode 100644 tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs create mode 100644 tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.stderr diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 51489019950a..4415300777f9 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -901,6 +901,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding, if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, parent_scope, + module, finalize, shadowing, ); @@ -1025,6 +1026,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { binding: Option>, shadowed_glob: Option>, parent_scope: &ParentScope<'ra>, + module: Module<'ra>, finalize: Finalize, shadowing: Shadowing, ) -> Result, (Determinacy, Weak)> { @@ -1076,6 +1078,37 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); } + // If we encounter a re-export for a type with private fields, it will not be able to + // be constructed through this re-export. We track that case here to expand later + // privacy errors with appropriate information. + if let Res::Def(_, def_id) = binding.res() { + let struct_ctor = match def_id.as_local() { + Some(def_id) => self.struct_constructors.get(&def_id).cloned(), + None => { + let ctor = self.cstore().ctor_untracked(def_id); + ctor.map(|(ctor_kind, ctor_def_id)| { + let ctor_res = Res::Def( + DefKind::Ctor(rustc_hir::def::CtorOf::Struct, ctor_kind), + ctor_def_id, + ); + let ctor_vis = self.tcx.visibility(ctor_def_id); + let field_visibilities = self + .tcx + .associated_item_def_ids(def_id) + .iter() + .map(|field_id| self.tcx.visibility(field_id)) + .collect(); + (ctor_res, ctor_vis, field_visibilities) + }) + } + }; + if let Some((_, _, fields)) = struct_ctor + && fields.iter().any(|vis| !self.is_accessible_from(*vis, module)) + { + self.inaccessible_ctor_reexport.insert(path_span, binding.span); + } + } + self.record_use(ident, binding, used); return Ok(binding); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 9e3c09388366..8c2ddda7f983 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1942,44 +1942,77 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { return true; }; + let update_message = + |this: &mut Self, err: &mut Diag<'_>, source: &PathSource<'_, '_, '_>| { + match source { + // e.g. `if let Enum::TupleVariant(field1, field2) = _` + PathSource::TupleStruct(_, pattern_spans) => { + err.primary_message( + "cannot match against a tuple struct which contains private fields", + ); + + // Use spans of the tuple struct pattern. + Some(Vec::from(*pattern_spans)) + } + // e.g. `let _ = Enum::TupleVariant(field1, field2);` + PathSource::Expr(Some(Expr { + kind: ExprKind::Call(path, args), + span: call_span, + .. + })) => { + err.primary_message( + "cannot initialize a tuple struct which contains private fields", + ); + this.suggest_alternative_construction_methods( + def_id, + err, + path.span, + *call_span, + &args[..], + ); + // Use spans of the tuple struct definition. + this.r + .field_idents(def_id) + .map(|fields| fields.iter().map(|f| f.span).collect::>()) + } + _ => None, + } + }; let is_accessible = self.r.is_accessible_from(ctor_vis, self.parent_scope.module); + if let Some(use_span) = self.r.inaccessible_ctor_reexport.get(&span) + && is_accessible + { + err.span_note( + *use_span, + "the type is accessed through this re-export, but the type's constructor \ + is not visible in this import's scope due to private fields", + ); + if is_accessible + && fields + .iter() + .all(|vis| self.r.is_accessible_from(*vis, self.parent_scope.module)) + { + err.span_suggestion_verbose( + span, + "the type can be constructed directly, because its fields are \ + available from the current scope", + // Using `tcx.def_path_str` causes the compiler to hang. + // We don't need to handle foreign crate types because in that case you + // can't access the ctor either way. + format!( + "crate{}", // The method already has leading `::`. + self.r.tcx.def_path(def_id).to_string_no_crate_verbose(), + ), + Applicability::MachineApplicable, + ); + } + update_message(self, err, &source); + } if !is_expected(ctor_def) || is_accessible { return true; } - let field_spans = match source { - // e.g. `if let Enum::TupleVariant(field1, field2) = _` - PathSource::TupleStruct(_, pattern_spans) => { - err.primary_message( - "cannot match against a tuple struct which contains private fields", - ); - - // Use spans of the tuple struct pattern. - Some(Vec::from(pattern_spans)) - } - // e.g. `let _ = Enum::TupleVariant(field1, field2);` - PathSource::Expr(Some(Expr { - kind: ExprKind::Call(path, args), - span: call_span, - .. - })) => { - err.primary_message( - "cannot initialize a tuple struct which contains private fields", - ); - self.suggest_alternative_construction_methods( - def_id, - err, - path.span, - *call_span, - &args[..], - ); - // Use spans of the tuple struct definition. - self.r - .field_idents(def_id) - .map(|fields| fields.iter().map(|f| f.span).collect::>()) - } - _ => None, - }; + let field_spans = update_message(self, err, &source); if let Some(spans) = field_spans.filter(|spans| spans.len() > 0 && fields.len() == spans.len()) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 8959068b2a67..b44b1c966a43 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1167,6 +1167,11 @@ pub struct Resolver<'ra, 'tcx> { /// Crate-local macro expanded `macro_export` referred to by a module-relative path. macro_expanded_macro_export_errors: BTreeSet<(Span, Span)> = BTreeSet::new(), + /// When a type is re-exported that has an inaccessible constructor because it has fields that + /// are inaccessible from the import's scope, we mark that as the type won't be able to be built + /// through the re-export. We use this information to extend the existing diagnostic. + inaccessible_ctor_reexport: FxHashMap, + arenas: &'ra ResolverArenas<'ra>, dummy_binding: NameBinding<'ra>, builtin_types_bindings: FxHashMap>, @@ -1595,6 +1600,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { glob_map: Default::default(), used_imports: FxHashSet::default(), maybe_unused_trait_imports: Default::default(), + inaccessible_ctor_reexport: Default::default(), arenas, dummy_binding: arenas.new_pub_res_binding(Res::Err, DUMMY_SP, LocalExpnId::ROOT), diff --git a/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.fixed b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.fixed new file mode 100644 index 000000000000..63cc3333b6b7 --- /dev/null +++ b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.fixed @@ -0,0 +1,20 @@ +#![allow(dead_code, unused_variables)] +//@ run-rustfix +pub use my_mod::Foo; +//~^ NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields +//~| NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields + +mod my_mod { + pub struct Foo(u32); + + mod my_sub_mod { + fn my_func() { + let crate::my_mod::Foo(x) = crate::my_mod::Foo(42); + //~^ ERROR cannot initialize a tuple struct which contains private fields + //~| HELP the type can be constructed directly, because its fields are available from the current scope + //~| ERROR cannot match against a tuple struct which contains private fields + //~| HELP the type can be constructed directly, because its fields are available from the current scope + } + } +} +fn main() {} diff --git a/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs new file mode 100644 index 000000000000..0b695f906545 --- /dev/null +++ b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs @@ -0,0 +1,20 @@ +#![allow(dead_code, unused_variables)] +//@ run-rustfix +pub use my_mod::Foo; +//~^ NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields +//~| NOTE the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields + +mod my_mod { + pub struct Foo(u32); + + mod my_sub_mod { + fn my_func() { + let crate::Foo(x) = crate::Foo(42); + //~^ ERROR cannot initialize a tuple struct which contains private fields + //~| HELP the type can be constructed directly, because its fields are available from the current scope + //~| ERROR cannot match against a tuple struct which contains private fields + //~| HELP the type can be constructed directly, because its fields are available from the current scope + } + } +} +fn main() {} diff --git a/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.stderr b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.stderr new file mode 100644 index 000000000000..6ab324cb32f3 --- /dev/null +++ b/tests/ui/privacy/ctor-not-accessible-due-to-inaccessible-field-in-reexport.stderr @@ -0,0 +1,36 @@ +error[E0423]: cannot initialize a tuple struct which contains private fields + --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:12:33 + | +LL | let crate::Foo(x) = crate::Foo(42); + | ^^^^^^^^^^ + | +note: the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields + --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:3:9 + | +LL | pub use my_mod::Foo; + | ^^^^^^^^^^^ +help: the type can be constructed directly, because its fields are available from the current scope + | +LL | let crate::Foo(x) = crate::my_mod::Foo(42); + | ++++++++ + +error[E0532]: cannot match against a tuple struct which contains private fields + --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:12:17 + | +LL | let crate::Foo(x) = crate::Foo(42); + | ^^^^^^^^^^ + | +note: the type is accessed through this re-export, but the type's constructor is not visible in this import's scope due to private fields + --> $DIR/ctor-not-accessible-due-to-inaccessible-field-in-reexport.rs:3:9 + | +LL | pub use my_mod::Foo; + | ^^^^^^^^^^^ +help: the type can be constructed directly, because its fields are available from the current scope + | +LL | let crate::my_mod::Foo(x) = crate::Foo(42); + | ++++++++ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0423, E0532. +For more information about an error, try `rustc --explain E0423`. From 0c9d0dfe046f0674f0507df564504ac3bac862d9 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 28 Sep 2025 14:40:39 -0700 Subject: [PATCH 17/23] remove explicit deref of AbiAlign for most methods Much of the compiler calls functions on Align projected from AbiAlign. AbiAlign impls Deref to its inner Align, so we can simplify these away. Also, it will minimize disruption when AbiAlign is removed. For now, preserve usages that might resolve to PartialOrd or PartialEq, as those have odd inference. --- compiler/rustc_abi/src/layout.rs | 6 +++--- compiler/rustc_abi/src/lib.rs | 2 +- compiler/rustc_codegen_cranelift/src/abi/comments.rs | 2 +- compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs | 2 +- compiler/rustc_codegen_cranelift/src/base.rs | 2 +- compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs | 2 +- .../rustc_codegen_cranelift/src/debuginfo/types.rs | 6 ++---- compiler/rustc_codegen_cranelift/src/unsize.rs | 6 +++--- .../rustc_codegen_cranelift/src/value_and_place.rs | 6 +++--- compiler/rustc_codegen_gcc/src/context.rs | 6 +++--- compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs | 2 +- .../src/debuginfo/metadata/enums/native.rs | 4 ++-- compiler/rustc_codegen_llvm/src/intrinsic.rs | 2 +- compiler/rustc_codegen_llvm/src/va_arg.rs | 4 ++-- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- compiler/rustc_codegen_ssa/src/size_of_val.rs | 8 ++++---- compiler/rustc_const_eval/src/interpret/operator.rs | 2 +- compiler/rustc_const_eval/src/util/alignment.rs | 2 +- .../src/util/check_validity_requirement.rs | 2 +- .../rustc_hir_analysis/src/hir_ty_lowering/cmse.rs | 2 +- compiler/rustc_middle/src/ty/vtable.rs | 2 +- .../rustc_mir_transform/src/dataflow_const_prop.rs | 2 +- compiler/rustc_mir_transform/src/gvn.rs | 2 +- compiler/rustc_mir_transform/src/known_panics_lint.rs | 2 +- compiler/rustc_target/src/callconv/arm.rs | 2 +- compiler/rustc_target/src/callconv/loongarch.rs | 2 +- compiler/rustc_target/src/callconv/nvptx64.rs | 4 ++-- compiler/rustc_target/src/callconv/powerpc64.rs | 2 +- compiler/rustc_target/src/callconv/riscv.rs | 2 +- compiler/rustc_target/src/callconv/xtensa.rs | 2 +- compiler/rustc_transmute/src/layout/tree.rs | 2 +- compiler/rustc_ty_utils/src/layout.rs | 10 +++++----- compiler/rustc_ty_utils/src/layout/invariant.rs | 6 +++--- .../clippy_lints/src/casts/cast_ptr_alignment.rs | 4 ++-- .../clippy_lints/src/casts/manual_dangling_ptr.rs | 2 +- src/tools/miri/src/machine.rs | 2 +- .../rust-analyzer/crates/hir-ty/src/layout/tests.rs | 4 ++-- src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs | 6 +++--- .../rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs | 4 ++-- src/tools/rust-analyzer/crates/hir/src/lib.rs | 2 +- 40 files changed, 66 insertions(+), 68 deletions(-) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 5004d0c80220..d56fbb5cb94f 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -1169,7 +1169,7 @@ impl LayoutCalculator { // To allow unsizing `&Foo` -> `&Foo`, the layout of the struct must // not depend on the layout of the tail. let max_field_align = - fields_excluding_tail.iter().map(|f| f.align.abi.bytes()).max().unwrap_or(1); + fields_excluding_tail.iter().map(|f| f.align.bytes()).max().unwrap_or(1); let largest_niche_size = fields_excluding_tail .iter() .filter_map(|f| f.largest_niche) @@ -1189,7 +1189,7 @@ impl LayoutCalculator { } else { // Returns `log2(effective-align)`. The calculation assumes that size is an // integer multiple of align, except for ZSTs. - let align = layout.align.abi.bytes(); + let align = layout.align.bytes(); let size = layout.size.bytes(); let niche_size = layout.largest_niche.map(|n| n.available(dl)).unwrap_or(0); // Group [u8; 4] with align-4 or [u8; 6] with align-2 fields. @@ -1488,7 +1488,7 @@ impl LayoutCalculator { for i in layout.fields.index_by_increasing_offset() { let offset = layout.fields.offset(i); let f = &fields[FieldIdx::new(i)]; - write!(s, "[o{}a{}s{}", offset.bytes(), f.align.abi.bytes(), f.size.bytes()).unwrap(); + write!(s, "[o{}a{}s{}", offset.bytes(), f.align.bytes(), f.size.bytes()).unwrap(); if let Some(n) = f.largest_niche { write!( s, diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs index 369874521e57..9a364f9be184 100644 --- a/compiler/rustc_abi/src/lib.rs +++ b/compiler/rustc_abi/src/lib.rs @@ -2159,7 +2159,7 @@ impl LayoutData { /// Returns `true` if the type is sized and a 1-ZST (meaning it has size 0 and alignment 1). pub fn is_1zst(&self) -> bool { - self.is_sized() && self.size.bytes() == 0 && self.align.abi.bytes() == 1 + self.is_sized() && self.size.bytes() == 0 && self.align.bytes() == 1 } /// Returns `true` if the type is a ZST and not unsized. diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs index c74efeb59f3f..d1b2b9a502ac 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs @@ -89,7 +89,7 @@ pub(super) fn add_local_place_comments<'tcx>( format!("{:?}", local), format!("{:?}", ty), size.bytes(), - align.abi.bytes(), + align.bytes(), if extra.is_empty() { "" } else { " " }, extra, )); diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs index 2031842062d9..7a909a740b05 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs @@ -233,7 +233,7 @@ pub(super) fn from_casted_value<'tcx>( // It may also be smaller for example when the type is a wrapper around an integer with a // larger alignment than the integer. std::cmp::max(abi_param_size, layout_size), - u32::try_from(layout.align.abi.bytes()).unwrap(), + u32::try_from(layout.align.bytes()).unwrap(), ); let mut block_params_iter = block_params.iter().copied(); for (offset, _) in abi_params { diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 41e11e1de616..2cc5b82ddd34 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -846,7 +846,7 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: let layout = fx.layout_of(fx.monomorphize(ty)); let val = match null_op { NullOp::SizeOf => layout.size.bytes(), - NullOp::AlignOf => layout.align.abi.bytes(), + NullOp::AlignOf => layout.align.bytes(), NullOp::OffsetOf(fields) => fx .tcx .offset_of_subfield( diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs index 286e02b986b3..4c438742f3d2 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/mod.rs @@ -304,7 +304,7 @@ impl DebugContext { entry.set(gimli::DW_AT_decl_file, AttributeValue::FileIndex(Some(file_id))); entry.set(gimli::DW_AT_decl_line, AttributeValue::Udata(line)); - entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.abi.bytes())); + entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(static_layout.align.bytes())); let mut expr = Expression::new(); expr.op_addr(address_for_data(data_id)); diff --git a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs index 25b922c8be4c..0d49f32373ca 100644 --- a/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs +++ b/compiler/rustc_codegen_cranelift/src/debuginfo/types.rs @@ -166,7 +166,7 @@ impl DebugContext { let tuple_entry = self.dwarf.unit.get_mut(tuple_type_id); tuple_entry.set(gimli::DW_AT_name, AttributeValue::StringRef(self.dwarf.strings.add(name))); tuple_entry.set(gimli::DW_AT_byte_size, AttributeValue::Udata(layout.size.bytes())); - tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.abi.bytes())); + tuple_entry.set(gimli::DW_AT_alignment, AttributeValue::Udata(layout.align.bytes())); for (i, (ty, dw_ty)) in components.into_iter().enumerate() { let member_id = self.dwarf.unit.add(tuple_type_id, gimli::DW_TAG_member); @@ -178,9 +178,7 @@ impl DebugContext { member_entry.set(gimli::DW_AT_type, AttributeValue::UnitRef(dw_ty)); member_entry.set( gimli::DW_AT_alignment, - AttributeValue::Udata( - FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.abi.bytes(), - ), + AttributeValue::Udata(FullyMonomorphizedLayoutCx(tcx).layout_of(ty).align.bytes()), ); member_entry.set( gimli::DW_AT_data_member_location, diff --git a/compiler/rustc_codegen_cranelift/src/unsize.rs b/compiler/rustc_codegen_cranelift/src/unsize.rs index 643c7feb89a2..d994f3e32ec3 100644 --- a/compiler/rustc_codegen_cranelift/src/unsize.rs +++ b/compiler/rustc_codegen_cranelift/src/unsize.rs @@ -167,7 +167,7 @@ pub(crate) fn size_and_align_of<'tcx>( if layout.is_sized() { return ( fx.bcx.ins().iconst(fx.pointer_type, layout.size.bytes() as i64), - fx.bcx.ins().iconst(fx.pointer_type, layout.align.abi.bytes() as i64), + fx.bcx.ins().iconst(fx.pointer_type, layout.align.bytes() as i64), ); } @@ -186,7 +186,7 @@ pub(crate) fn size_and_align_of<'tcx>( // times the unit size. ( fx.bcx.ins().imul_imm(info.unwrap(), unit.size.bytes() as i64), - fx.bcx.ins().iconst(fx.pointer_type, unit.align.abi.bytes() as i64), + fx.bcx.ins().iconst(fx.pointer_type, unit.align.bytes() as i64), ) } ty::Foreign(_) => { @@ -224,7 +224,7 @@ pub(crate) fn size_and_align_of<'tcx>( let unsized_offset_unadjusted = layout.fields.offset(i).bytes(); let unsized_offset_unadjusted = fx.bcx.ins().iconst(fx.pointer_type, unsized_offset_unadjusted as i64); - let sized_align = layout.align.abi.bytes(); + let sized_align = layout.align.bytes(); let sized_align = fx.bcx.ins().iconst(fx.pointer_type, sized_align as i64); // Recurse to get the size of the dynamically sized field (must be diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 4519fa1a270e..04e10cf17088 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -383,7 +383,7 @@ impl<'tcx> CPlace<'tcx> { let stack_slot = fx.create_stack_slot( u32::try_from(layout.size.bytes()).unwrap(), - u32::try_from(layout.align.abi.bytes()).unwrap(), + u32::try_from(layout.align.bytes()).unwrap(), ); CPlace { inner: CPlaceInner::Addr(stack_slot, None), layout } } @@ -641,8 +641,8 @@ impl<'tcx> CPlace<'tcx> { let size = dst_layout.size.bytes(); // `emit_small_memory_copy` uses `u8` for alignments, just use the maximum // alignment that fits in a `u8` if the actual alignment is larger. - let src_align = src_layout.align.abi.bytes().try_into().unwrap_or(128); - let dst_align = dst_layout.align.abi.bytes().try_into().unwrap_or(128); + let src_align = src_layout.align.bytes().try_into().unwrap_or(128); + let dst_align = dst_layout.align.bytes().try_into().unwrap_or(128); fx.bcx.emit_small_memory_copy( fx.target_config, to_addr, diff --git a/compiler/rustc_codegen_gcc/src/context.rs b/compiler/rustc_codegen_gcc/src/context.rs index 9815fb07eaae..c9ae96777de4 100644 --- a/compiler/rustc_codegen_gcc/src/context.rs +++ b/compiler/rustc_codegen_gcc/src/context.rs @@ -147,7 +147,7 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { let layout = tcx .layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(rust_type)) .unwrap(); - let align = layout.align.abi.bytes(); + let align = layout.align.bytes(); // For types with size 1, the alignment can be 1 and only 1 // So, we can skip the call to ``get_aligned`. // In the future, we can add a GCC API to query the type align, @@ -186,9 +186,9 @@ impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { (i128_type, u128_type) } else { /*let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.i128)).unwrap(); - let i128_align = layout.align.abi.bytes(); + let i128_align = layout.align.bytes(); let layout = tcx.layout_of(ParamEnv::reveal_all().and(tcx.types.u128)).unwrap(); - let u128_align = layout.align.abi.bytes();*/ + let u128_align = layout.align.bytes();*/ // TODO(antoyo): re-enable the alignment when libgccjit fixed the issue in // gcc_jit_context_new_array_constructor (it should not use reinterpret_cast). diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 4b74c04ed7ae..1e4ace4ca922 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1043,7 +1043,7 @@ fn create_member_type<'ll, 'tcx>( file_metadata, line_number, layout.size.bits(), - layout.align.abi.bits() as u32, + layout.align.bits() as u32, offset.bits(), flags, type_di_node, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs index 62d38d463aba..1ae6e6e5eeca 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/native.rs @@ -289,7 +289,7 @@ fn build_enum_variant_part_di_node<'ll, 'tcx>( file_metadata, line_number, enum_type_and_layout.size.bits(), - enum_type_and_layout.align.abi.bits() as u32, + enum_type_and_layout.align.bits() as u32, DIFlags::FlagZero, tag_member_di_node, create_DIArray(DIB(cx), &[]), @@ -449,7 +449,7 @@ fn build_enum_variant_member_di_node<'ll, 'tcx>( file_di_node, line_number, enum_type_and_layout.size.bits(), - enum_type_and_layout.align.abi.bits() as u32, + enum_type_and_layout.align.bits() as u32, Size::ZERO.bits(), discr, DIFlags::FlagZero, diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 013108d1286e..ba80352916b0 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -297,7 +297,7 @@ impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { let align = if name == sym::unaligned_volatile_load { 1 } else { - result.layout.align.abi.bytes() as u32 + result.layout.align.bytes() as u32 }; unsafe { llvm::LLVMSetAlignment(load, align); diff --git a/compiler/rustc_codegen_llvm/src/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs index d48c7cf874a0..b2c60db9c679 100644 --- a/compiler/rustc_codegen_llvm/src/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -193,7 +193,7 @@ fn emit_aapcs_va_arg<'ll, 'tcx>( // the offset again. bx.switch_to_block(maybe_reg); - if gr_type && layout.align.abi.bytes() > 8 { + if gr_type && layout.align.bytes() > 8 { reg_off_v = bx.add(reg_off_v, bx.const_i32(15)); reg_off_v = bx.and(reg_off_v, bx.const_i32(-16)); } @@ -761,7 +761,7 @@ fn x86_64_sysv64_va_arg_from_memory<'ll, 'tcx>( // byte boundary if alignment needed by type exceeds 8 byte boundary. // It isn't stated explicitly in the standard, but in practice we use // alignment greater than 16 where necessary. - if layout.layout.align.abi.bytes() > 8 { + if layout.layout.align.bytes() > 8 { unreachable!("all instances of VaArgSafe have an alignment <= 8"); } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 2602bf82095c..0a4b0f8d4949 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -617,7 +617,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::NullOp::AlignOf => { assert!(bx.cx().type_is_sized(ty)); - let val = layout.align.abi.bytes(); + let val = layout.align.bytes(); bx.cx().const_usize(val) } mir::NullOp::OffsetOf(fields) => { diff --git a/compiler/rustc_codegen_ssa/src/size_of_val.rs b/compiler/rustc_codegen_ssa/src/size_of_val.rs index 577012151e49..e1bd8014d7a2 100644 --- a/compiler/rustc_codegen_ssa/src/size_of_val.rs +++ b/compiler/rustc_codegen_ssa/src/size_of_val.rs @@ -21,7 +21,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( trace!("size_and_align_of_dst(ty={}, info={:?}): layout: {:?}", t, info, layout); if layout.is_sized() { let size = bx.const_usize(layout.size.bytes()); - let align = bx.const_usize(layout.align.abi.bytes()); + let align = bx.const_usize(layout.align.bytes()); return (size, align); } match t.kind() { @@ -49,7 +49,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // All slice sizes must fit into `isize`, so this multiplication cannot // wrap -- neither signed nor unsigned. bx.unchecked_sumul(info.unwrap(), bx.const_usize(unit.size.bytes())), - bx.const_usize(unit.align.abi.bytes()), + bx.const_usize(unit.align.bytes()), ) } ty::Foreign(_) => { @@ -82,7 +82,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // This function does not return so we can now return whatever we want. let size = bx.const_usize(layout.size.bytes()); - let align = bx.const_usize(layout.align.abi.bytes()); + let align = bx.const_usize(layout.align.bytes()); (size, align) } ty::Adt(..) | ty::Tuple(..) => { @@ -94,7 +94,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let i = layout.fields.count() - 1; let unsized_offset_unadjusted = layout.fields.offset(i).bytes(); - let sized_align = layout.align.abi.bytes(); + let sized_align = layout.align.bytes(); debug!( "DST {} offset of dyn field: {}, statically sized align: {}", t, unsized_offset_unadjusted, sized_align diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 74f8a0a7b093..f0819423aa0f 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -528,7 +528,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { if !layout.is_sized() { span_bug!(self.cur_span(), "unsized type for `NullaryOp::AlignOf`"); } - let val = layout.align.abi.bytes(); + let val = layout.align.bytes(); ImmTy::from_uint(val, usize_layout()) } OffsetOf(fields) => { diff --git a/compiler/rustc_const_eval/src/util/alignment.rs b/compiler/rustc_const_eval/src/util/alignment.rs index 9507b24f603e..9aafc7efd8a6 100644 --- a/compiler/rustc_const_eval/src/util/alignment.rs +++ b/compiler/rustc_const_eval/src/util/alignment.rs @@ -37,7 +37,7 @@ where debug!( "is_disaligned({:?}) - align = {}, packed = {}; not disaligned", place, - layout.align.abi.bytes(), + layout.align.bytes(), pack.bytes() ); false diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index b1f295987505..1dea7e4252d7 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -129,7 +129,7 @@ fn check_validity_requirement_lax<'tcx>( if let Some(pointee) = this.ty.builtin_deref(false) { let pointee = cx.layout_of(pointee)?; // We need to ensure that the LLVM attributes `aligned` and `dereferenceable(size)` are satisfied. - if pointee.align.abi.bytes() > 1 { + if pointee.align.bytes() > 1 { // 0x01-filling is not aligned. return Ok(false); } diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs index 81deb35920af..0458fa1204e8 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/cmse.rs @@ -138,7 +138,7 @@ fn is_valid_cmse_inputs<'tcx>( for (index, ty) in fn_sig.inputs().iter().enumerate() { let layout = tcx.layout_of(ty::TypingEnv::fully_monomorphized().as_query_input(*ty))?; - let align = layout.layout.align().abi.bytes(); + let align = layout.layout.align().bytes(); let size = layout.layout.size().bytes(); accum += size; diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs index e2f09fdcb4b4..a3e9054fdcb8 100644 --- a/compiler/rustc_middle/src/ty/vtable.rs +++ b/compiler/rustc_middle/src/ty/vtable.rs @@ -104,7 +104,7 @@ pub(super) fn vtable_allocation_provider<'tcx>( .expect("failed to build vtable representation"); assert!(layout.is_sized(), "can't create a vtable for an unsized type"); let size = layout.size.bytes(); - let align = layout.align.abi.bytes(); + let align = layout.align.bytes(); let ptr_size = tcx.data_layout.pointer_size(); let ptr_align = tcx.data_layout.pointer_align().abi; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 5c984984d3cc..491e910ff6f8 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -476,7 +476,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { }; let val = match null_op { NullOp::SizeOf if layout.is_sized() => layout.size.bytes(), - NullOp::AlignOf if layout.is_sized() => layout.align.abi.bytes(), + NullOp::AlignOf if layout.is_sized() => layout.align.bytes(), NullOp::OffsetOf(fields) => self .ecx .tcx diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index ebec3d125003..29f6879aacd0 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -618,7 +618,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } let val = match null_op { NullOp::SizeOf => arg_layout.size.bytes(), - NullOp::AlignOf => arg_layout.align.abi.bytes(), + NullOp::AlignOf => arg_layout.align.bytes(), NullOp::OffsetOf(fields) => self .ecx .tcx diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index aaacc5866a2a..5fffba55f17b 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -609,7 +609,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { let op_layout = self.ecx.layout_of(ty).ok()?; let val = match null_op { NullOp::SizeOf => op_layout.size.bytes(), - NullOp::AlignOf => op_layout.align.abi.bytes(), + NullOp::AlignOf => op_layout.align.bytes(), NullOp::OffsetOf(fields) => self .tcx .offset_of_subfield(self.typing_env, op_layout, fields.iter()) diff --git a/compiler/rustc_target/src/callconv/arm.rs b/compiler/rustc_target/src/callconv/arm.rs index 70830fa07b6e..abc9a404e2ea 100644 --- a/compiler/rustc_target/src/callconv/arm.rs +++ b/compiler/rustc_target/src/callconv/arm.rs @@ -77,7 +77,7 @@ where } } - let align = arg.layout.align.abi.bytes(); + let align = arg.layout.align.bytes(); let total = arg.layout.size; arg.cast_to(Uniform::consecutive(if align <= 4 { Reg::i32() } else { Reg::i64() }, total)); } diff --git a/compiler/rustc_target/src/callconv/loongarch.rs b/compiler/rustc_target/src/callconv/loongarch.rs index 9213d73e24ea..bc3c9601fa3d 100644 --- a/compiler/rustc_target/src/callconv/loongarch.rs +++ b/compiler/rustc_target/src/callconv/loongarch.rs @@ -322,7 +322,7 @@ fn classify_arg<'a, Ty, C>( } let total = arg.layout.size; - let align = arg.layout.align.abi.bits(); + let align = arg.layout.align.bits(); // "Scalars wider than 2✕XLEN are passed by reference and are replaced in // the argument list with the address." diff --git a/compiler/rustc_target/src/callconv/nvptx64.rs b/compiler/rustc_target/src/callconv/nvptx64.rs index 44977de7fcbc..dc32dd87a7e7 100644 --- a/compiler/rustc_target/src/callconv/nvptx64.rs +++ b/compiler/rustc_target/src/callconv/nvptx64.rs @@ -21,7 +21,7 @@ fn classify_arg(arg: &mut ArgAbi<'_, Ty>) { /// the pass mode used for aggregates in arg and ret position fn classify_aggregate(arg: &mut ArgAbi<'_, Ty>) { - let align_bytes = arg.layout.align.abi.bytes(); + let align_bytes = arg.layout.align.bytes(); let size = arg.layout.size; let reg = match align_bytes { @@ -60,7 +60,7 @@ where // "`extern \"ptx-kernel\"` doesn't allow passing types other than primitives and structs" // ); - let align_bytes = arg.layout.align.abi.bytes(); + let align_bytes = arg.layout.align.bytes(); let unit = match align_bytes { 1 => Reg::i8(), diff --git a/compiler/rustc_target/src/callconv/powerpc64.rs b/compiler/rustc_target/src/callconv/powerpc64.rs index 89ec85e4b666..be1d13816eff 100644 --- a/compiler/rustc_target/src/callconv/powerpc64.rs +++ b/compiler/rustc_target/src/callconv/powerpc64.rs @@ -89,7 +89,7 @@ where // Aggregates larger than i64 should be padded at the tail to fill out a whole number // of i64s or i128s, depending on the aggregate alignment. Always use an array for // this, even if there is only a single element. - let reg = if arg.layout.align.abi.bytes() > 8 { Reg::i128() } else { Reg::i64() }; + let reg = if arg.layout.align.bytes() > 8 { Reg::i128() } else { Reg::i64() }; arg.cast_to(Uniform::consecutive( reg, size.align_to(Align::from_bytes(reg.size.bytes()).unwrap()), diff --git a/compiler/rustc_target/src/callconv/riscv.rs b/compiler/rustc_target/src/callconv/riscv.rs index 161e2c1645f9..16de3fe070dd 100644 --- a/compiler/rustc_target/src/callconv/riscv.rs +++ b/compiler/rustc_target/src/callconv/riscv.rs @@ -328,7 +328,7 @@ fn classify_arg<'a, Ty, C>( } let total = arg.layout.size; - let align = arg.layout.align.abi.bits(); + let align = arg.layout.align.bits(); // "Scalars wider than 2✕XLEN are passed by reference and are replaced in // the argument list with the address." diff --git a/compiler/rustc_target/src/callconv/xtensa.rs b/compiler/rustc_target/src/callconv/xtensa.rs index a73a70a1a0c0..561ee98787de 100644 --- a/compiler/rustc_target/src/callconv/xtensa.rs +++ b/compiler/rustc_target/src/callconv/xtensa.rs @@ -48,7 +48,7 @@ where } let size = arg.layout.size.bits(); - let needed_align = arg.layout.align.abi.bits(); + let needed_align = arg.layout.align.bits(); let mut must_use_stack = false; // Determine the number of GPRs needed to pass the current argument diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs index a02e8ecf613f..7f626e8c4e88 100644 --- a/compiler/rustc_transmute/src/layout/tree.rs +++ b/compiler/rustc_transmute/src/layout/tree.rs @@ -361,7 +361,7 @@ pub(crate) mod rustc { ty::Ref(region, ty, mutability) => { let layout = layout_of(cx, *ty)?; - let referent_align = layout.align.abi.bytes_usize(); + let referent_align = layout.align.bytes_usize(); let referent_size = layout.size.bytes_usize(); Ok(Tree::Ref(Reference { diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index f59bc2117d53..317d101dafe0 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -795,7 +795,7 @@ fn variant_info_for_adt<'tcx>( name, offset: offset.bytes(), size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), + align: field_layout.align.bytes(), type_name: None, } }) @@ -804,7 +804,7 @@ fn variant_info_for_adt<'tcx>( VariantInfo { name: n, kind: if layout.is_unsized() { SizeKind::Min } else { SizeKind::Exact }, - align: layout.align.abi.bytes(), + align: layout.align.bytes(), size: if min_size.bytes() == 0 { layout.size.bytes() } else { min_size.bytes() }, fields: field_info, } @@ -877,7 +877,7 @@ fn variant_info_for_coroutine<'tcx>( name: *name, offset: offset.bytes(), size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), + align: field_layout.align.bytes(), type_name: None, } }) @@ -905,7 +905,7 @@ fn variant_info_for_coroutine<'tcx>( }), offset: offset.bytes(), size: field_layout.size.bytes(), - align: field_layout.align.abi.bytes(), + align: field_layout.align.bytes(), // Include the type name if there is no field name, or if the name is the // __awaitee placeholder symbol which means a child future being `.await`ed. type_name: (field_name.is_none() || field_name == Some(sym::__awaitee)) @@ -946,7 +946,7 @@ fn variant_info_for_coroutine<'tcx>( name: Some(Symbol::intern(&ty::CoroutineArgs::variant_name(variant_idx))), kind: SizeKind::Exact, size: variant_size.bytes(), - align: variant_layout.align.abi.bytes(), + align: variant_layout.align.bytes(), fields, } }) diff --git a/compiler/rustc_ty_utils/src/layout/invariant.rs b/compiler/rustc_ty_utils/src/layout/invariant.rs index 1311ee31182c..b768269215fa 100644 --- a/compiler/rustc_ty_utils/src/layout/invariant.rs +++ b/compiler/rustc_ty_utils/src/layout/invariant.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutCx, TyAndLayout}; pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayout<'tcx>) { let tcx = cx.tcx(); - if !layout.size.bytes().is_multiple_of(layout.align.abi.bytes()) { + if !layout.size.bytes().is_multiple_of(layout.align.bytes()) { bug!("size is not a multiple of align, in the following layout:\n{layout:#?}"); } if layout.size.bytes() >= tcx.data_layout.obj_size_bound() { @@ -300,8 +300,8 @@ pub(super) fn layout_sanity_check<'tcx>(cx: &LayoutCx<'tcx>, layout: &TyAndLayou if variant.align.abi > layout.align.abi { bug!( "Type with alignment {} bytes has variant with alignment {} bytes: {layout:#?}", - layout.align.abi.bytes(), - variant.align.abi.bytes(), + layout.align.bytes(), + variant.align.bytes(), ) } // Skip empty variants. diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs index d78da9396faf..7d14ba7fcf13 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs @@ -43,8 +43,8 @@ fn lint_cast_ptr_alignment<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, cast_f expr.span, format!( "casting from `{cast_from}` to a more-strictly-aligned pointer (`{cast_to}`) ({} < {} bytes)", - from_layout.align.abi.bytes(), - to_layout.align.abi.bytes(), + from_layout.align.bytes(), + to_layout.align.bytes(), ), ); } diff --git a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs index 92910cf8adf5..ff5320719aa2 100644 --- a/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs +++ b/src/tools/clippy/clippy_lints/src/casts/manual_dangling_ptr.rs @@ -72,7 +72,7 @@ fn is_literal_aligned(cx: &LateContext<'_>, lit: &Spanned, to: &Ty<'_>) cx.tcx .layout_of(cx.typing_env().as_query_input(to_mid_ty)) .is_ok_and(|layout| { - let align = u128::from(layout.align.abi.bytes()); + let align = u128::from(layout.align.bytes()); u128::from(val) <= align }) } diff --git a/src/tools/miri/src/machine.rs b/src/tools/miri/src/machine.rs index d307636e782f..412640a112c0 100644 --- a/src/tools/miri/src/machine.rs +++ b/src/tools/miri/src/machine.rs @@ -1341,7 +1341,7 @@ impl<'tcx> Machine<'tcx> for MiriMachine<'tcx> { name = ecx.tcx.def_path_str(def_id), krate = ecx.tcx.crate_name(def_id.krate), decl_size = extern_decl_layout.size.bytes(), - decl_align = extern_decl_layout.align.abi.bytes(), + decl_align = extern_decl_layout.align.bytes(), shim_size = info.size.bytes(), shim_align = info.align.bytes(), ) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs index 523ddad94666..8be5eaca63b8 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs @@ -150,7 +150,7 @@ fn check_size_and_align( ) { let l = eval_goal(ra_fixture, minicore).unwrap(); assert_eq!(l.size.bytes(), size, "size mismatch"); - assert_eq!(l.align.abi.bytes(), align, "align mismatch"); + assert_eq!(l.align.bytes(), align, "align mismatch"); } #[track_caller] @@ -162,7 +162,7 @@ fn check_size_and_align_expr( ) { let l = eval_expr(ra_fixture, minicore).unwrap(); assert_eq!(l.size.bytes(), size, "size mismatch"); - assert_eq!(l.align.abi.bytes(), align, "align mismatch"); + assert_eq!(l.align.bytes(), align, "align mismatch"); } #[track_caller] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 3e658cb93ed8..fc7d97fff465 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -2085,7 +2085,7 @@ impl<'db> Evaluator<'db> { if let Some(layout) = self.layout_cache.borrow().get(&ty.to_nextsolver(interner)) { return Ok(layout .is_sized() - .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize))); + .then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize))); } if let DefWithBodyId::VariantId(f) = locals.body.owner && let Some((AdtId::EnumId(e), _)) = ty.as_adt() @@ -2104,7 +2104,7 @@ impl<'db> Evaluator<'db> { let layout = layout?; Ok(layout .is_sized() - .then(|| (layout.size.bytes_usize(), layout.align.abi.bytes() as usize))) + .then(|| (layout.size.bytes_usize(), layout.align.bytes() as usize))) } /// A version of `self.size_of` which returns error if the type is unsized. `what` argument should @@ -2797,7 +2797,7 @@ impl<'db> Evaluator<'db> { )?; // FIXME: there is some leak here let size = layout.size.bytes_usize(); - let addr = self.heap_allocate(size, layout.align.abi.bytes() as usize)?; + let addr = self.heap_allocate(size, layout.align.bytes() as usize)?; self.write_memory(addr, &result)?; IntervalAndTy { interval: Interval { addr, size }, ty } }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs index f67778b0f12f..38480493048e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs @@ -767,7 +767,7 @@ impl Evaluator<'_> { "align_of generic arg is not provided".into(), )); }; - let align = self.layout(ty.to_nextsolver(interner))?.align.abi.bytes(); + let align = self.layout(ty.to_nextsolver(interner))?.align.bytes(); destination.write_from_bytes(self, &align.to_le_bytes()[0..destination.size]) } "size_of_val" => { @@ -1431,7 +1431,7 @@ impl Evaluator<'_> { field_types.iter().next_back().unwrap().1.clone().substitute(Interner, subst); let sized_part_size = layout.fields.offset(field_types.iter().count() - 1).bytes_usize(); - let sized_part_align = layout.align.abi.bytes() as usize; + let sized_part_align = layout.align.bytes() as usize; let (unsized_part_size, unsized_part_align) = self.size_align_of_unsized(&last_field_ty, metadata, locals)?; let align = sized_part_align.max(unsized_part_align) as isize; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 027a386abe8c..17767955d474 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -6094,7 +6094,7 @@ impl Layout { } pub fn align(&self) -> u64 { - self.0.align.abi.bytes() + self.0.align.bytes() } pub fn niches(&self) -> Option { From b71c4690409e8ce98a502216623a9264efaaa3e4 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 28 Sep 2025 18:44:19 +1000 Subject: [PATCH 18/23] Fix some crash-test directives --- tests/crashes/125772.rs | 2 +- tests/crashes/131292.rs | 2 +- tests/crashes/34127.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/crashes/125772.rs b/tests/crashes/125772.rs index 2965cfc9e7c3..2b6cffd9463a 100644 --- a/tests/crashes/125772.rs +++ b/tests/crashes/125772.rs @@ -1,5 +1,5 @@ //@ known-bug: rust-lang/rust#125772 -//@ only-x86_64 +//@ only-64bit #![feature(generic_const_exprs)] struct Outer(); diff --git a/tests/crashes/131292.rs b/tests/crashes/131292.rs index 01e0eca0bd6d..05b93d06b055 100644 --- a/tests/crashes/131292.rs +++ b/tests/crashes/131292.rs @@ -1,5 +1,5 @@ //@ known-bug: #131292 -//@ only-x86_64 +//@ needs-asm-support use std::arch::asm; unsafe fn f6() { diff --git a/tests/crashes/34127.rs b/tests/crashes/34127.rs index ea36b48ecba0..26ebe722475f 100644 --- a/tests/crashes/34127.rs +++ b/tests/crashes/34127.rs @@ -1,6 +1,6 @@ //@ compile-flags: -g -Copt-level=0 -Z verify-llvm-ir //@ known-bug: #34127 -//@ only-x86_64 +//@ only-64bit pub fn main() { let _a = [(); 1 << 63]; From 68a7c250788833305f73f816b284aafa9e62370a Mon Sep 17 00:00:00 2001 From: Yotam Ofek Date: Sat, 27 Sep 2025 20:57:50 +0300 Subject: [PATCH 19/23] Use `Iterator::eq` and (dogfood) `eq_by` in compiler and library --- compiler/rustc_ast/src/ast.rs | 3 +-- compiler/rustc_ast/src/lib.rs | 1 + compiler/rustc_ast/src/tokenstream.rs | 4 +--- compiler/rustc_attr_parsing/src/parser.rs | 2 +- compiler/rustc_builtin_macros/src/autodiff.rs | 3 +-- .../src/deriving/coerce_pointee.rs | 15 ++++----------- compiler/rustc_builtin_macros/src/format.rs | 2 +- compiler/rustc_builtin_macros/src/lib.rs | 1 + compiler/rustc_hir/src/hir.rs | 5 +---- compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs | 4 +--- compiler/rustc_hir_typeck/src/lib.rs | 1 + compiler/rustc_hir_typeck/src/method/suggest.rs | 4 +--- compiler/rustc_parse/src/lib.rs | 1 + .../rustc_parse/src/parser/tokenstream/tests.rs | 2 +- library/alloc/src/collections/btree/map.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/lib.rs | 1 + 17 files changed, 20 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3e8fddd9954e..082d5e88ac75 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -114,8 +114,7 @@ impl PartialEq for Path { impl PartialEq<&[Symbol]> for Path { #[inline] fn eq(&self, names: &&[Symbol]) -> bool { - self.segments.len() == names.len() - && self.segments.iter().zip(names.iter()).all(|(s1, s2)| s1 == s2) + self.segments.iter().eq(*names) } } diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index f1951049b476..5fe218776e53 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -15,6 +15,7 @@ #![feature(associated_type_defaults)] #![feature(box_patterns)] #![feature(if_let_guard)] +#![feature(iter_order_by)] #![feature(macro_metavar_expr)] #![feature(rustdoc_internals)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index a5d8fbfac612..4111182c3b7d 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -48,9 +48,7 @@ impl TokenTree { match (self, other) { (TokenTree::Token(token, _), TokenTree::Token(token2, _)) => token.kind == token2.kind, (TokenTree::Delimited(.., delim, tts), TokenTree::Delimited(.., delim2, tts2)) => { - delim == delim2 - && tts.len() == tts2.len() - && tts.iter().zip(tts2.iter()).all(|(a, b)| a.eq_unspanned(b)) + delim == delim2 && tts.iter().eq_by(tts2.iter(), |a, b| a.eq_unspanned(b)) } _ => false, } diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index 4f903594225e..3f4f56790157 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -49,7 +49,7 @@ impl<'a> PathParser<'a> { } pub fn segments_is(&self, segments: &[Symbol]) -> bool { - self.len() == segments.len() && self.segments().zip(segments).all(|(a, b)| a.name == *b) + self.segments().map(|segment| &segment.name).eq(segments) } pub fn word(&self) -> Option { diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index f4a923797e2d..ddc59bfe1414 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -377,8 +377,7 @@ mod llvm_enzyme { (ast::AttrKind::Normal(a), ast::AttrKind::Normal(b)) => { let a = &a.item.path; let b = &b.item.path; - a.segments.len() == b.segments.len() - && a.segments.iter().zip(b.segments.iter()).all(|(a, b)| a.ident == b.ident) + a.segments.iter().eq_by(&b.segments, |a, b| a.ident == b.ident) } _ => false, } diff --git a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs index 75db5d77783e..5b378de8bbdd 100644 --- a/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs +++ b/compiler/rustc_builtin_macros/src/deriving/coerce_pointee.rs @@ -356,21 +356,14 @@ fn contains_maybe_sized_bound(bounds: &[GenericBound]) -> bool { bounds.iter().any(is_maybe_sized_bound) } -fn path_segment_is_exact_match(path_segments: &[ast::PathSegment], syms: &[Symbol]) -> bool { - path_segments.iter().zip(syms).all(|(segment, &symbol)| segment.ident.name == symbol) -} - fn is_sized_marker(path: &ast::Path) -> bool { const CORE_UNSIZE: [Symbol; 3] = [sym::core, sym::marker, sym::Sized]; const STD_UNSIZE: [Symbol; 3] = [sym::std, sym::marker, sym::Sized]; - if path.segments.len() == 4 && path.is_global() { - path_segment_is_exact_match(&path.segments[1..], &CORE_UNSIZE) - || path_segment_is_exact_match(&path.segments[1..], &STD_UNSIZE) - } else if path.segments.len() == 3 { - path_segment_is_exact_match(&path.segments, &CORE_UNSIZE) - || path_segment_is_exact_match(&path.segments, &STD_UNSIZE) + let segments = || path.segments.iter().map(|segment| segment.ident.name); + if path.is_global() { + segments().skip(1).eq(CORE_UNSIZE) || segments().skip(1).eq(STD_UNSIZE) } else { - *path == sym::Sized + segments().eq(CORE_UNSIZE) || segments().eq(STD_UNSIZE) || *path == sym::Sized } } diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index d70888205a51..bffc0407e811 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -768,7 +768,7 @@ fn report_missing_placeholders( if !found_foreign && invalid_refs.is_empty() { // Show example if user didn't use any format specifiers - let show_example = used.iter().all(|used| !used); + let show_example = !used.contains(&true); if !show_example { if unused.len() > 1 { diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 4541e2cd3b41..57cf62ea6121 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -11,6 +11,7 @@ #![feature(box_patterns)] #![feature(decl_macro)] #![feature(if_let_guard)] +#![feature(iter_order_by)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![feature(rustdoc_internals)] diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 493236718a86..bc1c47e95c3a 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1298,10 +1298,7 @@ impl AttributeExt for Attribute { #[inline] fn path_matches(&self, name: &[Symbol]) -> bool { match &self { - Attribute::Unparsed(n) => { - n.path.segments.len() == name.len() - && n.path.segments.iter().zip(name).all(|(s, n)| s.name == *n) - } + Attribute::Unparsed(n) => n.path.segments.iter().map(|ident| &ident.name).eq(name), _ => false, } } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 7ca8580e0986..c8943d4634e2 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -2803,9 +2803,7 @@ impl<'a, 'b, 'tcx> ArgMatchingCtxt<'a, 'b, 'tcx> { if let Some((assoc, fn_sig)) = self.similar_assoc(call_name) && fn_sig.inputs()[1..] .iter() - .zip(input_types.iter()) - .all(|(expected, found)| self.may_coerce(*expected, *found)) - && fn_sig.inputs()[1..].len() == input_types.len() + .eq_by(input_types, |expected, found| self.may_coerce(*expected, found)) { let assoc_name = assoc.name(); err.span_suggestion_verbose( diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 43a23822fd1e..acc0481e457f 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -5,6 +5,7 @@ #![feature(box_patterns)] #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![feature(iter_order_by)] #![feature(never_type)] // tidy-alphabetical-end diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 024b9ee08c22..44602e628994 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1914,9 +1914,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(ref args) = call_args && fn_sig.inputs()[1..] .iter() - .zip(args.into_iter()) - .all(|(expected, found)| self.may_coerce(*expected, *found)) - && fn_sig.inputs()[1..].len() == args.len() + .eq_by(args, |expected, found| self.may_coerce(*expected, *found)) { err.span_suggestion_verbose( item_name.span, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 88b67d792deb..c26c7b9122af 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -9,6 +9,7 @@ #![feature(default_field_values)] #![feature(if_let_guard)] #![feature(iter_intersperse)] +#![feature(iter_order_by)] #![recursion_limit = "256"] // tidy-alphabetical-end diff --git a/compiler/rustc_parse/src/parser/tokenstream/tests.rs b/compiler/rustc_parse/src/parser/tokenstream/tests.rs index 19b2c98f5af8..63177a727449 100644 --- a/compiler/rustc_parse/src/parser/tokenstream/tests.rs +++ b/compiler/rustc_parse/src/parser/tokenstream/tests.rs @@ -15,7 +15,7 @@ fn sp(a: u32, b: u32) -> Span { } fn cmp_token_stream(a: &TokenStream, b: &TokenStream) -> bool { - a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.eq_unspanned(y)) + a.iter().eq_by(b.iter(), |x, y| x.eq_unspanned(y)) } #[test] diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 9dfbbd913225..adcb444d08c6 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -2413,7 +2413,7 @@ impl Default for BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] impl PartialEq for BTreeMap { fn eq(&self, other: &BTreeMap) -> bool { - self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a == b) + self.iter().eq(other) } } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c2cf39c4be06..4eb32585ffb9 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1685,7 +1685,7 @@ impl Type { match (self_cleared, other_cleared) { // Recursive cases. (Type::Tuple(a), Type::Tuple(b)) => { - a.len() == b.len() && a.iter().zip(b).all(|(a, b)| a.is_doc_subtype_of(b, cache)) + a.iter().eq_by(b, |a, b| a.is_doc_subtype_of(b, cache)) } (Type::Slice(a), Type::Slice(b)) => a.is_doc_subtype_of(b, cache), (Type::Array(a, al), Type::Array(b, bl)) => al == bl && a.is_doc_subtype_of(b, cache), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index c4f24e09ddbf..d7ffb25f8bd8 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -13,6 +13,7 @@ #![feature(if_let_guard)] #![feature(iter_advance_by)] #![feature(iter_intersperse)] +#![feature(iter_order_by)] #![feature(rustc_private)] #![feature(test)] #![warn(rustc::internal)] From 04ee9915897ba66a768440e1aaeaf1e63f14ba02 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Sun, 28 Sep 2025 13:16:10 +0100 Subject: [PATCH 20/23] Fix removed version of `doc_auto_cfg`, `doc_cfg_hide` --- compiler/rustc_feature/src/removed.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs index 3c51f91331a6..539d67e0b6bc 100644 --- a/compiler/rustc_feature/src/removed.rs +++ b/compiler/rustc_feature/src/removed.rs @@ -102,9 +102,9 @@ declare_features! ( /// Allows deriving traits as per `SmartPointer` specification (removed, derive_smart_pointer, "1.84.0", Some(123430), Some("replaced by `CoercePointee`"), 131284), /// Tells rustdoc to automatically generate `#[doc(cfg(...))]`. - (removed, doc_auto_cfg, "1.58.0", Some(43781), Some("merged into `doc_cfg`"), 138907), + (removed, doc_auto_cfg, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907), /// Allows `#[doc(cfg_hide(...))]`. - (removed, doc_cfg_hide, "1.57.0", Some(43781), Some("merged into `doc_cfg`"), 138907), + (removed, doc_cfg_hide, "CURRENT_RUSTC_VERSION", Some(43781), Some("merged into `doc_cfg`"), 138907), /// Allows using `#[doc(keyword = "...")]`. (removed, doc_keyword, "1.58.0", Some(51315), Some("merged into `#![feature(rustdoc_internals)]`"), 90420), From 9c97ba700e8d4059f8394efa19e6e9487def7afb Mon Sep 17 00:00:00 2001 From: joboet Date: Mon, 29 Sep 2025 11:20:40 +0200 Subject: [PATCH 21/23] add joboet to library review rotation --- triagebot.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/triagebot.toml b/triagebot.toml index 2d58c616bc27..a04f8d280723 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1382,6 +1382,7 @@ libs = [ "@tgross35", "@thomcc", "@ibraheemdev", + "@joboet", ] infra-ci = [ "@Mark-Simulacrum", From 8b51a63dbbe2663403e644009dee9e35f611ae32 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Tue, 30 Sep 2025 04:53:35 +0000 Subject: [PATCH 22/23] Prepare for merging from rust-lang/rust This updates the rust-version file to 29b7717de23f3969ceeb5bef5b01d9223f807655. --- src/tools/miri/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 1f90d4e5e498..70374af27e9c 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f957826bff7a68b267ce75b1ea56352aed0cca0a +29b7717de23f3969ceeb5bef5b01d9223f807655 From 3e26e2a3a9f047060d7c098c3c82a77d7c33c2aa Mon Sep 17 00:00:00 2001 From: Jynn Nelson Date: Wed, 24 Sep 2025 15:09:16 -0700 Subject: [PATCH 23/23] Don't unconditionally build alloc for `no-std` targets It's possible for targets to only support `core` and not `alloc`. Instead of building alloc unconditionally, pass a list of crates to build into `std_cargo`, and only pass `-p alloc` if the list of crates wasn't already filtered to a subset. The original use case was to reuse `std_cargo` for a rustc_driver that doesn't emit metadata. But this seems like a reasonable change regardless. --- src/bootstrap/src/core/build_steps/check.rs | 18 +++++------------ src/bootstrap/src/core/build_steps/clippy.rs | 6 +----- src/bootstrap/src/core/build_steps/compile.rs | 20 +++++++++++++------ src/bootstrap/src/core/build_steps/doc.rs | 6 +----- src/bootstrap/src/core/build_steps/test.rs | 2 +- 5 files changed, 22 insertions(+), 30 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 20c54a28dda8..d0edf6c90899 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -61,6 +61,9 @@ impl Step for Std { return; } + // Explicitly pass -p for all dependencies crates -- this will force cargo + // to also check the tests/benches/examples for these crates, rather + // than just the leaf crate. let crates = std_crates_for_run_make(&run); run.builder.ensure(Std { build_compiler: prepare_compiler_for_check(run.builder, run.target, Mode::Std) @@ -83,16 +86,12 @@ impl Step for Std { Kind::Check, ); - std_cargo(builder, target, &mut cargo); + std_cargo(builder, target, &mut cargo, &self.crates); if matches!(builder.config.cmd, Subcommand::Fix) { // By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot. cargo.arg("--lib"); } - for krate in &*self.crates { - cargo.arg("-p").arg(krate); - } - let _guard = builder.msg( Kind::Check, format_args!("library artifacts{}", crate_description(&self.crates)), @@ -135,14 +134,7 @@ impl Step for Std { Kind::Check, ); - std_cargo(builder, target, &mut cargo); - - // Explicitly pass -p for all dependencies krates -- this will force cargo - // to also check the tests/benches/examples for these crates, rather - // than just the leaf crate. - for krate in &*self.crates { - cargo.arg("-p").arg(krate); - } + std_cargo(builder, target, &mut cargo, &self.crates); let stamp = build_stamp::libstd_stamp(builder, build_compiler, target).with_prefix("check-test"); diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs index d5b15d790864..290a00aa3c13 100644 --- a/src/bootstrap/src/core/build_steps/clippy.rs +++ b/src/bootstrap/src/core/build_steps/clippy.rs @@ -195,11 +195,7 @@ impl Step for Std { Kind::Clippy, ); - std_cargo(builder, target, &mut cargo); - - for krate in &*self.crates { - cargo.arg("-p").arg(krate); - } + std_cargo(builder, target, &mut cargo, &self.crates); let _guard = builder.msg( Kind::Clippy, diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 96b4e15433f7..03046b1126be 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -266,10 +266,7 @@ impl Step for Std { target, Kind::Build, ); - std_cargo(builder, target, &mut cargo); - for krate in &*self.crates { - cargo.arg("-p").arg(krate); - } + std_cargo(builder, target, &mut cargo, &self.crates); cargo }; @@ -497,7 +494,12 @@ fn compiler_rt_for_profiler(builder: &Builder<'_>) -> PathBuf { /// Configure cargo to compile the standard library, adding appropriate env vars /// and such. -pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, cargo: &mut Cargo) { +pub fn std_cargo( + builder: &Builder<'_>, + target: TargetSelection, + cargo: &mut Cargo, + crates: &[String], +) { // rustc already ensures that it builds with the minimum deployment // target, so ideally we shouldn't need to do anything here. // @@ -605,6 +607,10 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, cargo: &mut Car cargo.env("CFG_DISABLE_UNSTABLE_FEATURES", "1"); } + for krate in crates { + cargo.args(["-p", krate]); + } + let mut features = String::new(); if builder.no_std(target) == Some(true) { @@ -614,8 +620,10 @@ pub fn std_cargo(builder: &Builder<'_>, target: TargetSelection, cargo: &mut Car } // for no-std targets we only compile a few no_std crates + if crates.is_empty() { + cargo.args(["-p", "alloc"]); + } cargo - .args(["-p", "alloc"]) .arg("--manifest-path") .arg(builder.src.join("library/alloc/Cargo.toml")) .arg("--features") diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs index 7865b6856593..7fb0fe17eb0c 100644 --- a/src/bootstrap/src/core/build_steps/doc.rs +++ b/src/bootstrap/src/core/build_steps/doc.rs @@ -783,7 +783,7 @@ fn doc_std( Kind::Doc, ); - compile::std_cargo(builder, target, &mut cargo); + compile::std_cargo(builder, target, &mut cargo, requested_crates); cargo .arg("--no-deps") .arg("--target-dir") @@ -803,10 +803,6 @@ fn doc_std( cargo.rustdocflag("--document-private-items").rustdocflag("--document-hidden-items"); } - for krate in requested_crates { - cargo.arg("-p").arg(krate); - } - let description = format!("library{} in {} format", crate_description(requested_crates), format.as_str()); let _guard = builder.msg(Kind::Doc, description, Mode::Std, build_compiler, target); diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 00aea8feab7d..2910de5e29ef 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -2963,7 +2963,7 @@ impl Step for Crate { .arg("--manifest-path") .arg(builder.src.join("library/sysroot/Cargo.toml")); } else { - compile::std_cargo(builder, target, &mut cargo); + compile::std_cargo(builder, target, &mut cargo, &[]); } } Mode::Rustc => {