From e4777322534026b246592d8b80d915085df07cf6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Tue, 9 Sep 2025 18:45:23 +0200 Subject: [PATCH 001/126] =?UTF-8?q?Don't=20strip=20shebang=20in=20expr-ctx?= =?UTF-8?q?t=20`include!(=E2=80=A6)`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../rustc_builtin_macros/src/source_util.rs | 4 +-- .../include-macros/auxiliary/shebang-expr.rs | 3 ++ .../include-macros/auxiliary/shebang-items.rs | 3 ++ .../ui/include-macros/shebang-in-expr-ctxt.rs | 16 +++++++++ .../shebang-in-expr-ctxt.stderr | 33 +++++++++++++++++++ .../ui/include-macros/shebang-in-item-ctxt.rs | 4 +++ 6 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 tests/ui/include-macros/auxiliary/shebang-expr.rs create mode 100644 tests/ui/include-macros/auxiliary/shebang-items.rs create mode 100644 tests/ui/include-macros/shebang-in-expr-ctxt.rs create mode 100644 tests/ui/include-macros/shebang-in-expr-ctxt.stderr create mode 100644 tests/ui/include-macros/shebang-in-item-ctxt.rs diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 16adaab15c52..b063413bce36 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -147,9 +147,7 @@ fn make_expr(self: Box>) -> Option> { let mut p = unwrap_or_emit_fatal(new_parser_from_file( self.psess, &self.path, - // Don't strip frontmatter for backward compatibility, `---` may be the start of a - // manifold negation. FIXME: Ideally, we wouldn't strip shebangs here either. - StripTokens::Shebang, + StripTokens::Nothing, Some(self.span), )); let expr = parse_expr(&mut p).ok()?; diff --git a/tests/ui/include-macros/auxiliary/shebang-expr.rs b/tests/ui/include-macros/auxiliary/shebang-expr.rs new file mode 100644 index 000000000000..73e92b5a889e --- /dev/null +++ b/tests/ui/include-macros/auxiliary/shebang-expr.rs @@ -0,0 +1,3 @@ +#!/usr/bin/env my-rust-expr-evaluator + +2 * (1 + 3) diff --git a/tests/ui/include-macros/auxiliary/shebang-items.rs b/tests/ui/include-macros/auxiliary/shebang-items.rs new file mode 100644 index 000000000000..b9011b62cc91 --- /dev/null +++ b/tests/ui/include-macros/auxiliary/shebang-items.rs @@ -0,0 +1,3 @@ +#!/usr/bin/env my-rust-script-runner + +fn main() {} diff --git a/tests/ui/include-macros/shebang-in-expr-ctxt.rs b/tests/ui/include-macros/shebang-in-expr-ctxt.rs new file mode 100644 index 000000000000..b6d3fa9e076f --- /dev/null +++ b/tests/ui/include-macros/shebang-in-expr-ctxt.rs @@ -0,0 +1,16 @@ +// Check that we *don't* strip shebang in files that were `include`d in an expression or +// expression statement context. +// We do that to be consistent with frontmatter (see test `frontmatter/include-in-expr-ctxt.rs`). +// While there could be niche use cases for such shebang, it seems more confusing than beneficial. + +fn main() { + // expr ctxt + _ = include!("auxiliary/shebang-expr.rs"); + //~^ ERROR non-expression macro in expression position + //~? ERROR expected `[`, found `/` + + // stmt ctxt (reuses expr expander) + include!("auxiliary/shebang-expr.rs"); + //~^ ERROR non-statement macro in statement position + //~? ERROR expected `[`, found `/` +} diff --git a/tests/ui/include-macros/shebang-in-expr-ctxt.stderr b/tests/ui/include-macros/shebang-in-expr-ctxt.stderr new file mode 100644 index 000000000000..9e95b02a78dc --- /dev/null +++ b/tests/ui/include-macros/shebang-in-expr-ctxt.stderr @@ -0,0 +1,33 @@ +error: expected `[`, found `/` + --> $DIR/auxiliary/shebang-expr.rs:1:3 + | +LL | #!/usr/bin/env my-rust-expr-evaluator + | ^ expected `[` + | + = note: the token sequence `#!` here looks like the start of a shebang interpreter directive but it is not + = help: if you meant this to be a shebang interpreter directive, move it to the very start of the file + +error: non-expression macro in expression position: include + --> $DIR/shebang-in-expr-ctxt.rs:8:9 + | +LL | _ = include!("auxiliary/shebang-expr.rs"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected `[`, found `/` + --> $DIR/auxiliary/shebang-expr.rs:1:3 + | +LL | #!/usr/bin/env my-rust-expr-evaluator + | ^ expected `[` + | + = note: the token sequence `#!` here looks like the start of a shebang interpreter directive but it is not + = help: if you meant this to be a shebang interpreter directive, move it to the very start of the file + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: non-statement macro in statement position: include + --> $DIR/shebang-in-expr-ctxt.rs:13:5 + | +LL | include!("auxiliary/shebang-expr.rs"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/tests/ui/include-macros/shebang-in-item-ctxt.rs b/tests/ui/include-macros/shebang-in-item-ctxt.rs new file mode 100644 index 000000000000..3e0718e287f0 --- /dev/null +++ b/tests/ui/include-macros/shebang-in-item-ctxt.rs @@ -0,0 +1,4 @@ +// Ensure that we strip shebang in files `include`d in item contexts. +//@ check-pass + +include!("auxiliary/shebang-items.rs"); From 7d0300b8a578d4c7498365576279dc7ef1cf211b Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Wed, 3 Dec 2025 12:03:13 +0000 Subject: [PATCH 002/126] Fix +vfp3,-d32 target configuration --- .../rustc_target/src/spec/targets/armv7_linux_androideabi.rs | 2 +- compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs | 2 +- .../src/spec/targets/armv7_unknown_linux_gnueabihf.rs | 2 +- .../src/spec/targets/armv7_unknown_linux_musleabihf.rs | 2 +- .../src/spec/targets/armv7_unknown_linux_uclibceabihf.rs | 2 +- .../src/spec/targets/armv7_unknown_netbsd_eabihf.rs | 2 +- .../rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs | 2 +- .../src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs | 2 +- compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs index ad8a14fdad53..3ccb99c9ab0f 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_linux_androideabi.rs @@ -28,7 +28,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: Abi::Eabi, llvm_floatabi: Some(FloatAbi::Soft), - features: "+v7,+thumb-mode,+thumb2,+vfp3,-d32,-neon".into(), + features: "+v7,+thumb-mode,+thumb2,+vfp3d16,-neon".into(), supported_sanitizers: SanitizerSet::ADDRESS, max_atomic_width: Some(64), ..base diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs index 0a8432ea8fe9..c358b530f742 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_freebsd.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: Abi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), + features: "+v7,+vfp3d16,+thumb2,-neon".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), ..base::freebsd::opts() diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs index cbf6d5d08dd0..639a9d225729 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_gnueabihf.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { abi: Abi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Info about features at https://wiki.debian.org/ArmHardFloatPort - features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), + features: "+v7,+vfp3d16,+thumb2,-neon".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs index 9b5fcd87b120..fb7bd1226a37 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_musleabihf.rs @@ -20,7 +20,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: Abi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), + features: "+v7,+vfp3d16,+thumb2,-neon".into(), max_atomic_width: Some(64), mcount: "\u{1}mcount".into(), // FIXME(compiler-team#422): musl targets should be dynamically linked by default. diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs index 927c910da596..8fb38d315bf6 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_linux_uclibceabihf.rs @@ -19,7 +19,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { // Info about features at https://wiki.debian.org/ArmHardFloatPort - features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), + features: "+v7,+vfp3d16,+thumb2,-neon".into(), cpu: "generic".into(), max_atomic_width: Some(64), mcount: "_mcount".into(), diff --git a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs index 788944e64c84..8869210ce002 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_unknown_netbsd_eabihf.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: Abi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), + features: "+v7,+vfp3d16,+thumb2,-neon".into(), max_atomic_width: Some(64), mcount: "__mcount".into(), ..base::netbsd::opts() diff --git a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs index e43e4fe85cad..27e81c5834f2 100644 --- a/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7_wrs_vxworks_eabihf.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { abi: Abi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), // Info about features at https://wiki.debian.org/ArmHardFloatPort - features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), + features: "+v7,+vfp3d16,+thumb2,-neon".into(), max_atomic_width: Some(64), ..base::vxworks::opts() }, diff --git a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs index 9433cbd46627..cb652e6a1e1b 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_kmc_solid_asp3_eabihf.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { abi: Abi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), linker: Some("arm-kmc-eabi-gcc".into()), - features: "+v7,+vfp3,-d32,+thumb2,-neon".into(), + features: "+v7,+vfp3d16,+thumb2,-neon".into(), relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(64), diff --git a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs index e03fe3e78b9d..28efdbe2291f 100644 --- a/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv7a_none_eabihf.rs @@ -16,7 +16,7 @@ pub(crate) fn target() -> Target { llvm_floatabi: Some(FloatAbi::Hard), linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), linker: Some("rust-lld".into()), - features: "+v7,+vfp3,-d32,+thumb2,-neon,+strict-align".into(), + features: "+v7,+vfp3d16,+thumb2,-neon,+strict-align".into(), relocation_model: RelocModel::Static, disable_redzone: true, max_atomic_width: Some(64), From 4ed68f01dc23b2877140c515ee16c6b59801a7a2 Mon Sep 17 00:00:00 2001 From: Adam Gemmell Date: Wed, 3 Dec 2025 12:04:41 +0000 Subject: [PATCH 003/126] Remove redundant -d32 in target specs --- .../src/spec/targets/arm_unknown_linux_gnueabihf.rs | 2 +- .../src/spec/targets/arm_unknown_linux_musleabihf.rs | 2 +- compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs | 2 +- .../src/spec/targets/armv6_unknown_netbsd_eabihf.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs index e003a65be393..1cae42c14559 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_gnueabihf.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: Abi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+strict-align,+v6,+vfp2,-d32".into(), + features: "+strict-align,+v6,+vfp2".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), diff --git a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs index 76051403a559..99995e27af0d 100644 --- a/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs +++ b/compiler/rustc_target/src/spec/targets/arm_unknown_linux_musleabihf.rs @@ -17,7 +17,7 @@ pub(crate) fn target() -> Target { llvm_floatabi: Some(FloatAbi::Hard), // Most of these settings are copied from the arm_unknown_linux_gnueabihf // target. - features: "+strict-align,+v6,+vfp2,-d32".into(), + features: "+strict-align,+v6,+vfp2".into(), max_atomic_width: Some(64), mcount: "\u{1}mcount".into(), // FIXME(compiler-team#422): musl targets should be dynamically linked by default. diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs index 20d91d6968a6..6d6dfeed96b0 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_freebsd.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: Abi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+v6,+vfp2,-d32".into(), + features: "+v6,+vfp2".into(), max_atomic_width: Some(64), mcount: "\u{1}__gnu_mcount_nc".into(), llvm_mcount_intrinsic: Some("llvm.arm.gnu.eabi.mcount".into()), diff --git a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs index 0316bd92999b..cb931e6c0e33 100644 --- a/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs +++ b/compiler/rustc_target/src/spec/targets/armv6_unknown_netbsd_eabihf.rs @@ -15,7 +15,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: Abi::EabiHf, llvm_floatabi: Some(FloatAbi::Hard), - features: "+v6,+vfp2,-d32".into(), + features: "+v6,+vfp2".into(), max_atomic_width: Some(64), mcount: "__mcount".into(), ..base::netbsd::opts() From df38e1521d62e9f04ec339badf9de6317c8602a0 Mon Sep 17 00:00:00 2001 From: tison Date: Tue, 9 Dec 2025 20:38:47 +0800 Subject: [PATCH 004/126] Add const default for OnceCell and OnceLock Signed-off-by: tison --- library/core/src/cell/once.rs | 3 ++- library/std/src/lib.rs | 1 + library/std/src/sync/once_lock.rs | 3 ++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 6c71e2216a71..af4469fad2cc 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -353,7 +353,8 @@ pub fn take(&mut self) -> Option { } #[stable(feature = "once_cell", since = "1.70.0")] -impl Default for OnceCell { +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for OnceCell { #[inline] fn default() -> Self { Self::new() diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 0401e9b39ff4..65ea85f36d93 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -274,6 +274,7 @@ #![feature(cfg_sanitizer_cfi)] #![feature(cfg_target_thread_local)] #![feature(cfi_encoding)] +#![feature(const_default)] #![feature(const_trait_impl)] #![feature(core_float_math)] #![feature(decl_macro)] diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index d1bbe0ff843c..b9a7077e420e 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -582,7 +582,8 @@ impl RefUnwindSafe for OnceLock {} impl UnwindSafe for OnceLock {} #[stable(feature = "once_cell", since = "1.70.0")] -impl Default for OnceLock { +#[rustc_const_unstable(feature = "const_default", issue = "143894")] +impl const Default for OnceLock { /// Creates a new uninitialized cell. /// /// # Example From 0428dd5586f3c90d7e7229ffbeb505d3b33dce34 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Dec 2025 18:51:58 +0100 Subject: [PATCH 005/126] miri: add -Zbinary-dep-depinfo to dependency builds --- src/tools/clippy/tests/compile-test.rs | 4 ++++ src/tools/miri/tests/ui.rs | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 1ac688935278..fa2b6cf26806 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -173,6 +173,10 @@ fn base_config(&self, test_dir: &str, mandatory_annotations: bool) -> Config { p.envs.push(("RUSTC_SNAPSHOT".into(), Some(rustc.into()))); p.envs.push(("RUSTC_SNAPSHOT_LIBDIR".into(), Some(libdir.into()))); p.envs.push(("RUSTC_SYSROOT".into(), Some(sysroot.into()))); + // Ensure we rebuild the dependencies when the sysroot changes. + // (Bootstrap usually sets this automatically, but since we invoke cargo + // ourselves we have to do it.) + p.args.push("-Zbinary-dep-depinfo".into()); } p }, diff --git a/src/tools/miri/tests/ui.rs b/src/tools/miri/tests/ui.rs index c2cbdd548078..338d55b9d773 100644 --- a/src/tools/miri/tests/ui.rs +++ b/src/tools/miri/tests/ui.rs @@ -133,7 +133,11 @@ fn miri_config( program: miri_path() .with_file_name(format!("cargo-miri{}", env::consts::EXE_SUFFIX)), // There is no `cargo miri build` so we just use `cargo miri run`. - args: ["miri", "run"].into_iter().map(Into::into).collect(), + // Add `-Zbinary-dep-depinfo` since it is needed for bootstrap builds (and doesn't harm otherwise). + args: ["miri", "run", "--quiet", "-Zbinary-dep-depinfo"] + .into_iter() + .map(Into::into) + .collect(), // Reset `RUSTFLAGS` to work around . envs: vec![("RUSTFLAGS".into(), None)], ..CommandBuilder::cargo() From ba6b40e6dc37cf3138aedc38a2cdf3a57c8aeb8f Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 14 Dec 2025 04:58:26 +0000 Subject: [PATCH 006/126] Prepare for merging from rust-lang/rust This updates the rust-version file to 2cd4ee6bcf517345dd76d7b102d56b2e873cddbc. --- 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 e79ad9362c08..a1b44d65c597 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -dc47a69ed94bc88b10b7d500cceacf29b87bcbbe +2cd4ee6bcf517345dd76d7b102d56b2e873cddbc From 1a227bd47ff200975f4afb287ec725861ab8b87a Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 9 Nov 2025 02:57:31 +0000 Subject: [PATCH 007/126] Replace Rvalue::NullaryOp by a variant in mir::ConstValue. --- compiler/rustc_borrowck/src/lib.rs | 4 -- .../src/polonius/legacy/loan_invalidations.rs | 2 - compiler/rustc_borrowck/src/type_check/mod.rs | 3 - compiler/rustc_codegen_cranelift/src/base.rs | 13 +---- .../rustc_codegen_cranelift/src/constant.rs | 5 ++ compiler/rustc_codegen_ssa/src/mir/operand.rs | 8 +++ compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 15 ----- .../src/check_consts/check.rs | 1 - .../src/check_consts/qualifs.rs | 4 +- .../src/check_consts/resolver.rs | 1 - .../rustc_const_eval/src/interpret/operand.rs | 4 ++ .../src/interpret/operator.rs | 8 --- .../rustc_const_eval/src/interpret/step.rs | 5 -- compiler/rustc_middle/src/mir/consts.rs | 39 ++++++++++++- compiler/rustc_middle/src/mir/mod.rs | 6 +- compiler/rustc_middle/src/mir/pretty.rs | 11 +--- compiler/rustc_middle/src/mir/statement.rs | 10 ---- compiler/rustc_middle/src/mir/syntax.rs | 32 ---------- compiler/rustc_middle/src/mir/traversal.rs | 4 +- compiler/rustc_middle/src/mir/visit.rs | 7 +-- .../rustc_middle/src/ty/structural_impls.rs | 2 +- .../src/impls/borrowed_locals.rs | 1 - .../src/move_paths/builder.rs | 5 +- .../rustc_mir_transform/src/cost_checker.rs | 29 +--------- .../src/dataflow_const_prop.rs | 3 - compiler/rustc_mir_transform/src/gvn.rs | 3 - .../rustc_mir_transform/src/instsimplify.rs | 43 ++++++++------ .../src/known_panics_lint.rs | 3 - compiler/rustc_mir_transform/src/lint.rs | 1 - .../src/lower_intrinsics.rs | 9 ++- .../rustc_mir_transform/src/promote_consts.rs | 4 -- compiler/rustc_mir_transform/src/validate.rs | 1 - compiler/rustc_public/src/alloc.rs | 1 + compiler/rustc_public/src/mir/body.rs | 20 ------- compiler/rustc_public/src/mir/pretty.rs | 3 - compiler/rustc_public/src/mir/visit.rs | 1 - compiler/rustc_public/src/ty.rs | 11 ++++ .../src/unstable/convert/stable/mir.rs | 21 ++++--- compiler/rustc_public/src/visitor.rs | 4 +- library/core/src/ub_checks.rs | 21 ++++--- .../clippy_utils/src/qualify_min_const_fn.rs | 4 +- tests/codegen-llvm/slice-iter-len-eq-zero.rs | 8 ++- ...ifyConstCondition-after-inst-simplify.diff | 5 +- ...ng_operand.test.GVN.32bit.panic-abort.diff | 58 +++++++++---------- ...ng_operand.test.GVN.64bit.panic-abort.diff | 58 +++++++++---------- ...l_unsigned_smaller.Inline.panic-abort.diff | 6 +- ..._unsigned_smaller.Inline.panic-unwind.diff | 6 +- ..._shr_signed_bigger.Inline.panic-abort.diff | 6 +- ...shr_signed_bigger.Inline.panic-unwind.diff | 6 +- ...d.unwrap_unchecked.Inline.panic-abort.diff | 5 +- ....unwrap_unchecked.Inline.panic-unwind.diff | 5 +- tests/mir-opt/instsimplify/ub_check.rs | 3 +- ...hecked.InstSimplify-after-simplifycfg.diff | 7 +-- 53 files changed, 210 insertions(+), 335 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d82357fca2d4..d15983075af2 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1560,10 +1560,6 @@ fn consume_rvalue( self.consume_operand(location, (operand2, span), state); } - Rvalue::NullaryOp(_op) => { - // nullary ops take no dynamic input; no borrowck effect. - } - Rvalue::Aggregate(aggregate_kind, operands) => { // We need to report back the list of mutable upvars that were // moved into the closure and subsequently used by the closure, diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index de479a7d74c8..85a08b7399e5 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -314,8 +314,6 @@ fn consume_rvalue(&mut self, location: Location, rvalue: &Rvalue<'tcx>) { self.consume_operand(location, operand2); } - Rvalue::NullaryOp(_op) => {} - Rvalue::Aggregate(_, operands) => { for operand in operands { self.consume_operand(location, operand); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 220de046293a..3507a1f8503c 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1046,8 +1046,6 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { } } - &Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {} - Rvalue::ShallowInitBox(_operand, ty) => { let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(LangItem::Sized, span), [*ty]); @@ -2276,7 +2274,6 @@ fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { fx.bcx.ins().nop(); } } - Rvalue::NullaryOp(ref null_op) => { - assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env())); - let val = match null_op { - NullOp::RuntimeChecks(kind) => kind.value(fx.tcx.sess), - }; - let val = CValue::by_val( - fx.bcx.ins().iconst(types::I8, i64::from(val)), - fx.layout_of(fx.tcx.types.bool), - ); - lval.write_cvalue(fx, val); - } Rvalue::Aggregate(ref kind, ref operands) if matches!(**kind, AggregateKind::RawPtr(..)) => { diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 2b65b8290681..29c8e8ab1e52 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -215,6 +215,11 @@ pub(crate) fn codegen_const_value<'tcx>( CValue::by_val(val, layout) } }, + ConstValue::RuntimeChecks(checks) => { + let int = checks.value(fx.tcx.sess); + let int = ScalarInt::try_from_uint(int, Size::from_bits(1)).unwrap(); + return CValue::const_val(fx, layout, int); + } ConstValue::Indirect { alloc_id, offset } => CValue::by_ref( Pointer::new(pointer_for_allocation(fx, alloc_id)) .offset_i64(fx, i64::try_from(offset.bytes()).unwrap()), diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 5a139702f81d..29108043feff 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -165,6 +165,14 @@ pub(crate) fn from_const>( let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); OperandValue::Immediate(llval) } + mir::ConstValue::RuntimeChecks(checks) => { + let BackendRepr::Scalar(scalar) = layout.backend_repr else { + bug!("from_const: invalid ByVal layout: {:#?}", layout); + }; + let x = Scalar::from_bool(checks.value(bx.tcx().sess)); + let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); + OperandValue::Immediate(llval) + } ConstValue::ZeroSized => return OperandRef::zero_sized(layout), ConstValue::Slice { alloc_id, meta } => { let BackendRepr::ScalarPair(a_scalar, _) = layout.backend_repr else { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index de626d04e785..ca8c8dd06ba6 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -619,21 +619,6 @@ pub(crate) fn codegen_rvalue_operand( } } - mir::Rvalue::NullaryOp(ref null_op) => { - let val = match null_op { - mir::NullOp::RuntimeChecks(kind) => { - let val = kind.value(bx.tcx().sess); - bx.cx().const_bool(val) - } - }; - let tcx = self.cx.tcx(); - OperandRef { - val: OperandValue::Immediate(val), - layout: self.cx.layout_of(null_op.ty(tcx)), - move_annotation: None, - } - } - mir::Rvalue::ThreadLocalRef(def_id) => { assert!(bx.cx().tcx().is_static(def_id)); let layout = bx.layout_of(bx.cx().tcx().static_ptr_ty(def_id, bx.typing_env())); diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 78e4066ca910..ed2c0bd6f98e 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -645,7 +645,6 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { Rvalue::Cast(_, _, _) => {} - Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {} Rvalue::ShallowInitBox(_, _) => {} Rvalue::UnaryOp(op, operand) => { diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index f50c6af53bf1..49a477d8fdba 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -230,9 +230,7 @@ pub fn in_rvalue<'tcx, Q, F>( F: FnMut(Local) -> bool, { match rvalue { - Rvalue::ThreadLocalRef(_) | Rvalue::NullaryOp(..) => { - Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) - } + Rvalue::ThreadLocalRef(_) => Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)), Rvalue::Discriminant(place) => in_place::(cx, in_local, place.as_ref()), diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index e6e3948305af..d4cc21996aea 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -198,7 +198,6 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) { | mir::Rvalue::ThreadLocalRef(..) | mir::Rvalue::Repeat(..) | mir::Rvalue::BinaryOp(..) - | mir::Rvalue::NullaryOp(..) | mir::Rvalue::UnaryOp(..) | mir::Rvalue::Discriminant(..) | mir::Rvalue::Aggregate(..) diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index d3d119c8fc9c..32d08d064923 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -892,6 +892,10 @@ pub(crate) fn const_val_to_op( let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO); Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self) } + mir::ConstValue::RuntimeChecks(checks) => { + let val = M::runtime_checks(self, checks)?; + Scalar::from_bool(val).into() + } }; interp_ok(OpTy { op: Operand::Immediate(imm), layout }) } diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 8548b774ddb4..ca8c096d3ab4 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -1,7 +1,6 @@ use either::Either; use rustc_abi::Size; use rustc_apfloat::{Float, FloatConvert}; -use rustc_middle::mir::NullOp; use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar}; use rustc_middle::ty::layout::TyAndLayout; use rustc_middle::ty::{self, FloatTy, ScalarInt}; @@ -505,11 +504,4 @@ pub fn unary_op( } } } - - pub fn nullary_op(&self, null_op: NullOp) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> { - use rustc_middle::mir::NullOp::*; - interp_ok(match null_op { - RuntimeChecks(r) => ImmTy::from_bool(M::runtime_checks(self, r)?, *self.tcx), - }) - } } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 88a116094758..47e8e2a9ec51 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -203,11 +203,6 @@ pub fn eval_rvalue_into_place( self.write_immediate(*result, &dest)?; } - NullaryOp(null_op) => { - let val = self.nullary_op(null_op)?; - self.write_immediate(*val, &dest)?; - } - Aggregate(box ref kind, ref operands) => { self.write_aggregate(kind, operands, &dest)?; } diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index fe352df3b9f0..1b7d3ec9345f 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -68,6 +68,10 @@ pub enum ConstValue { /// Offset into `alloc` offset: Size, }, + + /// Special constants whose value depends on the evaluation context. Their value depends on a + /// flag on the crate being codegenned. + RuntimeChecks(RuntimeChecks), } #[cfg(target_pointer_width = "64")] @@ -77,7 +81,10 @@ impl ConstValue { #[inline] pub fn try_to_scalar(&self) -> Option { match *self { - ConstValue::Indirect { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None, + ConstValue::Indirect { .. } + | ConstValue::Slice { .. } + | ConstValue::ZeroSized + | ConstValue::RuntimeChecks(_) => None, ConstValue::Scalar(val) => Some(val), } } @@ -133,7 +140,7 @@ pub fn try_get_slice_bytes_for_diagnostics<'tcx>( tcx: TyCtxt<'tcx>, ) -> Option<&'tcx [u8]> { let (alloc_id, start, len) = match self { - ConstValue::Scalar(_) | ConstValue::ZeroSized => { + ConstValue::Scalar(_) | ConstValue::ZeroSized | ConstValue::RuntimeChecks(_) => { bug!("`try_get_slice_bytes` on non-slice constant") } &ConstValue::Slice { alloc_id, meta } => (alloc_id, 0, meta), @@ -185,7 +192,9 @@ pub fn try_get_slice_bytes_for_diagnostics<'tcx>( /// Can return `true` even if there is no provenance. pub fn may_have_provenance(&self, tcx: TyCtxt<'_>, size: Size) -> bool { match *self { - ConstValue::ZeroSized | ConstValue::Scalar(Scalar::Int(_)) => return false, + ConstValue::ZeroSized + | ConstValue::Scalar(Scalar::Int(_)) + | ConstValue::RuntimeChecks(_) => return false, ConstValue::Scalar(Scalar::Ptr(..)) => return true, // It's hard to find out the part of the allocation we point to; // just conservatively check everything. @@ -224,6 +233,29 @@ pub fn all_bytes_uninit(&self, tcx: TyCtxt<'_>) -> bool { } } +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum RuntimeChecks { + /// Returns whether we should perform some UB-checking at runtime. + /// See the `ub_checks` intrinsic docs for details. + UbChecks, + /// Returns whether we should perform contract-checking at runtime. + /// See the `contract_checks` intrinsic docs for details. + ContractChecks, + /// Returns whether we should perform some overflow-checking at runtime. + /// See the `overflow_checks` intrinsic docs for details. + OverflowChecks, +} + +impl RuntimeChecks { + pub fn value(self, sess: &rustc_session::Session) -> bool { + match self { + Self::UbChecks => sess.ub_checks(), + Self::ContractChecks => sess.contract_checks(), + Self::OverflowChecks => sess.overflow_checks(), + } + } +} + /////////////////////////////////////////////////////////////////////////// /// Constants @@ -517,6 +549,7 @@ pub fn is_deterministic(&self) -> bool { ConstValue::Slice { .. } | ConstValue::ZeroSized | ConstValue::Scalar(_) + | ConstValue::RuntimeChecks(_) | ConstValue::Indirect { .. }, _, ) => true, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 4ae4152cfb93..bffff1b400d5 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -607,6 +607,9 @@ fn try_const_mono_switchint<'a>( typing_env, crate::ty::EarlyBinder::bind(constant.const_), ); + if let Const::Val(ConstValue::RuntimeChecks(check), _) = mono_literal { + return Some(check.value(tcx.sess) as u128); + } mono_literal.try_eval_bits(tcx, typing_env) }; @@ -649,9 +652,6 @@ fn try_const_mono_switchint<'a>( } match rvalue { - Rvalue::NullaryOp(NullOp::RuntimeChecks(kind)) => { - Some((kind.value(tcx.sess) as u128, targets)) - } Rvalue::Use(Operand::Constant(constant)) => { let bits = eval_mono_const(constant)?; Some((bits, targets)) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index b225dd4ef60a..e4f85a115096 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1097,15 +1097,6 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { BinaryOp(ref op, box (ref a, ref b)) => write!(fmt, "{op:?}({a:?}, {b:?})"), UnaryOp(ref op, ref a) => write!(fmt, "{op:?}({a:?})"), Discriminant(ref place) => write!(fmt, "discriminant({place:?})"), - NullaryOp(ref op) => match op { - NullOp::RuntimeChecks(RuntimeChecks::UbChecks) => write!(fmt, "UbChecks()"), - NullOp::RuntimeChecks(RuntimeChecks::ContractChecks) => { - write!(fmt, "ContractChecks()") - } - NullOp::RuntimeChecks(RuntimeChecks::OverflowChecks) => { - write!(fmt, "OverflowChecks()") - } - }, ThreadLocalRef(did) => ty::tls::with(|tcx| { let muta = tcx.static_mutability(did).unwrap().prefix_str(); write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did)) @@ -1527,6 +1518,7 @@ fn alloc_id_from_const_val(val: ConstValue) -> Option { match val { ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => Some(ptr.provenance.alloc_id()), ConstValue::Scalar(interpret::Scalar::Int { .. }) => None, + ConstValue::RuntimeChecks(_) => None, ConstValue::ZeroSized => None, ConstValue::Slice { alloc_id, .. } | ConstValue::Indirect { alloc_id, .. } => { // FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR. @@ -1977,6 +1969,7 @@ fn pretty_print_const_value_tcx<'tcx>( fmt.write_str(&p.into_buffer())?; return Ok(()); } + (ConstValue::RuntimeChecks(checks), _) => return write!(fmt, "{checks:?}"), (ConstValue::ZeroSized, ty::FnDef(d, s)) => { let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index bd4188dd0ff4..942eb727de67 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -756,7 +756,6 @@ pub fn is_safe_to_remove(&self) -> bool { _, ) | Rvalue::BinaryOp(_, _) - | Rvalue::NullaryOp(_) | Rvalue::UnaryOp(_, _) | Rvalue::Discriminant(_) | Rvalue::Aggregate(_, _) @@ -794,7 +793,6 @@ pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> op.ty(tcx, arg_ty) } Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), - Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => tcx.types.bool, Rvalue::Aggregate(ref ak, ref ops) => match **ak { AggregateKind::Array(ty) => Ty::new_array(tcx, ty, ops.len() as u64), AggregateKind::Tuple => { @@ -858,14 +856,6 @@ pub fn to_mutbl_lossy(self) -> hir::Mutability { } } -impl NullOp { - pub fn ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self { - NullOp::RuntimeChecks(_) => tcx.types.bool, - } - } -} - impl<'tcx> UnOp { pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> { match self { diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 204ad4815147..e96d6824c600 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1418,9 +1418,6 @@ pub enum Rvalue<'tcx> { /// matching types and return a value of that type. BinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>), - /// Computes a value as described by the operation. - NullaryOp(NullOp), - /// Exactly like `BinaryOp`, but less operands. /// /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; @@ -1561,35 +1558,6 @@ pub enum AggregateKind<'tcx> { RawPtr(Ty<'tcx>, Mutability), } -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum NullOp { - /// Returns whether we should perform some checking at runtime. - RuntimeChecks(RuntimeChecks), -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum RuntimeChecks { - /// Returns whether we should perform some UB-checking at runtime. - /// See the `ub_checks` intrinsic docs for details. - UbChecks, - /// Returns whether we should perform contract-checking at runtime. - /// See the `contract_checks` intrinsic docs for details. - ContractChecks, - /// Returns whether we should perform some overflow-checking at runtime. - /// See the `overflow_checks` intrinsic docs for details. - OverflowChecks, -} - -impl RuntimeChecks { - pub fn value(self, sess: &rustc_session::Session) -> bool { - match self { - Self::UbChecks => sess.ub_checks(), - Self::ContractChecks => sess.contract_checks(), - Self::OverflowChecks => sess.overflow_checks(), - } - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub enum UnOp { diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 7f6c7376501f..4f599aea0254 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -293,9 +293,9 @@ pub fn reverse_postorder<'a, 'tcx>( /// reachable. /// /// Such a traversal is mostly useful because it lets us skip lowering the `false` side -/// of `if ::CONST`, as well as [`NullOp::RuntimeChecks`]. +/// of `if ::CONST`, as well as [`ConstValue::RuntimeChecks`]. /// -/// [`NullOp::RuntimeChecks`]: rustc_middle::mir::NullOp::RuntimeChecks +/// [`ConstValue::RuntimeChecks`]: rustc_middle::mir::ConstValue::RuntimeChecks pub fn mono_reachable<'a, 'tcx>( body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 6d251988cbbd..da9b2b97235e 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -775,8 +775,6 @@ fn super_rvalue( ); } - Rvalue::NullaryOp(_op) => {} - Rvalue::Aggregate(kind, operands) => { let kind = &$($mutability)? **kind; match kind { @@ -972,10 +970,7 @@ fn super_const_operand( self.visit_span($(& $mutability)? *span); match const_ { Const::Ty(_, ct) => self.visit_ty_const($(&$mutability)? *ct, location), - Const::Val(_, ty) => { - self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); - } - Const::Unevaluated(_, ty) => { + Const::Val(_, ty) | Const::Unevaluated(_, ty) => { self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 4f70830002ce..5126d902a6d5 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -243,7 +243,6 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { crate::mir::FakeReadCause, crate::mir::Local, crate::mir::MirPhase, - crate::mir::NullOp, crate::mir::Promoted, crate::mir::RawPtrKind, crate::mir::RetagKind, @@ -284,6 +283,7 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // interners). TrivialTypeTraversalAndLiftImpls! { // tidy-alphabetical-start + crate::mir::RuntimeChecks, crate::ty::BoundTy, crate::ty::ParamTy, crate::ty::instance::ReifyReason, diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 331e41bd126b..4b2c52ad7999 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -91,7 +91,6 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { | Rvalue::ThreadLocalRef(..) | Rvalue::Repeat(..) | Rvalue::BinaryOp(..) - | Rvalue::NullaryOp(..) | Rvalue::UnaryOp(..) | Rvalue::Discriminant(..) | Rvalue::Aggregate(..) diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 0cd3405d1e61..a90f3ef35444 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -448,10 +448,7 @@ fn gather_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { } } Rvalue::CopyForDeref(..) => unreachable!(), - Rvalue::Ref(..) - | Rvalue::RawPtr(..) - | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => {} + Rvalue::Ref(..) | Rvalue::RawPtr(..) | Rvalue::Discriminant(..) => {} } } diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 1a9af0e22bbe..8f975866d135 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -60,7 +60,7 @@ fn instantiate_ty(&self, v: Ty<'tcx>) -> Ty<'tcx> { } impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { + fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { // Most costs are in rvalues and terminators, not in statements. match statement.kind { StatementKind::Intrinsic(ref ndi) => { @@ -69,31 +69,8 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { NonDivergingIntrinsic::CopyNonOverlapping(..) => CALL_PENALTY, }; } - _ => self.super_statement(statement, location), - } - } - - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, _location: Location) { - match rvalue { - // FIXME: Should we do the same for `OverflowChecks`? - Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks), ..) - if !self - .tcx - .sess - .opts - .unstable_opts - .inline_mir_preserve_debug - .unwrap_or(self.tcx.sess.ub_checks()) => - { - // If this is in optimized MIR it's because it's used later, - // so if we don't need UB checks this session, give a bonus - // here to offset the cost of the call later. - self.bonus += CALL_PENALTY; - } - // These are essentially constants that didn't end up in an Operand, - // so treat them as also being free. - Rvalue::NullaryOp(..) => {} - _ => self.penalty += INSTR_COST, + StatementKind::Assign(..) => self.penalty += INSTR_COST, + _ => {} } } diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index bccdd526ab7f..232f07d31adb 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -463,9 +463,6 @@ fn handle_rvalue( FlatSet::Top => FlatSet::Top, } } - Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => { - return ValueOrPlace::TOP; - } Rvalue::Discriminant(place) => state.get_discr(place.as_ref(), &self.map), Rvalue::Use(operand) => return self.handle_operand(operand, state), Rvalue::CopyForDeref(_) => bug!("`CopyForDeref` in runtime MIR"), diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 92c74e7fc276..f6bf678af5ba 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -248,7 +248,6 @@ enum Value<'a, 'tcx> { Discriminant(VnIndex), // Operations. - NullaryOp(NullOp), UnaryOp(UnOp, VnIndex), BinaryOp(BinOp, VnIndex, VnIndex), Cast { @@ -681,7 +680,6 @@ fn eval_to_const_inner(&mut self, value: VnIndex) -> Option> { self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?; discr_value.into() } - NullaryOp(NullOp::RuntimeChecks(_)) => return None, UnaryOp(un_op, operand) => { let operand = self.eval_to_const(operand)?; let operand = self.ecx.read_immediate(operand).discard_err()?; @@ -1034,7 +1032,6 @@ fn simplify_rvalue( let op = self.simplify_operand(op, location)?; Value::Repeat(op, amount) } - Rvalue::NullaryOp(op) => Value::NullaryOp(op), Rvalue::Aggregate(..) => return self.simplify_aggregate(lhs, rvalue, location), Rvalue::Ref(_, borrow_kind, ref mut place) => { self.simplify_place_projection(place, location); diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 4922d74743c9..7cb341818fab 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -4,10 +4,11 @@ use rustc_ast::attr; use rustc_hir::LangItem; use rustc_middle::bug; +use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::*; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, layout}; -use rustc_span::{DUMMY_SP, Symbol, sym}; +use rustc_span::{Symbol, sym}; use crate::simplify::simplify_duplicate_switch_targets; @@ -29,22 +30,22 @@ fn is_enabled(&self, sess: &rustc_session::Session) -> bool { } fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + let preserve_ub_checks = + attr::contains_name(tcx.hir_krate_attrs(), sym::rustc_preserve_ub_checks); + if !preserve_ub_checks { + SimplifyUbCheck { tcx }.visit_body(body); + } let ctx = InstSimplifyContext { tcx, local_decls: &body.local_decls, typing_env: body.typing_env(tcx), }; - let preserve_ub_checks = - attr::contains_name(tcx.hir_krate_attrs(), sym::rustc_preserve_ub_checks); for block in body.basic_blocks.as_mut() { for statement in block.statements.iter_mut() { let StatementKind::Assign(box (.., rvalue)) = &mut statement.kind else { continue; }; - if !preserve_ub_checks { - ctx.simplify_ub_check(rvalue); - } ctx.simplify_bool_cmp(rvalue); ctx.simplify_ref_deref(rvalue); ctx.simplify_ptr_aggregate(rvalue); @@ -168,17 +169,6 @@ fn simplify_ptr_aggregate(&self, rvalue: &mut Rvalue<'tcx>) { } } - fn simplify_ub_check(&self, rvalue: &mut Rvalue<'tcx>) { - // FIXME: Should we do the same for overflow checks? - let Rvalue::NullaryOp(NullOp::RuntimeChecks(RuntimeChecks::UbChecks)) = *rvalue else { - return; - }; - - let const_ = Const::from_bool(self.tcx, self.tcx.sess.ub_checks()); - let constant = ConstOperand { span: DUMMY_SP, const_, user_ty: None }; - *rvalue = Rvalue::Use(Operand::Constant(Box::new(constant))); - } - fn simplify_cast(&self, rvalue: &mut Rvalue<'tcx>) { let Rvalue::Cast(kind, operand, cast_ty) = rvalue else { return }; @@ -362,3 +352,22 @@ fn resolve_rust_intrinsic<'tcx>( let intrinsic = tcx.intrinsic(def_id)?; Some((intrinsic.name, args)) } + +struct SimplifyUbCheck<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for SimplifyUbCheck<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_operand(&mut self, operand: &mut Operand<'tcx>, _: Location) { + if let Operand::Constant(c) = operand + && let Const::Val(c, _) = &mut c.const_ + && let ConstValue::RuntimeChecks(RuntimeChecks::UbChecks) = c + { + *c = ConstValue::from_bool(self.tcx.sess.ub_checks()); + } + } +} diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 1f5d31932f1a..53cb02d9c5b2 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -444,7 +444,6 @@ fn check_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option< | Rvalue::Cast(..) | Rvalue::ShallowInitBox(..) | Rvalue::Discriminant(..) - | Rvalue::NullaryOp(..) | Rvalue::WrapUnsafeBinder(..) => {} } @@ -605,8 +604,6 @@ fn eval_rvalue(&mut self, rvalue: &Rvalue<'tcx>, dest: &Place<'tcx>) -> Option<( Ref(..) | RawPtr(..) => return None, - NullaryOp(NullOp::RuntimeChecks(_)) => return None, - ShallowInitBox(..) => return None, Cast(ref kind, ref value, to) => match kind { diff --git a/compiler/rustc_mir_transform/src/lint.rs b/compiler/rustc_mir_transform/src/lint.rs index 2ab49645dc44..88297a4efef7 100644 --- a/compiler/rustc_mir_transform/src/lint.rs +++ b/compiler/rustc_mir_transform/src/lint.rs @@ -88,7 +88,6 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { | Rvalue::ShallowInitBox(..) | Rvalue::WrapUnsafeBinder(..) => true, Rvalue::ThreadLocalRef(..) - | Rvalue::NullaryOp(..) | Rvalue::UnaryOp(..) | Rvalue::BinaryOp(..) | Rvalue::Ref(..) diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index f25874fbbcb8..6740aa97fc8b 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -35,7 +35,14 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { terminator.source_info, StatementKind::Assign(Box::new(( *destination, - Rvalue::NullaryOp(NullOp::RuntimeChecks(op)), + Rvalue::Use(Operand::Constant(Box::new(ConstOperand { + span: terminator.source_info.span, + user_ty: None, + const_: Const::Val( + ConstValue::RuntimeChecks(op), + tcx.types.bool, + ), + }))), ))), )); terminator.kind = TerminatorKind::Goto { target }; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 7d631e96c32a..506cfb7abf92 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -443,10 +443,6 @@ fn validate_rvalue(&mut self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> self.validate_operand(operand)?; } - Rvalue::NullaryOp(op) => match op { - NullOp::RuntimeChecks(_) => {} - }, - Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable), Rvalue::UnaryOp(op, operand) => { diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index cf8247c12abd..1afdb4639a0c 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1439,7 +1439,6 @@ macro_rules! check_kinds { Rvalue::Repeat(_, _) | Rvalue::ThreadLocalRef(_) | Rvalue::RawPtr(_, _) - | Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) | Rvalue::Discriminant(_) => {} Rvalue::WrapUnsafeBinder(op, ty) => { diff --git a/compiler/rustc_public/src/alloc.rs b/compiler/rustc_public/src/alloc.rs index 0c35b3b25dfc..5ede5b2b2712 100644 --- a/compiler/rustc_public/src/alloc.rs +++ b/compiler/rustc_public/src/alloc.rs @@ -53,6 +53,7 @@ pub(crate) fn try_new_allocation<'tcx>( ConstValue::Scalar(scalar) => { alloc::try_new_scalar(layout, scalar, cx).map(|alloc| alloc.stable(tables, cx)) } + ConstValue::RuntimeChecks(_) => todo!(), ConstValue::ZeroSized => Ok(new_empty_allocation(layout.align.abi)), ConstValue::Slice { alloc_id, meta } => { alloc::try_new_slice(layout, alloc_id, meta, cx).map(|alloc| alloc.stable(tables, cx)) diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 03f289f30f42..92882a001c47 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -587,9 +587,6 @@ pub enum Rvalue { /// nature of this operation? ThreadLocalRef(crate::CrateItem), - /// Computes a value as described by the operation. - NullaryOp(NullOp), - /// Exactly like `BinaryOp`, but less operands. /// /// Also does two's-complement arithmetic. Negation requires a signed integer or a float; @@ -641,7 +638,6 @@ pub fn ty(&self, locals: &[LocalDecl]) -> Result { .discriminant_ty() .ok_or_else(|| error!("Expected a `RigidTy` but found: {place_ty:?}")) } - Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) => Ok(Ty::bool_ty()), Rvalue::Aggregate(ak, ops) => match *ak { AggregateKind::Array(ty) => Ty::try_new_array(ty, ops.len() as u64), AggregateKind::Tuple => Ok(Ty::new_tuple( @@ -1018,22 +1014,6 @@ pub enum CastKind { Subtype, } -#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] -pub enum NullOp { - /// Codegen conditions for runtime checks. - RuntimeChecks(RuntimeChecks), -} - -#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] -pub enum RuntimeChecks { - /// cfg!(ub_checks), but at codegen time - UbChecks, - /// cfg!(contract_checks), but at codegen time - ContractChecks, - /// cfg!(overflow_checks), but at codegen time - OverflowChecks, -} - impl Operand { /// Get the type of an operand relative to the local declaration. /// diff --git a/compiler/rustc_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs index 08e4e0c7e0f9..d814947dc397 100644 --- a/compiler/rustc_public/src/mir/pretty.rs +++ b/compiler/rustc_public/src/mir/pretty.rs @@ -386,9 +386,6 @@ fn pretty_rvalue(writer: &mut W, rval: &Rvalue) -> io::Result<()> { Rvalue::ThreadLocalRef(item) => { write!(writer, "thread_local_ref{item:?}") } - Rvalue::NullaryOp(nul) => { - write!(writer, "{nul:?}() \" \"") - } Rvalue::UnaryOp(un, op) => { write!(writer, "{:?}({})", un, pretty_operand(op)) } diff --git a/compiler/rustc_public/src/mir/visit.rs b/compiler/rustc_public/src/mir/visit.rs index 35af39c43a27..f0fdbe059383 100644 --- a/compiler/rustc_public/src/mir/visit.rs +++ b/compiler/rustc_public/src/mir/visit.rs @@ -282,7 +282,6 @@ fn super_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) self.visit_operand(op, location) } Rvalue::ThreadLocalRef(_) => {} - Rvalue::NullaryOp(_) => {} Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => { self.visit_operand(op, location); } diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index 14656a2e594a..a87ac795da5c 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -1357,6 +1357,7 @@ pub enum ConstantKind { Ty(TyConst), Allocated(Allocation), Unevaluated(UnevaluatedConst), + RuntimeChecks(RuntimeChecks), Param(ParamConst), /// Store ZST constants. /// We have to special handle these constants since its type might be generic. @@ -1376,6 +1377,16 @@ pub struct UnevaluatedConst { pub promoted: Option, } +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] +pub enum RuntimeChecks { + /// cfg!(ub_checks), but at codegen time + UbChecks, + /// cfg!(contract_checks), but at codegen time + ContractChecks, + /// cfg!(overflow_checks), but at codegen time + OverflowChecks, +} + #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum TraitSpecializationKind { None, diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index e7a1c8218ce4..31f41653d4a2 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -232,7 +232,6 @@ fn stable<'cx>( ) } } - NullaryOp(null_op) => crate::mir::Rvalue::NullaryOp(null_op.stable(tables, cx)), UnaryOp(un_op, op) => { crate::mir::Rvalue::UnaryOp(un_op.stable(tables, cx), op.stable(tables, cx)) } @@ -312,21 +311,18 @@ fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &CompilerCtxt<'_, BridgeTys>) } } -impl<'tcx> Stable<'tcx> for mir::NullOp { - type T = crate::mir::NullOp; +impl<'tcx> Stable<'tcx> for mir::RuntimeChecks { + type T = crate::ty::RuntimeChecks; fn stable<'cx>( &self, _: &mut Tables<'cx, BridgeTys>, _: &CompilerCtxt<'cx, BridgeTys>, ) -> Self::T { - use rustc_middle::mir::NullOp::*; use rustc_middle::mir::RuntimeChecks::*; match self { - RuntimeChecks(op) => crate::mir::NullOp::RuntimeChecks(match op { - UbChecks => crate::mir::RuntimeChecks::UbChecks, - ContractChecks => crate::mir::RuntimeChecks::ContractChecks, - OverflowChecks => crate::mir::RuntimeChecks::OverflowChecks, - }), + UbChecks => crate::ty::RuntimeChecks::UbChecks, + ContractChecks => crate::ty::RuntimeChecks::ContractChecks, + OverflowChecks => crate::ty::RuntimeChecks::OverflowChecks, } } } @@ -890,6 +886,13 @@ fn stable<'cx>( let ty = ty.stable(tables, cx); MirConst::new(ConstantKind::ZeroSized, ty, id) } + mir::Const::Val(mir::ConstValue::RuntimeChecks(checks), ty) => { + let ty = cx.lift(ty).unwrap(); + let checks = cx.lift(checks).unwrap(); + let ty = ty.stable(tables, cx); + let kind = ConstantKind::RuntimeChecks(checks.stable(tables, cx)); + MirConst::new(kind, ty, id) + } mir::Const::Val(val, ty) => { let ty = cx.lift(ty).unwrap(); let val = cx.lift(val).unwrap(); diff --git a/compiler/rustc_public/src/visitor.rs b/compiler/rustc_public/src/visitor.rs index acc333476961..2ebd73a43e90 100644 --- a/compiler/rustc_public/src/visitor.rs +++ b/compiler/rustc_public/src/visitor.rs @@ -68,7 +68,9 @@ fn super_visit(&self, visitor: &mut V) -> ControlFlow { super::ty::ConstantKind::Ty(ct) => ct.visit(visitor)?, super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?, super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?, - super::ty::ConstantKind::Param(_) | super::ty::ConstantKind::ZeroSized => {} + super::ty::ConstantKind::RuntimeChecks(_) + | super::ty::ConstantKind::Param(_) + | super::ty::ConstantKind::ZeroSized => {} } self.ty().visit(visitor) } diff --git a/library/core/src/ub_checks.rs b/library/core/src/ub_checks.rs index 50e02320748b..f25781ea8ce5 100644 --- a/library/core/src/ub_checks.rs +++ b/library/core/src/ub_checks.rs @@ -95,17 +95,16 @@ const fn precondition_check($($name:$ty),*) { #[rustc_allow_const_fn_unstable(const_eval_select)] pub(crate) const fn check_language_ub() -> bool { // Only used for UB checks so we may const_eval_select. - intrinsics::ub_checks() - && const_eval_select!( - @capture { } -> bool: - if const { - // Always disable UB checks. - false - } else { - // Disable UB checks in Miri. - !cfg!(miri) - } - ) + const_eval_select!( + @capture { } -> bool: + if const { + // Always disable UB checks. + false + } else { + // Disable UB checks in Miri. + !cfg!(miri) + } + ) && intrinsics::ub_checks() } /// Checks whether `ptr` is properly aligned with respect to the given alignment, and diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 462cc644d4be..c1d00fc8d371 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -13,7 +13,7 @@ use rustc_infer::traits::Obligation; use rustc_lint::LateContext; use rustc_middle::mir::{ - Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, + Body, CastKind, NonDivergingIntrinsic, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::traits::{BuiltinImplSource, ImplSource, ObligationCause}; @@ -194,7 +194,7 @@ fn check_rvalue<'tcx>( )) } }, - Rvalue::NullaryOp(NullOp::RuntimeChecks(_)) | Rvalue::ShallowInitBox(_, _) => Ok(()), + Rvalue::ShallowInitBox(_, _) => Ok(()), Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, cx.tcx); if ty.is_integral() || ty.is_bool() { diff --git a/tests/codegen-llvm/slice-iter-len-eq-zero.rs b/tests/codegen-llvm/slice-iter-len-eq-zero.rs index 6998d98e498c..ae1bdb1d58b9 100644 --- a/tests/codegen-llvm/slice-iter-len-eq-zero.rs +++ b/tests/codegen-llvm/slice-iter-len-eq-zero.rs @@ -8,8 +8,10 @@ #[no_mangle] pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool { // CHECK-NOT: sub - // CHECK: %[[RET:.+]] = icmp eq ptr {{%y.0, %y.1|%y.1, %y.0}} - // CHECK: ret i1 %[[RET]] + // CHECK: %2 = icmp ne ptr %1, null + // CHECK-NEXT: tail call void @llvm.assume(i1 %2) + // CHECK-NEXT: %[[RET:.+]] = icmp eq ptr {{%0, %1|%1, %0}} + // CHECK-NEXT: ret i1 %[[RET]] y.len() == 0 } @@ -31,7 +33,7 @@ pub fn slice_iter_len_eq_zero_ref(y: &mut std::slice::Iter<'_, Demo>) -> bool { // CHECK-LABEL: @slice_zst_iter_len_eq_zero #[no_mangle] pub fn slice_zst_iter_len_eq_zero(y: std::slice::Iter<'_, MyZST>) -> bool { - // CHECK: %[[RET:.+]] = icmp eq ptr %y.1, null + // CHECK: %[[RET:.+]] = icmp eq ptr %1, null // CHECK: ret i1 %[[RET]] y.len() == 0 } diff --git a/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff b/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff index d14c42a330eb..4714e159396e 100644 --- a/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff +++ b/tests/mir-opt/const_prop/trivial_const.unwrap_unchecked.SimplifyConstCondition-after-inst-simplify.diff @@ -16,7 +16,6 @@ scope 4 (inlined #[track_caller] unreachable_unchecked) { let _5: (); scope 5 (inlined core::ub_checks::check_language_ub) { - let mut _6: bool; scope 6 (inlined core::ub_checks::check_language_ub::runtime) { } } @@ -38,9 +37,7 @@ } bb2: { -- StorageLive(_6); -- _6 = const false; -- assume(copy _6); +- assume(const false); - _5 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + unreachable; } diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index 38beb81e1ead..ae2b8e574303 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -13,7 +13,7 @@ let mut _11: *const (); let mut _16: usize; let mut _17: usize; - let mut _27: usize; + let mut _26: usize; scope 1 { debug vp_ctx => _1; let _5: *const (); @@ -27,7 +27,7 @@ debug _x => _8; } scope 18 (inlined foo) { - let mut _28: *const [()]; + let mut _27: *const [()]; } } scope 16 (inlined slice_from_raw_parts::<()>) { @@ -52,7 +52,7 @@ scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) { scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) { scope 13 (inlined NonNull::<[u8]>::cast::) { - let mut _26: *mut [u8]; + let mut _25: *mut [u8]; scope 14 (inlined NonNull::<[u8]>::as_ptr) { } } @@ -65,9 +65,8 @@ } } scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { - let mut _23: bool; - let _24: (); - let mut _25: std::ptr::Alignment; + let _23: (); + let mut _24: std::ptr::Alignment; } } } @@ -94,10 +93,8 @@ StorageLive(_20); StorageLive(_21); StorageLive(_22); - StorageLive(_24); StorageLive(_23); - _23 = UbChecks(); - switchInt(move _23) -> [0: bb6, otherwise: bb5]; + switchInt(const UbChecks) -> [0: bb6, otherwise: bb5]; } bb1: { @@ -117,14 +114,14 @@ bb4: { _21 = copy ((_19 as Ok).0: std::ptr::NonNull<[u8]>); -- StorageLive(_26); +- StorageLive(_25); + nop; - _26 = copy _21 as *mut [u8] (Transmute); - _12 = copy _26 as *mut u8 (PtrToPtr); -- StorageDead(_26); + _25 = copy _21 as *mut [u8] (Transmute); + _12 = copy _25 as *mut u8 (PtrToPtr); +- StorageDead(_25); + nop; StorageDead(_19); - StorageDead(_24); + StorageDead(_23); StorageDead(_22); StorageDead(_21); StorageDead(_20); @@ -132,7 +129,7 @@ StorageDead(_17); StorageDead(_16); - _13 = copy _12 as *const () (PtrToPtr); -+ _13 = copy _26 as *const () (PtrToPtr); ++ _13 = copy _25 as *const () (PtrToPtr); _14 = NonNull::<()> { pointer: copy _13 }; _15 = Unique::<()> { pointer: copy _14, _marker: const PhantomData::<()> }; _3 = Box::<()>(move _15, const std::alloc::Global); @@ -157,21 +154,21 @@ + nop; StorageLive(_7); _7 = copy _5; - StorageLive(_27); - _27 = const 1_usize; -- _6 = *const [()] from (copy _7, copy _27); + StorageLive(_26); + _26 = const 1_usize; +- _6 = *const [()] from (copy _7, copy _26); + _6 = *const [()] from (copy _5, const 1_usize); - StorageDead(_27); + StorageDead(_26); StorageDead(_7); StorageLive(_8); StorageLive(_9); _9 = copy _6; - StorageLive(_28); -- _28 = copy _9; + StorageLive(_27); +- _27 = copy _9; - _8 = copy _9 as *mut () (PtrToPtr); -+ _28 = copy _6; ++ _27 = copy _6; + _8 = copy _5 as *mut () (PtrToPtr); - StorageDead(_28); + StorageDead(_27); StorageDead(_9); _0 = const (); StorageDead(_8); @@ -183,18 +180,17 @@ } bb5: { -- _24 = Layout::from_size_align_unchecked::precondition_check(copy _16, copy _17) -> [return: bb6, unwind unreachable]; -+ _24 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; +- _23 = Layout::from_size_align_unchecked::precondition_check(copy _16, copy _17) -> [return: bb6, unwind unreachable]; ++ _23 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_23); - StorageLive(_25); -- _25 = copy _17 as std::ptr::Alignment (Transmute); -- _18 = Layout { size: copy _16, align: move _25 }; -+ _25 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); + StorageLive(_24); +- _24 = copy _17 as std::ptr::Alignment (Transmute); +- _18 = Layout { size: copy _16, align: move _24 }; ++ _24 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); + _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; - StorageDead(_25); + StorageDead(_24); StorageLive(_19); - _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _18, const false) -> [return: bb7, unwind unreachable]; + _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 047579cdb509..164aeb2d9037 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -13,7 +13,7 @@ let mut _11: *const (); let mut _16: usize; let mut _17: usize; - let mut _27: usize; + let mut _26: usize; scope 1 { debug vp_ctx => _1; let _5: *const (); @@ -27,7 +27,7 @@ debug _x => _8; } scope 18 (inlined foo) { - let mut _28: *const [()]; + let mut _27: *const [()]; } } scope 16 (inlined slice_from_raw_parts::<()>) { @@ -52,7 +52,7 @@ scope 11 (inlined NonNull::<[u8]>::as_mut_ptr) { scope 12 (inlined NonNull::<[u8]>::as_non_null_ptr) { scope 13 (inlined NonNull::<[u8]>::cast::) { - let mut _26: *mut [u8]; + let mut _25: *mut [u8]; scope 14 (inlined NonNull::<[u8]>::as_ptr) { } } @@ -65,9 +65,8 @@ } } scope 9 (inlined #[track_caller] Layout::from_size_align_unchecked) { - let mut _23: bool; - let _24: (); - let mut _25: std::ptr::Alignment; + let _23: (); + let mut _24: std::ptr::Alignment; } } } @@ -94,10 +93,8 @@ StorageLive(_20); StorageLive(_21); StorageLive(_22); - StorageLive(_24); StorageLive(_23); - _23 = UbChecks(); - switchInt(move _23) -> [0: bb6, otherwise: bb5]; + switchInt(const UbChecks) -> [0: bb6, otherwise: bb5]; } bb1: { @@ -117,14 +114,14 @@ bb4: { _21 = copy ((_19 as Ok).0: std::ptr::NonNull<[u8]>); -- StorageLive(_26); +- StorageLive(_25); + nop; - _26 = copy _21 as *mut [u8] (Transmute); - _12 = copy _26 as *mut u8 (PtrToPtr); -- StorageDead(_26); + _25 = copy _21 as *mut [u8] (Transmute); + _12 = copy _25 as *mut u8 (PtrToPtr); +- StorageDead(_25); + nop; StorageDead(_19); - StorageDead(_24); + StorageDead(_23); StorageDead(_22); StorageDead(_21); StorageDead(_20); @@ -132,7 +129,7 @@ StorageDead(_17); StorageDead(_16); - _13 = copy _12 as *const () (PtrToPtr); -+ _13 = copy _26 as *const () (PtrToPtr); ++ _13 = copy _25 as *const () (PtrToPtr); _14 = NonNull::<()> { pointer: copy _13 }; _15 = Unique::<()> { pointer: copy _14, _marker: const PhantomData::<()> }; _3 = Box::<()>(move _15, const std::alloc::Global); @@ -157,21 +154,21 @@ + nop; StorageLive(_7); _7 = copy _5; - StorageLive(_27); - _27 = const 1_usize; -- _6 = *const [()] from (copy _7, copy _27); + StorageLive(_26); + _26 = const 1_usize; +- _6 = *const [()] from (copy _7, copy _26); + _6 = *const [()] from (copy _5, const 1_usize); - StorageDead(_27); + StorageDead(_26); StorageDead(_7); StorageLive(_8); StorageLive(_9); _9 = copy _6; - StorageLive(_28); -- _28 = copy _9; + StorageLive(_27); +- _27 = copy _9; - _8 = copy _9 as *mut () (PtrToPtr); -+ _28 = copy _6; ++ _27 = copy _6; + _8 = copy _5 as *mut () (PtrToPtr); - StorageDead(_28); + StorageDead(_27); StorageDead(_9); _0 = const (); StorageDead(_8); @@ -183,18 +180,17 @@ } bb5: { -- _24 = Layout::from_size_align_unchecked::precondition_check(copy _16, copy _17) -> [return: bb6, unwind unreachable]; -+ _24 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; +- _23 = Layout::from_size_align_unchecked::precondition_check(copy _16, copy _17) -> [return: bb6, unwind unreachable]; ++ _23 = Layout::from_size_align_unchecked::precondition_check(const 0_usize, const 1_usize) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_23); - StorageLive(_25); -- _25 = copy _17 as std::ptr::Alignment (Transmute); -- _18 = Layout { size: copy _16, align: move _25 }; -+ _25 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); + StorageLive(_24); +- _24 = copy _17 as std::ptr::Alignment (Transmute); +- _18 = Layout { size: copy _16, align: move _24 }; ++ _24 = const std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0); + _18 = const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}; - StorageDead(_25); + StorageDead(_24); StorageLive(_19); - _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], copy _18, const false) -> [return: bb7, unwind unreachable]; + _19 = std::alloc::Global::alloc_impl(const alloc::alloc::exchange_malloc::promoted[0], const Layout {{ size: 0_usize, align: std::ptr::Alignment(std::ptr::alignment::AlignmentEnum::_Align1Shl0) }}, const false) -> [return: bb7, unwind unreachable]; diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff index 813796657b24..153e314fb6f4 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff @@ -10,7 +10,6 @@ + scope 1 (inlined #[track_caller] core::num::::unchecked_shl) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { -+ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -23,9 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; + StorageLive(_5); -+ StorageLive(_6); -+ _6 = UbChecks(); -+ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; ++ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { @@ -34,7 +31,6 @@ + + bb2: { + _0 = ShlUnchecked(copy _3, copy _4); -+ StorageDead(_6); + StorageDead(_5); StorageDead(_4); StorageDead(_3); diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff index 61fdb69f74b7..fd9f5838efc3 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff @@ -10,7 +10,6 @@ + scope 1 (inlined #[track_caller] core::num::::unchecked_shl) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { -+ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -23,9 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue]; + StorageLive(_5); -+ StorageLive(_6); -+ _6 = UbChecks(); -+ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; ++ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { @@ -34,7 +31,6 @@ + + bb2: { + _0 = ShlUnchecked(copy _3, copy _4); -+ StorageDead(_6); + StorageDead(_5); StorageDead(_4); StorageDead(_3); diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff index 5ea99e8301b8..5b12c1853359 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff @@ -10,7 +10,6 @@ + scope 1 (inlined #[track_caller] core::num::::unchecked_shr) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { -+ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -23,9 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; + StorageLive(_5); -+ StorageLive(_6); -+ _6 = UbChecks(); -+ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; ++ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { @@ -34,7 +31,6 @@ + + bb2: { + _0 = ShrUnchecked(copy _3, copy _4); -+ StorageDead(_6); + StorageDead(_5); StorageDead(_4); StorageDead(_3); diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff index b13531ab148f..e8474898b995 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff @@ -10,7 +10,6 @@ + scope 1 (inlined #[track_caller] core::num::::unchecked_shr) { + let _5: (); + scope 2 (inlined core::ub_checks::check_language_ub) { -+ let mut _6: bool; + scope 3 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -23,9 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue]; + StorageLive(_5); -+ StorageLive(_6); -+ _6 = UbChecks(); -+ switchInt(copy _6) -> [0: bb2, otherwise: bb1]; ++ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { @@ -34,7 +31,6 @@ + + bb2: { + _0 = ShrUnchecked(copy _3, copy _4); -+ StorageDead(_6); + StorageDead(_5); StorageDead(_4); StorageDead(_3); diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff index 0119dd799704..7bd93b804e7f 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff @@ -12,7 +12,6 @@ + scope 3 (inlined #[track_caller] unreachable_unchecked) { + let _4: (); + scope 4 (inlined core::ub_checks::check_language_ub) { -+ let mut _5: bool; + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -34,9 +33,7 @@ + } + + bb2: { -+ StorageLive(_5); -+ _5 = UbChecks(); -+ assume(copy _5); ++ assume(const UbChecks); + _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + } + diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff index d6a5eab1d6e9..ae194db56cc9 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff @@ -12,7 +12,6 @@ + scope 3 (inlined #[track_caller] unreachable_unchecked) { + let _4: (); + scope 4 (inlined core::ub_checks::check_language_ub) { -+ let mut _5: bool; + scope 5 (inlined core::ub_checks::check_language_ub::runtime) { + } + } @@ -38,9 +37,7 @@ - bb2 (cleanup): { - resume; + bb2: { -+ StorageLive(_5); -+ _5 = UbChecks(); -+ assume(copy _5); ++ assume(const UbChecks); + _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + } + diff --git a/tests/mir-opt/instsimplify/ub_check.rs b/tests/mir-opt/instsimplify/ub_check.rs index b513f60dc7b9..db890c184079 100644 --- a/tests/mir-opt/instsimplify/ub_check.rs +++ b/tests/mir-opt/instsimplify/ub_check.rs @@ -5,8 +5,7 @@ pub fn unwrap_unchecked(x: Option) -> i32 { // CHECK-LABEL: fn unwrap_unchecked( // CHECK-NOT: UbChecks() - // CHECK: [[assume:_.*]] = const false; - // CHECK-NEXT: assume(copy [[assume]]); + // CHECK: assume(const false); // CHECK-NEXT: unreachable_unchecked::precondition_check unsafe { x.unwrap_unchecked() } } diff --git a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff index 2c9071e6e207..890c87880441 100644 --- a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff +++ b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff @@ -12,7 +12,6 @@ scope 3 (inlined #[track_caller] unreachable_unchecked) { let _4: (); scope 4 (inlined core::ub_checks::check_language_ub) { - let mut _5: bool; scope 5 (inlined core::ub_checks::check_language_ub::runtime) { } } @@ -33,10 +32,8 @@ } bb2: { - StorageLive(_5); -- _5 = UbChecks(); -+ _5 = const false; - assume(copy _5); +- assume(const UbChecks); ++ assume(const false); _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; } From a0de5ae5a1933acfc0a161d945b1ce1d05c7e82e Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 9 Nov 2025 02:57:31 +0000 Subject: [PATCH 008/126] Replace Rvalue::NullaryOp by a variant in mir::ConstValue. --- src/base.rs | 13 +------------ src/constant.rs | 5 +++++ 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/base.rs b/src/base.rs index ac5b3c240785..4dbee7665eb8 100644 --- a/src/base.rs +++ b/src/base.rs @@ -10,7 +10,7 @@ use rustc_index::IndexVec; use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; -use rustc_middle::ty::layout::{FnAbiOf, HasTypingEnv}; +use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::config::OutputFilenames; use rustc_span::Symbol; @@ -853,17 +853,6 @@ fn is_wide_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool { fx.bcx.ins().nop(); } } - Rvalue::NullaryOp(ref null_op) => { - assert!(lval.layout().ty.is_sized(fx.tcx, fx.typing_env())); - let val = match null_op { - NullOp::RuntimeChecks(kind) => kind.value(fx.tcx.sess), - }; - let val = CValue::by_val( - fx.bcx.ins().iconst(types::I8, i64::from(val)), - fx.layout_of(fx.tcx.types.bool), - ); - lval.write_cvalue(fx, val); - } Rvalue::Aggregate(ref kind, ref operands) if matches!(**kind, AggregateKind::RawPtr(..)) => { diff --git a/src/constant.rs b/src/constant.rs index 2b65b8290681..29c8e8ab1e52 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -215,6 +215,11 @@ pub(crate) fn codegen_const_value<'tcx>( CValue::by_val(val, layout) } }, + ConstValue::RuntimeChecks(checks) => { + let int = checks.value(fx.tcx.sess); + let int = ScalarInt::try_from_uint(int, Size::from_bits(1)).unwrap(); + return CValue::const_val(fx, layout, int); + } ConstValue::Indirect { alloc_id, offset } => CValue::by_ref( Pointer::new(pointer_for_allocation(fx, alloc_id)) .offset_i64(fx, i64::try_from(offset.bytes()).unwrap()), From 6319bee585561a078de4a0f8d07d567ce69cf12c Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 16 Nov 2025 19:21:17 +0000 Subject: [PATCH 009/126] Introduce Operand::RuntimeChecks. --- .../src/diagnostics/explain_borrow.rs | 2 + compiler/rustc_borrowck/src/lib.rs | 4 +- .../src/polonius/legacy/loan_invalidations.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- compiler/rustc_codegen_cranelift/src/base.rs | 8 +++- .../rustc_codegen_cranelift/src/constant.rs | 9 ++--- compiler/rustc_codegen_ssa/src/mir/operand.rs | 19 +++++---- .../src/check_consts/qualifs.rs | 1 + .../src/const_eval/dummy_machine.rs | 7 ++++ .../src/const_eval/machine.rs | 10 +++++ .../rustc_const_eval/src/interpret/machine.rs | 12 +----- .../rustc_const_eval/src/interpret/operand.rs | 9 +++-- .../rustc_const_eval/src/interpret/step.rs | 2 +- compiler/rustc_middle/src/mir/consts.rs | 39 ++----------------- compiler/rustc_middle/src/mir/mod.rs | 7 ++-- compiler/rustc_middle/src/mir/pretty.rs | 3 +- compiler/rustc_middle/src/mir/statement.rs | 8 ++-- compiler/rustc_middle/src/mir/syntax.rs | 27 +++++++++++++ compiler/rustc_middle/src/mir/visit.rs | 1 + .../src/builder/custom/parse.rs | 1 + compiler/rustc_mir_build/src/builder/scope.rs | 4 +- .../src/move_paths/builder.rs | 5 ++- .../rustc_mir_transform/src/cost_checker.rs | 2 +- .../src/dataflow_const_prop.rs | 4 +- .../src/early_otherwise_branch.rs | 6 +-- .../src/function_item_references.rs | 7 +--- compiler/rustc_mir_transform/src/gvn.rs | 10 +++++ .../rustc_mir_transform/src/instsimplify.rs | 14 ++++--- .../rustc_mir_transform/src/jump_threading.rs | 1 + .../src/known_panics_lint.rs | 1 + compiler/rustc_mir_transform/src/lib.rs | 2 +- .../src/lower_intrinsics.rs | 9 +---- .../rustc_mir_transform/src/promote_consts.rs | 3 ++ .../src/simplify_branches.rs | 2 +- compiler/rustc_mir_transform/src/sroa.rs | 13 ++++--- compiler/rustc_public/src/alloc.rs | 1 - compiler/rustc_public/src/mir/body.rs | 12 ++++++ compiler/rustc_public/src/mir/pretty.rs | 1 + compiler/rustc_public/src/mir/visit.rs | 1 + compiler/rustc_public/src/ty.rs | 11 ------ .../src/unstable/convert/stable/mir.rs | 16 +++----- compiler/rustc_public/src/visitor.rs | 4 +- .../clippy_utils/src/mir/possible_borrower.rs | 4 +- .../clippy_utils/src/qualify_min_const_fn.rs | 1 + tests/codegen-llvm/slice-iter-len-eq-zero.rs | 8 ++-- 45 files changed, 167 insertions(+), 148 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 8e18bf557758..743a28822eb9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -764,6 +764,7 @@ fn later_use_kind( { // Just point to the function, to reduce the chance of overlapping spans. let function_span = match func { + Operand::RuntimeChecks(_) => span, Operand::Constant(c) => c.span, Operand::Copy(place) | Operand::Move(place) => { if let Some(l) = place.as_local() { @@ -809,6 +810,7 @@ fn later_use_kind( { // Just point to the function, to reduce the chance of overlapping spans. let function_span = match func { + Operand::RuntimeChecks(_) => span, Operand::Constant(c) => c.span, Operand::Copy(place) | Operand::Move(place) => { if let Some(l) = place.as_local() { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index d15983075af2..72956f245bf9 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1696,7 +1696,7 @@ fn propagate_closure_used_mut_upvar(&mut self, operand: &Operand<'tcx>) { _ => propagate_closure_used_mut_place(self, place), } } - Operand::Constant(..) => {} + Operand::Constant(..) | Operand::RuntimeChecks(_) => {} } } @@ -1747,7 +1747,7 @@ fn consume_operand( state, ); } - Operand::Constant(_) => {} + Operand::Constant(_) | Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 85a08b7399e5..d2eae2c7e65a 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -247,7 +247,7 @@ fn consume_operand(&mut self, location: Location, operand: &Operand<'tcx>) { LocalMutationIsAllowed::Yes, ); } - Operand::Constant(_) => {} + Operand::Constant(_) | Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 3507a1f8503c..097416b4f280 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1023,7 +1023,7 @@ fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { // element, so we require the `Copy` trait. if len.try_to_target_usize(tcx).is_none_or(|len| len > 1) { match operand { - Operand::Copy(..) | Operand::Constant(..) => { + Operand::Copy(..) | Operand::Constant(..) | Operand::RuntimeChecks(_) => { // These are always okay: direct use of a const, or a value that can // evidently be copied. } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 4dbee7665eb8..79f65141e66f 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -8,10 +8,10 @@ use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_index::IndexVec; -use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{ScalarInt, TypeVisitableExt}; use rustc_session::config::OutputFilenames; use rustc_span::Symbol; @@ -1039,6 +1039,12 @@ pub(crate) fn codegen_operand<'tcx>( cplace.to_cvalue(fx) } Operand::Constant(const_) => crate::constant::codegen_constant_operand(fx, const_), + Operand::RuntimeChecks(checks) => { + let int = checks.value(fx.tcx.sess); + let int = ScalarInt::try_from_uint(int, Size::from_bits(1)).unwrap(); + let layout = fx.layout_of(fx.tcx.types.bool); + return CValue::const_val(fx, layout, int); + } } } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 29c8e8ab1e52..c25034d4be22 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -215,11 +215,6 @@ pub(crate) fn codegen_const_value<'tcx>( CValue::by_val(val, layout) } }, - ConstValue::RuntimeChecks(checks) => { - let int = checks.value(fx.tcx.sess); - let int = ScalarInt::try_from_uint(int, Size::from_bits(1)).unwrap(); - return CValue::const_val(fx, layout, int); - } ConstValue::Indirect { alloc_id, offset } => CValue::by_ref( Pointer::new(pointer_for_allocation(fx, alloc_id)) .offset_i64(fx, i64::try_from(offset.bytes()).unwrap()), @@ -545,6 +540,10 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( operand: &Operand<'tcx>, ) -> Option { match operand { + Operand::RuntimeChecks(checks) => { + let int = checks.value(fx.tcx.sess); + ScalarInt::try_from_uint(int, Size::from_bits(1)) + } Operand::Constant(const_) => eval_mir_constant(fx, const_).0.try_to_scalar_int(), // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored // inside a temporary before being passed to the intrinsic requiring the const argument. diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 29108043feff..aa80812388af 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -165,14 +165,6 @@ pub(crate) fn from_const>( let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); OperandValue::Immediate(llval) } - mir::ConstValue::RuntimeChecks(checks) => { - let BackendRepr::Scalar(scalar) = layout.backend_repr else { - bug!("from_const: invalid ByVal layout: {:#?}", layout); - }; - let x = Scalar::from_bool(checks.value(bx.tcx().sess)); - let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); - OperandValue::Immediate(llval) - } ConstValue::ZeroSized => return OperandRef::zero_sized(layout), ConstValue::Slice { alloc_id, meta } => { let BackendRepr::ScalarPair(a_scalar, _) = layout.backend_repr else { @@ -1060,6 +1052,17 @@ pub fn codegen_operand( OperandRef { move_annotation, ..self.codegen_consume(bx, place.as_ref()) } } + mir::Operand::RuntimeChecks(checks) => { + let layout = bx.layout_of(bx.tcx().types.bool); + let BackendRepr::Scalar(scalar) = layout.backend_repr else { + bug!("from_const: invalid ByVal layout: {:#?}", layout); + }; + let x = Scalar::from_bool(checks.value(bx.tcx().sess)); + let llval = bx.scalar_to_backend(x, scalar, bx.immediate_backend_type(layout)); + let val = OperandValue::Immediate(llval); + OperandRef { val, layout, move_annotation: None } + } + mir::Operand::Constant(ref constant) => { let constant_ty = self.monomorphize(constant.ty()); // Most SIMD vector constants should be passed as immediates. diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index 49a477d8fdba..42943648ffdd 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -338,6 +338,7 @@ pub fn in_operand<'tcx, Q, F>( Operand::Copy(place) | Operand::Move(place) => { return in_place::(cx, in_local, place.as_ref()); } + Operand::RuntimeChecks(_) => return Q::in_any_value_of_ty(cx, cx.tcx.types.bool), Operand::Constant(c) => c, }; diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 438aed41b8be..40acff416bb0 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -122,6 +122,13 @@ fn assert_panic( unimplemented!() } + #[inline(always)] + fn runtime_checks(_ecx: &InterpCx<'tcx, Self>, r: RuntimeChecks) -> InterpResult<'tcx, bool> { + // We can't look at `tcx.sess` here as that can differ across crates, which can lead to + // unsound differences in evaluating the same constant at different instantiation sites. + panic!("compiletime machine evaluated {r:?}") + } + fn binary_ptr_op( ecx: &InterpCx<'tcx, Self>, bin_op: BinOp, diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 0c677b34df7b..7538130e9d92 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -637,6 +637,16 @@ fn assert_panic( Err(ConstEvalErrKind::AssertFailure(err)).into() } + #[inline(always)] + fn runtime_checks( + _ecx: &InterpCx<'tcx, Self>, + _r: mir::RuntimeChecks, + ) -> InterpResult<'tcx, bool> { + // We can't look at `tcx.sess` here as that can differ across crates, which can lead to + // unsound differences in evaluating the same constant at different instantiation sites. + interp_ok(true) + } + fn binary_ptr_op( _ecx: &InterpCx<'tcx, Self>, _bin_op: mir::BinOp, diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 753b2dd3b8ea..62ca47d23b4c 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -298,7 +298,7 @@ fn before_terminator(_ecx: &mut InterpCx<'tcx, Self>) -> InterpResult<'tcx> { interp_ok(()) } - /// Determines the result of a `NullaryOp::RuntimeChecks` invocation. + /// Determines the result of a `Operand::RuntimeChecks` invocation. fn runtime_checks( _ecx: &InterpCx<'tcx, Self>, r: mir::RuntimeChecks, @@ -680,16 +680,6 @@ fn float_fuse_mul_add(_ecx: &InterpCx<$tcx, Self>) -> bool { true } - #[inline(always)] - fn runtime_checks( - _ecx: &InterpCx<$tcx, Self>, - _r: mir::RuntimeChecks, - ) -> InterpResult<$tcx, bool> { - // We can't look at `tcx.sess` here as that can differ across crates, which can lead to - // unsound differences in evaluating the same constant at different instantiation sites. - interp_ok(true) - } - #[inline(always)] fn adjust_global_allocation<'b>( _ecx: &InterpCx<$tcx, Self>, diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 32d08d064923..9a956259ba57 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -845,6 +845,11 @@ pub fn eval_operand( // FIXME: do some more logic on `move` to invalidate the old location &Copy(place) | &Move(place) => self.eval_place_to_op(place, layout)?, + &RuntimeChecks(checks) => { + let val = M::runtime_checks(self, checks)?; + ImmTy::from_bool(val, self.tcx()).into() + } + Constant(constant) => { let c = self.instantiate_from_current_frame_and_normalize_erasing_regions( constant.const_, @@ -892,10 +897,6 @@ pub(crate) fn const_val_to_op( let ptr = Pointer::new(CtfeProvenance::from(alloc_id).as_immutable(), Size::ZERO); Immediate::new_slice(self.global_root_pointer(ptr)?.into(), meta, self) } - mir::ConstValue::RuntimeChecks(checks) => { - let val = M::runtime_checks(self, checks)?; - Scalar::from_bool(val).into() - } }; interp_ok(OpTy { op: Operand::Immediate(imm), layout }) } diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 47e8e2a9ec51..0ef4e4d4ae3c 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -387,7 +387,7 @@ fn eval_fn_call_argument( move_definitely_disjoint: bool, ) -> InterpResult<'tcx, FnArg<'tcx, M::Provenance>> { interp_ok(match op { - mir::Operand::Copy(_) | mir::Operand::Constant(_) => { + mir::Operand::Copy(_) | mir::Operand::Constant(_) | mir::Operand::RuntimeChecks(_) => { // Make a regular copy. let op = self.eval_operand(op, None)?; FnArg::Copy(op) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 1b7d3ec9345f..fe352df3b9f0 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -68,10 +68,6 @@ pub enum ConstValue { /// Offset into `alloc` offset: Size, }, - - /// Special constants whose value depends on the evaluation context. Their value depends on a - /// flag on the crate being codegenned. - RuntimeChecks(RuntimeChecks), } #[cfg(target_pointer_width = "64")] @@ -81,10 +77,7 @@ impl ConstValue { #[inline] pub fn try_to_scalar(&self) -> Option { match *self { - ConstValue::Indirect { .. } - | ConstValue::Slice { .. } - | ConstValue::ZeroSized - | ConstValue::RuntimeChecks(_) => None, + ConstValue::Indirect { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None, ConstValue::Scalar(val) => Some(val), } } @@ -140,7 +133,7 @@ pub fn try_get_slice_bytes_for_diagnostics<'tcx>( tcx: TyCtxt<'tcx>, ) -> Option<&'tcx [u8]> { let (alloc_id, start, len) = match self { - ConstValue::Scalar(_) | ConstValue::ZeroSized | ConstValue::RuntimeChecks(_) => { + ConstValue::Scalar(_) | ConstValue::ZeroSized => { bug!("`try_get_slice_bytes` on non-slice constant") } &ConstValue::Slice { alloc_id, meta } => (alloc_id, 0, meta), @@ -192,9 +185,7 @@ pub fn try_get_slice_bytes_for_diagnostics<'tcx>( /// Can return `true` even if there is no provenance. pub fn may_have_provenance(&self, tcx: TyCtxt<'_>, size: Size) -> bool { match *self { - ConstValue::ZeroSized - | ConstValue::Scalar(Scalar::Int(_)) - | ConstValue::RuntimeChecks(_) => return false, + ConstValue::ZeroSized | ConstValue::Scalar(Scalar::Int(_)) => return false, ConstValue::Scalar(Scalar::Ptr(..)) => return true, // It's hard to find out the part of the allocation we point to; // just conservatively check everything. @@ -233,29 +224,6 @@ pub fn all_bytes_uninit(&self, tcx: TyCtxt<'_>) -> bool { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] -pub enum RuntimeChecks { - /// Returns whether we should perform some UB-checking at runtime. - /// See the `ub_checks` intrinsic docs for details. - UbChecks, - /// Returns whether we should perform contract-checking at runtime. - /// See the `contract_checks` intrinsic docs for details. - ContractChecks, - /// Returns whether we should perform some overflow-checking at runtime. - /// See the `overflow_checks` intrinsic docs for details. - OverflowChecks, -} - -impl RuntimeChecks { - pub fn value(self, sess: &rustc_session::Session) -> bool { - match self { - Self::UbChecks => sess.ub_checks(), - Self::ContractChecks => sess.contract_checks(), - Self::OverflowChecks => sess.overflow_checks(), - } - } -} - /////////////////////////////////////////////////////////////////////////// /// Constants @@ -549,7 +517,6 @@ pub fn is_deterministic(&self) -> bool { ConstValue::Slice { .. } | ConstValue::ZeroSized | ConstValue::Scalar(_) - | ConstValue::RuntimeChecks(_) | ConstValue::Indirect { .. }, _, ) => true, diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index bffff1b400d5..418cdea01660 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -607,9 +607,6 @@ fn try_const_mono_switchint<'a>( typing_env, crate::ty::EarlyBinder::bind(constant.const_), ); - if let Const::Val(ConstValue::RuntimeChecks(check), _) = mono_literal { - return Some(check.value(tcx.sess) as u128); - } mono_literal.try_eval_bits(tcx, typing_env) }; @@ -623,6 +620,10 @@ fn try_const_mono_switchint<'a>( let bits = eval_mono_const(constant)?; return Some((bits, targets)); } + Operand::RuntimeChecks(check) => { + let bits = check.value(tcx.sess) as u128; + return Some((bits, targets)); + } Operand::Move(place) | Operand::Copy(place) => place, }; diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index e4f85a115096..1ac46fff1b4e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1255,6 +1255,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { Constant(ref a) => write!(fmt, "{a:?}"), Copy(ref place) => write!(fmt, "copy {place:?}"), Move(ref place) => write!(fmt, "move {place:?}"), + RuntimeChecks(checks) => write!(fmt, "const {checks:?}"), } } } @@ -1518,7 +1519,6 @@ fn alloc_id_from_const_val(val: ConstValue) -> Option { match val { ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => Some(ptr.provenance.alloc_id()), ConstValue::Scalar(interpret::Scalar::Int { .. }) => None, - ConstValue::RuntimeChecks(_) => None, ConstValue::ZeroSized => None, ConstValue::Slice { alloc_id, .. } | ConstValue::Indirect { alloc_id, .. } => { // FIXME: we don't actually want to print all of these, since some are printed nicely directly as values inline in MIR. @@ -1969,7 +1969,6 @@ fn pretty_print_const_value_tcx<'tcx>( fmt.write_str(&p.into_buffer())?; return Ok(()); } - (ConstValue::RuntimeChecks(checks), _) => return write!(fmt, "{checks:?}"), (ConstValue::ZeroSized, ty::FnDef(d, s)) => { let mut p = FmtPrinter::new(tcx, Namespace::ValueNS); p.print_alloc_ids = true; diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 942eb727de67..372b3313e13f 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -642,7 +642,7 @@ pub fn const_from_scalar( pub fn to_copy(&self) -> Self { match *self { - Operand::Copy(_) | Operand::Constant(_) => self.clone(), + Operand::Copy(_) | Operand::Constant(_) | Operand::RuntimeChecks(_) => self.clone(), Operand::Move(place) => Operand::Copy(place), } } @@ -652,7 +652,7 @@ pub fn to_copy(&self) -> Self { pub fn place(&self) -> Option> { match self { Operand::Copy(place) | Operand::Move(place) => Some(*place), - Operand::Constant(_) => None, + Operand::Constant(_) | Operand::RuntimeChecks(_) => None, } } @@ -661,7 +661,7 @@ pub fn place(&self) -> Option> { pub fn constant(&self) -> Option<&ConstOperand<'tcx>> { match self { Operand::Constant(x) => Some(&**x), - Operand::Copy(_) | Operand::Move(_) => None, + Operand::Copy(_) | Operand::Move(_) | Operand::RuntimeChecks(_) => None, } } @@ -681,6 +681,7 @@ pub fn ty(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> Ty<'tcx> match self { &Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty, Operand::Constant(c) => c.const_.ty(), + Operand::RuntimeChecks(_) => tcx.types.bool, } } @@ -693,6 +694,7 @@ pub fn span(&self, local_decls: &D) -> Span local_decls.local_decls()[l.local].source_info.span } Operand::Constant(c) => c.span, + Operand::RuntimeChecks(_) => DUMMY_SP, } } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index e96d6824c600..037caa8bfae1 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1327,6 +1327,10 @@ pub enum Operand<'tcx> { /// Constants are already semantically values, and remain unchanged. Constant(Box>), + + /// Special constants whose value depends on the evaluation context. Their value depends on a + /// flag on the crate being codegenned. + RuntimeChecks(RuntimeChecks), } #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)] @@ -1558,6 +1562,29 @@ pub enum AggregateKind<'tcx> { RawPtr(Ty<'tcx>, Mutability), } +#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] +pub enum RuntimeChecks { + /// Returns whether we should perform some UB-checking at runtime. + /// See the `ub_checks` intrinsic docs for details. + UbChecks, + /// Returns whether we should perform contract-checking at runtime. + /// See the `contract_checks` intrinsic docs for details. + ContractChecks, + /// Returns whether we should perform some overflow-checking at runtime. + /// See the `overflow_checks` intrinsic docs for details. + OverflowChecks, +} + +impl RuntimeChecks { + pub fn value(self, sess: &rustc_session::Session) -> bool { + match self { + Self::UbChecks => sess.ub_checks(), + Self::ContractChecks => sess.contract_checks(), + Self::OverflowChecks => sess.overflow_checks(), + } + } +} + #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub enum UnOp { diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index da9b2b97235e..07a36aef4320 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -845,6 +845,7 @@ fn super_operand( Operand::Constant(constant) => { self.visit_const_operand(constant, location); } + Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_mir_build/src/builder/custom/parse.rs b/compiler/rustc_mir_build/src/builder/custom/parse.rs index 10154461c339..c6ef362c6ea5 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse.rs @@ -261,6 +261,7 @@ fn parse_debuginfo(&mut self, stmts: impl Iterator) -> PResult<() let value = match operand { Operand::Constant(c) => VarDebugInfoContents::Const(*c), Operand::Copy(p) | Operand::Move(p) => VarDebugInfoContents::Place(p), + Operand::RuntimeChecks(_) => unreachable!(), }; let dbginfo = VarDebugInfo { name, diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index 966598736220..a176f3e49a50 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -1099,7 +1099,7 @@ pub(crate) fn break_for_tail_call( Some(DropData { source_info, local, kind: DropKind::Value }) } - Operand::Constant(_) => None, + Operand::Constant(_) | Operand::RuntimeChecks(_) => None, }) .collect(); @@ -1563,7 +1563,7 @@ pub(crate) fn record_operands_moved(&mut self, operands: &[Spanned // look for moves of a local variable, like `MOVE(_X)` let locals_moved = operands.iter().flat_map(|operand| match operand.node { - Operand::Copy(_) | Operand::Constant(_) => None, + Operand::Copy(_) | Operand::Constant(_) | Operand::RuntimeChecks(_) => None, Operand::Move(place) => place.as_local(), }); diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index a90f3ef35444..ced9bd735ba2 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -546,9 +546,10 @@ fn gather_terminator(&mut self, term: &Terminator<'tcx>) { fn gather_operand(&mut self, operand: &Operand<'tcx>) { match *operand { - Operand::Constant(..) | Operand::Copy(..) => {} // not-a-move + // not-a-move + Operand::Constant(..) | Operand::Copy(..) | Operand::RuntimeChecks(_) => {} + // a move Operand::Move(place) => { - // a move self.gather_move(place); } } diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index 8f975866d135..aaf735269b22 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -103,7 +103,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _: Location) { self.penalty += CALL_PENALTY; } TerminatorKind::SwitchInt { discr, targets } => { - if discr.constant().is_some() { + if matches!(discr, Operand::Constant(_) | Operand::RuntimeChecks(_)) { // Not only will this become a `Goto`, but likely other // things will be removable as unreachable. self.bonus += CONST_SWITCH_BONUS; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index 232f07d31adb..011c10b8bd1d 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -211,6 +211,7 @@ fn handle_operand( state: &mut State>, ) -> ValueOrPlace> { match operand { + Operand::RuntimeChecks(_) => ValueOrPlace::TOP, Operand::Constant(box constant) => { ValueOrPlace::Value(self.handle_constant(constant, state)) } @@ -530,6 +531,7 @@ fn assign_operand( operand: &Operand<'tcx>, ) { match operand { + Operand::RuntimeChecks(_) => {} Operand::Copy(rhs) | Operand::Move(rhs) => { if let Some(rhs) = self.map.find(rhs.as_ref()) { state.insert_place_idx(place, rhs, &self.map); @@ -1036,7 +1038,7 @@ fn visit_operand(&mut self, operand: &mut Operand<'tcx>, location: Location) { self.super_operand(operand, location) } } - Operand::Constant(_) => {} + Operand::Constant(_) | Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs index da88e5c698bf..47d735eed9b1 100644 --- a/compiler/rustc_mir_transform/src/early_otherwise_branch.rs +++ b/compiler/rustc_mir_transform/src/early_otherwise_branch.rs @@ -117,11 +117,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { unreachable!() }; // Always correct since we can only switch on `Copy` types - let parent_op = match parent_op { - Operand::Move(x) => Operand::Copy(*x), - Operand::Copy(x) => Operand::Copy(*x), - Operand::Constant(x) => Operand::Constant(x.clone()), - }; + let parent_op = parent_op.to_copy(); let parent_ty = parent_op.ty(body.local_decls(), tcx); let statements_before = bbs[parent].statements.len(); let parent_end = Location { block: parent, statement_index: statements_before }; diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs index 38b5ccdb32e7..2ae8f43cf6c8 100644 --- a/compiler/rustc_mir_transform/src/function_item_references.rs +++ b/compiler/rustc_mir_transform/src/function_item_references.rs @@ -136,12 +136,7 @@ fn is_fn_ref(ty: Ty<'tcx>) -> Option<(DefId, GenericArgsRef<'tcx>)> { } fn nth_arg_span(&self, args: &[Spanned>], n: usize) -> Span { - match &args[n].node { - Operand::Copy(place) | Operand::Move(place) => { - self.body.local_decls[place.local].source_info.span - } - Operand::Constant(constant) => constant.span, - } + args[n].node.span(&self.body.local_decls) } fn emit_lint( diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index f6bf678af5ba..5a4774154504 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -248,6 +248,7 @@ enum Value<'a, 'tcx> { Discriminant(VnIndex), // Operations. + RuntimeChecks(RuntimeChecks), UnaryOp(UnOp, VnIndex), BinaryOp(BinOp, VnIndex, VnIndex), Cast { @@ -569,6 +570,8 @@ fn eval_to_const_inner(&mut self, value: VnIndex) -> Option> { _ if ty.is_zst() => ImmTy::uninit(ty).into(), Opaque(_) => return None, + // Keep runtime check constants as symbolic. + RuntimeChecks(..) => return None, // In general, evaluating repeat expressions just consumes a lot of memory. // But in the special case that the element is just Immediate::Uninit, we can evaluate @@ -1005,11 +1008,16 @@ fn simplify_operand( location: Location, ) -> Option { match *operand { + Operand::RuntimeChecks(c) => { + Some(self.insert(self.tcx.types.bool, Value::RuntimeChecks(c))) + } Operand::Constant(ref constant) => Some(self.insert_constant(constant.const_)), Operand::Copy(ref mut place) | Operand::Move(ref mut place) => { let value = self.simplify_place_value(place, location)?; if let Some(const_) = self.try_as_constant(value) { *operand = Operand::Constant(Box::new(const_)); + } else if let Value::RuntimeChecks(c) = self.get(value) { + *operand = Operand::RuntimeChecks(c); } Some(value) } @@ -1777,6 +1785,8 @@ impl<'tcx> VnState<'_, '_, 'tcx> { fn try_as_operand(&mut self, index: VnIndex, location: Location) -> Option> { if let Some(const_) = self.try_as_constant(index) { Some(Operand::Constant(Box::new(const_))) + } else if let Value::RuntimeChecks(c) = self.get(index) { + Some(Operand::RuntimeChecks(c)) } else if let Some(place) = self.try_as_place(index, location, false) { self.reused_locals.insert(place.local); Some(Operand::Copy(place)) diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 7cb341818fab..fa9ceb018dd5 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -363,11 +363,15 @@ fn tcx(&self) -> TyCtxt<'tcx> { } fn visit_operand(&mut self, operand: &mut Operand<'tcx>, _: Location) { - if let Operand::Constant(c) = operand - && let Const::Val(c, _) = &mut c.const_ - && let ConstValue::RuntimeChecks(RuntimeChecks::UbChecks) = c - { - *c = ConstValue::from_bool(self.tcx.sess.ub_checks()); + if let Operand::RuntimeChecks(RuntimeChecks::UbChecks) = operand { + *operand = Operand::Constant(Box::new(ConstOperand { + span: rustc_span::DUMMY_SP, + user_ty: None, + const_: Const::Val( + ConstValue::from_bool(self.tcx.sess.ub_checks()), + self.tcx.types.bool, + ), + })); } } } diff --git a/compiler/rustc_mir_transform/src/jump_threading.rs b/compiler/rustc_mir_transform/src/jump_threading.rs index c021e7d4c3ae..e2959ca64bda 100644 --- a/compiler/rustc_mir_transform/src/jump_threading.rs +++ b/compiler/rustc_mir_transform/src/jump_threading.rs @@ -477,6 +477,7 @@ fn process_operand(&mut self, lhs: PlaceIndex, rhs: &Operand<'tcx>, state: &mut let Some(rhs) = self.map.find(rhs.as_ref()) else { return }; self.process_copy(lhs, rhs, state) } + Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 53cb02d9c5b2..caaf300a88d6 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -282,6 +282,7 @@ fn eval_place(&mut self, place: Place<'tcx>) -> Option> { /// or `eval_place`, depending on the variant of `Operand` used. fn eval_operand(&mut self, op: &Operand<'tcx>) -> Option> { match *op { + Operand::RuntimeChecks(_) => None, Operand::Constant(ref c) => self.eval_constant(c), Operand::Move(place) | Operand::Copy(place) => self.eval_place(place), } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 6415f3908499..701d7ff854a7 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -261,7 +261,7 @@ fn remap_mir_for_const_eval_select<'tcx>( if context == hir::Constness::Const { called_in_const } else { called_at_rt }; let (method, place): (fn(Place<'tcx>) -> Operand<'tcx>, Place<'tcx>) = match tupled_args.node { - Operand::Constant(_) => { + Operand::Constant(_) | Operand::RuntimeChecks(_) => { // There is no good way of extracting a tuple arg from a constant // (const generic stuff) so we just create a temporary and deconstruct // that. diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 6740aa97fc8b..dcee54c37108 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -35,14 +35,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { terminator.source_info, StatementKind::Assign(Box::new(( *destination, - Rvalue::Use(Operand::Constant(Box::new(ConstOperand { - span: terminator.source_info.span, - user_ty: None, - const_: Const::Val( - ConstValue::RuntimeChecks(op), - tcx.types.bool, - ), - }))), + Rvalue::Use(Operand::RuntimeChecks(op)), ))), )); terminator.kind = TerminatorKind::Goto { target }; diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 506cfb7abf92..faff0f23143a 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -360,6 +360,9 @@ fn validate_operand(&mut self, operand: &Operand<'tcx>) -> Result<(), Unpromotab match operand { Operand::Copy(place) | Operand::Move(place) => self.validate_place(place.as_ref()), + // Promoting a runtime check would transform a runtime error into a compile-time error. + Operand::RuntimeChecks(_) => Err(Unpromotable), + // The qualifs for a constant (e.g. `HasMutInterior`) are checked in // `validate_rvalue` upon access. Operand::Constant(c) => { diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs index ba2286fd40a7..70ae3433353b 100644 --- a/compiler/rustc_mir_transform/src/simplify_branches.rs +++ b/compiler/rustc_mir_transform/src/simplify_branches.rs @@ -41,7 +41,7 @@ fn try_get_const<'tcx, 'a>( { Some(const_operand) } - Operand::Copy(_) | Operand::Move(_) => None, + Operand::Copy(_) | Operand::Move(_) | Operand::RuntimeChecks(_) => None, } } diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs index 801383493837..a6ed66c8427b 100644 --- a/compiler/rustc_mir_transform/src/sroa.rs +++ b/compiler/rustc_mir_transform/src/sroa.rs @@ -392,11 +392,14 @@ fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Locatio // a_1 = move? place.1 // ... // ``` - StatementKind::Assign(box (lhs, Rvalue::Use(ref op))) => { - let (rplace, copy) = match *op { - Operand::Copy(rplace) => (rplace, true), - Operand::Move(rplace) => (rplace, false), - Operand::Constant(_) => bug!(), + StatementKind::Assign(box ( + lhs, + Rvalue::Use(ref op @ (Operand::Copy(rplace) | Operand::Move(rplace))), + )) => { + let copy = match *op { + Operand::Copy(_) => true, + Operand::Move(_) => false, + Operand::Constant(_) | Operand::RuntimeChecks(_) => bug!(), }; if let Some(final_locals) = self.replacements.place_fragments(lhs) { for (field, ty, new_local) in final_locals { diff --git a/compiler/rustc_public/src/alloc.rs b/compiler/rustc_public/src/alloc.rs index 5ede5b2b2712..0c35b3b25dfc 100644 --- a/compiler/rustc_public/src/alloc.rs +++ b/compiler/rustc_public/src/alloc.rs @@ -53,7 +53,6 @@ pub(crate) fn try_new_allocation<'tcx>( ConstValue::Scalar(scalar) => { alloc::try_new_scalar(layout, scalar, cx).map(|alloc| alloc.stable(tables, cx)) } - ConstValue::RuntimeChecks(_) => todo!(), ConstValue::ZeroSized => Ok(new_empty_allocation(layout.align.abi)), ConstValue::Slice { alloc_id, meta } => { alloc::try_new_slice(layout, alloc_id, meta, cx).map(|alloc| alloc.stable(tables, cx)) diff --git a/compiler/rustc_public/src/mir/body.rs b/compiler/rustc_public/src/mir/body.rs index 92882a001c47..e81b32ec9acf 100644 --- a/compiler/rustc_public/src/mir/body.rs +++ b/compiler/rustc_public/src/mir/body.rs @@ -673,6 +673,7 @@ pub enum Operand { Copy(Place), Move(Place), Constant(ConstOperand), + RuntimeChecks(RuntimeChecks), } #[derive(Clone, Eq, PartialEq, Hash, Serialize)] @@ -695,6 +696,16 @@ pub struct ConstOperand { pub const_: MirConst, } +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] +pub enum RuntimeChecks { + /// cfg!(ub_checks), but at codegen time + UbChecks, + /// cfg!(contract_checks), but at codegen time + ContractChecks, + /// cfg!(overflow_checks), but at codegen time + OverflowChecks, +} + /// Debug information pertaining to a user variable. #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub struct VarDebugInfo { @@ -1025,6 +1036,7 @@ pub fn ty(&self, locals: &[LocalDecl]) -> Result { match self { Operand::Copy(place) | Operand::Move(place) => place.ty(locals), Operand::Constant(c) => Ok(c.ty()), + Operand::RuntimeChecks(_) => Ok(Ty::bool_ty()), } } } diff --git a/compiler/rustc_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs index d814947dc397..fec5bd57efdd 100644 --- a/compiler/rustc_public/src/mir/pretty.rs +++ b/compiler/rustc_public/src/mir/pretty.rs @@ -332,6 +332,7 @@ fn pretty_operand(operand: &Operand) -> String { format!("move {mv:?}") } Operand::Constant(cnst) => pretty_mir_const(&cnst.const_), + Operand::RuntimeChecks(checks) => format!("const {checks:?}"), } } diff --git a/compiler/rustc_public/src/mir/visit.rs b/compiler/rustc_public/src/mir/visit.rs index f0fdbe059383..678205171ecf 100644 --- a/compiler/rustc_public/src/mir/visit.rs +++ b/compiler/rustc_public/src/mir/visit.rs @@ -296,6 +296,7 @@ fn super_operand(&mut self, operand: &$($mutability)? Operand, location: Locatio Operand::Constant(constant) => { self.visit_const_operand(constant, location); } + Operand::RuntimeChecks(_) => {} } } diff --git a/compiler/rustc_public/src/ty.rs b/compiler/rustc_public/src/ty.rs index a87ac795da5c..14656a2e594a 100644 --- a/compiler/rustc_public/src/ty.rs +++ b/compiler/rustc_public/src/ty.rs @@ -1357,7 +1357,6 @@ pub enum ConstantKind { Ty(TyConst), Allocated(Allocation), Unevaluated(UnevaluatedConst), - RuntimeChecks(RuntimeChecks), Param(ParamConst), /// Store ZST constants. /// We have to special handle these constants since its type might be generic. @@ -1377,16 +1376,6 @@ pub struct UnevaluatedConst { pub promoted: Option, } -#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize)] -pub enum RuntimeChecks { - /// cfg!(ub_checks), but at codegen time - UbChecks, - /// cfg!(contract_checks), but at codegen time - ContractChecks, - /// cfg!(overflow_checks), but at codegen time - OverflowChecks, -} - #[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize)] pub enum TraitSpecializationKind { None, diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index 31f41653d4a2..a77808cfb275 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -312,7 +312,7 @@ fn stable(&self, _: &mut Tables<'_, BridgeTys>, _: &CompilerCtxt<'_, BridgeTys>) } impl<'tcx> Stable<'tcx> for mir::RuntimeChecks { - type T = crate::ty::RuntimeChecks; + type T = crate::mir::RuntimeChecks; fn stable<'cx>( &self, _: &mut Tables<'cx, BridgeTys>, @@ -320,9 +320,9 @@ fn stable<'cx>( ) -> Self::T { use rustc_middle::mir::RuntimeChecks::*; match self { - UbChecks => crate::ty::RuntimeChecks::UbChecks, - ContractChecks => crate::ty::RuntimeChecks::ContractChecks, - OverflowChecks => crate::ty::RuntimeChecks::OverflowChecks, + UbChecks => crate::mir::RuntimeChecks::UbChecks, + ContractChecks => crate::mir::RuntimeChecks::ContractChecks, + OverflowChecks => crate::mir::RuntimeChecks::OverflowChecks, } } } @@ -379,6 +379,7 @@ fn stable<'cx>( Copy(place) => crate::mir::Operand::Copy(place.stable(tables, cx)), Move(place) => crate::mir::Operand::Move(place.stable(tables, cx)), Constant(c) => crate::mir::Operand::Constant(c.stable(tables, cx)), + RuntimeChecks(c) => crate::mir::Operand::RuntimeChecks(c.stable(tables, cx)), } } } @@ -886,13 +887,6 @@ fn stable<'cx>( let ty = ty.stable(tables, cx); MirConst::new(ConstantKind::ZeroSized, ty, id) } - mir::Const::Val(mir::ConstValue::RuntimeChecks(checks), ty) => { - let ty = cx.lift(ty).unwrap(); - let checks = cx.lift(checks).unwrap(); - let ty = ty.stable(tables, cx); - let kind = ConstantKind::RuntimeChecks(checks.stable(tables, cx)); - MirConst::new(kind, ty, id) - } mir::Const::Val(val, ty) => { let ty = cx.lift(ty).unwrap(); let val = cx.lift(val).unwrap(); diff --git a/compiler/rustc_public/src/visitor.rs b/compiler/rustc_public/src/visitor.rs index 2ebd73a43e90..acc333476961 100644 --- a/compiler/rustc_public/src/visitor.rs +++ b/compiler/rustc_public/src/visitor.rs @@ -68,9 +68,7 @@ fn super_visit(&self, visitor: &mut V) -> ControlFlow { super::ty::ConstantKind::Ty(ct) => ct.visit(visitor)?, super::ty::ConstantKind::Allocated(alloc) => alloc.visit(visitor)?, super::ty::ConstantKind::Unevaluated(uv) => uv.visit(visitor)?, - super::ty::ConstantKind::RuntimeChecks(_) - | super::ty::ConstantKind::Param(_) - | super::ty::ConstantKind::ZeroSized => {} + super::ty::ConstantKind::Param(_) | super::ty::ConstantKind::ZeroSized => {} } self.ty().visit(visitor) } diff --git a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs index f2bffc8156af..0ead5944b4b3 100644 --- a/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs +++ b/src/tools/clippy/clippy_utils/src/mir/possible_borrower.rs @@ -110,7 +110,7 @@ fn visit_terminator(&mut self, terminator: &mir::Terminator<'_>, _loc: mir::Loca immutable_borrowers.push(p.local); } }, - mir::Operand::Constant(..) => (), + mir::Operand::Constant(..) | mir::Operand::RuntimeChecks(..) => (), } } @@ -151,7 +151,7 @@ fn rvalue_locals(rvalue: &mir::Rvalue<'_>, mut visit: impl FnMut(mir::Local)) { let mut visit_op = |op: &mir::Operand<'_>| match op { mir::Operand::Copy(p) | mir::Operand::Move(p) => visit(p.local), - mir::Operand::Constant(..) => (), + mir::Operand::Constant(..) | mir::Operand::RuntimeChecks(..) => (), }; match rvalue { diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index c1d00fc8d371..06220f91c745 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -277,6 +277,7 @@ fn check_operand<'tcx>( Some(_) => Err((span, "cannot access `static` items in const fn".into())), None => Ok(()), }, + Operand::RuntimeChecks(..) => Ok(()), } } diff --git a/tests/codegen-llvm/slice-iter-len-eq-zero.rs b/tests/codegen-llvm/slice-iter-len-eq-zero.rs index ae1bdb1d58b9..6998d98e498c 100644 --- a/tests/codegen-llvm/slice-iter-len-eq-zero.rs +++ b/tests/codegen-llvm/slice-iter-len-eq-zero.rs @@ -8,10 +8,8 @@ #[no_mangle] pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool { // CHECK-NOT: sub - // CHECK: %2 = icmp ne ptr %1, null - // CHECK-NEXT: tail call void @llvm.assume(i1 %2) - // CHECK-NEXT: %[[RET:.+]] = icmp eq ptr {{%0, %1|%1, %0}} - // CHECK-NEXT: ret i1 %[[RET]] + // CHECK: %[[RET:.+]] = icmp eq ptr {{%y.0, %y.1|%y.1, %y.0}} + // CHECK: ret i1 %[[RET]] y.len() == 0 } @@ -33,7 +31,7 @@ pub fn slice_iter_len_eq_zero_ref(y: &mut std::slice::Iter<'_, Demo>) -> bool { // CHECK-LABEL: @slice_zst_iter_len_eq_zero #[no_mangle] pub fn slice_zst_iter_len_eq_zero(y: std::slice::Iter<'_, MyZST>) -> bool { - // CHECK: %[[RET:.+]] = icmp eq ptr %1, null + // CHECK: %[[RET:.+]] = icmp eq ptr %y.1, null // CHECK: ret i1 %[[RET]] y.len() == 0 } From fab64de7270010cde21f7421d5cfd0105dca554b Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Wed, 19 Nov 2025 01:06:37 +0000 Subject: [PATCH 010/126] Improve comments. --- compiler/rustc_const_eval/src/const_eval/dummy_machine.rs | 4 ++-- compiler/rustc_middle/src/mir/statement.rs | 1 + compiler/rustc_middle/src/mir/syntax.rs | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs index 40acff416bb0..f41b68bb1f7e 100644 --- a/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/dummy_machine.rs @@ -124,8 +124,8 @@ fn assert_panic( #[inline(always)] fn runtime_checks(_ecx: &InterpCx<'tcx, Self>, r: RuntimeChecks) -> InterpResult<'tcx, bool> { - // We can't look at `tcx.sess` here as that can differ across crates, which can lead to - // unsound differences in evaluating the same constant at different instantiation sites. + // Runtime checks have different value depending on the crate they are codegenned in. + // Verify we aren't trying to evaluate them in mir-optimizations. panic!("compiletime machine evaluated {r:?}") } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index 372b3313e13f..1ba1ae3e1531 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -694,6 +694,7 @@ pub fn span(&self, local_decls: &D) -> Span local_decls.local_decls()[l.local].source_info.span } Operand::Constant(c) => c.span, + // User code should not contain this operand, so we should not need this span. Operand::RuntimeChecks(_) => DUMMY_SP, } } diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 037caa8bfae1..83e9a1f1784b 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1328,8 +1328,8 @@ pub enum Operand<'tcx> { /// Constants are already semantically values, and remain unchanged. Constant(Box>), - /// Special constants whose value depends on the evaluation context. Their value depends on a - /// flag on the crate being codegenned. + /// Query the compilation session of the current crate for a particular flag. This is not quite + /// a const since its value can differ across crates within a single crate graph. RuntimeChecks(RuntimeChecks), } From d8b897e3170fd56952c576f8bdc43c0d1b10490d Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Wed, 19 Nov 2025 01:23:04 +0000 Subject: [PATCH 011/126] Change pretty-printing. --- compiler/rustc_middle/src/mir/pretty.rs | 2 +- ...ind_without_updating_operand.test.GVN.32bit.panic-abort.diff | 2 +- ...ind_without_updating_operand.test.GVN.64bit.panic-abort.diff | 2 +- ...hifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff | 2 +- ...ifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff | 2 +- ...d_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff | 2 +- ..._shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff | 2 +- .../unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff | 2 +- .../unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff | 2 +- ...b_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 1ac46fff1b4e..2d84e919359e 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1255,7 +1255,7 @@ fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { Constant(ref a) => write!(fmt, "{a:?}"), Copy(ref place) => write!(fmt, "copy {place:?}"), Move(ref place) => write!(fmt, "move {place:?}"), - RuntimeChecks(checks) => write!(fmt, "const {checks:?}"), + RuntimeChecks(checks) => write!(fmt, "{checks:?}"), } } } diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff index ae2b8e574303..2aa92fd34ebf 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.32bit.panic-abort.diff @@ -94,7 +94,7 @@ StorageLive(_21); StorageLive(_22); StorageLive(_23); - switchInt(const UbChecks) -> [0: bb6, otherwise: bb5]; + switchInt(UbChecks) -> [0: bb6, otherwise: bb5]; } bb1: { diff --git a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff index 164aeb2d9037..408ff60712e1 100644 --- a/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff +++ b/tests/mir-opt/dont_reset_cast_kind_without_updating_operand.test.GVN.64bit.panic-abort.diff @@ -94,7 +94,7 @@ StorageLive(_21); StorageLive(_22); StorageLive(_23); - switchInt(const UbChecks) -> [0: bb6, otherwise: bb5]; + switchInt(UbChecks) -> [0: bb6, otherwise: bb5]; } bb1: { diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff index 153e314fb6f4..d66223b91bc4 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-abort.diff @@ -22,7 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind unreachable]; + StorageLive(_5); -+ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; ++ switchInt(UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff index fd9f5838efc3..54907cf809b4 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.panic-unwind.diff @@ -22,7 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shl(move _3, move _4) -> [return: bb1, unwind continue]; + StorageLive(_5); -+ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; ++ switchInt(UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff index 5b12c1853359..c118f5b0df3f 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-abort.diff @@ -22,7 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind unreachable]; + StorageLive(_5); -+ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; ++ switchInt(UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff index e8474898b995..6a1e6a0a2d26 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_bigger.Inline.panic-unwind.diff @@ -22,7 +22,7 @@ _4 = copy _2; - _0 = core::num::::unchecked_shr(move _3, move _4) -> [return: bb1, unwind continue]; + StorageLive(_5); -+ switchInt(const UbChecks) -> [0: bb2, otherwise: bb1]; ++ switchInt(UbChecks) -> [0: bb2, otherwise: bb1]; } bb1: { diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff index 7bd93b804e7f..041dd27cb564 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-abort.diff @@ -33,7 +33,7 @@ + } + + bb2: { -+ assume(const UbChecks); ++ assume(UbChecks); + _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + } + diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff index ae194db56cc9..be89063a8ac9 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.panic-unwind.diff @@ -37,7 +37,7 @@ - bb2 (cleanup): { - resume; + bb2: { -+ assume(const UbChecks); ++ assume(UbChecks); + _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; + } + diff --git a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff index 890c87880441..c4fa526a7af9 100644 --- a/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff +++ b/tests/mir-opt/instsimplify/ub_check.unwrap_unchecked.InstSimplify-after-simplifycfg.diff @@ -32,7 +32,7 @@ } bb2: { -- assume(const UbChecks); +- assume(UbChecks); + assume(const false); _4 = unreachable_unchecked::precondition_check() -> [return: bb1, unwind unreachable]; } From b6bb7f96459583ef66094b2dcbc5ea3e7955fbcc Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Wed, 19 Nov 2025 01:28:59 +0000 Subject: [PATCH 012/126] Bless codegen test. --- tests/codegen-llvm/slice-iter-len-eq-zero.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/codegen-llvm/slice-iter-len-eq-zero.rs b/tests/codegen-llvm/slice-iter-len-eq-zero.rs index 6998d98e498c..3085fbaed36a 100644 --- a/tests/codegen-llvm/slice-iter-len-eq-zero.rs +++ b/tests/codegen-llvm/slice-iter-len-eq-zero.rs @@ -8,7 +8,7 @@ #[no_mangle] pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool { // CHECK-NOT: sub - // CHECK: %[[RET:.+]] = icmp eq ptr {{%y.0, %y.1|%y.1, %y.0}} + // CHECK: %[[RET:.+]] = icmp eq ptr {{%0, %1|%1, %0}} // CHECK: ret i1 %[[RET]] y.len() == 0 } @@ -31,7 +31,7 @@ pub fn slice_iter_len_eq_zero_ref(y: &mut std::slice::Iter<'_, Demo>) -> bool { // CHECK-LABEL: @slice_zst_iter_len_eq_zero #[no_mangle] pub fn slice_zst_iter_len_eq_zero(y: std::slice::Iter<'_, MyZST>) -> bool { - // CHECK: %[[RET:.+]] = icmp eq ptr %y.1, null + // CHECK: %[[RET:.+]] = icmp eq ptr %1, null // CHECK: ret i1 %[[RET]] y.len() == 0 } From fc9d9b88e6829be5db5db76bde56c58253e2a068 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Wed, 19 Nov 2025 01:34:15 +0000 Subject: [PATCH 013/126] Update ui-fulldeps test. --- tests/ui-fulldeps/rustc_public/check_transform.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui-fulldeps/rustc_public/check_transform.rs b/tests/ui-fulldeps/rustc_public/check_transform.rs index 900bb4014d54..815dec57b8be 100644 --- a/tests/ui-fulldeps/rustc_public/check_transform.rs +++ b/tests/ui-fulldeps/rustc_public/check_transform.rs @@ -69,6 +69,7 @@ fn check_msg(body: &Body, expected: &str) { }) .unwrap() } + Operand::RuntimeChecks(_) => panic!("unexpected runtime checks"), }; let ConstantKind::Allocated(alloc) = msg_const.const_.kind() else { unreachable!() From 0f9b7893d77d97738388ac478aa1afd52d6b7013 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Thu, 20 Nov 2025 01:27:07 +0000 Subject: [PATCH 014/126] Update doc. --- compiler/rustc_middle/src/mir/traversal.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_middle/src/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs index 4f599aea0254..a3c0a5b83ffa 100644 --- a/compiler/rustc_middle/src/mir/traversal.rs +++ b/compiler/rustc_middle/src/mir/traversal.rs @@ -293,9 +293,9 @@ pub fn reverse_postorder<'a, 'tcx>( /// reachable. /// /// Such a traversal is mostly useful because it lets us skip lowering the `false` side -/// of `if ::CONST`, as well as [`ConstValue::RuntimeChecks`]. +/// of `if ::CONST`, as well as [`Operand::RuntimeChecks`]. /// -/// [`ConstValue::RuntimeChecks`]: rustc_middle::mir::ConstValue::RuntimeChecks +/// [`Operand::RuntimeChecks`]: rustc_middle::mir::Operand::RuntimeChecks pub fn mono_reachable<'a, 'tcx>( body: &'a Body<'tcx>, tcx: TyCtxt<'tcx>, From a3676bd0facf44a576af975ee7529abd61122d55 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 16 Nov 2025 19:21:17 +0000 Subject: [PATCH 015/126] Introduce Operand::RuntimeChecks. --- src/base.rs | 8 +++++++- src/constant.rs | 9 ++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/base.rs b/src/base.rs index 4dbee7665eb8..79f65141e66f 100644 --- a/src/base.rs +++ b/src/base.rs @@ -8,10 +8,10 @@ use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_index::IndexVec; -use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{ScalarInt, TypeVisitableExt}; use rustc_session::config::OutputFilenames; use rustc_span::Symbol; @@ -1039,6 +1039,12 @@ pub(crate) fn codegen_operand<'tcx>( cplace.to_cvalue(fx) } Operand::Constant(const_) => crate::constant::codegen_constant_operand(fx, const_), + Operand::RuntimeChecks(checks) => { + let int = checks.value(fx.tcx.sess); + let int = ScalarInt::try_from_uint(int, Size::from_bits(1)).unwrap(); + let layout = fx.layout_of(fx.tcx.types.bool); + return CValue::const_val(fx, layout, int); + } } } diff --git a/src/constant.rs b/src/constant.rs index 29c8e8ab1e52..c25034d4be22 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -215,11 +215,6 @@ pub(crate) fn codegen_const_value<'tcx>( CValue::by_val(val, layout) } }, - ConstValue::RuntimeChecks(checks) => { - let int = checks.value(fx.tcx.sess); - let int = ScalarInt::try_from_uint(int, Size::from_bits(1)).unwrap(); - return CValue::const_val(fx, layout, int); - } ConstValue::Indirect { alloc_id, offset } => CValue::by_ref( Pointer::new(pointer_for_allocation(fx, alloc_id)) .offset_i64(fx, i64::try_from(offset.bytes()).unwrap()), @@ -545,6 +540,10 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( operand: &Operand<'tcx>, ) -> Option { match operand { + Operand::RuntimeChecks(checks) => { + let int = checks.value(fx.tcx.sess); + ScalarInt::try_from_uint(int, Size::from_bits(1)) + } Operand::Constant(const_) => eval_mir_constant(fx, const_).0.try_to_scalar_int(), // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored // inside a temporary before being passed to the intrinsic requiring the const argument. From a601e768572a0e9753f40ad45c6d734c276d1043 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 14 Dec 2025 17:29:59 +0000 Subject: [PATCH 016/126] Use ScalarInt from bool. --- compiler/rustc_codegen_cranelift/src/base.rs | 7 +++---- compiler/rustc_codegen_cranelift/src/constant.rs | 5 +---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 79f65141e66f..1a916c876824 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -8,10 +8,10 @@ use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_index::IndexVec; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{ScalarInt, TypeVisitableExt}; use rustc_session::config::OutputFilenames; use rustc_span::Symbol; @@ -1040,10 +1040,9 @@ pub(crate) fn codegen_operand<'tcx>( } Operand::Constant(const_) => crate::constant::codegen_constant_operand(fx, const_), Operand::RuntimeChecks(checks) => { - let int = checks.value(fx.tcx.sess); - let int = ScalarInt::try_from_uint(int, Size::from_bits(1)).unwrap(); + let val = checks.value(fx.tcx.sess); let layout = fx.layout_of(fx.tcx.types.bool); - return CValue::const_val(fx, layout, int); + return CValue::const_val(fx, layout, val.into()); } } } diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index c25034d4be22..ff8e6744bd32 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -540,10 +540,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( operand: &Operand<'tcx>, ) -> Option { match operand { - Operand::RuntimeChecks(checks) => { - let int = checks.value(fx.tcx.sess); - ScalarInt::try_from_uint(int, Size::from_bits(1)) - } + Operand::RuntimeChecks(checks) => Some(checks.value(fx.tcx.sess).into()), Operand::Constant(const_) => eval_mir_constant(fx, const_).0.try_to_scalar_int(), // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored // inside a temporary before being passed to the intrinsic requiring the const argument. From 85921620d1ea3f7f725b6942b386ed1aa8c3d18f Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 14 Dec 2025 17:29:59 +0000 Subject: [PATCH 017/126] Use ScalarInt from bool. --- src/base.rs | 7 +++---- src/constant.rs | 5 +---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/base.rs b/src/base.rs index 79f65141e66f..1a916c876824 100644 --- a/src/base.rs +++ b/src/base.rs @@ -8,10 +8,10 @@ use rustc_codegen_ssa::base::is_call_from_compiler_builtins_to_upstream_monomorphization; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_index::IndexVec; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::{ScalarInt, TypeVisitableExt}; use rustc_session::config::OutputFilenames; use rustc_span::Symbol; @@ -1040,10 +1040,9 @@ pub(crate) fn codegen_operand<'tcx>( } Operand::Constant(const_) => crate::constant::codegen_constant_operand(fx, const_), Operand::RuntimeChecks(checks) => { - let int = checks.value(fx.tcx.sess); - let int = ScalarInt::try_from_uint(int, Size::from_bits(1)).unwrap(); + let val = checks.value(fx.tcx.sess); let layout = fx.layout_of(fx.tcx.types.bool); - return CValue::const_val(fx, layout, int); + return CValue::const_val(fx, layout, val.into()); } } } diff --git a/src/constant.rs b/src/constant.rs index c25034d4be22..ff8e6744bd32 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -540,10 +540,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( operand: &Operand<'tcx>, ) -> Option { match operand { - Operand::RuntimeChecks(checks) => { - let int = checks.value(fx.tcx.sess); - ScalarInt::try_from_uint(int, Size::from_bits(1)) - } + Operand::RuntimeChecks(checks) => Some(checks.value(fx.tcx.sess).into()), Operand::Constant(const_) => eval_mir_constant(fx, const_).0.try_to_scalar_int(), // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored // inside a temporary before being passed to the intrinsic requiring the const argument. From 8759e5a8c68dec8b3aa67ddbdd24e1270700cd7e Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 14 Dec 2025 17:30:07 +0000 Subject: [PATCH 018/126] Update doc. --- compiler/rustc_mir_transform/src/promote_consts.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index faff0f23143a..11266ccc2832 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -360,7 +360,8 @@ fn validate_operand(&mut self, operand: &Operand<'tcx>) -> Result<(), Unpromotab match operand { Operand::Copy(place) | Operand::Move(place) => self.validate_place(place.as_ref()), - // Promoting a runtime check would transform a runtime error into a compile-time error. + // `RuntimeChecks` behaves different in const-eval and runtime MIR, + // so we do not promote it. Operand::RuntimeChecks(_) => Err(Unpromotable), // The qualifs for a constant (e.g. `HasMutInterior`) are checked in From 60c387afbd335f0cd377dafd6f027694ab673972 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 14 Dec 2025 17:30:21 +0000 Subject: [PATCH 019/126] Do not pprint as const. --- compiler/rustc_public/src/mir/pretty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_public/src/mir/pretty.rs b/compiler/rustc_public/src/mir/pretty.rs index fec5bd57efdd..5ba72965cb29 100644 --- a/compiler/rustc_public/src/mir/pretty.rs +++ b/compiler/rustc_public/src/mir/pretty.rs @@ -332,7 +332,7 @@ fn pretty_operand(operand: &Operand) -> String { format!("move {mv:?}") } Operand::Constant(cnst) => pretty_mir_const(&cnst.const_), - Operand::RuntimeChecks(checks) => format!("const {checks:?}"), + Operand::RuntimeChecks(checks) => format!("{checks:?}"), } } From a02dc3487afa61780ea4a74d9a7ecda3f85b86ab Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 14 Dec 2025 18:36:06 +0000 Subject: [PATCH 020/126] Bless codegen. --- tests/codegen-llvm/lib-optimizations/ilog10-range.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/codegen-llvm/lib-optimizations/ilog10-range.rs b/tests/codegen-llvm/lib-optimizations/ilog10-range.rs index b466855389fb..a459e3536127 100644 --- a/tests/codegen-llvm/lib-optimizations/ilog10-range.rs +++ b/tests/codegen-llvm/lib-optimizations/ilog10-range.rs @@ -148,8 +148,7 @@ fn usize_ilog10_range(value: usize) { // CHECK-LABEL: @usize_ilog10_range( // CHECK-NOT: panic - // CHECK: ret void - // CHECK-NEXT: } + // CHECK: } assert!(value == 0 || value.ilog10() <= MAX_RESULT); assert!(value.checked_ilog10().is_none_or(|result| result <= MAX_RESULT)); } From cc68f2227dd73471242f1a9ff600a5443a0b7785 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Sun, 14 Dec 2025 00:49:48 -0600 Subject: [PATCH 021/126] Enable llvm-libunwind by default for Hexagon targets Fixes library linking issues where libgcc_s was incorrectly being linked instead of the appropriate LLVM runtime libraries for Hexagon targets. * Set llvm-libunwind as default for all hexagon targets in bootstrap * Exclude hexagon from automatic libgcc_s linking in unwind * Enable libunwind.a copying for hexagon targets * Remove manual library linking from hexagon target specification --- library/unwind/src/lib.rs | 19 ++++++++++++++++++- src/bootstrap/src/core/build_steps/compile.rs | 5 ++++- src/bootstrap/src/core/config/config.rs | 2 +- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index e3a0a77f53f0..cff2aa7b08b9 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -73,11 +73,28 @@ } _ => { #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] - #[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))] + #[link(name = "gcc_s", cfg(all(not(target_feature = "crt-static"), not(target_arch = "hexagon"))))] unsafe extern "C" {} } } +// Hexagon with musl uses llvm-libunwind by default +#[cfg(all(target_env = "musl", target_arch = "hexagon"))] +cfg_select! { + feature = "llvm-libunwind" => { + #[link(name = "unwind", kind = "static", modifiers = "-bundle")] + unsafe extern "C" {} + } + feature = "system-llvm-libunwind" => { + #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] + #[link(name = "unwind", cfg(not(target_feature = "crt-static")))] + unsafe extern "C" {} + } + _ => { + // Fallback: should not happen since hexagon defaults to llvm-libunwind + } +} + // This is the same as musl except that we default to using the system libunwind // instead of libgcc. #[cfg(target_env = "ohos")] diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index 82cc25f123bc..725e69ecee9b 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -354,7 +354,10 @@ fn copy_third_party_objects( if target == "x86_64-fortanix-unknown-sgx" || builder.config.llvm_libunwind(target) == LlvmLibunwind::InTree - && (target.contains("linux") || target.contains("fuchsia") || target.contains("aix")) + && (target.contains("linux") + || target.contains("fuchsia") + || target.contains("aix") + || target.contains("hexagon")) { let libunwind_path = copy_llvm_libunwind(builder, target, &builder.sysroot_target_libdir(*compiler, target)); diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 2f493658ec0e..6e6f5a1ea773 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -1851,7 +1851,7 @@ pub fn llvm_libunwind(&self, target: TargetSelection) -> LlvmLibunwind { .get(&target) .and_then(|t| t.llvm_libunwind) .or(self.llvm_libunwind_default) - .unwrap_or(if target.contains("fuchsia") { + .unwrap_or(if target.contains("fuchsia") || target.contains("hexagon") { LlvmLibunwind::InTree } else { LlvmLibunwind::No From f7a81885909e5552a686362bbd8fa56a1a8d5453 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Mon, 15 Dec 2025 05:00:57 +0000 Subject: [PATCH 022/126] Prepare for merging from rust-lang/rust This updates the rust-version file to 0208ee09be465f69005a7a12c28d5eccac7d5f34. --- 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 a1b44d65c597..dcf82c94aaee 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -2cd4ee6bcf517345dd76d7b102d56b2e873cddbc +0208ee09be465f69005a7a12c28d5eccac7d5f34 From 141342c34f3b3a623a132e08cbfcc883d3e97017 Mon Sep 17 00:00:00 2001 From: usamoi Date: Mon, 15 Dec 2025 18:57:33 +0800 Subject: [PATCH 023/126] stabilize lazy_get --- library/core/src/cell/lazy.rs | 11 +--- library/core/src/lib.rs | 1 - library/coretests/tests/lib.rs | 1 - library/std/src/lib.rs | 1 - library/std/src/sync/lazy_lock.rs | 11 +--- library/std/tests/sync/lib.rs | 1 - ...onst-item-interior-mutations-const-cell.rs | 1 - ...-item-interior-mutations-const-cell.stderr | 44 +++++++------- .../const-item-interior-mutations-const.fixed | 1 - .../const-item-interior-mutations-const.rs | 1 - ...const-item-interior-mutations-const.stderr | 60 +++++++++---------- 11 files changed, 58 insertions(+), 75 deletions(-) diff --git a/library/core/src/cell/lazy.rs b/library/core/src/cell/lazy.rs index 3dae6c64200c..8ffa9b3def51 100644 --- a/library/core/src/cell/lazy.rs +++ b/library/core/src/cell/lazy.rs @@ -165,7 +165,6 @@ pub fn force(this: &LazyCell) -> &T { /// # Examples /// /// ``` - /// #![feature(lazy_get)] /// use std::cell::LazyCell; /// /// let mut lazy = LazyCell::new(|| 92); @@ -176,7 +175,7 @@ pub fn force(this: &LazyCell) -> &T { /// assert_eq!(*lazy, 44); /// ``` #[inline] - #[unstable(feature = "lazy_get", issue = "129333")] + #[stable(feature = "lazy_get", since = "CURRENT_RUSTC_VERSION")] pub fn force_mut(this: &mut LazyCell) -> &mut T { #[cold] /// # Safety @@ -264,8 +263,6 @@ impl LazyCell { /// # Examples /// /// ``` - /// #![feature(lazy_get)] - /// /// use std::cell::LazyCell; /// /// let mut lazy = LazyCell::new(|| 92); @@ -276,7 +273,7 @@ impl LazyCell { /// assert_eq!(*lazy, 44); /// ``` #[inline] - #[unstable(feature = "lazy_get", issue = "129333")] + #[stable(feature = "lazy_get", since = "CURRENT_RUSTC_VERSION")] pub fn get_mut(this: &mut LazyCell) -> Option<&mut T> { let state = this.state.get_mut(); match state { @@ -291,8 +288,6 @@ pub fn get_mut(this: &mut LazyCell) -> Option<&mut T> { /// # Examples /// /// ``` - /// #![feature(lazy_get)] - /// /// use std::cell::LazyCell; /// /// let lazy = LazyCell::new(|| 92); @@ -302,7 +297,7 @@ pub fn get_mut(this: &mut LazyCell) -> Option<&mut T> { /// assert_eq!(LazyCell::get(&lazy), Some(&92)); /// ``` #[inline] - #[unstable(feature = "lazy_get", issue = "129333")] + #[stable(feature = "lazy_get", since = "CURRENT_RUSTC_VERSION")] pub fn get(this: &LazyCell) -> Option<&T> { // SAFETY: // This is sound for the same reason as in `force`: once the state is diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 9ecc2365e69b..962b0cea4a4f 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -113,7 +113,6 @@ #![feature(internal_impls_macro)] #![feature(ip)] #![feature(is_ascii_octdigit)] -#![feature(lazy_get)] #![feature(link_cfg)] #![feature(offset_of_enum)] #![feature(panic_internals)] diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 0387b442562d..b28e7338859c 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -79,7 +79,6 @@ #![feature(iterator_try_collect)] #![feature(iterator_try_reduce)] #![feature(layout_for_ptr)] -#![feature(lazy_get)] #![feature(maybe_uninit_fill)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(min_specialization)] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 8fb1b1b05d20..1a1746c91edd 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -343,7 +343,6 @@ #![feature(hint_must_use)] #![feature(int_from_ascii)] #![feature(ip)] -#![feature(lazy_get)] #![feature(maybe_uninit_array_assume_init)] #![feature(panic_can_unwind)] #![feature(panic_internals)] diff --git a/library/std/src/sync/lazy_lock.rs b/library/std/src/sync/lazy_lock.rs index ef58b64d4967..ef5c949e471f 100644 --- a/library/std/src/sync/lazy_lock.rs +++ b/library/std/src/sync/lazy_lock.rs @@ -172,7 +172,6 @@ pub fn into_inner(mut this: Self) -> Result { /// # Examples /// /// ``` - /// #![feature(lazy_get)] /// use std::sync::LazyLock; /// /// let mut lazy = LazyLock::new(|| 92); @@ -183,7 +182,7 @@ pub fn into_inner(mut this: Self) -> Result { /// assert_eq!(*lazy, 44); /// ``` #[inline] - #[unstable(feature = "lazy_get", issue = "129333")] + #[stable(feature = "lazy_get", since = "CURRENT_RUSTC_VERSION")] pub fn force_mut(this: &mut LazyLock) -> &mut T { #[cold] /// # Safety @@ -279,8 +278,6 @@ impl LazyLock { /// # Examples /// /// ``` - /// #![feature(lazy_get)] - /// /// use std::sync::LazyLock; /// /// let mut lazy = LazyLock::new(|| 92); @@ -291,7 +288,7 @@ impl LazyLock { /// assert_eq!(*lazy, 44); /// ``` #[inline] - #[unstable(feature = "lazy_get", issue = "129333")] + #[stable(feature = "lazy_get", since = "CURRENT_RUSTC_VERSION")] pub fn get_mut(this: &mut LazyLock) -> Option<&mut T> { // `state()` does not perform an atomic load, so prefer it over `is_complete()`. let state = this.once.state(); @@ -309,8 +306,6 @@ pub fn get_mut(this: &mut LazyLock) -> Option<&mut T> { /// # Examples /// /// ``` - /// #![feature(lazy_get)] - /// /// use std::sync::LazyLock; /// /// let lazy = LazyLock::new(|| 92); @@ -320,7 +315,7 @@ pub fn get_mut(this: &mut LazyLock) -> Option<&mut T> { /// assert_eq!(LazyLock::get(&lazy), Some(&92)); /// ``` #[inline] - #[unstable(feature = "lazy_get", issue = "129333")] + #[stable(feature = "lazy_get", since = "CURRENT_RUSTC_VERSION")] #[rustc_should_not_be_called_on_const_items] pub fn get(this: &LazyLock) -> Option<&T> { if this.once.is_completed() { diff --git a/library/std/tests/sync/lib.rs b/library/std/tests/sync/lib.rs index 20e34c9aa6bd..7ade9f623147 100644 --- a/library/std/tests/sync/lib.rs +++ b/library/std/tests/sync/lib.rs @@ -1,4 +1,3 @@ -#![feature(lazy_get)] #![feature(mapped_lock_guards)] #![feature(mpmc_channel)] #![feature(once_cell_try)] diff --git a/tests/ui/lint/const-item-interior-mutations-const-cell.rs b/tests/ui/lint/const-item-interior-mutations-const-cell.rs index b4a7f54c8e7a..22b465fa0a95 100644 --- a/tests/ui/lint/const-item-interior-mutations-const-cell.rs +++ b/tests/ui/lint/const-item-interior-mutations-const-cell.rs @@ -4,7 +4,6 @@ #![feature(sync_unsafe_cell)] #![feature(once_cell_try_insert)] #![feature(once_cell_try)] -#![feature(lazy_get)] use std::cell::{Cell, RefCell, SyncUnsafeCell, UnsafeCell}; use std::cell::{LazyCell, OnceCell}; diff --git a/tests/ui/lint/const-item-interior-mutations-const-cell.stderr b/tests/ui/lint/const-item-interior-mutations-const-cell.stderr index d9f19c61fa77..ec3a5f4e38ee 100644 --- a/tests/ui/lint/const-item-interior-mutations-const-cell.stderr +++ b/tests/ui/lint/const-item-interior-mutations-const-cell.stderr @@ -1,5 +1,5 @@ warning: mutation of an interior mutable `const` item with call to `force` - --> $DIR/const-item-interior-mutations-const-cell.rs:16:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:15:13 | LL | let _ = LazyCell::force(&A); | ^^^^^^^^^^^^^^^^^-^ @@ -17,7 +17,7 @@ LL + static A: LazyCell = LazyCell::new(|| 0); | warning: mutation of an interior mutable `const` item with call to `set` - --> $DIR/const-item-interior-mutations-const-cell.rs:23:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:22:13 | LL | let _ = A.set(10); | -^^^^^^^^ @@ -34,7 +34,7 @@ LL + static A: OnceCell = OnceCell::new(); | warning: mutation of an interior mutable `const` item with call to `try_insert` - --> $DIR/const-item-interior-mutations-const-cell.rs:26:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:25:13 | LL | let _ = A.try_insert(20); | -^^^^^^^^^^^^^^^ @@ -51,7 +51,7 @@ LL + static A: OnceCell = OnceCell::new(); | warning: mutation of an interior mutable `const` item with call to `get_or_init` - --> $DIR/const-item-interior-mutations-const-cell.rs:29:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:28:13 | LL | let _ = A.get_or_init(|| 30); | -^^^^^^^^^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL + static A: OnceCell = OnceCell::new(); | warning: mutation of an interior mutable `const` item with call to `get_or_try_init` - --> $DIR/const-item-interior-mutations-const-cell.rs:32:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:31:13 | LL | let _ = A.get_or_try_init(|| Ok::<_, ()>(40)); | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + static A: OnceCell = OnceCell::new(); | warning: mutation of an interior mutable `const` item with call to `set` - --> $DIR/const-item-interior-mutations-const-cell.rs:39:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:38:13 | LL | let _ = A.set(1); | -^^^^^^^ @@ -102,7 +102,7 @@ LL + static A: Cell = Cell::new(0); | warning: mutation of an interior mutable `const` item with call to `swap` - --> $DIR/const-item-interior-mutations-const-cell.rs:42:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:41:13 | LL | let _ = A.swap(&A); | -^^^^^^^^^ @@ -119,7 +119,7 @@ LL + static A: Cell = Cell::new(0); | warning: mutation of an interior mutable `const` item with call to `replace` - --> $DIR/const-item-interior-mutations-const-cell.rs:45:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:44:13 | LL | let _ = A.replace(2); | -^^^^^^^^^^^ @@ -136,7 +136,7 @@ LL + static A: Cell = Cell::new(0); | warning: mutation of an interior mutable `const` item with call to `get` - --> $DIR/const-item-interior-mutations-const-cell.rs:48:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:47:13 | LL | let _ = A.get(); | -^^^^^^ @@ -153,7 +153,7 @@ LL + static A: Cell = Cell::new(0); | warning: mutation of an interior mutable `const` item with call to `update` - --> $DIR/const-item-interior-mutations-const-cell.rs:51:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:50:13 | LL | let _ = A.update(|x| x + 1); | -^^^^^^^^^^^^^^^^^^ @@ -170,7 +170,7 @@ LL + static A: Cell = Cell::new(0); | warning: mutation of an interior mutable `const` item with call to `replace` - --> $DIR/const-item-interior-mutations-const-cell.rs:58:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:57:13 | LL | let _ = A.replace(1); | -^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL + static A: RefCell = RefCell::new(0); | warning: mutation of an interior mutable `const` item with call to `replace_with` - --> $DIR/const-item-interior-mutations-const-cell.rs:61:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:60:13 | LL | let _ = A.replace_with(|x| *x + 2); | -^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -204,7 +204,7 @@ LL + static A: RefCell = RefCell::new(0); | warning: mutation of an interior mutable `const` item with call to `swap` - --> $DIR/const-item-interior-mutations-const-cell.rs:64:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:63:13 | LL | let _ = A.swap(&A); | -^^^^^^^^^ @@ -221,7 +221,7 @@ LL + static A: RefCell = RefCell::new(0); | warning: mutation of an interior mutable `const` item with call to `borrow` - --> $DIR/const-item-interior-mutations-const-cell.rs:67:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:66:13 | LL | let _ = A.borrow(); | -^^^^^^^^^ @@ -238,7 +238,7 @@ LL + static A: RefCell = RefCell::new(0); | warning: mutation of an interior mutable `const` item with call to `try_borrow` - --> $DIR/const-item-interior-mutations-const-cell.rs:70:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:69:13 | LL | let _ = A.try_borrow(); | -^^^^^^^^^^^^^ @@ -255,7 +255,7 @@ LL + static A: RefCell = RefCell::new(0); | warning: mutation of an interior mutable `const` item with call to `borrow_mut` - --> $DIR/const-item-interior-mutations-const-cell.rs:73:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:72:13 | LL | let _ = A.borrow_mut(); | -^^^^^^^^^^^^^ @@ -272,7 +272,7 @@ LL + static A: RefCell = RefCell::new(0); | warning: mutation of an interior mutable `const` item with call to `try_borrow_mut` - --> $DIR/const-item-interior-mutations-const-cell.rs:76:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:75:13 | LL | let _ = A.try_borrow_mut(); | -^^^^^^^^^^^^^^^^^ @@ -289,7 +289,7 @@ LL + static A: RefCell = RefCell::new(0); | warning: mutation of an interior mutable `const` item with call to `replace` - --> $DIR/const-item-interior-mutations-const-cell.rs:83:22 + --> $DIR/const-item-interior-mutations-const-cell.rs:82:22 | LL | let _ = unsafe { A.replace(1) }; | -^^^^^^^^^^^ @@ -306,7 +306,7 @@ LL + static A: UnsafeCell = UnsafeCell::new(0); | warning: mutation of an interior mutable `const` item with call to `get` - --> $DIR/const-item-interior-mutations-const-cell.rs:86:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:85:13 | LL | let _ = A.get(); | -^^^^^^ @@ -323,7 +323,7 @@ LL + static A: UnsafeCell = UnsafeCell::new(0); | warning: mutation of an interior mutable `const` item with call to `as_ref_unchecked` - --> $DIR/const-item-interior-mutations-const-cell.rs:90:17 + --> $DIR/const-item-interior-mutations-const-cell.rs:89:17 | LL | let _ = A.as_ref_unchecked(); | -^^^^^^^^^^^^^^^^^^^ @@ -340,7 +340,7 @@ LL + static A: UnsafeCell = UnsafeCell::new(0); | warning: mutation of an interior mutable `const` item with call to `as_mut_unchecked` - --> $DIR/const-item-interior-mutations-const-cell.rs:93:17 + --> $DIR/const-item-interior-mutations-const-cell.rs:92:17 | LL | let _ = A.as_mut_unchecked(); | -^^^^^^^^^^^^^^^^^^^ @@ -357,7 +357,7 @@ LL + static A: UnsafeCell = UnsafeCell::new(0); | warning: mutation of an interior mutable `const` item with call to `get` - --> $DIR/const-item-interior-mutations-const-cell.rs:101:13 + --> $DIR/const-item-interior-mutations-const-cell.rs:100:13 | LL | let _ = A.get(); | -^^^^^^ diff --git a/tests/ui/lint/const-item-interior-mutations-const.fixed b/tests/ui/lint/const-item-interior-mutations-const.fixed index 82f3fdac43a3..97091ab10af8 100644 --- a/tests/ui/lint/const-item-interior-mutations-const.fixed +++ b/tests/ui/lint/const-item-interior-mutations-const.fixed @@ -6,7 +6,6 @@ #![feature(lock_value_accessors)] #![feature(once_cell_try_insert)] #![feature(once_cell_try)] -#![feature(lazy_get)] use std::sync::{Condvar, LazyLock, Mutex, Once, OnceLock, RwLock}; use std::time::Duration; diff --git a/tests/ui/lint/const-item-interior-mutations-const.rs b/tests/ui/lint/const-item-interior-mutations-const.rs index 5dbbfd8ca32f..40565118ca79 100644 --- a/tests/ui/lint/const-item-interior-mutations-const.rs +++ b/tests/ui/lint/const-item-interior-mutations-const.rs @@ -6,7 +6,6 @@ #![feature(lock_value_accessors)] #![feature(once_cell_try_insert)] #![feature(once_cell_try)] -#![feature(lazy_get)] use std::sync::{Condvar, LazyLock, Mutex, Once, OnceLock, RwLock}; use std::time::Duration; diff --git a/tests/ui/lint/const-item-interior-mutations-const.stderr b/tests/ui/lint/const-item-interior-mutations-const.stderr index 7d3e7bee7fbb..2fe8f190dbed 100644 --- a/tests/ui/lint/const-item-interior-mutations-const.stderr +++ b/tests/ui/lint/const-item-interior-mutations-const.stderr @@ -1,5 +1,5 @@ warning: mutation of an interior mutable `const` item with call to `set` - --> $DIR/const-item-interior-mutations-const.rs:17:14 + --> $DIR/const-item-interior-mutations-const.rs:16:14 | LL | let _a = A.set(1); | -^^^^^^^ @@ -17,7 +17,7 @@ LL + static A: Mutex = Mutex::new(0); | warning: mutation of an interior mutable `const` item with call to `replace` - --> $DIR/const-item-interior-mutations-const.rs:20:14 + --> $DIR/const-item-interior-mutations-const.rs:19:14 | LL | let _a = A.replace(2); | -^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL + static A: Mutex = Mutex::new(0); | warning: mutation of an interior mutable `const` item with call to `lock` - --> $DIR/const-item-interior-mutations-const.rs:23:10 + --> $DIR/const-item-interior-mutations-const.rs:22:10 | LL | drop(A.lock()); | -^^^^^^^ @@ -51,7 +51,7 @@ LL + static A: Mutex = Mutex::new(0); | warning: mutation of an interior mutable `const` item with call to `try_lock` - --> $DIR/const-item-interior-mutations-const.rs:26:10 + --> $DIR/const-item-interior-mutations-const.rs:25:10 | LL | drop(A.try_lock()); | -^^^^^^^^^^^ @@ -68,7 +68,7 @@ LL + static A: Mutex = Mutex::new(0); | warning: mutation of an interior mutable `const` item with call to `clear_poison` - --> $DIR/const-item-interior-mutations-const.rs:29:14 + --> $DIR/const-item-interior-mutations-const.rs:28:14 | LL | let _a = A.clear_poison(); | -^^^^^^^^^^^^^^^ @@ -85,7 +85,7 @@ LL + static A: Mutex = Mutex::new(0); | warning: mutation of an interior mutable `const` item with call to `call_once` - --> $DIR/const-item-interior-mutations-const.rs:36:14 + --> $DIR/const-item-interior-mutations-const.rs:35:14 | LL | let _a = A.call_once(|| {}); | -^^^^^^^^^^^^^^^^^ @@ -102,7 +102,7 @@ LL + static A: Once = Once::new(); | warning: mutation of an interior mutable `const` item with call to `call_once_force` - --> $DIR/const-item-interior-mutations-const.rs:39:14 + --> $DIR/const-item-interior-mutations-const.rs:38:14 | LL | let _a = A.call_once_force(|_| {}); | -^^^^^^^^^^^^^^^^^^^^^^^^ @@ -119,7 +119,7 @@ LL + static A: Once = Once::new(); | warning: mutation of an interior mutable `const` item with call to `wait` - --> $DIR/const-item-interior-mutations-const.rs:42:14 + --> $DIR/const-item-interior-mutations-const.rs:41:14 | LL | let _a = A.wait(); | -^^^^^^^ @@ -136,7 +136,7 @@ LL + static A: Once = Once::new(); | warning: mutation of an interior mutable `const` item with call to `wait_force` - --> $DIR/const-item-interior-mutations-const.rs:45:14 + --> $DIR/const-item-interior-mutations-const.rs:44:14 | LL | let _a = A.wait_force(); | -^^^^^^^^^^^^^ @@ -153,7 +153,7 @@ LL + static A: Once = Once::new(); | warning: mutation of an interior mutable `const` item with call to `set` - --> $DIR/const-item-interior-mutations-const.rs:52:14 + --> $DIR/const-item-interior-mutations-const.rs:51:14 | LL | let _a = A.set(1); | -^^^^^^^ @@ -170,7 +170,7 @@ LL + static A: RwLock = RwLock::new(0); | warning: mutation of an interior mutable `const` item with call to `replace` - --> $DIR/const-item-interior-mutations-const.rs:55:14 + --> $DIR/const-item-interior-mutations-const.rs:54:14 | LL | let _a = A.replace(2); | -^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL + static A: RwLock = RwLock::new(0); | warning: mutation of an interior mutable `const` item with call to `read` - --> $DIR/const-item-interior-mutations-const.rs:58:10 + --> $DIR/const-item-interior-mutations-const.rs:57:10 | LL | drop(A.read()); | -^^^^^^^ @@ -204,7 +204,7 @@ LL + static A: RwLock = RwLock::new(0); | warning: mutation of an interior mutable `const` item with call to `try_read` - --> $DIR/const-item-interior-mutations-const.rs:61:10 + --> $DIR/const-item-interior-mutations-const.rs:60:10 | LL | drop(A.try_read()); | -^^^^^^^^^^^ @@ -221,7 +221,7 @@ LL + static A: RwLock = RwLock::new(0); | warning: mutation of an interior mutable `const` item with call to `write` - --> $DIR/const-item-interior-mutations-const.rs:64:10 + --> $DIR/const-item-interior-mutations-const.rs:63:10 | LL | drop(A.write()); | -^^^^^^^^ @@ -238,7 +238,7 @@ LL + static A: RwLock = RwLock::new(0); | warning: mutation of an interior mutable `const` item with call to `try_write` - --> $DIR/const-item-interior-mutations-const.rs:67:10 + --> $DIR/const-item-interior-mutations-const.rs:66:10 | LL | drop(A.try_write()); | -^^^^^^^^^^^^ @@ -255,7 +255,7 @@ LL + static A: RwLock = RwLock::new(0); | warning: mutation of an interior mutable `const` item with call to `force` - --> $DIR/const-item-interior-mutations-const.rs:74:14 + --> $DIR/const-item-interior-mutations-const.rs:73:14 | LL | let _a = LazyLock::force(&A); | ^^^^^^^^^^^^^^^^^-^ @@ -272,7 +272,7 @@ LL + static A: LazyLock = LazyLock::new(|| 0); | warning: mutation of an interior mutable `const` item with call to `get` - --> $DIR/const-item-interior-mutations-const.rs:77:14 + --> $DIR/const-item-interior-mutations-const.rs:76:14 | LL | let _a = LazyLock::get(&A); | ^^^^^^^^^^^^^^^-^ @@ -289,7 +289,7 @@ LL + static A: LazyLock = LazyLock::new(|| 0); | warning: mutation of an interior mutable `const` item with call to `get` - --> $DIR/const-item-interior-mutations-const.rs:84:14 + --> $DIR/const-item-interior-mutations-const.rs:83:14 | LL | let _a = A.get(); | -^^^^^^ @@ -306,7 +306,7 @@ LL + static A: OnceLock = OnceLock::new(); | warning: mutation of an interior mutable `const` item with call to `wait` - --> $DIR/const-item-interior-mutations-const.rs:87:14 + --> $DIR/const-item-interior-mutations-const.rs:86:14 | LL | let _a = A.wait(); | -^^^^^^^ @@ -323,7 +323,7 @@ LL + static A: OnceLock = OnceLock::new(); | warning: mutation of an interior mutable `const` item with call to `set` - --> $DIR/const-item-interior-mutations-const.rs:90:14 + --> $DIR/const-item-interior-mutations-const.rs:89:14 | LL | let _a = A.set(10); | -^^^^^^^^ @@ -340,7 +340,7 @@ LL + static A: OnceLock = OnceLock::new(); | warning: mutation of an interior mutable `const` item with call to `try_insert` - --> $DIR/const-item-interior-mutations-const.rs:93:14 + --> $DIR/const-item-interior-mutations-const.rs:92:14 | LL | let _a = A.try_insert(20); | -^^^^^^^^^^^^^^^ @@ -357,7 +357,7 @@ LL + static A: OnceLock = OnceLock::new(); | warning: mutation of an interior mutable `const` item with call to `get_or_init` - --> $DIR/const-item-interior-mutations-const.rs:96:14 + --> $DIR/const-item-interior-mutations-const.rs:95:14 | LL | let _a = A.get_or_init(|| 30); | -^^^^^^^^^^^^^^^^^^^ @@ -374,7 +374,7 @@ LL + static A: OnceLock = OnceLock::new(); | warning: mutation of an interior mutable `const` item with call to `get_or_try_init` - --> $DIR/const-item-interior-mutations-const.rs:99:14 + --> $DIR/const-item-interior-mutations-const.rs:98:14 | LL | let _a = A.get_or_try_init(|| Ok::<_, ()>(40)); | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -391,7 +391,7 @@ LL + static A: OnceLock = OnceLock::new(); | warning: mutation of an interior mutable `const` item with call to `wait` - --> $DIR/const-item-interior-mutations-const.rs:109:14 + --> $DIR/const-item-interior-mutations-const.rs:108:14 | LL | let _a = A.wait(guard); | -^^^^^^^^^^^^ @@ -408,7 +408,7 @@ LL + static A: Condvar = Condvar::new(); | warning: mutation of an interior mutable `const` item with call to `wait_while` - --> $DIR/const-item-interior-mutations-const.rs:114:14 + --> $DIR/const-item-interior-mutations-const.rs:113:14 | LL | let _a = A.wait_while(guard, |x| *x == 0); | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -425,7 +425,7 @@ LL + static A: Condvar = Condvar::new(); | warning: mutation of an interior mutable `const` item with call to `wait_timeout_ms` - --> $DIR/const-item-interior-mutations-const.rs:119:14 + --> $DIR/const-item-interior-mutations-const.rs:118:14 | LL | let _a = A.wait_timeout_ms(guard, 10); | -^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -442,7 +442,7 @@ LL + static A: Condvar = Condvar::new(); | warning: mutation of an interior mutable `const` item with call to `wait_timeout` - --> $DIR/const-item-interior-mutations-const.rs:124:14 + --> $DIR/const-item-interior-mutations-const.rs:123:14 | LL | let _a = A.wait_timeout(guard, Duration::from_millis(10)); | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -459,7 +459,7 @@ LL + static A: Condvar = Condvar::new(); | warning: mutation of an interior mutable `const` item with call to `wait_timeout_while` - --> $DIR/const-item-interior-mutations-const.rs:129:14 + --> $DIR/const-item-interior-mutations-const.rs:128:14 | LL | let _a = A.wait_timeout_while(guard, Duration::from_millis(10), |x| *x == 0); | -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -476,7 +476,7 @@ LL + static A: Condvar = Condvar::new(); | warning: mutation of an interior mutable `const` item with call to `notify_one` - --> $DIR/const-item-interior-mutations-const.rs:132:14 + --> $DIR/const-item-interior-mutations-const.rs:131:14 | LL | let _a = A.notify_one(); | -^^^^^^^^^^^^^ @@ -493,7 +493,7 @@ LL + static A: Condvar = Condvar::new(); | warning: mutation of an interior mutable `const` item with call to `notify_all` - --> $DIR/const-item-interior-mutations-const.rs:135:14 + --> $DIR/const-item-interior-mutations-const.rs:134:14 | LL | let _a = A.notify_all(); | -^^^^^^^^^^^^^ From 3493f8c0b6393430b3437121a463a6c6d69f3f3d Mon Sep 17 00:00:00 2001 From: Almog Gavra Date: Mon, 15 Dec 2025 13:02:47 -0800 Subject: [PATCH 024/126] fix docustring on fetch_or --- library/core/src/sync/atomic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index 0601019abbd5..1eae06ebd33e 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -1151,8 +1151,8 @@ pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool { /// assert_eq!(foo.fetch_or(false, Ordering::SeqCst), true); /// assert_eq!(foo.load(Ordering::SeqCst), true); /// - /// let foo = AtomicBool::new(true); - /// assert_eq!(foo.fetch_or(true, Ordering::SeqCst), true); + /// let foo = AtomicBool::new(false); + /// assert_eq!(foo.fetch_or(true, Ordering::SeqCst), false); /// assert_eq!(foo.load(Ordering::SeqCst), true); /// /// let foo = AtomicBool::new(false); From 38ef5c1cdbd7861dbe26c256f232a1722967a065 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Tue, 16 Dec 2025 06:04:11 +0200 Subject: [PATCH 025/126] improve cg_gcc.md a little --- .../rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md index 7a1c5b9a98c0..9ed91550b262 100644 --- a/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md +++ b/src/doc/rustc-dev-guide/src/tests/codegen-backend-tests/cg_gcc.md @@ -79,10 +79,10 @@ if there are no local changes to the GCC sources and the given host target is av ## Providing your own GCC -There are cases where you will want to provide yourself the `libgccjit.so` file. +There are cases where you will want to provide your own `libgccjit.so` file. One such case is when you want to cross-compile `rustc` to another target since GCC is not a multi-target compiler. To support this use case, there is the bootstrap option `gcc.libgccjit-libs-dir`. -This option override `gcc.download-ci-gcc`, meaning `libgccjit.so` won't be downloaded or built locally by bootstrap. +This option overrides `gcc.download-ci-gcc`, meaning `libgccjit.so` won't be downloaded or built locally by bootstrap. The directory structure of this directory is `//libgccjit.so`, for instance: ``` From fc16679419b9f17cbfde666aa26fa728781fb435 Mon Sep 17 00:00:00 2001 From: usamoi Date: Sun, 14 Dec 2025 17:59:55 +0800 Subject: [PATCH 026/126] add avx512 pshufb --- src/tools/miri/src/shims/x86/avx2.rs | 25 +---------- src/tools/miri/src/shims/x86/avx512.rs | 9 +++- src/tools/miri/src/shims/x86/mod.rs | 45 +++++++++++++++++++ src/tools/miri/src/shims/x86/ssse3.rs | 24 +--------- .../pass/shims/x86/intrinsics-x86-avx512.rs | 24 ++++++++++ 5 files changed, 81 insertions(+), 46 deletions(-) diff --git a/src/tools/miri/src/shims/x86/avx2.rs b/src/tools/miri/src/shims/x86/avx2.rs index 8fe225c494d5..b089a0249bd7 100644 --- a/src/tools/miri/src/shims/x86/avx2.rs +++ b/src/tools/miri/src/shims/x86/avx2.rs @@ -6,7 +6,7 @@ use super::{ ShiftOp, horizontal_bin_op, mpsadbw, packssdw, packsswb, packusdw, packuswb, permute, pmaddbw, - pmulhrsw, psadbw, psign, shift_simd_by_scalar, + pmulhrsw, psadbw, pshufb, psign, shift_simd_by_scalar, }; use crate::*; @@ -189,28 +189,7 @@ fn emulate_x86_avx2_intrinsic( let [left, right] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let (left, left_len) = this.project_to_simd(left)?; - let (right, right_len) = this.project_to_simd(right)?; - let (dest, dest_len) = this.project_to_simd(dest)?; - - assert_eq!(dest_len, left_len); - assert_eq!(dest_len, right_len); - - for i in 0..dest_len { - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u8()?; - let dest = this.project_index(&dest, i)?; - - let res = if right & 0x80 == 0 { - // Shuffle each 128-bit (16-byte) block independently. - let j = u64::from(right % 16).strict_add(i & !15); - this.read_scalar(&this.project_index(&left, j)?)? - } else { - // If the highest bit in `right` is 1, write zero. - Scalar::from_u8(0) - }; - - this.write_scalar(res, &dest)?; - } + pshufb(this, left, right, dest)?; } // Used to implement the _mm256_sign_epi{8,16,32} functions. // Negates elements from `left` when the corresponding element in diff --git a/src/tools/miri/src/shims/x86/avx512.rs b/src/tools/miri/src/shims/x86/avx512.rs index 9b43aad96e5c..a886f5622ced 100644 --- a/src/tools/miri/src/shims/x86/avx512.rs +++ b/src/tools/miri/src/shims/x86/avx512.rs @@ -3,7 +3,7 @@ use rustc_span::Symbol; use rustc_target::callconv::FnAbi; -use super::{permute, pmaddbw, psadbw}; +use super::{permute, pmaddbw, psadbw, pshufb}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -102,6 +102,13 @@ fn emulate_x86_avx512_intrinsic( permute(this, left, right, dest)?; } + // Used to implement the _mm512_shuffle_epi8 intrinsic. + "pshuf.b.512" => { + let [left, right] = + this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; + + pshufb(this, left, right, dest)?; + } _ => return interp_ok(EmulateItemResult::NotSupported), } interp_ok(EmulateItemResult::NeedsReturn) diff --git a/src/tools/miri/src/shims/x86/mod.rs b/src/tools/miri/src/shims/x86/mod.rs index 40dcd7ac1c2d..a5164cc87ab4 100644 --- a/src/tools/miri/src/shims/x86/mod.rs +++ b/src/tools/miri/src/shims/x86/mod.rs @@ -1155,6 +1155,51 @@ fn pclmulqdq<'tcx>( interp_ok(()) } +/// Shuffles bytes from `left` using `right` as pattern. Each 16-byte block is shuffled independently. +/// +/// `left` and `right` are both vectors of type `len` x i8. +/// +/// If the highest bit of a byte in `right` is not set, the corresponding byte in `dest` is taken +/// from the current 16-byte block of `left` at the position indicated by the lowest 4 bits of this +/// byte in `right`. If the highest bit of a byte in `right` is set, the corresponding byte in +/// `dest` is set to `0`. +/// +/// +/// +/// +fn pshufb<'tcx>( + ecx: &mut crate::MiriInterpCx<'tcx>, + left: &OpTy<'tcx>, + right: &OpTy<'tcx>, + dest: &MPlaceTy<'tcx>, +) -> InterpResult<'tcx, ()> { + let (left, left_len) = ecx.project_to_simd(left)?; + let (right, right_len) = ecx.project_to_simd(right)?; + let (dest, dest_len) = ecx.project_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let right = ecx.read_scalar(&ecx.project_index(&right, i)?)?.to_u8()?; + let dest = ecx.project_index(&dest, i)?; + + let res = if right & 0x80 == 0 { + // Shuffle each 128-bit (16-byte) block independently. + let block_offset = i & !15; // round down to previous multiple of 16 + let j = block_offset.strict_add((right % 16).into()); + ecx.read_scalar(&ecx.project_index(&left, j)?)? + } else { + // If the highest bit in `right` is 1, write zero. + Scalar::from_u8(0) + }; + + ecx.write_scalar(res, &dest)?; + } + + interp_ok(()) +} + /// Packs two N-bit integer vectors to a single N/2-bit integers. /// /// The conversion from N-bit to N/2-bit should be provided by `f`. diff --git a/src/tools/miri/src/shims/x86/ssse3.rs b/src/tools/miri/src/shims/x86/ssse3.rs index 56fc63ce1473..b01a8795b4d1 100644 --- a/src/tools/miri/src/shims/x86/ssse3.rs +++ b/src/tools/miri/src/shims/x86/ssse3.rs @@ -4,7 +4,7 @@ use rustc_span::Symbol; use rustc_target::callconv::FnAbi; -use super::{horizontal_bin_op, pmaddbw, pmulhrsw, psign}; +use super::{horizontal_bin_op, pmaddbw, pmulhrsw, pshufb, psign}; use crate::*; impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} @@ -29,27 +29,7 @@ fn emulate_x86_ssse3_intrinsic( let [left, right] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let (left, left_len) = this.project_to_simd(left)?; - let (right, right_len) = this.project_to_simd(right)?; - let (dest, dest_len) = this.project_to_simd(dest)?; - - assert_eq!(dest_len, left_len); - assert_eq!(dest_len, right_len); - - for i in 0..dest_len { - let right = this.read_scalar(&this.project_index(&right, i)?)?.to_u8()?; - let dest = this.project_index(&dest, i)?; - - let res = if right & 0x80 == 0 { - let j = right % 16; // index wraps around - this.read_scalar(&this.project_index(&left, j.into())?)? - } else { - // If the highest bit in `right` is 1, write zero. - Scalar::from_u8(0) - }; - - this.write_scalar(res, &dest)?; - } + pshufb(this, left, right, dest)?; } // Used to implement the _mm_h{adds,subs}_epi16 functions. // Horizontally add / subtract with saturation adjacent 16-bit diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs index e778567b483f..f95429d59ebe 100644 --- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs +++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs @@ -143,6 +143,30 @@ unsafe fn test_mm512_permutexvar_epi32() { assert_eq_m512i(r, e); } test_mm512_permutexvar_epi32(); + + #[target_feature(enable = "avx512bw")] + unsafe fn test_mm512_shuffle_epi8() { + #[rustfmt::skip] + let a = _mm512_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63); + #[rustfmt::skip] + let b = _mm512_set_epi8(-1, 127, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, 127, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, 127, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + -1, 127, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_shuffle_epi8(a, b); + // `_mm512_set_epi8` sets the bytes in inverse order (?!?), so the indices in `b` seem to + // index from the *back* of the corresponding 16-byte block in `a`. + #[rustfmt::skip] + let e = _mm512_set_epi8(0, 0, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 0, 16, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 0, 32, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, + 0, 48, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62, 62); + assert_eq_m512i(r, e); + } + test_mm512_shuffle_epi8(); } // Some of the constants in the tests below are just bit patterns. They should not From a412446bb39f33c2ff614960cae02cf1e8b1821a Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Wed, 17 Dec 2025 07:22:03 +0000 Subject: [PATCH 027/126] Prepare for merging from rust-lang/rust This updates the rust-version file to 2dc30247c5d8293aaa31e1d7dae2ed2fde908ada. --- src/doc/rustc-dev-guide/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/rust-version b/src/doc/rustc-dev-guide/rust-version index 71a84e2bda12..7345c25066a8 100644 --- a/src/doc/rustc-dev-guide/rust-version +++ b/src/doc/rustc-dev-guide/rust-version @@ -1 +1 @@ -cec70080fd441d16e9fb08a0d1d1a04c72d1ed25 +2dc30247c5d8293aaa31e1d7dae2ed2fde908ada From 8fcddc639303a83fcfbae47b1d7c88adc94e917c Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Wed, 17 Dec 2025 16:41:00 +0100 Subject: [PATCH 028/126] remove `legacy_const_generic_args` cache --- compiler/rustc_ast_lowering/src/expr.rs | 3 ++- compiler/rustc_ast_lowering/src/lib.rs | 16 +++++++++------- compiler/rustc_middle/src/ty/mod.rs | 3 +-- compiler/rustc_resolve/src/lib.rs | 10 ++-------- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c8a311443a58..0502fd2873e9 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -114,7 +114,8 @@ pub(super) fn lower_expr_mut(&mut self, e: &Expr) -> hir::Expr<'hir> { } ExprKind::Tup(elts) => hir::ExprKind::Tup(self.lower_exprs(elts)), ExprKind::Call(f, args) => { - if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f) { + if let Some(legacy_args) = self.resolver.legacy_const_generic_args(f, self.tcx) + { self.lower_legacy_const_generics((**f).clone(), args.clone(), &legacy_args) } else { let f = self.lower_expr(f); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index d0871b0b98f4..1bc8d7c25bb5 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -47,13 +47,14 @@ use rustc_data_structures::sync::spawn; use rustc_data_structures::tagged_ptr::TaggedRef; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle}; +use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::definitions::{DefPathData, DisambiguatorState}; use rustc_hir::lints::DelayedLint; use rustc_hir::{ self as hir, AngleBrackets, ConstArg, GenericArg, HirId, ItemLocalMap, LifetimeSource, - LifetimeSyntax, ParamName, Target, TraitCandidate, + LifetimeSyntax, ParamName, Target, TraitCandidate, find_attr, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -236,7 +237,7 @@ fn lower(&self, span: Span) -> Span { #[extension(trait ResolverAstLoweringExt)] impl ResolverAstLowering { - fn legacy_const_generic_args(&self, expr: &Expr) -> Option> { + fn legacy_const_generic_args(&self, expr: &Expr, tcx: TyCtxt<'_>) -> Option> { let ExprKind::Path(None, path) = &expr.kind else { return None; }; @@ -256,11 +257,12 @@ fn legacy_const_generic_args(&self, expr: &Expr) -> Option> { return None; } - if let Some(v) = self.legacy_const_generic_args.get(&def_id) { - return v.clone(); - } - - None + find_attr!( + // we can use parsed attrs here since for other crates they're already available + tcx.get_all_attrs(def_id), + AttributeKind::RustcLegacyConstGenerics{fn_indexes,..} => fn_indexes + ) + .map(|fn_indexes| fn_indexes.iter().map(|(num, _)| *num).collect()) } fn get_partial_res(&self, id: NodeId) -> Option { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 2021f175cd84..5239fc242c86 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -31,7 +31,7 @@ use rustc_ast::expand::typetree::{FncTree, Kind, Type, TypeTree}; use rustc_ast::node_id::NodeMap; pub use rustc_ast_ir::{Movability, Mutability, try_visit}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; @@ -196,7 +196,6 @@ pub struct ResolverGlobalCtxt { /// This struct is meant to be consumed by lowering. #[derive(Debug)] pub struct ResolverAstLowering { - pub legacy_const_generic_args: FxHashMap>>, /// Resolutions for nodes that have a single resolution. pub partial_res_map: NodeMap, /// Resolutions for import nodes, which have multiple resolutions in different namespaces. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 5d4134fd91c3..01687e6f4889 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1271,7 +1271,6 @@ pub struct Resolver<'ra, 'tcx> { /// and how the `impl Trait` fragments were introduced. invocation_parents: FxHashMap, - legacy_const_generic_args: FxHashMap>>, /// Amount of lifetime parameters for each item in the crate. item_generics_num_lifetimes: FxHashMap, delegation_fn_sigs: LocalDefIdMap, @@ -1675,7 +1674,6 @@ pub fn new( node_id_to_def_id, disambiguator: DisambiguatorState::new(), placeholder_field_indices: Default::default(), - legacy_const_generic_args: Default::default(), invocation_parents, item_generics_num_lifetimes: Default::default(), trait_impls: Default::default(), @@ -1805,7 +1803,6 @@ pub fn into_outputs(self) -> ResolverOutputs { stripped_cfg_items, }; let ast_lowering = ty::ResolverAstLowering { - legacy_const_generic_args: self.legacy_const_generic_args, partial_res_map: self.partial_res_map, import_res_map: self.import_res_map, label_res_map: self.label_res_map, @@ -2413,15 +2410,12 @@ fn legacy_const_generic_args(&mut self, expr: &Expr) -> Option> { return None; } - let indexes = find_attr!( + find_attr!( // we can use parsed attrs here since for other crates they're already available self.tcx.get_all_attrs(def_id), AttributeKind::RustcLegacyConstGenerics{fn_indexes,..} => fn_indexes ) - .map(|fn_indexes| fn_indexes.iter().map(|(num, _)| *num).collect()); - - self.legacy_const_generic_args.insert(def_id, indexes.clone()); - indexes + .map(|fn_indexes| fn_indexes.iter().map(|(num, _)| *num).collect()) } fn resolve_main(&mut self) { From 15069c2a378e2e5c954cafdaca61cef3c7ce6e57 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Mon, 2 Jun 2025 11:51:40 -0700 Subject: [PATCH 029/126] Implement SetFileInformationByHandle, as well as direct shim test for it --- .../miri/src/shims/windows/foreign_items.rs | 6 ++ src/tools/miri/src/shims/windows/fs.rs | 85 +++++++++++++++++++ .../miri/tests/pass-dep/shims/windows-fs.rs | 35 +++++++- src/tools/miri/tests/pass/shims/fs.rs | 13 ++- 4 files changed, 133 insertions(+), 6 deletions(-) diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index c824147ad4be..7d30582c582c 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -307,6 +307,12 @@ fn emulate_foreign_item_inner( let res = this.GetFileInformationByHandle(handle, info)?; this.write_scalar(res, dest)?; } + "SetFileInformationByHandle" => { + let [handle, class, info, size] = + this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let res = this.SetFileInformationByHandle(handle, class, info, size)?; + this.write_scalar(res, dest)?; + } "DeleteFileW" => { let [file_name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; let res = this.DeleteFileW(file_name)?; diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs index ad22df2425af..967164cb250d 100644 --- a/src/tools/miri/src/shims/windows/fs.rs +++ b/src/tools/miri/src/shims/windows/fs.rs @@ -5,6 +5,7 @@ use std::time::SystemTime; use bitflags::bitflags; +use rustc_abi::Size; use rustc_target::spec::Os; use crate::shims::files::{FdId, FileDescription, FileHandle}; @@ -372,6 +373,90 @@ fn GetFileInformationByHandle( interp_ok(this.eval_windows("c", "TRUE")) } + fn SetFileInformationByHandle( + &mut self, + file: &OpTy<'tcx>, // HANDLE + class: &OpTy<'tcx>, // FILE_INFO_BY_HANDLE_CLASS + file_information: &OpTy<'tcx>, // LPVOID + buffer_size: &OpTy<'tcx>, // DWORD + ) -> InterpResult<'tcx, Scalar> { + // ^ Returns BOOL (i32 on Windows) + let this = self.eval_context_mut(); + this.assert_target_os(Os::Windows, "SetFileInformationByHandle"); + this.check_no_isolation("`SetFileInformationByHandle`")?; + + let class = this.read_scalar(class)?.to_u32()?; + let buffer_size = this.read_scalar(buffer_size)?.to_u32()?; + let file_information = this.read_pointer(file_information)?; + this.check_ptr_access( + file_information, + Size::from_bytes(buffer_size), + CheckInAllocMsg::MemoryAccess, + )?; + + let file = this.read_handle(file, "SetFileInformationByHandle")?; + let Handle::File(fd_num) = file else { this.invalid_handle("SetFileInformationByHandle")? }; + let Some(desc) = this.machine.fds.get(fd_num) else { + this.invalid_handle("SetFileInformationByHandle")? + }; + let file = desc.downcast::().ok_or_else(|| { + err_unsup_format!( + "`SetFileInformationByHandle` is only supported on file-backed file descriptors" + ) + })?; + + if class == this.eval_windows_u32("c", "FileEndOfFileInfo") { + let place = this + .ptr_to_mplace(file_information, this.windows_ty_layout("FILE_END_OF_FILE_INFO")); + let new_len = + this.read_scalar(&this.project_field_named(&place, "EndOfFile")?)?.to_i64()?; + match file.file.set_len(new_len.try_into().unwrap()) { + Ok(_) => interp_ok(this.eval_windows("c", "TRUE")), + Err(e) => { + this.set_last_error(e)?; + interp_ok(this.eval_windows("c", "FALSE")) + } + } + } else if class == this.eval_windows_u32("c", "FileAllocationInfo") { + // On Windows, files are somewhat similar to a `Vec` in that they have a separate + // "length" (called "EOF position") and "capacity" (called "allocation size"). + // Growing the allocation size is largely a performance hint which we can + // ignore -- it can also be directly queried, but we currently do not support that. + // So we only need to do something if this operation shrinks the allocation size + // so far that it affects the EOF position. + let place = this + .ptr_to_mplace(file_information, this.windows_ty_layout("FILE_ALLOCATION_INFO")); + let new_alloc_size: u64 = this + .read_scalar(&this.project_field_named(&place, "AllocationSize")?)? + .to_i64()? + .try_into() + .unwrap(); + let old_len = match file.file.metadata() { + Ok(m) => m.len(), + Err(e) => { + this.set_last_error(e)?; + return interp_ok(this.eval_windows("c", "FALSE")); + } + }; + if new_alloc_size < old_len { + match file.file.set_len(new_alloc_size) { + Ok(_) => interp_ok(this.eval_windows("c", "TRUE")), + Err(e) => { + this.set_last_error(e)?; + interp_ok(this.eval_windows("c", "FALSE")) + } + } + } else { + interp_ok(this.eval_windows("c", "TRUE")) + } + } else { + throw_unsup_format!( + "SetFileInformationByHandle: Unsupported `FileInformationClass` value {}", + class + ) + } + } + fn DeleteFileW( &mut self, file_name: &OpTy<'tcx>, // LPCWSTR diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs index 7b756603d929..0037f34d3c9a 100644 --- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs +++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs @@ -19,9 +19,11 @@ }; use windows_sys::Win32::Storage::FileSystem::{ BY_HANDLE_FILE_INFORMATION, CREATE_ALWAYS, CREATE_NEW, CreateFileW, DeleteFileW, - FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_BEGIN, FILE_CURRENT, - FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, - FILE_SHARE_WRITE, GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, SetFilePointerEx, + FILE_ALLOCATION_INFO, FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_BEGIN, + FILE_CURRENT, FILE_END_OF_FILE_INFO, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, + FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, FileAllocationInfo, FileEndOfFileInfo, + GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, SetFileInformationByHandle, + SetFilePointerEx, }; use windows_sys::Win32::System::IO::IO_STATUS_BLOCK; use windows_sys::Win32::System::Threading::GetCurrentProcess; @@ -37,6 +39,7 @@ fn main() { test_ntstatus_to_dos(); test_file_read_write(); test_file_seek(); + test_set_file_info(); test_dup_handle(); } } @@ -275,6 +278,32 @@ unsafe fn test_file_read_write() { assert_eq!(GetLastError(), 1234); } +unsafe fn test_set_file_info() { + let temp = utils::tmp().join("test_set_file.txt"); + let mut file = fs::File::create(&temp).unwrap(); + let handle = file.as_raw_handle(); + + let info = FILE_END_OF_FILE_INFO { EndOfFile: 20 }; + let res = SetFileInformationByHandle( + handle, + FileEndOfFileInfo, + ptr::from_ref(&info).cast(), + size_of::().try_into().unwrap(), + ); + assert!(res != 0); + assert_eq!(file.seek(SeekFrom::End(0)).unwrap(), 20); + + let info = FILE_ALLOCATION_INFO { AllocationSize: 0 }; + let res = SetFileInformationByHandle( + handle, + FileAllocationInfo, + ptr::from_ref(&info).cast(), + size_of::().try_into().unwrap(), + ); + assert!(res != 0); + assert_eq!(file.metadata().unwrap().len(), 0); +} + unsafe fn test_dup_handle() { let temp = utils::tmp().join("test_dup.txt"); diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 43fbf6b085f7..70bca703cc2f 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -28,9 +28,9 @@ fn main() { test_errors(); test_from_raw_os_error(); test_file_clone(); + test_file_set_len(); // Windows file handling is very incomplete. if cfg!(not(windows)) { - test_file_set_len(); test_file_sync(); test_rename(); test_directory(); @@ -77,6 +77,9 @@ fn test_file() { // However, writing 0 bytes can succeed or fail. let _ignore = file.write(&[]); + // Test calling File::create on an existing file, since that uses a different code path + File::create(&path).unwrap(); + // Removing file should succeed. remove_file(&path).unwrap(); } @@ -87,7 +90,6 @@ fn test_file_partial_reads_writes() { // Ensure we sometimes do incomplete writes. check_nondet(|| { - let _ = remove_file(&path1); // FIXME(win, issue #4483): errors if the file already exists let mut file = File::create(&path1).unwrap(); file.write(&[0; 4]).unwrap() == 4 }); @@ -210,7 +212,12 @@ fn test_file_set_len() { // Can't use set_len on a file not opened for writing let file = OpenOptions::new().read(true).open(&path).unwrap(); - assert_eq!(ErrorKind::InvalidInput, file.set_len(14).unwrap_err().kind()); + // Due to https://github.com/rust-lang/miri/issues/4457, we have to assume the failure could + // be either of the Windows or Unix kind, no matter which platform we're on. + assert!( + [ErrorKind::PermissionDenied, ErrorKind::InvalidInput] + .contains(&file.set_len(14).unwrap_err().kind()) + ); remove_file(&path).unwrap(); } From 977bf0a134609bd601343023bbb561137392f18f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 17 Dec 2025 20:29:58 +0200 Subject: [PATCH 030/126] crash test readme: point to rustc-dev-guide There is information that is duplicated here and in rustc-dev-guide, and the latter is more comprehensive, so point there. --- tests/crashes/README.md | 26 +------------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/tests/crashes/README.md b/tests/crashes/README.md index 2dc81a115df3..8026b7c2463c 100644 --- a/tests/crashes/README.md +++ b/tests/crashes/README.md @@ -1,25 +1 @@ -This is serves as a collection of crashes so that accidental ICE fixes are tracked. -This was formally done at https://github.com/rust-lang/glacier but doing it inside -the rustc testsuite is more convenient. - -It is imperative that a test in the suite causes an internal compiler error/panic -or makes rustc crash in some other way. -A test will "pass" if rustc exits with something other than 1 or 0. - -When adding crashes from https://github.com/rust-lang/rust/issues, the -issue number should be noted in the file name (12345.rs should suffice) -and also inside the file via `//@ known-bug #4321` if possible. - -If you happen to fix one of the crashes, please move it to a fitting -subdirectory in `tests/ui` and give it a meaningful name. -Also please add a doc comment at the top of the file explaining why -this test exists. :) -Adding -Fixes #NNNNN -Fixes #MMMMM -to the description of your pull request will ensure the -corresponding tickets will be closed automatically upon merge. -The ticket ids can be found in the file name or the `known-bug` annotation -inside the testfile. - -Please do not re-report any crashes that you find here! +Documentation on crash tests is at https://rustc-dev-guide.rust-lang.org/tests/compiletest#crash-tests From e17c2f3eccc7436d7f94c6ed4bc8a367f4c6a7fb Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 17 Dec 2025 21:25:19 +0200 Subject: [PATCH 031/126] show how to view docs locally --- tests/crashes/README.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/crashes/README.md b/tests/crashes/README.md index 8026b7c2463c..a809ae798c20 100644 --- a/tests/crashes/README.md +++ b/tests/crashes/README.md @@ -1 +1,9 @@ -Documentation on crash tests is at https://rustc-dev-guide.rust-lang.org/tests/compiletest#crash-tests +Documentation on crash tests is at https://rustc-dev-guide.rust-lang.org/tests/compiletest#crash-tests. + +Alternatively, you can build the documentation from this repository: + +```console +mdbook serve --open src/doc/rustc-dev-guide +``` + +The documentation will then be available at http://localhost:3000/tests/compiletest.html#crash-tests. From fd513105d8c6292e75db21e613375c13585a27cd Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 17 Dec 2025 21:38:54 +0200 Subject: [PATCH 032/126] output of "git diff" is better, and is what I use mostly --- src/doc/rustc-dev-guide/ci/sembr/Cargo.lock | 26 -------------------- src/doc/rustc-dev-guide/ci/sembr/Cargo.toml | 1 - src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 17 ------------- 3 files changed, 44 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/sembr/Cargo.lock b/src/doc/rustc-dev-guide/ci/sembr/Cargo.lock index 077fa42d2e5b..4defe49579f3 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/Cargo.lock +++ b/src/doc/rustc-dev-guide/ci/sembr/Cargo.lock @@ -148,12 +148,6 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "globset" version = "0.4.18" @@ -167,15 +161,6 @@ dependencies = [ "regex-syntax", ] -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "foldhash", -] - [[package]] name = "heck" version = "0.5.0" @@ -198,16 +183,6 @@ dependencies = [ "winapi-util", ] -[[package]] -name = "imara-diff" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f01d462f766df78ab820dd06f5eb700233c51f0f4c2e846520eaf4ba6aa5c5c" -dependencies = [ - "hashbrown", - "memchr", -] - [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -295,7 +270,6 @@ dependencies = [ "anyhow", "clap", "ignore", - "imara-diff", "regex", ] diff --git a/src/doc/rustc-dev-guide/ci/sembr/Cargo.toml b/src/doc/rustc-dev-guide/ci/sembr/Cargo.toml index 00818e2b3c2d..46228ea47922 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/Cargo.toml +++ b/src/doc/rustc-dev-guide/ci/sembr/Cargo.toml @@ -5,7 +5,6 @@ edition = "2024" [dependencies] anyhow = "1" ignore = "0.4" -imara-diff = "0.2" [dependencies.regex] version = "1" diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index 2539a9eadda3..c19f19541846 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -5,7 +5,6 @@ use anyhow::Result; use clap::Parser; use ignore::Walk; -use imara_diff::{Algorithm, BasicLineDiffPrinter, Diff, InternedInput, UnifiedDiffConfig}; use regex::Regex; #[derive(Parser)] @@ -18,8 +17,6 @@ struct Cli { /// Applies to lines that are to be split #[arg(long, default_value_t = 100)] line_length_limit: usize, - #[arg(long)] - show_diff: bool, } static REGEX_IGNORE_END: LazyLock = @@ -54,10 +51,6 @@ fn main() -> Result<()> { } else if cli.overwrite { fs::write(&path, new)?; made_compliant.push(path.clone()); - } else if cli.show_diff { - println!("{}:", path.display()); - show_diff(&old, &new); - println!("---"); } else { not_compliant.push(path.clone()); } @@ -76,16 +69,6 @@ fn main() -> Result<()> { Ok(()) } -fn show_diff(old: &str, new: &str) { - let input = InternedInput::new(old, new); - let mut diff = Diff::compute(Algorithm::Histogram, &input); - diff.postprocess_lines(&input); - let diff = diff - .unified_diff(&BasicLineDiffPrinter(&input.interner), UnifiedDiffConfig::default(), &input) - .to_string(); - print!("{diff}"); -} - fn display(header: &str, paths: &[PathBuf]) { println!("{header}:"); for element in paths { From 64c1e97f32cacc482ccb35cfe20813169ef8f913 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 17 Dec 2025 23:40:38 +0200 Subject: [PATCH 033/126] place it all in just 2 unit tests --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 49 ++++++-------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index c19f19541846..aa34fbbb53f2 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -196,6 +196,9 @@ fn test_sembr() { sentence with *italics* should not be ignored. truly. git log main.. compiler foo. bar. baz +o? whatever +r? @reviewer + r? @reviewer "; let expected = " # some. heading @@ -221,6 +224,10 @@ fn test_sembr() { foo. bar. baz +o? +whatever +r? @reviewer + r? @reviewer "; assert_eq!(expected, comply(original)); } @@ -247,6 +254,12 @@ fn test_prettify() { leave the text alone ``` + + handle the + indented well + +[a target]: https://example.com +[another target]: https://example.com "; let expected = "\ do not split short sentences @@ -267,43 +280,11 @@ fn test_prettify() { leave the text alone ``` -"; - assert_eq!(expected, lengthen_lines(original, 50)); -} -#[test] -fn test_prettify_prefix_spaces() { - let original = "\ - do not split - short sentences -"; - let expected = "\ - do not split short sentences -"; - assert_eq!(expected, lengthen_lines(original, 50)); -} + handle the indented well -#[test] -fn test_prettify_ignore_link_targets() { - let original = "\ [a target]: https://example.com [another target]: https://example.com "; - assert_eq!(original, lengthen_lines(original, 100)); -} - -#[test] -fn test_sembr_question_mark() { - let original = " -o? whatever -r? @reviewer - r? @reviewer -"; - let expected = " -o? -whatever -r? @reviewer - r? @reviewer -"; - assert_eq!(expected, comply(original)); + assert_eq!(expected, lengthen_lines(original, 50)); } From e254e7ef2d54ee546f75db6c1a75aa6bb1b83514 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 17 Dec 2025 23:47:04 +0200 Subject: [PATCH 034/126] match fn name --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index aa34fbbb53f2..8e963627066a 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -233,7 +233,7 @@ fn test_sembr() { } #[test] -fn test_prettify() { +fn test_lengthen_lines() { let original = "\ do not split short sentences From 8b2c9d8189ab55595f3a636b9e1cfe41b0748217 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 17 Dec 2025 23:49:54 +0200 Subject: [PATCH 035/126] sembr src/about-this-guide.md --- src/doc/rustc-dev-guide/src/about-this-guide.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/about-this-guide.md b/src/doc/rustc-dev-guide/src/about-this-guide.md index 841691d859f9..2082481a200e 100644 --- a/src/doc/rustc-dev-guide/src/about-this-guide.md +++ b/src/doc/rustc-dev-guide/src/about-this-guide.md @@ -77,8 +77,7 @@ You might also find the following sites useful: - [std-dev-guide] -- a similar guide for developing the standard library. - [rust-analyzer book] -- documentation for the rust-analyzer. - [The t-compiler Zulip][z] -- The [Rust Internals forum][rif], a place to ask questions and - discuss Rust's internals +- The [Rust Internals forum][rif], a place to ask questions and discuss Rust's internals - The [Rust reference][rr], even though it doesn't specifically talk about Rust's internals, is a great resource nonetheless - Although out of date, [Tom Lee's great blog article][tlgba] is very helpful @@ -89,11 +88,10 @@ You might also find the following sites useful: the compiler, the books, the references, and the guides) to quickly find information about the language and compiler. - You can also use Rustdoc's built-in search feature to find documentation on - types and functions within the crates you're looking at. You can also search - by type signature! For example, searching for `* -> vec` should find all - functions that return a `Vec`. - _Hint:_ Find more tips and keyboard shortcuts by typing `?` on any Rustdoc - page! + types and functions within the crates you're looking at. + You can also search by type signature! + For example, searching for `* -> vec` should find all functions that return a `Vec`. + _Hint:_ Find more tips and keyboard shortcuts by typing `?` on any Rustdoc page! [rustc dev guide]: about-this-guide.md From 6a911741048a5a585c92533677b62ee65aaa8dcb Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Wed, 17 Dec 2025 23:53:15 +0200 Subject: [PATCH 036/126] sembr src/appendix/bibliography.md --- .../src/appendix/bibliography.md | 66 +++++++++++-------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/appendix/bibliography.md b/src/doc/rustc-dev-guide/src/appendix/bibliography.md index 13a9c3a0b40b..c161bba5b34f 100644 --- a/src/doc/rustc-dev-guide/src/appendix/bibliography.md +++ b/src/doc/rustc-dev-guide/src/appendix/bibliography.md @@ -1,7 +1,7 @@ # Rust Bibliography -This is a reading list of material relevant to Rust. It includes prior -research that has - at one time or another - influenced the design of +This is a reading list of material relevant to Rust. +It includes prior research that has - at one time or another - influenced the design of Rust, as well as publications about Rust. ## Type system @@ -44,8 +44,7 @@ Rust, as well as publications about Rust. ## Papers *about* Rust -* [GPU Programming in Rust: Implementing High Level Abstractions in a Systems - Level +* [GPU Programming in Rust: Implementing High Level Abstractions in a Systems Level Language](https://ieeexplore.ieee.org/document/6650903). Early GPU work by Eric Holk. * [Parallel closures: a new twist on an old @@ -55,38 +54,47 @@ Rust, as well as publications about Rust. Language](https://dada.cs.washington.edu/research/tr/2015/03/UW-CSE-15-03-02.pdf). Early formalization of a subset of the type system, by Eric Reed. * [Experience Report: Developing the Servo Web Browser Engine using - Rust](https://arxiv.org/abs/1505.07383). By Lars Bergstrom. + Rust](https://arxiv.org/abs/1505.07383). + By Lars Bergstrom. * [Implementing a Generic Radix Trie in - Rust](https://michaelsproul.github.io/rust_radix_paper/rust-radix-sproul.pdf). Undergrad - paper by Michael Sproul. + Rust](https://michaelsproul.github.io/rust_radix_paper/rust-radix-sproul.pdf). + Undergrad paper by Michael Sproul. * [Reenix: Implementing a Unix-Like Operating System in - Rust](https://scialex.github.io/reenix.pdf). Undergrad paper by Alex - Light. + Rust](https://scialex.github.io/reenix.pdf). + Undergrad paper by Alex Light. * [Evaluation of performance and productivity metrics of potential programming languages in the HPC environment](https://github.com/1wilkens/thesis-ba). - Bachelor's thesis by Florian Wilkens. Compares C, Go and Rust. + Bachelor's thesis by Florian Wilkens. + Compares C, Go and Rust. * [Nom, a byte oriented, streaming, zero copy, parser combinators library - in Rust](http://spw15.langsec.org/papers/couprie-nom.pdf). By - Geoffroy Couprie, research for VLC. + in Rust](http://spw15.langsec.org/papers/couprie-nom.pdf). + By Geoffroy Couprie, research for VLC. * [Graph-Based Higher-Order Intermediate - Representation](https://compilers.cs.uni-saarland.de/papers/lkh15_cgo.pdf). An - experimental IR implemented in Impala, a Rust-like language. -* [Code Refinement of Stencil - Codes](https://compilers.cs.uni-saarland.de/papers/ppl14_web.pdf). Another - paper using Impala. + Representation](https://compilers.cs.uni-saarland.de/papers/lkh15_cgo.pdf). + An experimental IR implemented in Impala, a Rust-like language. +* [Code Refinement of Stencil Codes](https://compilers.cs.uni-saarland.de/papers/ppl14_web.pdf). + Another paper using Impala. * [Parallelization in Rust with fork-join and - friends](http://publications.lib.chalmers.se/records/fulltext/219016/219016.pdf). Linus - Farnstrand's master's thesis. -* [Session Types for - Rust](https://munksgaard.me/papers/laumann-munksgaard-larsen.pdf). Philip - Munksgaard's master's thesis. Research for Servo. -* [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. al.](https://amitlevy.com/papers/tock-plos2015.pdf) -* [You can't spell trust without Rust](https://faultlore.com/blah/papers/thesis.pdf). Aria Beingessner's master's thesis. -* [Rust-Bio: a fast and safe bioinformatics library](https://rust-bio.github.io/). Johannes Köster -* [Safe, Correct, and Fast Low-Level Networking](https://csperkins.org/research/thesis-msci-clipsham.pdf). Robert Clipsham's master's thesis. -* [Formalizing Rust traits](https://open.library.ubc.ca/cIRcle/collections/ubctheses/24/items/1.0220521). Jonatan Milewski's master's thesis. + friends](http://publications.lib.chalmers.se/records/fulltext/219016/219016.pdf). + Linus Farnstrand's master's thesis. +* [Session Types for Rust](https://munksgaard.me/papers/laumann-munksgaard-larsen.pdf). + Philip Munksgaard's master's thesis. + Research for Servo. +* [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. + al.](https://amitlevy.com/papers/tock-plos2015.pdf) +* [You can't spell trust without Rust](https://faultlore.com/blah/papers/thesis.pdf). + Aria Beingessner's master's thesis. +* [Rust-Bio: a fast and safe bioinformatics library](https://rust-bio.github.io/). + Johannes Köster +* [Safe, Correct, and Fast Low-Level Networking](https://csperkins.org/research/thesis-msci-clipsham.pdf). + Robert Clipsham's master's thesis. +* [Formalizing Rust traits](https://open.library.ubc.ca/cIRcle/collections/ubctheses/24/items/1.0220521). + Jonatan Milewski's master's thesis. * [Rust as a Language for High Performance GC Implementation](https://dl.acm.org/doi/pdf/10.1145/3241624.2926707) -* [Simple Verification of Rust Programs via Functional Purification](https://github.com/Kha/electrolysis). Sebastian Ullrich's master's thesis. +* [Simple Verification of Rust Programs via Functional Purification](https://github.com/Kha/electrolysis). + Sebastian Ullrich's master's thesis. * [Writing parsers like it is 2017](http://spw17.langsec.org/papers/chifflier-parsing-in-2017.pdf) Pierre Chifflier and Geoffroy Couprie for the Langsec Workshop * [The Case for Writing a Kernel in Rust](https://www.tockos.org/assets/papers/rust-kernel-apsys2017.pdf) * [RustBelt: Securing the Foundations of the Rust Programming Language](https://plv.mpi-sws.org/rustbelt/popl18/) -* [Oxide: The Essence of Rust](https://arxiv.org/abs/1903.00982). By Aaron Weiss, Olek Gierczak, Daniel Patterson, Nicholas D. Matsakis, and Amal Ahmed. +* [Oxide: The Essence of Rust](https://arxiv.org/abs/1903.00982). + By Aaron Weiss, Olek Gierczak, Daniel Patterson, Nicholas D. + Matsakis, and Amal Ahmed. From f685b240d8169cd0be8b21312cec07241f7fae08 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 18 Dec 2025 00:09:33 +0200 Subject: [PATCH 037/126] fix corner case --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index 8e963627066a..2eb32491e3aa 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -80,6 +80,7 @@ fn ignore(line: &str, in_code_block: bool) -> bool { in_code_block || line.to_lowercase().contains("e.g.") || line.contains("i.e.") + || line.contains("et. al") || line.contains('|') || line.trim_start().starts_with('>') || line.starts_with('#') From e1fe9c64624a1040b88da91eef5044e3d810a537 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 18 Dec 2025 00:11:34 +0200 Subject: [PATCH 038/126] sembr src/appendix/bibliography.md (after fix from parent commit) Please enter the commit message for your changes. Lines starting --- src/doc/rustc-dev-guide/src/appendix/bibliography.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/appendix/bibliography.md b/src/doc/rustc-dev-guide/src/appendix/bibliography.md index c161bba5b34f..4f87e4d2fa00 100644 --- a/src/doc/rustc-dev-guide/src/appendix/bibliography.md +++ b/src/doc/rustc-dev-guide/src/appendix/bibliography.md @@ -79,8 +79,7 @@ Rust, as well as publications about Rust. * [Session Types for Rust](https://munksgaard.me/papers/laumann-munksgaard-larsen.pdf). Philip Munksgaard's master's thesis. Research for Servo. -* [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. - al.](https://amitlevy.com/papers/tock-plos2015.pdf) +* [Ownership is Theft: Experiences Building an Embedded OS in Rust - Amit Levy, et. al.](https://amitlevy.com/papers/tock-plos2015.pdf) * [You can't spell trust without Rust](https://faultlore.com/blah/papers/thesis.pdf). Aria Beingessner's master's thesis. * [Rust-Bio: a fast and safe bioinformatics library](https://rust-bio.github.io/). From 2dac444b7e2b7a87157b46b6a708c6fa6bce4c27 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 18 Dec 2025 00:18:45 +0200 Subject: [PATCH 039/126] sembr src/diagnostics/error-codes.md --- .../src/diagnostics/error-codes.md | 37 +++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md index c7bb6669dce4..9a302f9100f1 100644 --- a/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md +++ b/src/doc/rustc-dev-guide/src/diagnostics/error-codes.md @@ -1,24 +1,24 @@ # Error codes -We generally try to assign each error message a unique code like `E0123`. These -codes are defined in the compiler in the `diagnostics.rs` files found in each -crate, which basically consist of macros. All error codes have an associated -explanation: new error codes must include them. Note that not all _historical_ -(no longer emitted) error codes have explanations. +We generally try to assign each error message a unique code like `E0123`. +These codes are defined in the compiler in the `diagnostics.rs` files found in each +crate, which basically consist of macros. +All error codes have an associated explanation: new error codes must include them. +Note that not all _historical_ (no longer emitted) error codes have explanations. ## Error explanations The explanations are written in Markdown (see the [CommonMark Spec] for -specifics around syntax), and all of them are linked in the [`rustc_error_codes`] -crate. Please read [RFC 1567] for details on how to format and write long error -codes. As of February 2023, there is an -effort[^new-explanations] to replace this largely outdated RFC with a new more -flexible standard. +specifics around syntax), and all of them are linked in the [`rustc_error_codes`] crate. +Please read [RFC 1567] for details on how to format and write long error codes. +As of February 2023, there is an +effort[^new-explanations] to replace this largely outdated RFC with a new more flexible standard. Error explanations should expand on the error message and provide details about -_why_ the error occurs. It is not helpful for users to copy-paste a quick fix; -explanations should help users understand why their code cannot be accepted by -the compiler. Rust prides itself on helpful error messages and long-form -explanations are no exception. However, before error explanations are +_why_ the error occurs. +It is not helpful for users to copy-paste a quick fix; +explanations should help users understand why their code cannot be accepted by the compiler. +Rust prides itself on helpful error messages and long-form explanations are no exception. +However, before error explanations are overhauled[^new-explanations] it is a bit open as to how exactly they should be written, as always: ask your reviewer or ask around on the Rust Zulip. @@ -33,12 +33,12 @@ written, as always: ask your reviewer or ask around on the Rust Zulip. Error codes are stored in `compiler/rustc_error_codes`. -To create a new error, you first need to find the next available code. +To create a new error, you first need to find the next available code. You can find it by opening `rustc_error_codes/src/lib.rs` and scrolling down to the end of the `error_codes!` macro declaration. -Here we might see the highest error code in use is `E0805`, so we _probably_ want -`E0806`. To be sure, run `rg E0806` and check, you should see no references. +Here we might see the highest error code in use is `E0805`, so we _probably_ want `E0806`. +To be sure, run `rg E0806` and check, you should see no references. You will have to write an extended description for your error, which will go in `rustc_error_codes/src/error_codes/E0806.md`. @@ -62,8 +62,7 @@ struct_span_code_err!(self.dcx(), // some path to the `DiagCtxt` here .emit() // actually issue the error ``` -If you want to add notes or other snippets, you can invoke methods before you -call `.emit()`: +If you want to add notes or other snippets, you can invoke methods before you call `.emit()`: ```rust struct_span_code_err!(...) From 5e1352b6318d1e10560546c831f682debf0e43f4 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 18 Dec 2025 00:25:13 +0200 Subject: [PATCH 040/126] sembr src/query.md --- src/doc/rustc-dev-guide/src/query.md | 104 ++++++++++++++------------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 5df9de762038..28e421acb207 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -2,11 +2,13 @@ As described in [Overview of the compiler], the Rust compiler is still (as of July 2021) transitioning from a -traditional "pass-based" setup to a "demand-driven" system. The compiler query -system is the key to rustc's demand-driven organization. -The idea is pretty simple. Instead of entirely independent passes +traditional "pass-based" setup to a "demand-driven" system. +The compiler query system is the key to rustc's demand-driven organization. +The idea is pretty simple. +Instead of entirely independent passes (parsing, type-checking, etc.), a set of function-like *queries* -compute information about the input source. For example, +compute information about the input source. +For example, there is a query called `type_of` that, given the [`DefId`] of some item, will compute the type of that item and return it to you. @@ -14,25 +16,21 @@ some item, will compute the type of that item and return it to you. [Overview of the compiler]: overview.md#queries Query execution is *memoized*. The first time you invoke a -query, it will go do the computation, but the next time, the result is -returned from a hashtable. Moreover, query execution fits nicely into +query, it will go do the computation, but the next time, the result is returned from a hashtable. +Moreover, query execution fits nicely into *incremental computation*; the idea is roughly that, when you invoke a -query, the result *may* be returned to you by loading stored data -from disk.[^incr-comp-detail] +query, the result *may* be returned to you by loading stored data from disk.[^incr-comp-detail] -Eventually, we want the entire compiler -control-flow to be query driven. There will effectively be one -top-level query (`compile`) that will run compilation on a crate; this -will in turn demand information about that crate, starting from the -*end*. For example: +Eventually, we want the entire compiler control-flow to be query driven. +There will effectively be one top-level query (`compile`) that will run compilation on a crate; this +will in turn demand information about that crate, starting from the *end*. For example: - The `compile` query might demand to get a list of codegen-units (i.e. modules that need to be compiled by LLVM). - But computing the list of codegen-units would invoke some subquery that returns the list of all modules defined in the Rust source. - That query in turn would invoke something asking for the HIR. -- This keeps going further and further back until we wind up doing the - actual parsing. +- This keeps going further and further back until we wind up doing the actual parsing. Although this vision is not fully realized, large sections of the compiler (for example, generating [MIR]) currently work exactly like this. @@ -46,9 +44,9 @@ If you intend to write a query of your own, this is a good read. ## Invoking queries -Invoking a query is simple. The [`TyCtxt`] ("type context") struct offers a method -for each defined query. For example, to invoke the `type_of` -query, you would just do this: +Invoking a query is simple. +The [`TyCtxt`] ("type context") struct offers a method for each defined query. +For example, to invoke the `type_of` query, you would just do this: ```rust,ignore let ty = tcx.type_of(some_def_id); @@ -58,8 +56,8 @@ let ty = tcx.type_of(some_def_id); ## How the compiler executes a query -So you may be wondering what happens when you invoke a query -method. The answer is that, for each query, the compiler maintains a +So you may be wondering what happens when you invoke a query method. +The answer is that, for each query, the compiler maintains a cache – if your query has already been executed, then, the answer is simple: we clone the return value out of the cache and return it (therefore, you should try to ensure that the return types of queries @@ -68,11 +66,12 @@ are cheaply cloneable; insert an `Rc` if necessary). ### Providers If, however, the query is *not* in the cache, then the compiler will -call the corresponding **provider** function. A provider is a function -implemented in a specific module and **manually registered** into either +call the corresponding **provider** function. +A provider is a function implemented in a specific module and **manually registered** into either the [`Providers`][providers_struct] struct (for local crate queries) or the [`ExternProviders`][extern_providers_struct] struct (for external crate queries) -during compiler initialization. The macro system generates both structs, +during compiler initialization. +The macro system generates both structs, which act as function tables for all query implementations, where each field is a function pointer to the actual provider. @@ -80,8 +79,8 @@ field is a function pointer to the actual provider. They are **not** Rust traits, but plain structs with function pointer fields. **Providers are defined per-crate.** The compiler maintains, -internally, a table of providers for every crate, at least -conceptually. There are two sets of providers: +internally, a table of providers for every crate, at least conceptually. +There are two sets of providers: - The `Providers` struct for queries about the **local crate** (that is, the one being compiled) - The `ExternProviders` struct for queries about **external crates** (that is, dependencies of the local crate) @@ -89,8 +88,7 @@ dependencies of the local crate) Note that what determines the crate that a query is targeting is not the *kind* of query, but the *key*. For example, when you invoke `tcx.type_of(def_id)`, that could be a local query or an external query, depending on what crate the `def_id` -is referring to (see the [`self::keys::Key`][Key] trait for more -information on how that works). +is referring to (see the [`self::keys::Key`][Key] trait for more information on how that works). Providers always have the same signature: @@ -106,10 +104,11 @@ fn provider<'tcx>( Providers take two arguments: the `tcx` and the query key. They return the result of the query. -N.B. Most of the `rustc_*` crates only provide **local +N.B. +Most of the `rustc_*` crates only provide **local providers**. Almost all **extern providers** wind up going through the -[`rustc_metadata` crate][rustc_metadata], which loads the information -from the crate metadata. But in some cases there are crates that +[`rustc_metadata` crate][rustc_metadata], which loads the information from the crate metadata. +But in some cases there are crates that provide queries for *both* local and external crates, in which case they define both a `provide` and a `provide_extern` function, through [`wasm_import_module_map`][wasm_import_module_map], that `rustc_driver` can invoke. @@ -120,7 +119,8 @@ they define both a `provide` and a `provide_extern` function, through ### How providers are set up When the tcx is created, it is given both the local and external providers by its creator using -the `Providers` struct from `rustc_middle::util`. This struct contains both the local and external providers: +the `Providers` struct from `rustc_middle::util`. +This struct contains both the local and external providers: ```rust,ignore pub struct Providers { @@ -134,7 +134,7 @@ Each of these provider structs is generated by the macros and contains function #### How are providers registered? -The `util::Providers` struct is filled in during compiler initialization, by the `rustc_interface` crate from the `DEFAULT_QUERY_PROVIDERS` static. +The `util::Providers` struct is filled in during compiler initialization, by the `rustc_interface` crate from the `DEFAULT_QUERY_PROVIDERS` static. The actual provider functions are defined across various `rustc_*` crates (like `rustc_middle`, `rustc_hir_analysis`, etc). To register providers, each crate exposes a [`provide`][provide_fn] function that looks like this: @@ -151,7 +151,9 @@ pub fn provide(providers: &mut query::Providers) { } ``` -Note that this function accepts `query::Providers` not `util::Providers`. It is exceedingly rare to need a `provide` function that doesn't just accept `query::Providers`. If more than the `queries` field of `util::Providers` is being updated then `util::Providers` can be accepted instead: +Note that this function accepts `query::Providers` not `util::Providers`. +It is exceedingly rare to need a `provide` function that doesn't just accept `query::Providers`. +If more than the `queries` field of `util::Providers` is being updated then `util::Providers` can be accepted instead: ```rust,ignore pub fn provide(providers: &mut rustc_middle::util::Providers) { providers.queries.type_of = type_of; @@ -173,7 +175,8 @@ Note that `util::Providers` implements `DerefMut` to `query::Providers` so calle #### Adding a new provider -Suppose you want to add a new query called `fubar`. This section focuses on wiring up the providers; for how to declare the query itself in the big `rustc_queries!` macro, see [Adding a new query](#adding-a-new-query) below. +Suppose you want to add a new query called `fubar`. +This section focuses on wiring up the providers; for how to declare the query itself in the big `rustc_queries!` macro, see [Adding a new query](#adding-a-new-query) below. In practice you usually: @@ -184,7 +187,8 @@ In practice you usually: // existing assignments } ``` - If it exists, you will extend it to set the field for your new query. If the crate does not yet have a `provide` function, add one and make sure it is included in `DEFAULT_QUERY_PROVIDERS` in the `rustc_interface` crate so that it actually gets called during initialization (see the discussion above). + If it exists, you will extend it to set the field for your new query. + If the crate does not yet have a `provide` function, add one and make sure it is included in `DEFAULT_QUERY_PROVIDERS` in the `rustc_interface` crate so that it actually gets called during initialization (see the discussion above). 3. Implement the provider function itself: ```rust,ignore fn fubar<'tcx>(tcx: TyCtxt<'tcx>, key: LocalDefId) -> Fubar<'tcx> { ... } @@ -210,7 +214,8 @@ The process works like this: This determines whether to use the local provider from [`Providers`][providers_struct] or the external provider from [`ExternProviders`][extern_providers_struct]. 2. For external crates, the query system will look for a provider in the [`ExternProviders`][extern_providers_struct] struct. - The `rustc_metadata` crate registers these external providers through the `provide_extern` function in `rustc_metadata/src/rmeta/decoder/cstore_impl.rs`. Just like: + The `rustc_metadata` crate registers these external providers through the `provide_extern` function in `rustc_metadata/src/rmeta/decoder/cstore_impl.rs`. + Just like: ```rust pub fn provide_extern(providers: &mut ExternProviders) { providers.foo = |tcx, def_id| { @@ -222,7 +227,8 @@ The process works like this: } ``` -3. The metadata is stored in a binary format in `.rmeta` files that contains pre-computed information about the external crate, such as types, function signatures, trait implementations, and other information needed by the compiler. When an external query is made, the `rustc_metadata` crate: +3. The metadata is stored in a binary format in `.rmeta` files that contains pre-computed information about the external crate, such as types, function signatures, trait implementations, and other information needed by the compiler. + When an external query is made, the `rustc_metadata` crate: - Loads the `.rmeta` file for the external crate - Decodes the metadata using the `Decodable` trait - Returns the decoded information to the query system @@ -234,10 +240,11 @@ Here is a simplified example, when you call `tcx.type_of(def_id)` for a type def 3. The provider will load and decode the type information from the external crate's metadata 4. Return the decoded type to the caller -This is why most `rustc_*` crates only need to provide local providers - the external providers are handled by the metadata system. +This is why most `rustc_*` crates only need to provide local providers - the external providers are handled by the metadata system. The only exception is when a crate needs to provide special handling for external queries, in which case it would implement both local and external providers. -When we define a new query that should work across crates, it does not automatically become cross-crate just because it is listed in `rustc_queries!`. You will typically need to: +When we define a new query that should work across crates, it does not automatically become cross-crate just because it is listed in `rustc_queries!`. +You will typically need to: - Add the query to `rustc_queries!` with appropriate modifiers (for example whether it is cached on disk). - Implement a local provider in the owning crate and register it via that crate's `provide` function. @@ -296,17 +303,16 @@ query keyword Let's go over these elements one by one: - **Query keyword:** indicates a start of a query definition. -- **Name of query:** the name of the query method - (`tcx.type_of(..)`). Also used as the name of a struct - (`ty::queries::type_of`) that will be generated to represent +- **Name of query:** the name of the query method (`tcx.type_of(..)`). + Also used as the name of a struct (`ty::queries::type_of`) that will be generated to represent this query. - **Query key type:** the type of the argument to this query. This type must implement the [`ty::query::keys::Key`][Key] trait, which defines (for example) how to map it to a crate, and so forth. -- **Result type of query:** the type produced by this query. This type - should (a) not use `RefCell` or other interior mutability and (b) be - cheaply cloneable. Interning or using `Rc` or `Arc` is recommended for - non-trivial data types.[^steal] +- **Result type of query:** the type produced by this query. + This type should (a) not use `RefCell` or other interior mutability and (b) be + cheaply cloneable. + Interning or using `Rc` or `Arc` is recommended for non-trivial data types.[^steal] - **Query modifiers:** various flags and options that customize how the query is processed (mostly with respect to [incremental compilation][incrcomp]). @@ -320,9 +326,9 @@ So, to add a query: or add a new one if needed and ensure that `rustc_driver` is invoking it. [^steal]: The one exception to those rules is the `ty::steal::Steal` type, -which is used to cheaply modify MIR in place. See the definition -of `Steal` for more details. New uses of `Steal` should **not** be -added without alerting `@rust-lang/compiler`. +which is used to cheaply modify MIR in place. +See the definition of `Steal` for more details. +New uses of `Steal` should **not** be added without alerting `@rust-lang/compiler`. ## External links From 40d05f8108b551e435445a86977d7d8e8b2e2cfa Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 18 Dec 2025 00:36:27 +0200 Subject: [PATCH 041/126] corner case --- src/doc/rustc-dev-guide/ci/sembr/src/main.rs | 1 + src/doc/rustc-dev-guide/src/query.md | 9 ++++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs index 2eb32491e3aa..d41a57d6f747 100644 --- a/src/doc/rustc-dev-guide/ci/sembr/src/main.rs +++ b/src/doc/rustc-dev-guide/ci/sembr/src/main.rs @@ -79,6 +79,7 @@ fn display(header: &str, paths: &[PathBuf]) { fn ignore(line: &str, in_code_block: bool) -> bool { in_code_block || line.to_lowercase().contains("e.g.") + || line.to_lowercase().contains("n.b.") || line.contains("i.e.") || line.contains("et. al") || line.contains('|') diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 28e421acb207..90bb08d8abcd 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -104,8 +104,7 @@ fn provider<'tcx>( Providers take two arguments: the `tcx` and the query key. They return the result of the query. -N.B. -Most of the `rustc_*` crates only provide **local +N.B. Most of the `rustc_*` crates only provide **local providers**. Almost all **extern providers** wind up going through the [`rustc_metadata` crate][rustc_metadata], which loads the information from the crate metadata. But in some cases there are crates that @@ -158,10 +157,10 @@ If more than the `queries` field of `util::Providers` is being updated then `ut pub fn provide(providers: &mut rustc_middle::util::Providers) { providers.queries.type_of = type_of; // ... add more local providers here - + providers.extern_queries.type_of = extern_type_of; // ... add more external providers here - + providers.hooks.some_hook = some_hook; // ... add more hooks here } @@ -205,7 +204,7 @@ In practice you usually: ### How queries interact with external crate metadata -When a query is made for an external crate (i.e., a dependency), the query system needs to load the information from that crate's metadata. +When a query is made for an external crate (i.e., a dependency), the query system needs to load the information from that crate's metadata. This is handled by the [`rustc_metadata` crate][rustc_metadata], which is responsible for decoding and providing the information stored in the `.rmeta` files. The process works like this: From 2fe2052bbec7bab1951712ddde3f3c0863575c4d Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 18 Dec 2025 00:40:03 +0200 Subject: [PATCH 042/126] manual sembr --- src/doc/rustc-dev-guide/src/query.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/query.md b/src/doc/rustc-dev-guide/src/query.md index 90bb08d8abcd..1961d68509f9 100644 --- a/src/doc/rustc-dev-guide/src/query.md +++ b/src/doc/rustc-dev-guide/src/query.md @@ -23,7 +23,9 @@ query, the result *may* be returned to you by loading stored data from disk.[^in Eventually, we want the entire compiler control-flow to be query driven. There will effectively be one top-level query (`compile`) that will run compilation on a crate; this -will in turn demand information about that crate, starting from the *end*. For example: +will in turn demand information about that crate, starting from the *end*. + +For example: - The `compile` query might demand to get a list of codegen-units (i.e. modules that need to be compiled by LLVM). From 4673d56b4178fbbccb428784f9a1c706bdcc8f3f Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 18 Dec 2025 00:41:31 +0200 Subject: [PATCH 043/126] sembr src/conventions.md --- src/doc/rustc-dev-guide/src/conventions.md | 64 ++++++++++------------ 1 file changed, 29 insertions(+), 35 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index 92ed0825c8c3..36ea0c584240 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -1,9 +1,8 @@ # Coding conventions -This file offers some tips on the coding conventions for rustc. This -chapter covers [formatting](#formatting), [coding for correctness](#cc), -[using crates from crates.io](#cio), and some tips on -[structuring your PR for easy review](#er). +This file offers some tips on the coding conventions for rustc. +This chapter covers [formatting](#formatting), [coding for correctness](#cc), +[using crates from crates.io](#cio), and some tips on [structuring your PR for easy review](#er). @@ -15,11 +14,11 @@ However, for now we don't use stable `rustfmt`; we use a pinned version with a special config, so this may result in different style from normal [`rustfmt`]. Therefore, formatting this repository using `cargo fmt` is not recommended. -Instead, formatting should be done using `./x fmt`. It's a good habit to run -`./x fmt` before every commit, as this reduces conflicts later. +Instead, formatting should be done using `./x fmt`. +It's a good habit to run `./x fmt` before every commit, as this reduces conflicts later. -Formatting is checked by the `tidy` script. It runs automatically when you do -`./x test` and can be run in isolation with `./x fmt --check`. +Formatting is checked by the `tidy` script. +It runs automatically when you do `./x test` and can be run in isolation with `./x fmt --check`. > **Note: Formatting and test suites** > @@ -47,13 +46,12 @@ When modifying that code, use this command to format it: ./x test tidy --extra-checks cpp:fmt --bless ``` -This uses a pinned version of `clang-format`, to avoid relying on the local -environment. +This uses a pinned version of `clang-format`, to avoid relying on the local environment. ### Formatting and linting Python code -The Rust repository contains quite a lot of Python code. We try to keep -it both linted and formatted by the [ruff] tool. +The Rust repository contains quite a lot of Python code. +We try to keep it both linted and formatted by the [ruff] tool. When modifying Python code, use this command to format it: @@ -78,8 +76,8 @@ These use a pinned version of `ruff`, to avoid relying on the local environment. ### Copyright notice -In the past, files began with a copyright and license notice. Please **omit** -this notice for new files licensed under the standard terms (dual +In the past, files began with a copyright and license notice. +Please **omit** this notice for new files licensed under the standard terms (dual MIT/Apache-2.0). All of the copyright notices should be gone by now, but if you come across one @@ -87,8 +85,8 @@ in the rust-lang/rust repo, feel free to open a PR to remove it. ### Line length -Lines should be at most 100 characters. It's even better if you can -keep things to 80. +Lines should be at most 100 characters. +It's even better if you can keep things to 80. Sometimes, and particularly for tests, it can be necessary to exempt yourself from this limit. In that case, you can add a comment towards the top of the file like so: @@ -105,17 +103,15 @@ Prefer 4-space indents. ## Coding for correctness -Beyond formatting, there are a few other tips that are worth -following. +Beyond formatting, there are a few other tips that are worth following. ### Prefer exhaustive matches Using `_` in a match is convenient, but it means that when new variants are added to the enum, they may not get handled correctly. Ask yourself: if a new variant were added to this enum, what's the -chance that it would want to use the `_` code, versus having some -other treatment? Unless the answer is "low", then prefer an -exhaustive match. +chance that it would want to use the `_` code, versus having some other treatment? +Unless the answer is "low", then prefer an exhaustive match. The same advice applies to `if let` and `while let`, which are effectively tests for a single variant. @@ -155,41 +151,39 @@ See the [crates.io dependencies][crates] section. ## How to structure your PR -How you prepare the commits in your PR can make a big difference for the -reviewer. Here are some tips. +How you prepare the commits in your PR can make a big difference for the reviewer. +Here are some tips. **Isolate "pure refactorings" into their own commit.** For example, if you rename a method, then put that rename into its own commit, along with the renames of all the uses. **More commits is usually better.** If you are doing a large change, -it's almost always better to break it up into smaller steps that can -be independently understood. The one thing to be aware of is that if +it's almost always better to break it up into smaller steps that can be independently understood. +The one thing to be aware of is that if you introduce some code following one strategy, then change it -dramatically (versus adding to it) in a later commit, that -'back-and-forth' can be confusing. +dramatically (versus adding to it) in a later commit, that 'back-and-forth' can be confusing. **Format liberally.** While only the final commit of a PR must be correctly formatted, it is both easier to review and less noisy to format each commit individually using `./x fmt`. -**No merges.** We do not allow merge commits into our history, other -than those by bors. If you get a merge conflict, rebase instead via a +**No merges.** We do not allow merge commits into our history, other than those by bors. +If you get a merge conflict, rebase instead via a command like `git rebase --interactive rust-lang/main` (presuming you use the name `rust-lang` for your remote). **Individual commits do not have to build (but it's nice).** We do not require that every intermediate commit successfully builds – we only -expect to be able to bisect at a PR level. However, if you *can* make -individual commits build, that is always helpful. +expect to be able to bisect at a PR level. +However, if you *can* make individual commits build, that is always helpful. ## Naming conventions -Apart from normal Rust style/naming conventions, there are also some specific -to the compiler. +Apart from normal Rust style/naming conventions, there are also some specific to the compiler. -- `cx` tends to be short for "context" and is often used as a suffix. For - example, `tcx` is a common name for the [Typing Context][tcx]. +- `cx` tends to be short for "context" and is often used as a suffix. + For example, `tcx` is a common name for the [Typing Context][tcx]. - [`'tcx`][tcx] is used as the lifetime name for the Typing Context. From 3aa4a794a7e76fd0977dcd9d020bfd59aa9a43be Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Thu, 18 Dec 2025 00:48:43 +0200 Subject: [PATCH 044/126] that basically repeats the title --- src/doc/rustc-dev-guide/src/conventions.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/conventions.md b/src/doc/rustc-dev-guide/src/conventions.md index 36ea0c584240..5153f2c5711a 100644 --- a/src/doc/rustc-dev-guide/src/conventions.md +++ b/src/doc/rustc-dev-guide/src/conventions.md @@ -1,6 +1,5 @@ # Coding conventions -This file offers some tips on the coding conventions for rustc. This chapter covers [formatting](#formatting), [coding for correctness](#cc), [using crates from crates.io](#cio), and some tips on [structuring your PR for easy review](#er). From 186fc3c0003c70f73e7cdeddd51d2531c033d82a Mon Sep 17 00:00:00 2001 From: Redddy Date: Thu, 18 Dec 2025 12:00:12 +0900 Subject: [PATCH 045/126] Clarify serialization macros documentation remove `MetadataDecodable` and add `BlobDecodable` and `LazyDecodable`. --- src/doc/rustc-dev-guide/src/serialization.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/serialization.md b/src/doc/rustc-dev-guide/src/serialization.md index a6c2ee17a667..fcea4f3e605b 100644 --- a/src/doc/rustc-dev-guide/src/serialization.md +++ b/src/doc/rustc-dev-guide/src/serialization.md @@ -126,20 +126,21 @@ and `Encodable`. all `Encoders` and `Decoders`. These should be used in crates that don't depend on [`rustc_middle`], or that have to be serialized by a type that does not implement `TyEncoder`. -- [`MetadataEncodable`] and [`MetadataDecodable`] generate implementations that - only allow decoding by [`rustc_metadata::rmeta::encoder::EncodeContext`] and - [`rustc_metadata::rmeta::decoder::DecodeContext`]. These are used for types - that contain [`rustc_metadata::rmeta::`]`Lazy*`. +- [`MetadataEncodable`] generate implementations that + only allow decoding by [`rustc_metadata::rmeta::encoder::EncodeContext`]. +- [`BlobDecodable`] and [`LazyDecodable`] generate implementations that decode + with the metadata blob decoders in [`rustc_metadata::rmeta`]; use `BlobDecodable` + when the type has no lazy metadata handles, and `LazyDecodable` when it does. - `TyEncodable` and `TyDecodable` generate implementation that apply to any `TyEncoder` or `TyDecoder`. These should be used for types that are only serialized in crate metadata and/or the incremental cache, which is most serializable types in `rustc_middle`. -[`MetadataDecodable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_macros/derive.MetadataDecodable.html +[`BlobDecodable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_macros/derive.BlobDecodable.html +[`LazyDecodable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_macros/derive.LazyDecodable.html [`MetadataEncodable`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_macros/derive.MetadataEncodable.html [`rustc_macros`]: https://github.com/rust-lang/rust/tree/HEAD/compiler/rustc_macros -[`rustc_metadata::rmeta::`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/index.html -[`rustc_metadata::rmeta::decoder::DecodeContext`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/decoder/struct.DecodeContext.html +[`rustc_metadata::rmeta`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/index.html [`rustc_metadata::rmeta::encoder::EncodeContext`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_metadata/rmeta/encoder/struct.EncodeContext.html [`rustc_middle`]: https://github.com/rust-lang/rust/tree/HEAD/compiler/rustc_middle From c92d39e454c407bc78820fa610bf9576ee995a4d Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Thu, 18 Dec 2025 04:58:27 +0000 Subject: [PATCH 046/126] Prepare for merging from rust-lang/rust This updates the rust-version file to 686f9cefc37c5bdec069a75357f0277b390657ca. --- 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 dcf82c94aaee..11c138c28c24 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -0208ee09be465f69005a7a12c28d5eccac7d5f34 +686f9cefc37c5bdec069a75357f0277b390657ca From b48defae19f25b821fbd4236e2abf44823160f27 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Fri, 12 Dec 2025 11:53:05 -0800 Subject: [PATCH 047/126] Implement FlushFileBuffers --- .../miri/src/shims/windows/foreign_items.rs | 5 +++ src/tools/miri/src/shims/windows/fs.rs | 33 +++++++++++++++++++ src/tools/miri/tests/pass/shims/fs.rs | 14 +++++--- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs index 7d30582c582c..3bc52dddfe8b 100644 --- a/src/tools/miri/src/shims/windows/foreign_items.rs +++ b/src/tools/miri/src/shims/windows/foreign_items.rs @@ -313,6 +313,11 @@ fn emulate_foreign_item_inner( let res = this.SetFileInformationByHandle(handle, class, info, size)?; this.write_scalar(res, dest)?; } + "FlushFileBuffers" => { + let [handle] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; + let res = this.FlushFileBuffers(handle)?; + this.write_scalar(res, dest)?; + } "DeleteFileW" => { let [file_name] = this.check_shim_sig_lenient(abi, sys_conv, link_name, args)?; let res = this.DeleteFileW(file_name)?; diff --git a/src/tools/miri/src/shims/windows/fs.rs b/src/tools/miri/src/shims/windows/fs.rs index 967164cb250d..e5a98e86d645 100644 --- a/src/tools/miri/src/shims/windows/fs.rs +++ b/src/tools/miri/src/shims/windows/fs.rs @@ -457,6 +457,39 @@ fn SetFileInformationByHandle( } } + fn FlushFileBuffers( + &mut self, + file: &OpTy<'tcx>, // HANDLE + ) -> InterpResult<'tcx, Scalar> { + // ^ returns BOOL (i32 on Windows) + let this = self.eval_context_mut(); + this.assert_target_os(Os::Windows, "FlushFileBuffers"); + + let file = this.read_handle(file, "FlushFileBuffers")?; + let Handle::File(fd_num) = file else { this.invalid_handle("FlushFileBuffers")? }; + let Some(desc) = this.machine.fds.get(fd_num) else { + this.invalid_handle("FlushFileBuffers")? + }; + let file = desc.downcast::().ok_or_else(|| { + err_unsup_format!( + "`FlushFileBuffers` is only supported on file-backed file descriptors" + ) + })?; + + if !file.writable { + this.set_last_error(IoError::WindowsError("ERROR_ACCESS_DENIED"))?; + return interp_ok(this.eval_windows("c", "FALSE")); + } + + match file.file.sync_all() { + Ok(_) => interp_ok(this.eval_windows("c", "TRUE")), + Err(e) => { + this.set_last_error(e)?; + interp_ok(this.eval_windows("c", "FALSE")) + } + } + } + fn DeleteFileW( &mut self, file_name: &OpTy<'tcx>, // LPCWSTR diff --git a/src/tools/miri/tests/pass/shims/fs.rs b/src/tools/miri/tests/pass/shims/fs.rs index 70bca703cc2f..648c90b5dd97 100644 --- a/src/tools/miri/tests/pass/shims/fs.rs +++ b/src/tools/miri/tests/pass/shims/fs.rs @@ -29,9 +29,9 @@ fn main() { test_from_raw_os_error(); test_file_clone(); test_file_set_len(); + test_file_sync(); // Windows file handling is very incomplete. if cfg!(not(windows)) { - test_file_sync(); test_rename(); test_directory(); test_canonicalize(); @@ -231,10 +231,16 @@ fn test_file_sync() { file.sync_data().unwrap(); file.sync_all().unwrap(); - // Test that we can call sync_data and sync_all on a file opened for reading. + // Test that we can call sync_data and sync_all on a file opened for reading on unix, but not + // on Windows let file = File::open(&path).unwrap(); - file.sync_data().unwrap(); - file.sync_all().unwrap(); + if cfg!(unix) { + file.sync_data().unwrap(); + file.sync_all().unwrap(); + } else { + file.sync_data().unwrap_err(); + file.sync_all().unwrap_err(); + } remove_file(&path).unwrap(); } From b63e6fb7d238ec986cb89454a8fe93bfa3611604 Mon Sep 17 00:00:00 2001 From: Rune Tynan Date: Fri, 12 Dec 2025 11:56:35 -0800 Subject: [PATCH 048/126] Implement direct shim test --- .../miri/tests/pass-dep/shims/windows-fs.rs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs index 0037f34d3c9a..91639c502325 100644 --- a/src/tools/miri/tests/pass-dep/shims/windows-fs.rs +++ b/src/tools/miri/tests/pass-dep/shims/windows-fs.rs @@ -22,8 +22,8 @@ FILE_ALLOCATION_INFO, FILE_ATTRIBUTE_DIRECTORY, FILE_ATTRIBUTE_NORMAL, FILE_BEGIN, FILE_CURRENT, FILE_END_OF_FILE_INFO, FILE_FLAG_BACKUP_SEMANTICS, FILE_FLAG_OPEN_REPARSE_POINT, FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE, FileAllocationInfo, FileEndOfFileInfo, - GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, SetFileInformationByHandle, - SetFilePointerEx, + FlushFileBuffers, GetFileInformationByHandle, OPEN_ALWAYS, OPEN_EXISTING, + SetFileInformationByHandle, SetFilePointerEx, }; use windows_sys::Win32::System::IO::IO_STATUS_BLOCK; use windows_sys::Win32::System::Threading::GetCurrentProcess; @@ -41,6 +41,7 @@ fn main() { test_file_seek(); test_set_file_info(); test_dup_handle(); + test_flush_buffers(); } } @@ -362,6 +363,19 @@ unsafe fn test_file_seek() { assert_eq!(pos, 5); } +unsafe fn test_flush_buffers() { + let temp = utils::tmp().join("test_flush_buffers.txt"); + let file = fs::File::options().create(true).write(true).read(true).open(&temp).unwrap(); + if FlushFileBuffers(file.as_raw_handle()) == 0 { + panic!("Failed to flush buffers"); + } + + let file = fs::File::options().read(true).open(&temp).unwrap(); + if FlushFileBuffers(file.as_raw_handle()) != 0 { + panic!("Successfully flushed buffers on read-only file"); + } +} + fn to_wide_cstr(path: &Path) -> Vec { let mut raw_path = path.as_os_str().encode_wide().collect::>(); raw_path.extend([0, 0]); From 3fd2d64dc4e47b9a4ae9e9ac7fa430ffe6a24d19 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Dec 2025 08:09:56 +0100 Subject: [PATCH 049/126] remove spin_loop hint intrinsics we no longer need --- src/tools/miri/src/shims/aarch64.rs | 14 -------------- src/tools/miri/src/shims/foreign_items.rs | 16 ---------------- 2 files changed, 30 deletions(-) diff --git a/src/tools/miri/src/shims/aarch64.rs b/src/tools/miri/src/shims/aarch64.rs index 6e422b4ab716..595a6595b531 100644 --- a/src/tools/miri/src/shims/aarch64.rs +++ b/src/tools/miri/src/shims/aarch64.rs @@ -19,20 +19,6 @@ fn emulate_aarch64_intrinsic( // Prefix should have already been checked. let unprefixed_name = link_name.as_str().strip_prefix("llvm.aarch64.").unwrap(); match unprefixed_name { - "isb" => { - let [arg] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let arg = this.read_scalar(arg)?.to_i32()?; - match arg { - // SY ("full system scope") - 15 => { - this.yield_active_thread(); - } - _ => { - throw_unsup_format!("unsupported llvm.aarch64.isb argument {}", arg); - } - } - } - // Used to implement the vpmaxq_u8 function. // Computes the maximum of adjacent pairs; the first half of the output is produced from the // `left` input, the second half of the output from the `right` input. diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs index 48f4ca53cdca..74ae93348d58 100644 --- a/src/tools/miri/src/shims/foreign_items.rs +++ b/src/tools/miri/src/shims/foreign_items.rs @@ -813,22 +813,6 @@ fn emulate_foreign_item_inner( this, link_name, abi, args, dest, ); } - // FIXME: Move this to an `arm` submodule. - "llvm.arm.hint" if this.tcx.sess.target.arch == Arch::Arm => { - let [arg] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; - let arg = this.read_scalar(arg)?.to_i32()?; - // Note that different arguments might have different target feature requirements. - match arg { - // YIELD - 1 => { - this.expect_target_feature_for_intrinsic(link_name, "v6")?; - this.yield_active_thread(); - } - _ => { - throw_unsup_format!("unsupported llvm.arm.hint argument {}", arg); - } - } - } // Fallback to shims in submodules. _ => { From 1dff3e71a46c4bdde01ba52c37c07902ed089c6e Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Thu, 18 Dec 2025 01:25:57 -0800 Subject: [PATCH 050/126] stabilization_guide: add missing `)` in prose --- src/doc/rustc-dev-guide/src/stabilization_guide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/stabilization_guide.md b/src/doc/rustc-dev-guide/src/stabilization_guide.md index 19296b22cecf..6167546a2bc8 100644 --- a/src/doc/rustc-dev-guide/src/stabilization_guide.md +++ b/src/doc/rustc-dev-guide/src/stabilization_guide.md @@ -64,7 +64,7 @@ Before the stabilization will be considered by the lang team, there must be a co There is a central listing of unstable feature-gates in [`compiler/rustc_feature/src/unstable.rs`]. Search for the `declare_features!` macro. There should be an entry for the feature you are aiming to stabilize, -something like the following (taken from [rust-lang/rust#32409]: +something like the following (taken from [rust-lang/rust#32409]): ```rust,ignore // pub(restricted) visibilities (RFC 1422) From 45671b42e6b951c065d73b9f7ccaa0ff576cf9cb Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 18 Dec 2025 11:50:08 +0000 Subject: [PATCH 051/126] Merge commit '8de4afd39ba48f25be98684cdb7a96ec6da89d10' into sync_cg_clif-2025-12-18 --- .github/workflows/main.yml | 8 ++++---- .github/workflows/rustc.yml | 4 ++-- example/std_example.rs | 18 ++++++++++++++++++ rust-toolchain | 4 ---- rust-toolchain.toml | 4 ++++ scripts/rustup.sh | 5 ++--- scripts/test_rustc_tests.sh | 29 ++++++++++++++++++++++++----- src/driver/jit.rs | 2 +- src/intrinsics/llvm_x86.rs | 29 +++++++++++++++++++++++++++++ triagebot.toml | 3 --- 10 files changed, 84 insertions(+), 22 deletions(-) delete mode 100644 rust-toolchain create mode 100644 rust-toolchain.toml diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 0930b924d177..07d9af4a9b54 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -28,7 +28,7 @@ jobs: - name: Avoid installing rustc-dev run: | - sed -i 's/components.*/components = ["rustfmt"]/' rust-toolchain + sed -i 's/components.*/components = ["rustfmt"]/' rust-toolchain.toml rustfmt -v - name: Rustfmt @@ -88,7 +88,7 @@ jobs: uses: actions/cache@v4 with: path: build/cg_clif - key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} - name: Set MinGW as the default toolchain if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' @@ -158,7 +158,7 @@ jobs: uses: actions/cache@v4 with: path: build/cg_clif - key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + key: ${{ runner.os }}-x86_64-unknown-linux-gnu-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} - name: Install hyperfine run: | @@ -207,7 +207,7 @@ jobs: uses: actions/cache@v4 with: path: build/cg_clif - key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-dist-cargo-build-target-${{ hashFiles('rust-toolchain.toml', '**/Cargo.lock') }} - name: Set MinGW as the default toolchain if: matrix.os == 'windows-latest' && matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu' diff --git a/.github/workflows/rustc.yml b/.github/workflows/rustc.yml index 9253ab96353c..b22725fdc9d4 100644 --- a/.github/workflows/rustc.yml +++ b/.github/workflows/rustc.yml @@ -20,7 +20,7 @@ jobs: uses: actions/cache@v4 with: path: build/cg_clif - key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }} + key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }} - name: Test run: ./scripts/test_bootstrap.sh @@ -40,7 +40,7 @@ jobs: uses: actions/cache@v4 with: path: build/cg_clif - key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain', 'Cargo.lock') }} + key: ${{ runner.os }}-rustc-test-cargo-build-target-${{ hashFiles('rust-toolchain.toml', 'Cargo.lock') }} - name: Install ripgrep run: | diff --git a/example/std_example.rs b/example/std_example.rs index c569ef0ef829..33db75f0943a 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -259,6 +259,9 @@ unsafe fn test_simd() { test_mm_cvttps_epi32(); test_mm_cvtsi128_si64(); + #[cfg(not(jit))] + test_mm_cvtps_ph(); + test_mm_extract_epi8(); test_mm_insert_epi16(); test_mm_shuffle_epi8(); @@ -558,6 +561,21 @@ unsafe fn test_mm_cvttps_epi32() { } } +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "f16c")] +#[cfg(not(jit))] +unsafe fn test_mm_cvtps_ph() { + const F16_ONE: i16 = 0x3c00; + const F16_TWO: i16 = 0x4000; + const F16_THREE: i16 = 0x4200; + const F16_FOUR: i16 = 0x4400; + + let a = _mm_set_ps(1.0, 2.0, 3.0, 4.0); + let r = _mm_cvtps_ph::<_MM_FROUND_CUR_DIRECTION>(a); + let e = _mm_set_epi16(0, 0, 0, 0, F16_ONE, F16_TWO, F16_THREE, F16_FOUR); + assert_eq_m128i(r, e); +} + fn test_checked_mul() { let u: Option = u8::from_str_radix("1000", 10).ok(); assert_eq!(u, None); diff --git a/rust-toolchain b/rust-toolchain deleted file mode 100644 index 461dbcdb0fb5..000000000000 --- a/rust-toolchain +++ /dev/null @@ -1,4 +0,0 @@ -[toolchain] -channel = "nightly-2025-12-08" -components = ["rust-src", "rustc-dev", "llvm-tools"] -profile = "minimal" diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 000000000000..6ce49eb4ccf0 --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,4 @@ +[toolchain] +channel = "nightly-2025-12-18" +components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] +profile = "minimal" diff --git a/scripts/rustup.sh b/scripts/rustup.sh index 1a82193303e2..e26be307328f 100755 --- a/scripts/rustup.sh +++ b/scripts/rustup.sh @@ -22,8 +22,7 @@ case $1 in "prepare") echo "=> Installing new nightly" rustup toolchain install --profile minimal "nightly-${TOOLCHAIN}" # Sanity check to see if the nightly exists - sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain - rustup component add rustfmt || true + sed -i "s/\"nightly-.*\"/\"nightly-${TOOLCHAIN}\"/" rust-toolchain.toml echo "=> Uninstalling all old nightlies" for nightly in $(rustup toolchain list | grep nightly | grep -v "$TOOLCHAIN" | grep -v nightly-x86_64); do @@ -35,7 +34,7 @@ case $1 in ./y.sh prepare ;; "commit") - git add rust-toolchain + git add rust-toolchain.toml git commit -m "Rustup to $(rustc -V)" ;; "push") diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index b5af585a732e..b25269d1430a 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -35,6 +35,7 @@ git checkout -- tests/ui/entry-point/auxiliary/bad_main_functions.rs rm tests/ui/asm/x86_64/evex512-implicit-feature.rs # unimplemented AVX512 x86 vendor intrinsic rm tests/ui/simd/dont-invalid-bitcast-x86_64.rs # unimplemented llvm.x86.sse41.round.ps rm tests/ui/simd/intrinsic/generic-arithmetic-pass.rs # unimplemented simd_funnel_{shl,shr} +rm -r tests/ui/scalable-vectors # scalable vectors are unsupported # exotic linkages rm tests/incremental/hashes/function_interfaces.rs @@ -53,23 +54,29 @@ rm tests/ui/sanitizer/kcfi-c-variadic.rs # same rm tests/ui/c-variadic/same-program-multiple-abis-x86_64.rs # variadics for calling conventions other than C unsupported rm tests/ui/delegation/fn-header.rs +# inline assembly features +rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly +rm tests/ui/asm/global-asm-mono-sym-fn.rs # same +rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same +rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported +rm tests/ui/asm/label-operand.rs # same +rm tests/ui/asm/may_unwind.rs # asm unwinding not supported +rm tests/ui/asm/aarch64/may_unwind.rs # same + # misc unimplemented things rm tests/ui/target-feature/missing-plusminus.rs # error not implemented rm -r tests/run-make/repr128-dwarf # debuginfo test rm -r tests/run-make/split-debuginfo # same rm -r tests/run-make/target-specs # i686 not supported by Cranelift rm -r tests/run-make/mismatching-target-triples # same -rm tests/ui/asm/x86_64/issue-96797.rs # const and sym inline asm operands don't work entirely correctly -rm tests/ui/asm/global-asm-mono-sym-fn.rs # same -rm tests/ui/asm/naked-asm-mono-sym-fn.rs # same -rm tests/ui/asm/x86_64/goto.rs # inline asm labels not supported -rm tests/ui/asm/label-operand.rs # same rm tests/ui/simd/simd-bitmask-notpow2.rs # non-pow-of-2 simd vector sizes rm -r tests/run-make/used-proc-macro # used(linker) isn't supported yet rm tests/ui/linking/no-gc-encapsulation-symbols.rs # same rm tests/ui/attributes/fn-align-dyn.rs # per-function alignment not supported rm -r tests/ui/explicit-tail-calls # tail calls rm -r tests/run-make/pointer-auth-link-with-c # pointer auth +rm -r tests/ui/eii # EII not yet implemented +rm -r tests/run-make/forced-unwind-terminate-pof # forced unwinding doesn't take precedence # requires LTO rm -r tests/run-make/cdylib @@ -78,6 +85,7 @@ rm -r tests/run-make/lto-* rm -r tests/run-make/reproducible-build-2 rm -r tests/run-make/no-builtins-lto rm -r tests/run-make/reachable-extern-fn-available-lto +rm -r tests/run-make/no-builtins-linker-plugin-lto # coverage instrumentation rm tests/ui/consts/precise-drop-with-coverage.rs @@ -87,6 +95,7 @@ rm -r tests/ui/instrument-coverage/ # ================== rm tests/ui/codegen/issue-28950.rs # depends on stack size optimizations rm tests/ui/codegen/init-large-type.rs # same +rm tests/ui/codegen/StackColoring-not-blowup-stack-issue-40883.rs # same rm tests/ui/statics/const_generics.rs # tests an optimization rm tests/ui/linking/executable-no-mangle-strip.rs # requires --gc-sections to work for statics @@ -143,6 +152,15 @@ rm tests/ui/errors/remap-path-prefix-sysroot.rs # different sysroot source path rm -r tests/run-make/export/extern-opt # something about rustc version mismatches rm -r tests/run-make/export # same rm -r tests/ui/compiletest-self-test/compile-flags-incremental.rs # needs compiletest compiled with panic=unwind +rm tests/ui/async-await/in-trait/dont-project-to-specializable-projection.rs # something going wrong with stdlib source remapping +rm tests/ui/consts/miri_unleashed/drop.rs # same +rm tests/ui/error-emitter/multiline-removal-suggestion.rs # same +rm tests/ui/lint/lint-const-item-mutation.rs # same +rm tests/ui/lint/use-redundant/use-redundant-issue-71450.rs # same +rm tests/ui/lint/use-redundant/use-redundant-prelude-rust-2021.rs # same +rm tests/ui/specialization/const_trait_impl.rs # same +rm tests/ui/thir-print/offset_of.rs # same +rm tests/ui/traits/const-traits/const_closure-const_trait_impl-ice-113381.rs # same # genuine bugs # ============ @@ -157,6 +175,7 @@ rm tests/ui/lint/non-snake-case/lint-non-snake-case-crate.rs # same rm tests/ui/async-await/async-drop/async-drop-initial.rs # same (rust-lang/rust#140493) rm -r tests/ui/codegen/equal-pointers-unequal # make incorrect assumptions about the location of stack variables rm -r tests/run-make-cargo/rustdoc-scrape-examples-paths # FIXME(rust-lang/rust#145580) incr comp bug +rm -r tests/incremental/extern_static/issue-49153.rs # assumes reference to undefined static gets optimized away rm tests/ui/intrinsics/panic-uninitialized-zeroed.rs # really slow with unoptimized libstd rm tests/ui/process/process-panic-after-fork.rs # same diff --git a/src/driver/jit.rs b/src/driver/jit.rs index 9dba46363936..3a8ca25a5fc0 100644 --- a/src/driver/jit.rs +++ b/src/driver/jit.rs @@ -190,7 +190,7 @@ fn dep_symbol_lookup_fn( diag.emit(); } Linkage::Dynamic => { - dylib_paths.push(src.dylib.as_ref().unwrap().0.clone()); + dylib_paths.push(src.dylib.as_ref().unwrap().clone()); } } } diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 37fbe4be1b0f..61f48fa97743 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -1313,6 +1313,35 @@ fn select4( ret.write_cvalue_transmute(fx, res); } + "llvm.x86.vcvtps2ph.128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvtps_ph + intrinsic_args!(fx, args => (a, _imm8); intrinsic); + let a = a.load_scalar(fx); + + let imm8 = + if let Some(imm8) = crate::constant::mir_operand_get_const_val(fx, &args[1].node) { + imm8 + } else { + fx.tcx + .dcx() + .span_fatal(span, "Index argument for `_mm_cvtps_ph` is not a constant"); + }; + + let imm8 = imm8.to_u32(); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(format!("vcvtps2ph xmm0, xmm0, {imm8}").into())], + &[CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + _ => { fx.tcx .dcx() diff --git a/triagebot.toml b/triagebot.toml index 13da0a87def3..eb0c7b011f60 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -2,6 +2,3 @@ # Prevents un-canonicalized issue links (to avoid wrong issues being linked in r-l/rust) [issue-links] - -# Prevents mentions in commits to avoid users being spammed -[no-mentions] From e1e8e0648cebb900fd0a1c44057caa1513bba126 Mon Sep 17 00:00:00 2001 From: Redddy Date: Thu, 18 Dec 2025 21:13:17 +0900 Subject: [PATCH 052/126] fix typo Co-authored-by: Tshepang Mbambo --- src/doc/rustc-dev-guide/src/serialization.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/serialization.md b/src/doc/rustc-dev-guide/src/serialization.md index fcea4f3e605b..0fb7870c3a5f 100644 --- a/src/doc/rustc-dev-guide/src/serialization.md +++ b/src/doc/rustc-dev-guide/src/serialization.md @@ -126,9 +126,9 @@ and `Encodable`. all `Encoders` and `Decoders`. These should be used in crates that don't depend on [`rustc_middle`], or that have to be serialized by a type that does not implement `TyEncoder`. -- [`MetadataEncodable`] generate implementations that +- [`MetadataEncodable`] generates implementations that only allow decoding by [`rustc_metadata::rmeta::encoder::EncodeContext`]. -- [`BlobDecodable`] and [`LazyDecodable`] generate implementations that decode +- [`BlobDecodable`] and [`LazyDecodable`] generates implementations that decode with the metadata blob decoders in [`rustc_metadata::rmeta`]; use `BlobDecodable` when the type has no lazy metadata handles, and `LazyDecodable` when it does. - `TyEncodable` and `TyDecodable` generate implementation that apply to any From 54a25b152642d5e72b367a45e1080d255b5a6314 Mon Sep 17 00:00:00 2001 From: Redddy Date: Thu, 18 Dec 2025 23:54:18 +0900 Subject: [PATCH 053/126] Clarify descriptions for BlobDecodable and LazyDecodable --- src/doc/rustc-dev-guide/src/serialization.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/serialization.md b/src/doc/rustc-dev-guide/src/serialization.md index 0fb7870c3a5f..91b2cc92125e 100644 --- a/src/doc/rustc-dev-guide/src/serialization.md +++ b/src/doc/rustc-dev-guide/src/serialization.md @@ -128,9 +128,10 @@ and `Encodable`. not implement `TyEncoder`. - [`MetadataEncodable`] generates implementations that only allow decoding by [`rustc_metadata::rmeta::encoder::EncodeContext`]. -- [`BlobDecodable`] and [`LazyDecodable`] generates implementations that decode - with the metadata blob decoders in [`rustc_metadata::rmeta`]; use `BlobDecodable` - when the type has no lazy metadata handles, and `LazyDecodable` when it does. +- [`BlobDecodable`] and [`LazyDecodable`] serve as the decoding counterparts to + `MetadataEncodable`. They generate implementations that decode with the + metadata blob decoders in `rustc_metadata::rmeta`; use `BlobDecodable` when + the type has no lazy metadata handles, and `LazyDecodable` when it does. - `TyEncodable` and `TyDecodable` generate implementation that apply to any `TyEncoder` or `TyDecoder`. These should be used for types that are only serialized in crate metadata and/or the incremental cache, which is most From 005046ddd4f990f48dee63a24f49fb47de992646 Mon Sep 17 00:00:00 2001 From: Moulins Date: Thu, 18 Dec 2025 00:27:02 +0100 Subject: [PATCH 054/126] layout: Store inverse memory index in `FieldsShape::Arbitrary` All usages of `memory_index` start by calling `invert_bijective_mapping`, so storing the inverted mapping directly saves some work and simplifies the code. --- src/pretty_clif.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index 2878fa7aa298..65779b38ad1c 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -10,7 +10,7 @@ //! function u0:22(i64) -> i8, i8 system_v { //! ; symbol _ZN97_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$RF$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17hd361e9f5c3d1c4deE //! ; instance Instance { def: Item(DefId(0:42 ~ example[3895]::{impl#0}::call_once)), args: ['{erased}, '{erased}] } -//! ; abi FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: IsNotEmpty, layout: Layout { size: Size(0 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: Memory { sized: true }, fields: Arbitrary { offsets: [], memory_index: [] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 12266848898570219025 } }, mode: Ignore }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false } +//! ; abi FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: IsNotEmpty, layout: Layout { size: Size(0 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: Memory { sized: true }, fields: Arbitrary { offsets: [], in_memory_order: [] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 12266848898570219025 } }, mode: Ignore }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], in_memory_order: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false } //! //! ; kind loc.idx param pass mode ty //! ; ssa _0 (u8, u8) 2b 1 var=(0, 1) @@ -41,7 +41,7 @@ //! ; //! ; _0 = >::call_mut(move _3, copy _2) //! v2 = stack_load.i64 ss0 -//! ; abi: FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: &mut IsNotEmpty, layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(1 bytes)) }) }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false } +//! ; abi: FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: &mut IsNotEmpty, layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(1 bytes)) }) }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, backend_repr: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(8 bytes), randomization_seed: 281492156579847 } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, backend_repr: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], in_memory_order: [0, 1] }, largest_niche: None, uninhabited: false, variants: Single { index: 0 }, max_repr_align: None, unadjusted_abi_align: Align(1 bytes), randomization_seed: 71776127651151873 } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false } //! v3, v4 = call fn0(v1, v2) ; v1 = 1 //! v5 -> v3 //! v6 -> v4 From ef494feccca725d5e5148a721e64a2655763be6f Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 19 Dec 2025 04:58:34 +0000 Subject: [PATCH 055/126] Prepare for merging from rust-lang/rust This updates the rust-version file to 526a91cbcc4601b92b0587405015e07b9c0d79f6. --- 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 11c138c28c24..d4fbfacf4eda 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -686f9cefc37c5bdec069a75357f0277b390657ca +526a91cbcc4601b92b0587405015e07b9c0d79f6 From 8870bb8d9c07f0c2e110dfca17794eef0c474eae Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Fri, 19 Dec 2025 05:07:13 +0000 Subject: [PATCH 056/126] fmt --- src/tools/miri/tests/fail/closures/deref-in-pattern.rs | 7 ++++--- .../miri/tests/fail/closures/deref-in-pattern.stderr | 2 +- src/tools/miri/tests/fail/closures/partial-pattern.rs | 9 +++++---- .../miri/tests/fail/closures/partial-pattern.stderr | 2 +- .../miri/tests/fail/closures/uninhabited-variant.rs | 9 +++++---- 5 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/tools/miri/tests/fail/closures/deref-in-pattern.rs b/src/tools/miri/tests/fail/closures/deref-in-pattern.rs index c729469c78b0..27915a9a489b 100644 --- a/src/tools/miri/tests/fail/closures/deref-in-pattern.rs +++ b/src/tools/miri/tests/fail/closures/deref-in-pattern.rs @@ -9,12 +9,13 @@ fn main() { // the inner reference is dangling let x: &&u32 = unsafe { let x: u32 = 42; - &&* &raw const x + &&*&raw const x }; - let _ = || { //~ ERROR: encountered a dangling reference + //~v ERROR: encountered a dangling reference + let _ = || { match x { - &&_y => {}, + &&_y => {} } }; } diff --git a/src/tools/miri/tests/fail/closures/deref-in-pattern.stderr b/src/tools/miri/tests/fail/closures/deref-in-pattern.stderr index 1264f4e3fb95..fae2d286c487 100644 --- a/src/tools/miri/tests/fail/closures/deref-in-pattern.stderr +++ b/src/tools/miri/tests/fail/closures/deref-in-pattern.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: constructing invalid value: encountered a dangling re LL | let _ = || { | _____________^ LL | | match x { -LL | | &&_y => {}, +LL | | &&_y => {} LL | | } LL | | }; | |_____^ Undefined Behavior occurred here diff --git a/src/tools/miri/tests/fail/closures/partial-pattern.rs b/src/tools/miri/tests/fail/closures/partial-pattern.rs index cb6446208180..f70fe096fd80 100644 --- a/src/tools/miri/tests/fail/closures/partial-pattern.rs +++ b/src/tools/miri/tests/fail/closures/partial-pattern.rs @@ -15,14 +15,15 @@ fn main() { let x: &(&u32, &u32) = unsafe { let a = 21; let b = 37; - let ra = &* &raw const a; - let rb = &* &raw const b; + let ra = &*&raw const a; + let rb = &*&raw const b; &(ra, rb) }; - let _ = || { //~ ERROR: encountered a dangling reference + //~v ERROR: encountered a dangling reference + let _ = || { match x { - (&_y, _) => {}, + (&_y, _) => {} } }; } diff --git a/src/tools/miri/tests/fail/closures/partial-pattern.stderr b/src/tools/miri/tests/fail/closures/partial-pattern.stderr index 5b7ee35ecc73..8dea4d4d8c64 100644 --- a/src/tools/miri/tests/fail/closures/partial-pattern.stderr +++ b/src/tools/miri/tests/fail/closures/partial-pattern.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: constructing invalid value: encountered a dangling re LL | let _ = || { | _____________^ LL | | match x { -LL | | (&_y, _) => {}, +LL | | (&_y, _) => {} LL | | } LL | | }; | |_____^ Undefined Behavior occurred here diff --git a/src/tools/miri/tests/fail/closures/uninhabited-variant.rs b/src/tools/miri/tests/fail/closures/uninhabited-variant.rs index 9c50fdc13a35..0a2dfe9a7f64 100644 --- a/src/tools/miri/tests/fail/closures/uninhabited-variant.rs +++ b/src/tools/miri/tests/fail/closures/uninhabited-variant.rs @@ -5,9 +5,9 @@ #[repr(C)] #[allow(dead_code)] enum E { - V0, // discriminant: 0 - V1, // 1 - V2(!), // 2 + V0, // discriminant: 0 + V1, // 1 + V2(!), // 2 } fn main() { @@ -20,7 +20,8 @@ fn main() { // After rust-lang/rust#138961, constructing the closure performs a reborrow of r. // Nevertheless, the discriminant is only actually inspected when the closure // is called. - match r { //~ ERROR: read discriminant of an uninhabited enum variant + match r { + //~^ ERROR: read discriminant of an uninhabited enum variant E::V0 => {} E::V1 => {} E::V2(_) => {} From 678f58151e36741d0588e150cc46cda14263bedb Mon Sep 17 00:00:00 2001 From: Aditya-PS-05 Date: Fri, 19 Dec 2025 18:05:11 +0530 Subject: [PATCH 057/126] fix ICE when {{root}} appears in import suggestions --- compiler/rustc_resolve/src/diagnostics.rs | 6 +++++- .../nested-import-root-symbol-150103.rs | 13 ++++++++++++ .../nested-import-root-symbol-150103.stderr | 20 +++++++++++++++++++ 3 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 tests/ui/imports/nested-import-root-symbol-150103.rs create mode 100644 tests/ui/imports/nested-import-root-symbol-150103.stderr diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 3eccbd4682da..b0cdfe8ab87d 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -2223,7 +2223,11 @@ fn report_privacy_error(&mut self, privacy_error: &PrivacyError<'ra>) { match binding.kind { NameBindingKind::Import { import, .. } => { for segment in import.module_path.iter().skip(1) { - path.push(segment.ident); + // Don't include `{{root}}` in suggestions - it's an internal symbol + // that should never be shown to users. + if segment.ident.name != kw::PathRoot { + path.push(segment.ident); + } } sugg_paths.push(( path.iter().cloned().chain(std::iter::once(ident)).collect::>(), diff --git a/tests/ui/imports/nested-import-root-symbol-150103.rs b/tests/ui/imports/nested-import-root-symbol-150103.rs new file mode 100644 index 000000000000..066ed37d8bbb --- /dev/null +++ b/tests/ui/imports/nested-import-root-symbol-150103.rs @@ -0,0 +1,13 @@ +// Issue: https://github.com/rust-lang/rust/issues/150103 +// ICE when using `::` at start of nested imports +// caused by `{{root}}` appearing in diagnostic suggestions + +mod A { + use Iuse::{ ::Fish }; //~ ERROR failed to resolve: use of unresolved module or unlinked crate +} + +mod B { + use A::{::Fish}; //~ ERROR failed to resolve: crate root in paths can only be used in start position +} + +fn main() {} diff --git a/tests/ui/imports/nested-import-root-symbol-150103.stderr b/tests/ui/imports/nested-import-root-symbol-150103.stderr new file mode 100644 index 000000000000..be8b8c12d218 --- /dev/null +++ b/tests/ui/imports/nested-import-root-symbol-150103.stderr @@ -0,0 +1,20 @@ +error[E0433]: failed to resolve: use of unresolved module or unlinked crate `Iuse` + --> $DIR/nested-import-root-symbol-150103.rs:6:9 + | +LL | use Iuse::{ ::Fish }; + | ^^^^ use of unresolved module or unlinked crate `Iuse` + | +help: you might be missing a crate named `Iuse`, add it to your project and import it in your code + | +LL + extern crate Iuse; + | + +error[E0433]: failed to resolve: crate root in paths can only be used in start position + --> $DIR/nested-import-root-symbol-150103.rs:10:13 + | +LL | use A::{::Fish}; + | ^ crate root in paths can only be used in start position + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0433`. From 0bc29cec45412ee3cc68a1ef1556814885543d55 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 19 Dec 2025 17:55:19 +0100 Subject: [PATCH 058/126] Add regression test for `const_item_interior_mutations` deref FP --- ...nst-item-interior-mutations-const-deref.rs | 30 +++++++++++++++ ...item-interior-mutations-const-deref.stderr | 37 +++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 tests/ui/lint/const-item-interior-mutations-const-deref.rs create mode 100644 tests/ui/lint/const-item-interior-mutations-const-deref.stderr diff --git a/tests/ui/lint/const-item-interior-mutations-const-deref.rs b/tests/ui/lint/const-item-interior-mutations-const-deref.rs new file mode 100644 index 000000000000..ce684abacccd --- /dev/null +++ b/tests/ui/lint/const-item-interior-mutations-const-deref.rs @@ -0,0 +1,30 @@ +// Regression test for +// +// We shouldn't lint on user types, including through deref. + +//@ check-pass + +use std::cell::Cell; +use std::ops::Deref; + +// Cut down version of the issue reproducer without the thread local to just a Deref +pub struct LocalKey { + inner: T, +} + +impl Deref for LocalKey { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +const LOCAL_COUNT: LocalKey> = LocalKey { inner: Cell::new(8) }; + +fn main() { + let count = LOCAL_COUNT.get(); + //~^ WARN mutation of an interior mutable `const` + LOCAL_COUNT.set(count); + //~^ WARN mutation of an interior mutable `const` +} diff --git a/tests/ui/lint/const-item-interior-mutations-const-deref.stderr b/tests/ui/lint/const-item-interior-mutations-const-deref.stderr new file mode 100644 index 000000000000..35696d0ba100 --- /dev/null +++ b/tests/ui/lint/const-item-interior-mutations-const-deref.stderr @@ -0,0 +1,37 @@ +warning: mutation of an interior mutable `const` item with call to `get` + --> $DIR/const-item-interior-mutations-const-deref.rs:26:17 + | +LL | let count = LOCAL_COUNT.get(); + | -----------^^^^^^ + | | + | `LOCAL_COUNT` is a interior mutable `const` item of type `LocalKey>` + | + = note: each usage of a `const` item creates a new temporary + = note: only the temporaries and never the original `const LOCAL_COUNT` will be modified + = help: for more details on interior mutability see + = note: `#[warn(const_item_interior_mutations)]` on by default +help: for a shared instance of `LOCAL_COUNT`, consider making it a `static` item instead + | +LL - const LOCAL_COUNT: LocalKey> = LocalKey { inner: Cell::new(8) }; +LL + static LOCAL_COUNT: LocalKey> = LocalKey { inner: Cell::new(8) }; + | + +warning: mutation of an interior mutable `const` item with call to `set` + --> $DIR/const-item-interior-mutations-const-deref.rs:28:5 + | +LL | LOCAL_COUNT.set(count); + | -----------^^^^^^^^^^^ + | | + | `LOCAL_COUNT` is a interior mutable `const` item of type `LocalKey>` + | + = note: each usage of a `const` item creates a new temporary + = note: only the temporaries and never the original `const LOCAL_COUNT` will be modified + = help: for more details on interior mutability see +help: for a shared instance of `LOCAL_COUNT`, consider making it a `static` item instead + | +LL - const LOCAL_COUNT: LocalKey> = LocalKey { inner: Cell::new(8) }; +LL + static LOCAL_COUNT: LocalKey> = LocalKey { inner: Cell::new(8) }; + | + +warning: 2 warnings emitted + From 897e88c63ded83e8b6be47ea09c661f7bd8c0ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 19 Dec 2025 12:34:59 +0100 Subject: [PATCH 059/126] add test for 149980 --- tests/ui/eii/error_statement_position.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/ui/eii/error_statement_position.rs diff --git a/tests/ui/eii/error_statement_position.rs b/tests/ui/eii/error_statement_position.rs new file mode 100644 index 000000000000..a9c606991574 --- /dev/null +++ b/tests/ui/eii/error_statement_position.rs @@ -0,0 +1,6 @@ +#![feature(extern_item_impls)] + +fn main() { + #[eii] + impl Bar {} +} From c316c05dc512bba366d461e1719f0a8620a07453 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 19 Dec 2025 14:42:20 +0100 Subject: [PATCH 060/126] refactor how eii expansion is wrapped fixing 149980 --- compiler/rustc_builtin_macros/src/eii.rs | 45 +++++++++----------- tests/ui/eii/error_statement_position.rs | 10 +++++ tests/ui/eii/error_statement_position.stderr | 8 ++++ 3 files changed, 38 insertions(+), 25 deletions(-) create mode 100644 tests/ui/eii/error_statement_position.stderr diff --git a/compiler/rustc_builtin_macros/src/eii.rs b/compiler/rustc_builtin_macros/src/eii.rs index e29b29fc6ccb..9049639925dd 100644 --- a/compiler/rustc_builtin_macros/src/eii.rs +++ b/compiler/rustc_builtin_macros/src/eii.rs @@ -60,12 +60,18 @@ fn eii_( ) -> Vec { let eii_attr_span = ecx.with_def_site_ctxt(eii_attr_span); - let (item, stmt) = if let Annotatable::Item(item) = item { - (item, false) + let (item, wrap_item): (_, &dyn Fn(_) -> _) = if let Annotatable::Item(item) = item { + (item, &Annotatable::Item) } else if let Annotatable::Stmt(ref stmt) = item && let StmtKind::Item(ref item) = stmt.kind { - (item.clone(), true) + (item.clone(), &|item| { + Annotatable::Stmt(Box::new(Stmt { + id: DUMMY_NODE_ID, + kind: StmtKind::Item(item), + span: eii_attr_span, + })) + }) } else { ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { span: eii_attr_span, @@ -74,23 +80,25 @@ fn eii_( return vec![item]; }; - let orig_item = item.clone(); - - let item = *item; - - let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } = item else { + let ast::Item { attrs, id: _, span: _, vis, kind: ItemKind::Fn(func), tokens: _ } = + item.as_ref() + else { ecx.dcx().emit_err(EiiSharedMacroExpectedFunction { span: eii_attr_span, name: path_to_string(&meta_item.path), }); - return vec![Annotatable::Item(Box::new(item))]; + return vec![wrap_item(item)]; }; + // only clone what we need + let attrs = attrs.clone(); + let func = (**func).clone(); + let vis = vis.clone(); let attrs_from_decl = filter_attrs_for_multiple_eii_attr(ecx, attrs, eii_attr_span, &meta_item.path); let Ok(macro_name) = name_for_impl_macro(ecx, &func, &meta_item) else { - return vec![Annotatable::Item(orig_item)]; + return vec![wrap_item(item)]; }; // span of the declaring item without attributes @@ -115,7 +123,7 @@ fn eii_( ecx, eii_attr_span, item_span, - *func, + func, vis, &attrs_from_decl, ))); @@ -128,20 +136,7 @@ fn eii_( decl_span, ))); - if stmt { - return_items - .into_iter() - .map(|i| { - Annotatable::Stmt(Box::new(Stmt { - id: DUMMY_NODE_ID, - kind: StmtKind::Item(i), - span: eii_attr_span, - })) - }) - .collect() - } else { - return_items.into_iter().map(|i| Annotatable::Item(i)).collect() - } + return_items.into_iter().map(wrap_item).collect() } /// Decide on the name of the macro that can be used to implement the EII. diff --git a/tests/ui/eii/error_statement_position.rs b/tests/ui/eii/error_statement_position.rs index a9c606991574..cf81e7e6a8b2 100644 --- a/tests/ui/eii/error_statement_position.rs +++ b/tests/ui/eii/error_statement_position.rs @@ -1,6 +1,16 @@ #![feature(extern_item_impls)] +// EIIs can, despite not being super useful, be declared in statement position +// nested inside items. Items in statement position, when expanded as part of a macro, +// need to be wrapped slightly differently (in an `ast::Statement`). +// We did this on the happy path (no errors), but when there was an error, we'd +// replace it with *just* an `ast::Item` not wrapped in an `ast::Statement`. +// This caused an ICE (https://github.com/rust-lang/rust/issues/149980). +// this test fails to build, but demonstrates that no ICE is produced. fn main() { + struct Bar; + #[eii] + //~^ ERROR `#[eii]` is only valid on functions impl Bar {} } diff --git a/tests/ui/eii/error_statement_position.stderr b/tests/ui/eii/error_statement_position.stderr new file mode 100644 index 000000000000..01b7394ef00f --- /dev/null +++ b/tests/ui/eii/error_statement_position.stderr @@ -0,0 +1,8 @@ +error: `#[eii]` is only valid on functions + --> $DIR/error_statement_position.rs:13:5 + | +LL | #[eii] + | ^^^^^^ + +error: aborting due to 1 previous error + From c34ea6e56dcea96bed3739c37580bd559c75c0e8 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Fri, 19 Dec 2025 11:02:57 -0800 Subject: [PATCH 061/126] remove llvm_enzyme and enzyme fallbacks from most places, enable the autodiff frontend on nightly --- compiler/rustc_builtin_macros/messages.ftl | 1 - compiler/rustc_builtin_macros/src/autodiff.rs | 5 - compiler/rustc_builtin_macros/src/errors.rs | 11 -- compiler/rustc_codegen_llvm/Cargo.toml | 4 +- compiler/rustc_codegen_llvm/src/back/lto.rs | 1 - compiler/rustc_codegen_llvm/src/back/write.rs | 6 +- compiler/rustc_codegen_llvm/src/errors.rs | 1 - compiler/rustc_codegen_llvm/src/lib.rs | 4 +- .../rustc_codegen_llvm/src/llvm/enzyme_ffi.rs | 143 ------------------ compiler/rustc_codegen_llvm/src/typetree.rs | 36 ++--- tests/pretty/autodiff/autodiff_forward.pp | 2 +- tests/pretty/autodiff/autodiff_forward.rs | 2 +- tests/pretty/autodiff/autodiff_reverse.pp | 2 +- tests/pretty/autodiff/autodiff_reverse.rs | 2 +- tests/pretty/autodiff/inherent_impl.pp | 2 +- tests/pretty/autodiff/inherent_impl.rs | 2 +- tests/ui/autodiff/visibility.rs | 2 +- .../autodiff/visibility.std_autodiff.stderr | 10 +- ... feature-gate-autodiff-use.nightly.stderr} | 2 +- .../feature-gate-autodiff-use.rs | 21 ++- ...> feature-gate-autodiff-use.stable.stderr} | 10 +- 21 files changed, 46 insertions(+), 223 deletions(-) rename tests/ui/feature-gates/{feature-gate-autodiff-use.has_support.stderr => feature-gate-autodiff-use.nightly.stderr} (95%) rename tests/ui/feature-gates/{feature-gate-autodiff-use.no_support.stderr => feature-gate-autodiff-use.stable.stderr} (78%) diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 542f34d9d831..f0f6f2dcf82c 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -55,7 +55,6 @@ builtin_macros_assert_requires_expression = macro requires an expression as an a builtin_macros_autodiff = autodiff must be applied to function builtin_macros_autodiff_missing_config = autodiff requires at least a name and mode builtin_macros_autodiff_mode_activity = {$act} can not be used in {$mode} Mode -builtin_macros_autodiff_not_build = this rustc version does not support autodiff builtin_macros_autodiff_number_activities = expected {$expected} activities, but found {$found} builtin_macros_autodiff_ret_activity = invalid return activity {$act} in {$mode} Mode builtin_macros_autodiff_ty_activity = {$act} can not be used for this type diff --git a/compiler/rustc_builtin_macros/src/autodiff.rs b/compiler/rustc_builtin_macros/src/autodiff.rs index 6bf985fcc9f0..39abb66df30c 100644 --- a/compiler/rustc_builtin_macros/src/autodiff.rs +++ b/compiler/rustc_builtin_macros/src/autodiff.rs @@ -209,11 +209,6 @@ pub(crate) fn expand_with_mode( mut item: Annotatable, mode: DiffMode, ) -> Vec { - // FIXME(bjorn3) maybe have the backend directly tell if autodiff is supported? - if cfg!(not(feature = "llvm_enzyme")) { - ecx.sess.dcx().emit_err(errors::AutoDiffSupportNotBuild { span: meta_item.span }); - return vec![item]; - } let dcx = ecx.sess.dcx(); // first get information about the annotable item: visibility, signature, name and generic diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs index 2a4c499349ad..ad31eae10f60 100644 --- a/compiler/rustc_builtin_macros/src/errors.rs +++ b/compiler/rustc_builtin_macros/src/errors.rs @@ -216,17 +216,6 @@ pub(crate) struct AutoDiffInvalidApplication { } } -pub(crate) use ad_fallback::*; -mod ad_fallback { - use super::*; - #[derive(Diagnostic)] - #[diag(builtin_macros_autodiff_not_build)] - pub(crate) struct AutoDiffSupportNotBuild { - #[primary_span] - pub(crate) span: Span, - } -} - #[derive(Diagnostic)] #[diag(builtin_macros_concat_bytes_invalid)] pub(crate) struct ConcatBytesInvalid { diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 076ec5e59eb6..b40962b759d8 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -14,7 +14,7 @@ bitflags = "2.4.1" gimli = "0.31" itertools = "0.12" libc = "0.2" -libloading = { version = "0.9.0", optional = true } +libloading = { version = "0.9.0" } measureme = "12.0.1" object = { version = "0.37.0", default-features = false, features = ["std", "read"] } rustc-demangle = "0.1.21" @@ -47,7 +47,7 @@ tracing = "0.1" [features] # tidy-alphabetical-start check_only = ["rustc_llvm/check_only"] -llvm_enzyme = ["dep:libloading"] +llvm_enzyme = [] llvm_offload = [] # tidy-alphabetical-end diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index 314e64272ffe..52c2ca7b1696 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -528,7 +528,6 @@ fn thin_lto( } } -#[cfg(feature = "llvm_enzyme")] pub(crate) fn enable_autodiff_settings(ad: &[config::AutoDiff]) { let mut enzyme = llvm::EnzymeWrapper::get_instance(); diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index 18da945f5a31..f5566cc84ce9 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -568,8 +568,7 @@ pub(crate) unsafe fn llvm_optimize( // FIXME(ZuseZ4): In a future update we could figure out how to only optimize individual functions getting // differentiated. - let consider_ad = - cfg!(feature = "llvm_enzyme") && config.autodiff.contains(&config::AutoDiff::Enable); + let consider_ad = config.autodiff.contains(&config::AutoDiff::Enable); let run_enzyme = autodiff_stage == AutodiffStage::DuringAD; let print_before_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModBefore); let print_after_enzyme = config.autodiff.contains(&config::AutoDiff::PrintModAfter); @@ -819,8 +818,7 @@ pub(crate) fn optimize( // If we know that we will later run AD, then we disable vectorization and loop unrolling. // Otherwise we pretend AD is already done and run the normal opt pipeline (=PostAD). - let consider_ad = - cfg!(feature = "llvm_enzyme") && config.autodiff.contains(&config::AutoDiff::Enable); + let consider_ad = config.autodiff.contains(&config::AutoDiff::Enable); let autodiff_stage = if consider_ad { AutodiffStage::PreAD } else { AutodiffStage::PostAD }; // The embedded bitcode is used to run LTO/ThinLTO. // The bitcode obtained during the `codegen` phase is no longer suitable for performing LTO. diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index f2e147b1ee0a..b59067b9745b 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -32,7 +32,6 @@ fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { } } -#[cfg(feature = "llvm_enzyme")] #[derive(Diagnostic)] #[diag(codegen_llvm_autodiff_component_unavailable)] pub(crate) struct AutoDiffComponentUnavailable; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 4d0f8dbb9302..d96d7d13e7cc 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -242,7 +242,9 @@ fn name(&self) -> &'static str { fn init(&self, sess: &Session) { llvm_util::init(sess); // Make sure llvm is inited - #[cfg(feature = "llvm_enzyme")] + // autodiff is based on Enzyme, a library which we might not have available, when it was + // neither build, nor downloaded via rustup. If autodiff is used, but not available we emit + // an early error here and abort compilation. { use rustc_session::config::AutoDiff; diff --git a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs index 956a4e43a7de..b11310b970d0 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/enzyme_ffi.rs @@ -86,10 +86,8 @@ pub(crate) enum LLVMRustVerifierFailureAction { LLVMReturnStatusAction = 2, } -#[cfg(feature = "llvm_enzyme")] pub(crate) use self::Enzyme_AD::*; -#[cfg(feature = "llvm_enzyme")] pub(crate) mod Enzyme_AD { use std::ffi::{c_char, c_void}; use std::sync::{Mutex, MutexGuard, OnceLock}; @@ -450,147 +448,6 @@ fn get_enzyme_path(sysroot: &Sysroot) -> Result { } } -#[cfg(not(feature = "llvm_enzyme"))] -pub(crate) use self::Fallback_AD::*; - -#[cfg(not(feature = "llvm_enzyme"))] -pub(crate) mod Fallback_AD { - #![allow(unused_variables)] - - use std::ffi::c_void; - use std::sync::{Mutex, MutexGuard}; - - use libc::c_char; - use rustc_codegen_ssa::back::write::CodegenContext; - use rustc_codegen_ssa::traits::WriteBackendMethods; - - use super::{CConcreteType, CTypeTreeRef, Context, EnzymeTypeTree}; - - pub(crate) struct EnzymeWrapper { - pub registerEnzymeAndPassPipeline: *const c_void, - } - - impl EnzymeWrapper { - pub(crate) fn get_or_init( - _sysroot: &rustc_session::config::Sysroot, - ) -> Result, Box> { - unimplemented!("Enzyme not available: build with llvm_enzyme feature") - } - - pub(crate) fn init<'a, B: WriteBackendMethods>( - _cgcx: &'a CodegenContext, - ) -> &'static Mutex { - unimplemented!("Enzyme not available: build with llvm_enzyme feature") - } - - pub(crate) fn get_instance() -> MutexGuard<'static, Self> { - unimplemented!("Enzyme not available: build with llvm_enzyme feature") - } - - pub(crate) fn new_type_tree(&self) -> CTypeTreeRef { - unimplemented!() - } - - pub(crate) fn new_type_tree_ct( - &self, - t: CConcreteType, - ctx: &Context, - ) -> *mut EnzymeTypeTree { - unimplemented!() - } - - pub(crate) fn new_type_tree_tr(&self, tree: CTypeTreeRef) -> CTypeTreeRef { - unimplemented!() - } - - pub(crate) fn free_type_tree(&self, tree: CTypeTreeRef) { - unimplemented!() - } - - pub(crate) fn merge_type_tree(&self, tree1: CTypeTreeRef, tree2: CTypeTreeRef) -> bool { - unimplemented!() - } - - pub(crate) fn tree_only_eq(&self, tree: CTypeTreeRef, num: i64) { - unimplemented!() - } - - pub(crate) fn tree_data0_eq(&self, tree: CTypeTreeRef) { - unimplemented!() - } - - pub(crate) fn shift_indicies_eq( - &self, - tree: CTypeTreeRef, - data_layout: *const c_char, - offset: i64, - max_size: i64, - add_offset: u64, - ) { - unimplemented!() - } - - pub(crate) fn tree_insert_eq( - &self, - tree: CTypeTreeRef, - indices: *const i64, - len: usize, - ct: CConcreteType, - ctx: &Context, - ) { - unimplemented!() - } - - pub(crate) fn tree_to_string(&self, tree: *mut EnzymeTypeTree) -> *const c_char { - unimplemented!() - } - - pub(crate) fn tree_to_string_free(&self, ch: *const c_char) { - unimplemented!() - } - - pub(crate) fn get_max_type_depth(&self) -> usize { - unimplemented!() - } - - pub(crate) fn set_inline(&mut self, val: bool) { - unimplemented!() - } - - pub(crate) fn set_print_perf(&mut self, print: bool) { - unimplemented!() - } - - pub(crate) fn set_print_activity(&mut self, print: bool) { - unimplemented!() - } - - pub(crate) fn set_print_type(&mut self, print: bool) { - unimplemented!() - } - - pub(crate) fn set_print_type_fun(&mut self, fun_name: &str) { - unimplemented!() - } - - pub(crate) fn set_print(&mut self, print: bool) { - unimplemented!() - } - - pub(crate) fn set_strict_aliasing(&mut self, strict: bool) { - unimplemented!() - } - - pub(crate) fn set_loose_types(&mut self, loose: bool) { - unimplemented!() - } - - pub(crate) fn set_rust_rules(&mut self, val: bool) { - unimplemented!() - } - } -} - impl TypeTree { pub(crate) fn new() -> TypeTree { let wrapper = EnzymeWrapper::get_instance(); diff --git a/compiler/rustc_codegen_llvm/src/typetree.rs b/compiler/rustc_codegen_llvm/src/typetree.rs index 513a832e7fe8..4f433f273c8c 100644 --- a/compiler/rustc_codegen_llvm/src/typetree.rs +++ b/compiler/rustc_codegen_llvm/src/typetree.rs @@ -1,15 +1,10 @@ -use rustc_ast::expand::typetree::FncTree; -#[cfg(feature = "llvm_enzyme")] -use { - crate::attributes, - crate::llvm::EnzymeWrapper, - rustc_ast::expand::typetree::TypeTree as RustTypeTree, - std::ffi::{CString, c_char, c_uint}, -}; +use std::ffi::{CString, c_char, c_uint}; -use crate::llvm::{self, Value}; +use rustc_ast::expand::typetree::{FncTree, TypeTree as RustTypeTree}; + +use crate::attributes; +use crate::llvm::{self, EnzymeWrapper, Value}; -#[cfg(feature = "llvm_enzyme")] fn to_enzyme_typetree( rust_typetree: RustTypeTree, _data_layout: &str, @@ -19,7 +14,6 @@ fn to_enzyme_typetree( process_typetree_recursive(&mut enzyme_tt, &rust_typetree, &[], llcx); enzyme_tt } -#[cfg(feature = "llvm_enzyme")] fn process_typetree_recursive( enzyme_tt: &mut llvm::TypeTree, rust_typetree: &RustTypeTree, @@ -57,13 +51,21 @@ fn process_typetree_recursive( } } -#[cfg(feature = "llvm_enzyme")] +#[cfg_attr(not(feature = "llvm_enzyme"), allow(unused))] pub(crate) fn add_tt<'ll>( llmod: &'ll llvm::Module, llcx: &'ll llvm::Context, fn_def: &'ll Value, tt: FncTree, ) { + // TypeTree processing uses functions from Enzyme, which we might not have available if we did + // not build this compiler with `llvm_enzyme`. This feature is not strictly necessary, but + // skipping this function increases the chance that Enzyme fails to compile some code. + // FIXME(autodiff): In the future we should conditionally run this function even without the + // `llvm_enzyme` feature, in case that libEnzyme was provided via rustup. + #[cfg(not(feature = "llvm_enzyme"))] + return; + let inputs = tt.args; let ret_tt: RustTypeTree = tt.ret; @@ -113,13 +115,3 @@ pub(crate) fn add_tt<'ll>( enzyme_wrapper.tree_to_string_free(c_str.as_ptr()); } } - -#[cfg(not(feature = "llvm_enzyme"))] -pub(crate) fn add_tt<'ll>( - _llmod: &'ll llvm::Module, - _llcx: &'ll llvm::Context, - _fn_def: &'ll Value, - _tt: FncTree, -) { - unimplemented!() -} diff --git a/tests/pretty/autodiff/autodiff_forward.pp b/tests/pretty/autodiff/autodiff_forward.pp index 6eddb5669c7a..ea4e294f1ac3 100644 --- a/tests/pretty/autodiff/autodiff_forward.pp +++ b/tests/pretty/autodiff/autodiff_forward.pp @@ -1,6 +1,6 @@ #![feature(prelude_import)] #![no_std] -//@ needs-enzyme +//@ only-nightly #![feature(autodiff)] #[macro_use] diff --git a/tests/pretty/autodiff/autodiff_forward.rs b/tests/pretty/autodiff/autodiff_forward.rs index e23a1b3e241e..4fa02bc85e3e 100644 --- a/tests/pretty/autodiff/autodiff_forward.rs +++ b/tests/pretty/autodiff/autodiff_forward.rs @@ -1,4 +1,4 @@ -//@ needs-enzyme +//@ only-nightly #![feature(autodiff)] //@ pretty-mode:expanded diff --git a/tests/pretty/autodiff/autodiff_reverse.pp b/tests/pretty/autodiff/autodiff_reverse.pp index 8f598b865c7b..9202e0a76635 100644 --- a/tests/pretty/autodiff/autodiff_reverse.pp +++ b/tests/pretty/autodiff/autodiff_reverse.pp @@ -1,6 +1,6 @@ #![feature(prelude_import)] #![no_std] -//@ needs-enzyme +//@ only-nightly #![feature(autodiff)] #[macro_use] diff --git a/tests/pretty/autodiff/autodiff_reverse.rs b/tests/pretty/autodiff/autodiff_reverse.rs index c50b81d7780d..f1a8f9b50a77 100644 --- a/tests/pretty/autodiff/autodiff_reverse.rs +++ b/tests/pretty/autodiff/autodiff_reverse.rs @@ -1,4 +1,4 @@ -//@ needs-enzyme +//@ only-nightly #![feature(autodiff)] //@ pretty-mode:expanded diff --git a/tests/pretty/autodiff/inherent_impl.pp b/tests/pretty/autodiff/inherent_impl.pp index 36a9222640ae..bc70c4076121 100644 --- a/tests/pretty/autodiff/inherent_impl.pp +++ b/tests/pretty/autodiff/inherent_impl.pp @@ -1,6 +1,6 @@ #![feature(prelude_import)] #![no_std] -//@ needs-enzyme +//@ only-nightly #![feature(autodiff)] #[macro_use] diff --git a/tests/pretty/autodiff/inherent_impl.rs b/tests/pretty/autodiff/inherent_impl.rs index 11ff209f9d89..e2702b7e51f6 100644 --- a/tests/pretty/autodiff/inherent_impl.rs +++ b/tests/pretty/autodiff/inherent_impl.rs @@ -1,4 +1,4 @@ -//@ needs-enzyme +//@ only-nightly #![feature(autodiff)] //@ pretty-mode:expanded diff --git a/tests/ui/autodiff/visibility.rs b/tests/ui/autodiff/visibility.rs index a84df75e7996..3cf13b5b5dce 100644 --- a/tests/ui/autodiff/visibility.rs +++ b/tests/ui/autodiff/visibility.rs @@ -1,5 +1,6 @@ //@ ignore-enzyme //@ revisions: std_autodiff no_std_autodiff +//@ only-nightly //@[no_std_autodiff] check-pass //@ proc-macro: my_macro.rs #![crate_type = "lib"] @@ -12,5 +13,4 @@ #[autodiff_forward(dfoo)] //[std_autodiff]~^^^ ERROR the name `autodiff_forward` is defined multiple times -//[std_autodiff]~^^ ERROR this rustc version does not support autodiff fn foo() {} diff --git a/tests/ui/autodiff/visibility.std_autodiff.stderr b/tests/ui/autodiff/visibility.std_autodiff.stderr index e45f1139012a..6a0cdd492e2d 100644 --- a/tests/ui/autodiff/visibility.std_autodiff.stderr +++ b/tests/ui/autodiff/visibility.std_autodiff.stderr @@ -1,5 +1,5 @@ error[E0252]: the name `autodiff_forward` is defined multiple times - --> $DIR/visibility.rs:11:5 + --> $DIR/visibility.rs:12:5 | LL | use std::autodiff::autodiff_forward; | ------------------------------- previous import of the macro `autodiff_forward` here @@ -13,12 +13,6 @@ help: you can use `as` to change the binding name of the import LL | use my_macro::autodiff_forward as other_autodiff_forward; // bring `autodiff_forward` in scope | +++++++++++++++++++++++++ -error: this rustc version does not support autodiff - --> $DIR/visibility.rs:13:1 - | -LL | #[autodiff_forward(dfoo)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0252`. diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff-use.nightly.stderr similarity index 95% rename from tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr rename to tests/ui/feature-gates/feature-gate-autodiff-use.nightly.stderr index e5edd8e45e6c..ca724632063d 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.has_support.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.nightly.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `autodiff` - --> $DIR/feature-gate-autodiff-use.rs:13:3 + --> $DIR/feature-gate-autodiff-use.rs:16:3 | LL | #[autodiff_reverse(dfoo)] | ^^^^^^^^^^^^^^^^ diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.rs b/tests/ui/feature-gates/feature-gate-autodiff-use.rs index 2864b786c121..d97c06de7de5 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.rs +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.rs @@ -1,17 +1,22 @@ -//@ revisions: has_support no_support -//@[no_support] ignore-enzyme -//@[has_support] needs-enzyme +//@ revisions: nightly stable +//@[nightly] only-nightly +//@[stable] only-stable // This checks that without enabling the autodiff feature, we can't import std::autodiff::autodiff; #![crate_type = "lib"] use std::autodiff::autodiff_reverse; -//[has_support]~^ ERROR use of unstable library feature `autodiff` -//[no_support]~^^ ERROR use of unstable library feature `autodiff` +//[nightly]~^ ERROR use of unstable library feature `autodiff` +//[stable]~^^ ERROR use of unstable library feature `autodiff` +//[stable]~| NOTE see issue #124509 for more information +//[stable]~| HELP add `#![feature(autodiff)]` to the crate attributes to enable +//[stable]~| NOTE this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date #[autodiff_reverse(dfoo)] -//[has_support]~^ ERROR use of unstable library feature `autodiff` [E0658] -//[no_support]~^^ ERROR use of unstable library feature `autodiff` [E0658] -//[no_support]~| ERROR this rustc version does not support autodiff +//[nightly]~^ ERROR use of unstable library feature `autodiff` [E0658] +//[stable]~^^ ERROR use of unstable library feature `autodiff` [E0658] +//[stable]~| NOTE see issue #124509 for more information +//[stable]~| HELP add `#![feature(autodiff)]` to the crate attributes to enable +//[stable]~| NOTE this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date fn foo() {} diff --git a/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr b/tests/ui/feature-gates/feature-gate-autodiff-use.stable.stderr similarity index 78% rename from tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr rename to tests/ui/feature-gates/feature-gate-autodiff-use.stable.stderr index 65ba033b3589..ca724632063d 100644 --- a/tests/ui/feature-gates/feature-gate-autodiff-use.no_support.stderr +++ b/tests/ui/feature-gates/feature-gate-autodiff-use.stable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature `autodiff` - --> $DIR/feature-gate-autodiff-use.rs:13:3 + --> $DIR/feature-gate-autodiff-use.rs:16:3 | LL | #[autodiff_reverse(dfoo)] | ^^^^^^^^^^^^^^^^ @@ -8,12 +8,6 @@ LL | #[autodiff_reverse(dfoo)] = help: add `#![feature(autodiff)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: this rustc version does not support autodiff - --> $DIR/feature-gate-autodiff-use.rs:13:1 - | -LL | #[autodiff_reverse(dfoo)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - error[E0658]: use of unstable library feature `autodiff` --> $DIR/feature-gate-autodiff-use.rs:9:5 | @@ -24,6 +18,6 @@ LL | use std::autodiff::autodiff_reverse; = help: add `#![feature(autodiff)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. From 2581c2571c904c180ec8dc2b0242413a5b251358 Mon Sep 17 00:00:00 2001 From: Urgau Date: Fri, 19 Dec 2025 18:13:07 +0100 Subject: [PATCH 062/126] Don't lint on interior mutable `const` item coming from derefs --- .../rustc_lint/src/interior_mutable_consts.rs | 8 ++++ ...nst-item-interior-mutations-const-deref.rs | 2 - ...item-interior-mutations-const-deref.stderr | 37 ------------------- 3 files changed, 8 insertions(+), 39 deletions(-) delete mode 100644 tests/ui/lint/const-item-interior-mutations-const-deref.stderr diff --git a/compiler/rustc_lint/src/interior_mutable_consts.rs b/compiler/rustc_lint/src/interior_mutable_consts.rs index 8576698dec33..4c7d2c6af93b 100644 --- a/compiler/rustc_lint/src/interior_mutable_consts.rs +++ b/compiler/rustc_lint/src/interior_mutable_consts.rs @@ -1,6 +1,7 @@ use rustc_hir::attrs::AttributeKind; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{Expr, ExprKind, ItemKind, Node, find_attr}; +use rustc_middle::ty::adjustment::Adjust; use rustc_session::{declare_lint, declare_lint_pass}; use crate::lints::{ConstItemInteriorMutationsDiag, ConstItemInteriorMutationsSuggestionStatic}; @@ -77,6 +78,13 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if let ExprKind::Path(qpath) = &receiver.kind && let Res::Def(DefKind::Const | DefKind::AssocConst, const_did) = typeck.qpath_res(qpath, receiver.hir_id) + // Don't consider derefs as those can do arbitrary things + // like using thread local (see rust-lang/rust#150157) + && !cx + .typeck_results() + .expr_adjustments(receiver) + .into_iter() + .any(|adj| matches!(adj.kind, Adjust::Deref(_))) // Let's do the attribute check after the other checks for perf reasons && find_attr!( cx.tcx.get_all_attrs(method_did), diff --git a/tests/ui/lint/const-item-interior-mutations-const-deref.rs b/tests/ui/lint/const-item-interior-mutations-const-deref.rs index ce684abacccd..021e0952da70 100644 --- a/tests/ui/lint/const-item-interior-mutations-const-deref.rs +++ b/tests/ui/lint/const-item-interior-mutations-const-deref.rs @@ -24,7 +24,5 @@ fn deref(&self) -> &Self::Target { fn main() { let count = LOCAL_COUNT.get(); - //~^ WARN mutation of an interior mutable `const` LOCAL_COUNT.set(count); - //~^ WARN mutation of an interior mutable `const` } diff --git a/tests/ui/lint/const-item-interior-mutations-const-deref.stderr b/tests/ui/lint/const-item-interior-mutations-const-deref.stderr deleted file mode 100644 index 35696d0ba100..000000000000 --- a/tests/ui/lint/const-item-interior-mutations-const-deref.stderr +++ /dev/null @@ -1,37 +0,0 @@ -warning: mutation of an interior mutable `const` item with call to `get` - --> $DIR/const-item-interior-mutations-const-deref.rs:26:17 - | -LL | let count = LOCAL_COUNT.get(); - | -----------^^^^^^ - | | - | `LOCAL_COUNT` is a interior mutable `const` item of type `LocalKey>` - | - = note: each usage of a `const` item creates a new temporary - = note: only the temporaries and never the original `const LOCAL_COUNT` will be modified - = help: for more details on interior mutability see - = note: `#[warn(const_item_interior_mutations)]` on by default -help: for a shared instance of `LOCAL_COUNT`, consider making it a `static` item instead - | -LL - const LOCAL_COUNT: LocalKey> = LocalKey { inner: Cell::new(8) }; -LL + static LOCAL_COUNT: LocalKey> = LocalKey { inner: Cell::new(8) }; - | - -warning: mutation of an interior mutable `const` item with call to `set` - --> $DIR/const-item-interior-mutations-const-deref.rs:28:5 - | -LL | LOCAL_COUNT.set(count); - | -----------^^^^^^^^^^^ - | | - | `LOCAL_COUNT` is a interior mutable `const` item of type `LocalKey>` - | - = note: each usage of a `const` item creates a new temporary - = note: only the temporaries and never the original `const LOCAL_COUNT` will be modified - = help: for more details on interior mutability see -help: for a shared instance of `LOCAL_COUNT`, consider making it a `static` item instead - | -LL - const LOCAL_COUNT: LocalKey> = LocalKey { inner: Cell::new(8) }; -LL + static LOCAL_COUNT: LocalKey> = LocalKey { inner: Cell::new(8) }; - | - -warning: 2 warnings emitted - From c3bd76b7afc20bb46c503d1a4edab9da82484f13 Mon Sep 17 00:00:00 2001 From: Redddy Date: Sat, 20 Dec 2025 15:22:41 +0900 Subject: [PATCH 063/126] Add Rustc Explore video link --- src/doc/rustc-dev-guide/src/appendix/compiler-lecture.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/rustc-dev-guide/src/appendix/compiler-lecture.md b/src/doc/rustc-dev-guide/src/appendix/compiler-lecture.md index 90c4097cc3e6..0bd4c6eb1339 100644 --- a/src/doc/rustc-dev-guide/src/appendix/compiler-lecture.md +++ b/src/doc/rustc-dev-guide/src/appendix/compiler-lecture.md @@ -6,6 +6,7 @@ These are videos where various experts explain different parts of the compiler: - [January 2019: Tom Tromey discusses debugging support in rustc](https://www.youtube.com/watch?v=elBxMRSNYr4) - [June 2019: Responsive compilers - Nicholas Matsakis - PLISS 2019](https://www.youtube.com/watch?v=N6b44kMS6OM) - [June 2019: Things I Learned (TIL) - Nicholas Matsakis - PLISS 2019](https://www.youtube.com/watch?v=LIYkT3p5gTs) +- [October 2022: Rustc Explore](https://www.youtube.com/playlist?list=PL85XCvVPmGQj3-MujOJ0jcoSqQ6Yi6Rkk) ## Rust Analyzer - [January 2019: How Salsa Works](https://www.youtube.com/watch?v=_muY4HjSqVw) @@ -46,4 +47,4 @@ These are videos where various experts explain different parts of the compiler: ## Code Generation - [January 2019: Cranelift](https://www.youtube.com/watch?v=9OIA7DTFQWU) -- [December 2024: LLVM Developers' Meeting - Rust ❤️ LLVM](https://www.youtube.com/watch?v=Kqz-umsAnk8) \ No newline at end of file +- [December 2024: LLVM Developers' Meeting - Rust ❤️ LLVM](https://www.youtube.com/watch?v=Kqz-umsAnk8) From 69c43e838df4d097c63079513edf3404f9541f0b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Dec 2025 08:12:48 +0100 Subject: [PATCH 064/126] Prepare for merging from rust-lang/rust This updates the rust-version file to f51d1bcdc69f9bba47cc1656260ff76e6ff5fba3. --- 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 d4fbfacf4eda..de0270f31fe5 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -526a91cbcc4601b92b0587405015e07b9c0d79f6 +f51d1bcdc69f9bba47cc1656260ff76e6ff5fba3 From d11ac79eeffab870de09ab62de1ef1383f38b429 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Dec 2025 08:22:15 +0100 Subject: [PATCH 065/126] normalize file name changes away --- src/tools/miri/tests/panic/mir-validation.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tools/miri/tests/panic/mir-validation.rs b/src/tools/miri/tests/panic/mir-validation.rs index 11c4e395920c..4c863c5a9de8 100644 --- a/src/tools/miri/tests/panic/mir-validation.rs +++ b/src/tools/miri/tests/panic/mir-validation.rs @@ -5,6 +5,8 @@ //@normalize-stderr-test: "\n +\[\.\.\. omitted [0-9]+ frames? \.\.\.\].*" -> "" //@normalize-stderr-test: "\n[ =]*note:.*" -> "" //@normalize-stderr-test: "DefId\([^()]*\)" -> "DefId" +// Paths differ between bootstrap and stand-alone Miri runs, normalize them to be the same +//@normalize-stderr-test: "/rustc-dev/[^/]*/" -> "" // Somehow on rustc Windows CI, the "Miri caused an ICE" message is not shown // and we don't even get a regular panic; rustc aborts with a different exit code instead. //@ignore-host: windows From 19f74f46f999fda8910a596746dd595337be7139 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 20 Dec 2025 18:26:02 +1100 Subject: [PATCH 066/126] Use the same length type for `TestableCase::Slice` and `TestKind::Len` If we convert the minimum length to `u64` up-front when creating `TestableCase::Slice`, we can avoid more conversions to `u64` later. --- compiler/rustc_mir_build/src/builder/matches/buckets.rs | 4 ++-- compiler/rustc_mir_build/src/builder/matches/match_pair.rs | 2 +- compiler/rustc_mir_build/src/builder/matches/mod.rs | 2 +- compiler/rustc_mir_build/src/builder/matches/test.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/buckets.rs b/compiler/rustc_mir_build/src/builder/matches/buckets.rs index 6c5f0ed28a82..8cbbb8e14095 100644 --- a/compiler/rustc_mir_build/src/builder/matches/buckets.rs +++ b/compiler/rustc_mir_build/src/builder/matches/buckets.rs @@ -218,7 +218,7 @@ fn choose_bucket_for_candidate( &TestKind::Len { len: test_len, op: BinOp::Eq }, &TestableCase::Slice { len, variable_length }, ) => { - match (test_len.cmp(&(len as u64)), variable_length) { + match (test_len.cmp(&len), variable_length) { (Ordering::Equal, false) => { // on true, min_len = len = $actual_length, // on false, len != $actual_length @@ -251,7 +251,7 @@ fn choose_bucket_for_candidate( &TestableCase::Slice { len, variable_length }, ) => { // the test is `$actual_len >= test_len` - match (test_len.cmp(&(len as u64)), variable_length) { + match (test_len.cmp(&len), variable_length) { (Ordering::Equal, true) => { // $actual_len >= test_len = pat_len, // so we can match. diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 6b4ba9243479..9b9ee1836956 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -256,7 +256,7 @@ pub(super) fn for_pattern( None } else { Some(TestableCase::Slice { - len: prefix.len() + suffix.len(), + len: u64::try_from(prefix.len() + suffix.len()).unwrap(), variable_length: slice.is_some(), }) } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 66e36a99d3c4..8897ca7c7210 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1264,7 +1264,7 @@ enum TestableCase<'tcx> { Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx }, Constant { value: ty::Value<'tcx> }, Range(Arc>), - Slice { len: usize, variable_length: bool }, + Slice { len: u64, variable_length: bool }, Deref { temp: Place<'tcx>, mutability: Mutability }, Never, Or { pats: Box<[FlatPat<'tcx>]> }, diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 55e21ff18aae..402587bff7e8 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -47,7 +47,7 @@ pub(super) fn pick_test_for_match_pair( TestableCase::Slice { len, variable_length } => { let op = if variable_length { BinOp::Ge } else { BinOp::Eq }; - TestKind::Len { len: len as u64, op } + TestKind::Len { len, op } } TestableCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability }, From 889ad15b62c46ed81187d27df8cc762226ae4520 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Dec 2025 11:02:37 +0100 Subject: [PATCH 067/126] interpreter/visitor: always iterate in in-memory order --- .../rustc_const_eval/src/interpret/visitor.rs | 17 +---------------- src/tools/miri/src/helpers.rs | 7 ------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs index 95106c7c143b..a8d472bc2ea2 100644 --- a/compiler/rustc_const_eval/src/interpret/visitor.rs +++ b/compiler/rustc_const_eval/src/interpret/visitor.rs @@ -4,7 +4,6 @@ use std::num::NonZero; use rustc_abi::{FieldIdx, FieldsShape, VariantIdx, Variants}; -use rustc_index::{Idx as _, IndexVec}; use rustc_middle::mir::interpret::InterpResult; use rustc_middle::ty::{self, Ty}; use tracing::trace; @@ -24,20 +23,6 @@ fn read_discriminant(&mut self, v: &Self::V) -> InterpResult<'tcx, VariantIdx> { self.ecx().read_discriminant(&v.to_op(self.ecx())?) } - /// This function provides the chance to reorder the order in which fields are visited for - /// `FieldsShape::Aggregate`. - /// - /// The default means we iterate in source declaration order; alternatively this can use - /// `in_memory_order` to iterate in memory order. - #[inline(always)] - fn aggregate_field_iter( - in_memory_order: &IndexVec, - ) -> impl Iterator { - // Allow the optimizer to elide the bounds checking when creating each index. - let _ = FieldIdx::new(in_memory_order.len()); - (0..in_memory_order.len()).map(FieldIdx::new) - } - // Recursive actions, ready to be overloaded. /// Visits the given value, dispatching as appropriate to more specialized visitors. #[inline(always)] @@ -171,7 +156,7 @@ fn walk_value(&mut self, v: &Self::V) -> InterpResult<'tcx> { self.visit_union(v, fields)?; } FieldsShape::Arbitrary { in_memory_order, .. } => { - for idx in Self::aggregate_field_iter(in_memory_order) { + for idx in in_memory_order.iter().copied() { let field = self.ecx().project_field(v, idx)?; self.visit_field(v, idx.as_usize(), &field)?; } diff --git a/src/tools/miri/src/helpers.rs b/src/tools/miri/src/helpers.rs index 218e4ffe5e2f..f4fc478481a7 100644 --- a/src/tools/miri/src/helpers.rs +++ b/src/tools/miri/src/helpers.rs @@ -10,7 +10,6 @@ use rustc_hir::Safety; use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::def_id::{CRATE_DEF_INDEX, CrateNum, DefId, LOCAL_CRATE}; -use rustc_index::IndexVec; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::ExportedSymbol; @@ -583,12 +582,6 @@ fn ecx(&self) -> &MiriInterpCx<'tcx> { self.ecx } - fn aggregate_field_iter( - in_memory_order: &IndexVec, - ) -> impl Iterator { - in_memory_order.iter().copied() - } - // Hook to detect `UnsafeCell`. fn visit_value(&mut self, v: &MPlaceTy<'tcx>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); From 5d8a096afeb4cd9b7ef7693aa6692afe71fbf5bc Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Fri, 19 Dec 2025 14:46:18 +0000 Subject: [PATCH 068/126] change non-canonical clone impl to {*self}, fix some doc comments --- compiler/rustc_graphviz/src/lib.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_pattern_analysis/src/lib.rs | 2 +- compiler/rustc_pattern_analysis/src/pat.rs | 5 +---- compiler/rustc_pattern_analysis/src/usefulness.rs | 2 +- compiler/rustc_thread_pool/src/registry.rs | 14 ++++++-------- 6 files changed, 11 insertions(+), 16 deletions(-) diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 9f75578aa636..cd1e573ea28d 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -416,7 +416,7 @@ pub fn as_slice(&'a self) -> &'a str { /// it in the generated .dot file. They can also provide more /// elaborate (and non-unique) label text that is used in the graphviz /// rendered output. - +/// /// The graph instance is responsible for providing the DOT compatible /// identifiers for the nodes and (optionally) rendered labels for the nodes and /// edges, as well as an identifier for the graph itself. diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 471bd1d937e9..9e4692b96418 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2654,7 +2654,7 @@ pub fn debug_stats(self) -> impl fmt::Debug { impl<'tcx, T: 'tcx + ?Sized + PointeeSized> Clone for InternedInSet<'tcx, T> { fn clone(&self) -> Self { - InternedInSet(self.0) + *self } } diff --git a/compiler/rustc_pattern_analysis/src/lib.rs b/compiler/rustc_pattern_analysis/src/lib.rs index d9bb93a829b5..f3308086ddc6 100644 --- a/compiler/rustc_pattern_analysis/src/lib.rs +++ b/compiler/rustc_pattern_analysis/src/lib.rs @@ -141,7 +141,7 @@ pub struct MatchArm<'p, Cx: PatCx> { impl<'p, Cx: PatCx> Clone for MatchArm<'p, Cx> { fn clone(&self) -> Self { - Self { pat: self.pat, has_guard: self.has_guard, arm_data: self.arm_data } + *self } } diff --git a/compiler/rustc_pattern_analysis/src/pat.rs b/compiler/rustc_pattern_analysis/src/pat.rs index 901b72e53995..51d0703f9c5c 100644 --- a/compiler/rustc_pattern_analysis/src/pat.rs +++ b/compiler/rustc_pattern_analysis/src/pat.rs @@ -174,10 +174,7 @@ pub(crate) enum PatOrWild<'p, Cx: PatCx> { impl<'p, Cx: PatCx> Clone for PatOrWild<'p, Cx> { fn clone(&self) -> Self { - match self { - PatOrWild::Wild => PatOrWild::Wild, - PatOrWild::Pat(pat) => PatOrWild::Pat(pat), - } + *self } } diff --git a/compiler/rustc_pattern_analysis/src/usefulness.rs b/compiler/rustc_pattern_analysis/src/usefulness.rs index 19446a1efe9c..971616b18914 100644 --- a/compiler/rustc_pattern_analysis/src/usefulness.rs +++ b/compiler/rustc_pattern_analysis/src/usefulness.rs @@ -824,7 +824,7 @@ struct PlaceCtxt<'a, Cx: PatCx> { impl<'a, Cx: PatCx> Copy for PlaceCtxt<'a, Cx> {} impl<'a, Cx: PatCx> Clone for PlaceCtxt<'a, Cx> { fn clone(&self) -> Self { - Self { cx: self.cx, ty: self.ty } + *self } } diff --git a/compiler/rustc_thread_pool/src/registry.rs b/compiler/rustc_thread_pool/src/registry.rs index 4a018ea743ae..92bb8961e7df 100644 --- a/compiler/rustc_thread_pool/src/registry.rs +++ b/compiler/rustc_thread_pool/src/registry.rs @@ -153,8 +153,8 @@ pub struct Registry { terminate_count: AtomicUsize, } -/// //////////////////////////////////////////////////////////////////////// -/// Initialization +/////////////////////////////////////////////////////////////////////////// +// Initialization static mut THE_REGISTRY: Option> = None; static THE_REGISTRY_SET: Once = Once::new(); @@ -407,12 +407,12 @@ pub(crate) fn release_thread(&self) { } } - /// //////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////////////// /// MAIN LOOP /// /// So long as all of the worker threads are hanging out in their /// top-level loop, there is no work to be done. - + /// /// Push a job into the given `registry`. If we are running on a /// worker thread for the registry, this will push onto the /// deque. Else, it will inject from the outside (which is slower). @@ -668,8 +668,8 @@ fn new(stealer: Stealer) -> ThreadInfo { } } -/// //////////////////////////////////////////////////////////////////////// -/// WorkerThread identifiers +/////////////////////////////////////////////////////////////////////////// +// WorkerThread identifiers pub(super) struct WorkerThread { /// the "worker" half of our local deque @@ -1019,8 +1019,6 @@ fn steal(&self) -> Option { } } -/// //////////////////////////////////////////////////////////////////////// - unsafe fn main_loop(thread: ThreadBuilder) { let worker_thread = &WorkerThread::from(thread); unsafe { WorkerThread::set_current(worker_thread) }; From c556e9c2fa0a287f0289dc1548159ac9822c5318 Mon Sep 17 00:00:00 2001 From: Brian Campbell Date: Sat, 20 Dec 2025 03:07:05 -0500 Subject: [PATCH 069/126] [rustdoc] Add missing close tags in extern crate reexports --- src/librustdoc/html/render/print_item.rs | 1 + tests/rustdoc/extern/pub-extern-crate-150176.rs | 5 +++++ 2 files changed, 6 insertions(+) create mode 100644 tests/rustdoc/extern/pub-extern-crate-150176.rs diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index f88a5b8974fb..0b52c0b56b82 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -439,6 +439,7 @@ fn cmp(i1: &clean::Item, i2: &clean::Item, tcx: TyCtxt<'_>) -> Ordering { )?; } } + write!(w, "")? } clean::ImportItem(ref import) => { let stab_tags = diff --git a/tests/rustdoc/extern/pub-extern-crate-150176.rs b/tests/rustdoc/extern/pub-extern-crate-150176.rs new file mode 100644 index 000000000000..b68619c5a02d --- /dev/null +++ b/tests/rustdoc/extern/pub-extern-crate-150176.rs @@ -0,0 +1,5 @@ +//@ aux-build:pub-extern-crate.rs + +//@ has pub_extern_crate_150176/index.html +//@ hasraw - 'pub extern crate inner;' +pub extern crate inner; From 93fbf3b885fa9d0bd2a0fec2cbb32cfdb91cc5eb Mon Sep 17 00:00:00 2001 From: Justin Geibel Date: Sat, 20 Dec 2025 11:23:38 -0500 Subject: [PATCH 070/126] Drop the From derive macro from the v1 prelude This was accidentally added to the prelude in 3f4dc1e02d759aa3c3807d4efc1f7f6e293536a5. --- library/core/src/prelude/v1.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/library/core/src/prelude/v1.rs b/library/core/src/prelude/v1.rs index 977fd1926fd0..a5d9a5352dfc 100644 --- a/library/core/src/prelude/v1.rs +++ b/library/core/src/prelude/v1.rs @@ -118,13 +118,6 @@ )] pub use crate::macros::builtin::define_opaque; -#[unstable( - feature = "derive_from", - issue = "144889", - reason = "`derive(From)` is unstable" -)] -pub use crate::macros::builtin::From; - #[unstable(feature = "extern_item_impls", issue = "125418")] pub use crate::macros::builtin::{eii, unsafe_eii}; From 44a9d841f47006c34ccddad7809cca2a21e02e1e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 19 Dec 2025 21:20:27 -0500 Subject: [PATCH 071/126] Don't export upstream monomorphizations from compiler-builtins --- compiler/rustc_middle/src/ty/context.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 471bd1d937e9..779a5f3f5218 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2272,6 +2272,12 @@ pub fn serialize_query_result_cache(self, encoder: FileEncoder) -> FileEncodeRes #[inline] pub fn local_crate_exports_generics(self) -> bool { + // compiler-builtins has some special treatment in codegen, which can result in confusing + // behavior if another crate ends up calling into its monomorphizations. + // https://github.com/rust-lang/rust/issues/150173 + if self.is_compiler_builtins(LOCAL_CRATE) { + return false; + } self.crate_types().iter().any(|crate_type| { match crate_type { CrateType::Executable From b7a0f84a5aef6b097636c29408c8bddf89a711bf Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 20 Dec 2025 20:35:30 +0100 Subject: [PATCH 072/126] tests/debuginfo/function-arg-initialization.rs: Stop disabling SingleUseConsts MIR pass --- tests/debuginfo/function-arg-initialization.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/debuginfo/function-arg-initialization.rs b/tests/debuginfo/function-arg-initialization.rs index c3b7ed81d026..78fecd8a4bfe 100644 --- a/tests/debuginfo/function-arg-initialization.rs +++ b/tests/debuginfo/function-arg-initialization.rs @@ -6,8 +6,7 @@ // function name. //@ min-lldb-version: 1800 -//@ compile-flags:-g -Zmir-enable-passes=-SingleUseConsts -// SingleUseConsts shouldn't need to be disabled, see #128945 +//@ compile-flags:-g //@ disable-gdb-pretty-printers //@ ignore-backends: gcc From 8825e1fe5d3a142228277f0df36dae19310a723f Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Wed, 17 Dec 2025 10:32:13 +0100 Subject: [PATCH 073/126] library/coretests/tests/fmt/mod.rs: Add HRTB fn pointer case --- library/coretests/tests/fmt/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs index d0ae7124f474..0fb099ef4191 100644 --- a/library/coretests/tests/fmt/mod.rs +++ b/library/coretests/tests/fmt/mod.rs @@ -30,6 +30,12 @@ fn test_format_flags() { assert_eq!(format!("{:p} {:x}", p, 16), format!("{p:p} 10")); assert_eq!(format!("{: >3}", 'a'), " a"); + + /// Regression test for . + fn show(a: fn() -> f32, b: fn(&Vec) -> f32) { + println!("the two pointers: {:p} {:p}", a, b); + } + show(|| 1.0, |_| 2.0); } #[test] From c67b99fa093492459b59438235bc1a1301641067 Mon Sep 17 00:00:00 2001 From: Camille Gillot Date: Sun, 21 Dec 2025 00:42:34 +0000 Subject: [PATCH 074/126] Reinstate bonus for unused `UbChecks`. --- .../rustc_mir_transform/src/cost_checker.rs | 26 +- tests/codegen-llvm/slice-iter-len-eq-zero.rs | 4 +- ..._conditions.JumpThreading.panic-abort.diff | 446 ++++++++++++++++-- ...conditions.JumpThreading.panic-unwind.diff | 446 ++++++++++++++++-- 4 files changed, 862 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_mir_transform/src/cost_checker.rs b/compiler/rustc_mir_transform/src/cost_checker.rs index aaf735269b22..331c98fc198e 100644 --- a/compiler/rustc_mir_transform/src/cost_checker.rs +++ b/compiler/rustc_mir_transform/src/cost_checker.rs @@ -60,7 +60,27 @@ fn instantiate_ty(&self, v: Ty<'tcx>) -> Ty<'tcx> { } impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { + fn visit_operand(&mut self, operand: &Operand<'tcx>, _: Location) { + match operand { + Operand::RuntimeChecks(RuntimeChecks::UbChecks) => { + if !self + .tcx + .sess + .opts + .unstable_opts + .inline_mir_preserve_debug + .unwrap_or(self.tcx.sess.ub_checks()) + { + // If this is in optimized MIR it's because it's used later, so if we don't need UB + // checks this session, give a bonus here to offset the cost of the call later. + self.bonus += CALL_PENALTY; + } + } + _ => {} + } + } + + fn visit_statement(&mut self, statement: &Statement<'tcx>, loc: Location) { // Most costs are in rvalues and terminators, not in statements. match statement.kind { StatementKind::Intrinsic(ref ndi) => { @@ -72,9 +92,10 @@ fn visit_statement(&mut self, statement: &Statement<'tcx>, _: Location) { StatementKind::Assign(..) => self.penalty += INSTR_COST, _ => {} } + self.super_statement(statement, loc) } - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _: Location) { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, loc: Location) { match &terminator.kind { TerminatorKind::Drop { place, unwind, .. } => { // If the place doesn't actually need dropping, treat it like a regular goto. @@ -151,6 +172,7 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, _: Location) { bug!("{kind:?} should not be in runtime MIR"); } } + self.super_terminator(terminator, loc) } } diff --git a/tests/codegen-llvm/slice-iter-len-eq-zero.rs b/tests/codegen-llvm/slice-iter-len-eq-zero.rs index 3085fbaed36a..6998d98e498c 100644 --- a/tests/codegen-llvm/slice-iter-len-eq-zero.rs +++ b/tests/codegen-llvm/slice-iter-len-eq-zero.rs @@ -8,7 +8,7 @@ #[no_mangle] pub fn slice_iter_len_eq_zero(y: std::slice::Iter<'_, Demo>) -> bool { // CHECK-NOT: sub - // CHECK: %[[RET:.+]] = icmp eq ptr {{%0, %1|%1, %0}} + // CHECK: %[[RET:.+]] = icmp eq ptr {{%y.0, %y.1|%y.1, %y.0}} // CHECK: ret i1 %[[RET]] y.len() == 0 } @@ -31,7 +31,7 @@ pub fn slice_iter_len_eq_zero_ref(y: &mut std::slice::Iter<'_, Demo>) -> bool { // CHECK-LABEL: @slice_zst_iter_len_eq_zero #[no_mangle] pub fn slice_zst_iter_len_eq_zero(y: std::slice::Iter<'_, MyZST>) -> bool { - // CHECK: %[[RET:.+]] = icmp eq ptr %1, null + // CHECK: %[[RET:.+]] = icmp eq ptr %y.1, null // CHECK: ret i1 %[[RET]] y.len() == 0 } diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff index f09a187bfaf8..8777ac426d78 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-abort.diff @@ -43,10 +43,192 @@ scope 4 (inlined std::cmp::impls:: for &String>::eq) { let mut _27: &std::string::String; let mut _28: &str; + scope 5 (inlined >::eq) { + scope 6 (inlined #[track_caller] >::index) { + let _29: &str; + scope 7 (inlined String::as_str) { + let _30: &[u8]; + let mut _31: &std::vec::Vec; + scope 8 (inlined Vec::::as_slice) { + let mut _32: *const u8; + let mut _33: usize; + scope 9 (inlined Vec::::as_ptr) { + scope 10 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 11 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 12 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _34: std::ptr::NonNull; + scope 13 (inlined Unique::::cast::) { + scope 14 (inlined NonNull::::cast::) { + scope 15 (inlined NonNull::::as_ptr) { + } + } + } + scope 16 (inlined Unique::::as_non_null_ptr) { + } + } + scope 17 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 18 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { + let _35: (); + let mut _36: *mut (); + let _37: *const [u8]; + scope 19 (inlined ub_checks::check_language_ub) { + scope 20 (inlined ub_checks::check_language_ub::runtime) { + } + } + scope 21 (inlined std::mem::size_of::) { + } + scope 22 (inlined std::mem::align_of::) { + } + scope 23 (inlined slice_from_raw_parts::) { + scope 24 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + } + } + } + } + scope 25 (inlined from_utf8_unchecked) { + } + } + scope 26 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + } + } + scope 27 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 28 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + } + } + scope 29 (inlined core::str::traits::::eq) { + let mut _38: &&[u8]; + let _39: &[u8]; + let mut _40: &&[u8]; + let _41: &[u8]; + scope 30 (inlined core::str::::as_bytes) { + } + scope 31 (inlined core::str::::as_bytes) { + } + scope 32 (inlined std::cmp::impls::::eq) { + scope 33 (inlined core::slice::cmp::::eq) { + scope 34 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { + let mut _42: bool; + let mut _43: usize; + let mut _44: usize; + let _45: usize; + let mut _46: i32; + let mut _47: *const u8; + let mut _48: *const u8; + scope 35 { + scope 37 (inlined core::slice::::as_ptr) { + let mut _50: *const [u8]; + } + scope 38 (inlined core::slice::::as_ptr) { + let mut _51: *const [u8]; + } + } + scope 36 (inlined std::mem::size_of_val::<[u8]>) { + let mut _49: *const [u8]; + } + } + } + } + } + } } - scope 5 (inlined std::cmp::impls:: for &String>::eq) { - let mut _29: &std::string::String; - let mut _30: &str; + scope 39 (inlined std::cmp::impls:: for &String>::eq) { + let mut _52: &std::string::String; + let mut _53: &str; + scope 40 (inlined >::eq) { + scope 41 (inlined #[track_caller] >::index) { + let _54: &str; + scope 42 (inlined String::as_str) { + let _55: &[u8]; + let mut _56: &std::vec::Vec; + scope 43 (inlined Vec::::as_slice) { + let mut _57: *const u8; + let mut _58: usize; + scope 44 (inlined Vec::::as_ptr) { + scope 45 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 46 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 47 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _59: std::ptr::NonNull; + scope 48 (inlined Unique::::cast::) { + scope 49 (inlined NonNull::::cast::) { + scope 50 (inlined NonNull::::as_ptr) { + } + } + } + scope 51 (inlined Unique::::as_non_null_ptr) { + } + } + scope 52 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 53 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { + let _60: (); + let mut _61: *mut (); + let _62: *const [u8]; + scope 54 (inlined ub_checks::check_language_ub) { + scope 55 (inlined ub_checks::check_language_ub::runtime) { + } + } + scope 56 (inlined std::mem::size_of::) { + } + scope 57 (inlined std::mem::align_of::) { + } + scope 58 (inlined slice_from_raw_parts::) { + scope 59 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + } + } + } + } + scope 60 (inlined from_utf8_unchecked) { + } + } + scope 61 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + } + } + scope 62 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 63 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + } + } + scope 64 (inlined core::str::traits::::eq) { + let mut _63: &&[u8]; + let _64: &[u8]; + let mut _65: &&[u8]; + let _66: &[u8]; + scope 65 (inlined core::str::::as_bytes) { + } + scope 66 (inlined core::str::::as_bytes) { + } + scope 67 (inlined std::cmp::impls::::eq) { + scope 68 (inlined core::slice::cmp::::eq) { + scope 69 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { + let mut _67: bool; + let mut _68: usize; + let mut _69: usize; + let _70: usize; + let mut _71: i32; + let mut _72: *const u8; + let mut _73: *const u8; + scope 70 { + scope 72 (inlined core::slice::::as_ptr) { + let mut _75: *const [u8]; + } + scope 73 (inlined core::slice::::as_ptr) { + let mut _76: *const [u8]; + } + } + scope 71 (inlined std::mem::size_of_val::<[u8]>) { + let mut _74: *const [u8]; + } + } + } + } + } + } } bb0: { @@ -71,7 +253,7 @@ bb3: { _1 = chained_conditions::BacktraceStyle::Off; - goto -> bb18; -+ goto -> bb23; ++ goto -> bb37; } bb4: { @@ -89,7 +271,16 @@ StorageLive(_28); _27 = copy (*_8); _28 = copy (*_10); - _7 = >::eq(move _27, move _28) -> [return: bb19, unwind unreachable]; + StorageLive(_29); + StorageLive(_35); + StorageLive(_30); + StorageLive(_34); + StorageLive(_32); + _34 = copy ((((((*_27).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _32 = copy _34 as *const u8 (Transmute); + StorageLive(_33); + _33 = copy (((*_27).0: std::vec::Vec).1: usize); + switchInt(UbChecks) -> [0: bb21, otherwise: bb19]; } bb5: { @@ -120,18 +311,27 @@ StorageLive(_17); _20 = const chained_conditions::promoted[0]; _17 = &(*_20); - StorageLive(_29); - StorageLive(_30); - _29 = copy (*_15); - _30 = copy (*_17); - _14 = >::eq(move _29, move _30) -> [return: bb20, unwind unreachable]; + StorageLive(_52); + StorageLive(_53); + _52 = copy (*_15); + _53 = copy (*_17); + StorageLive(_54); + StorageLive(_60); + StorageLive(_55); + StorageLive(_59); + StorageLive(_57); + _59 = copy ((((((*_52).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _57 = copy _59 as *const u8 (Transmute); + StorageLive(_58); + _58 = copy (((*_52).0: std::vec::Vec).1: usize); + switchInt(UbChecks) -> [0: bb29, otherwise: bb27]; } bb7: { StorageDead(_5); StorageDead(_6); - goto -> bb18; -+ goto -> bb21; ++ goto -> bb39; } bb8: { @@ -154,14 +354,14 @@ StorageDead(_13); _1 = chained_conditions::BacktraceStyle::Short; - goto -> bb18; -+ goto -> bb23; ++ goto -> bb37; } bb10: { StorageDead(_12); StorageDead(_13); - goto -> bb18; -+ goto -> bb21; ++ goto -> bb39; } bb11: { @@ -206,33 +406,223 @@ } bb19: { + StorageLive(_36); + _36 = copy _34 as *mut () (Transmute); + _35 = std::slice::from_raw_parts::precondition_check(move _36, const ::SIZE, const ::ALIGN, copy _33) -> [return: bb20, unwind unreachable]; + } + + bb20: { + StorageDead(_36); + goto -> bb21; + } + + bb21: { + StorageLive(_37); + _37 = *const [u8] from (copy _32, copy _33); + _30 = &(*_37); + StorageDead(_37); + StorageDead(_33); + StorageDead(_32); + StorageDead(_34); + _29 = copy _30 as &str (Transmute); + StorageDead(_30); + StorageLive(_39); + StorageLive(_41); + _39 = copy _29 as &[u8] (Transmute); + _41 = copy _28 as &[u8] (Transmute); + StorageLive(_45); + StorageLive(_50); + StorageLive(_51); + StorageLive(_42); + StorageLive(_43); + _43 = PtrMetadata(copy _39); + StorageLive(_44); + _44 = PtrMetadata(copy _41); + _42 = Ne(move _43, move _44); + switchInt(move _42) -> [0: bb24, otherwise: bb23]; + } + + bb22: { + StorageDead(_51); + StorageDead(_50); + StorageDead(_45); + StorageDead(_41); + StorageDead(_39); + StorageDead(_35); + StorageDead(_29); StorageDead(_28); StorageDead(_27); switchInt(move _7) -> [0: bb6, otherwise: bb5]; } - bb20: { - StorageDead(_30); - StorageDead(_29); + bb23: { + StorageDead(_44); + StorageDead(_43); + _7 = const false; + StorageDead(_42); +- goto -> bb22; ++ goto -> bb35; + } + + bb24: { + StorageDead(_44); + StorageDead(_43); + StorageDead(_42); + StorageLive(_49); + _49 = &raw const (*_39); + _45 = std::intrinsics::size_of_val::<[u8]>(move _49) -> [return: bb26, unwind unreachable]; + } + + bb25: { + StorageDead(_48); + StorageDead(_47); + _7 = Eq(move _46, const 0_i32); + StorageDead(_46); + goto -> bb22; + } + + bb26: { + StorageDead(_49); + StorageLive(_46); + StorageLive(_47); + _50 = &raw const (*_39); + _47 = copy _50 as *const u8 (PtrToPtr); + StorageLive(_48); + _51 = &raw const (*_41); + _48 = copy _51 as *const u8 (PtrToPtr); + _46 = compare_bytes(move _47, move _48, move _45) -> [return: bb25, unwind unreachable]; + } + + bb27: { + StorageLive(_61); + _61 = copy _59 as *mut () (Transmute); + _60 = std::slice::from_raw_parts::precondition_check(move _61, const ::SIZE, const ::ALIGN, copy _58) -> [return: bb28, unwind unreachable]; + } + + bb28: { + StorageDead(_61); + goto -> bb29; + } + + bb29: { + StorageLive(_62); + _62 = *const [u8] from (copy _57, copy _58); + _55 = &(*_62); + StorageDead(_62); + StorageDead(_58); + StorageDead(_57); + StorageDead(_59); + _54 = copy _55 as &str (Transmute); + StorageDead(_55); + StorageLive(_64); + StorageLive(_66); + _64 = copy _54 as &[u8] (Transmute); + _66 = copy _53 as &[u8] (Transmute); + StorageLive(_70); + StorageLive(_75); + StorageLive(_76); + StorageLive(_67); + StorageLive(_68); + _68 = PtrMetadata(copy _64); + StorageLive(_69); + _69 = PtrMetadata(copy _66); + _67 = Ne(move _68, move _69); + switchInt(move _67) -> [0: bb32, otherwise: bb31]; + } + + bb30: { + StorageDead(_76); + StorageDead(_75); + StorageDead(_70); + StorageDead(_66); + StorageDead(_64); + StorageDead(_60); + StorageDead(_54); + StorageDead(_53); + StorageDead(_52); switchInt(move _14) -> [0: bb9, otherwise: bb8]; + } + + bb31: { + StorageDead(_69); + StorageDead(_68); + _14 = const false; + StorageDead(_67); +- goto -> bb30; ++ goto -> bb36; + } + + bb32: { + StorageDead(_69); + StorageDead(_68); + StorageDead(_67); + StorageLive(_74); + _74 = &raw const (*_64); + _70 = std::intrinsics::size_of_val::<[u8]>(move _74) -> [return: bb34, unwind unreachable]; + } + + bb33: { + StorageDead(_73); + StorageDead(_72); + _14 = Eq(move _71, const 0_i32); + StorageDead(_71); + goto -> bb30; + } + + bb34: { + StorageDead(_74); + StorageLive(_71); + StorageLive(_72); + _75 = &raw const (*_64); + _72 = copy _75 as *const u8 (PtrToPtr); + StorageLive(_73); + _76 = &raw const (*_66); + _73 = copy _76 as *const u8 (PtrToPtr); + _71 = compare_bytes(move _72, move _73, move _70) -> [return: bb33, unwind unreachable]; + } + -+ bb21: { ++ bb35: { ++ StorageDead(_51); ++ StorageDead(_50); ++ StorageDead(_45); ++ StorageDead(_41); ++ StorageDead(_39); ++ StorageDead(_35); ++ StorageDead(_29); ++ StorageDead(_28); ++ StorageDead(_27); ++ goto -> bb6; ++ } ++ ++ bb36: { ++ StorageDead(_76); ++ StorageDead(_75); ++ StorageDead(_70); ++ StorageDead(_66); ++ StorageDead(_64); ++ StorageDead(_60); ++ StorageDead(_54); ++ StorageDead(_53); ++ StorageDead(_52); ++ goto -> bb9; ++ } ++ ++ bb37: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb22, otherwise: bb15]; ++ switchInt(move _24) -> [1: bb38, otherwise: bb15]; + } + -+ bb22: { -+ goto -> bb15; -+ } -+ -+ bb23: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb24, otherwise: bb15]; -+ } -+ -+ bb24: { ++ bb38: { + goto -> bb17; ++ } ++ ++ bb39: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb40, otherwise: bb15]; ++ } ++ ++ bb40: { ++ goto -> bb15; } } diff --git a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff index afd40c1862c3..822d33c89391 100644 --- a/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff +++ b/tests/mir-opt/jump_threading.chained_conditions.JumpThreading.panic-unwind.diff @@ -43,10 +43,192 @@ scope 4 (inlined std::cmp::impls:: for &String>::eq) { let mut _27: &std::string::String; let mut _28: &str; + scope 5 (inlined >::eq) { + scope 6 (inlined #[track_caller] >::index) { + let _29: &str; + scope 7 (inlined String::as_str) { + let _30: &[u8]; + let mut _31: &std::vec::Vec; + scope 8 (inlined Vec::::as_slice) { + let mut _32: *const u8; + let mut _33: usize; + scope 9 (inlined Vec::::as_ptr) { + scope 10 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 11 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 12 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _34: std::ptr::NonNull; + scope 13 (inlined Unique::::cast::) { + scope 14 (inlined NonNull::::cast::) { + scope 15 (inlined NonNull::::as_ptr) { + } + } + } + scope 16 (inlined Unique::::as_non_null_ptr) { + } + } + scope 17 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 18 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { + let _35: (); + let mut _36: *mut (); + let _37: *const [u8]; + scope 19 (inlined ub_checks::check_language_ub) { + scope 20 (inlined ub_checks::check_language_ub::runtime) { + } + } + scope 21 (inlined std::mem::size_of::) { + } + scope 22 (inlined std::mem::align_of::) { + } + scope 23 (inlined slice_from_raw_parts::) { + scope 24 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + } + } + } + } + scope 25 (inlined from_utf8_unchecked) { + } + } + scope 26 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + } + } + scope 27 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 28 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + } + } + scope 29 (inlined core::str::traits::::eq) { + let mut _38: &&[u8]; + let _39: &[u8]; + let mut _40: &&[u8]; + let _41: &[u8]; + scope 30 (inlined core::str::::as_bytes) { + } + scope 31 (inlined core::str::::as_bytes) { + } + scope 32 (inlined std::cmp::impls::::eq) { + scope 33 (inlined core::slice::cmp::::eq) { + scope 34 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { + let mut _42: bool; + let mut _43: usize; + let mut _44: usize; + let _45: usize; + let mut _46: i32; + let mut _47: *const u8; + let mut _48: *const u8; + scope 35 { + scope 37 (inlined core::slice::::as_ptr) { + let mut _50: *const [u8]; + } + scope 38 (inlined core::slice::::as_ptr) { + let mut _51: *const [u8]; + } + } + scope 36 (inlined std::mem::size_of_val::<[u8]>) { + let mut _49: *const [u8]; + } + } + } + } + } + } } - scope 5 (inlined std::cmp::impls:: for &String>::eq) { - let mut _29: &std::string::String; - let mut _30: &str; + scope 39 (inlined std::cmp::impls:: for &String>::eq) { + let mut _52: &std::string::String; + let mut _53: &str; + scope 40 (inlined >::eq) { + scope 41 (inlined #[track_caller] >::index) { + let _54: &str; + scope 42 (inlined String::as_str) { + let _55: &[u8]; + let mut _56: &std::vec::Vec; + scope 43 (inlined Vec::::as_slice) { + let mut _57: *const u8; + let mut _58: usize; + scope 44 (inlined Vec::::as_ptr) { + scope 45 (inlined alloc::raw_vec::RawVec::::ptr) { + scope 46 (inlined alloc::raw_vec::RawVecInner::ptr::) { + scope 47 (inlined alloc::raw_vec::RawVecInner::non_null::) { + let mut _59: std::ptr::NonNull; + scope 48 (inlined Unique::::cast::) { + scope 49 (inlined NonNull::::cast::) { + scope 50 (inlined NonNull::::as_ptr) { + } + } + } + scope 51 (inlined Unique::::as_non_null_ptr) { + } + } + scope 52 (inlined NonNull::::as_ptr) { + } + } + } + } + scope 53 (inlined #[track_caller] std::slice::from_raw_parts::<'_, u8>) { + let _60: (); + let mut _61: *mut (); + let _62: *const [u8]; + scope 54 (inlined ub_checks::check_language_ub) { + scope 55 (inlined ub_checks::check_language_ub::runtime) { + } + } + scope 56 (inlined std::mem::size_of::) { + } + scope 57 (inlined std::mem::align_of::) { + } + scope 58 (inlined slice_from_raw_parts::) { + scope 59 (inlined std::ptr::from_raw_parts::<[u8], u8>) { + } + } + } + } + scope 60 (inlined from_utf8_unchecked) { + } + } + scope 61 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + } + } + scope 62 (inlined #[track_caller] core::str::traits:: for str>::index) { + scope 63 (inlined #[track_caller] core::str::traits:: for RangeFull>::index) { + } + } + scope 64 (inlined core::str::traits::::eq) { + let mut _63: &&[u8]; + let _64: &[u8]; + let mut _65: &&[u8]; + let _66: &[u8]; + scope 65 (inlined core::str::::as_bytes) { + } + scope 66 (inlined core::str::::as_bytes) { + } + scope 67 (inlined std::cmp::impls::::eq) { + scope 68 (inlined core::slice::cmp::::eq) { + scope 69 (inlined <[u8] as core::slice::cmp::SlicePartialEq>::equal) { + let mut _67: bool; + let mut _68: usize; + let mut _69: usize; + let _70: usize; + let mut _71: i32; + let mut _72: *const u8; + let mut _73: *const u8; + scope 70 { + scope 72 (inlined core::slice::::as_ptr) { + let mut _75: *const [u8]; + } + scope 73 (inlined core::slice::::as_ptr) { + let mut _76: *const [u8]; + } + } + scope 71 (inlined std::mem::size_of_val::<[u8]>) { + let mut _74: *const [u8]; + } + } + } + } + } + } } bb0: { @@ -71,7 +253,7 @@ bb3: { _1 = chained_conditions::BacktraceStyle::Off; - goto -> bb19; -+ goto -> bb27; ++ goto -> bb41; } bb4: { @@ -89,7 +271,16 @@ StorageLive(_28); _27 = copy (*_8); _28 = copy (*_10); - _7 = >::eq(move _27, move _28) -> [return: bb23, unwind: bb22]; + StorageLive(_29); + StorageLive(_35); + StorageLive(_30); + StorageLive(_34); + StorageLive(_32); + _34 = copy ((((((*_27).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _32 = copy _34 as *const u8 (Transmute); + StorageLive(_33); + _33 = copy (((*_27).0: std::vec::Vec).1: usize); + switchInt(UbChecks) -> [0: bb25, otherwise: bb23]; } bb5: { @@ -120,18 +311,27 @@ StorageLive(_17); _20 = const chained_conditions::promoted[0]; _17 = &(*_20); - StorageLive(_29); - StorageLive(_30); - _29 = copy (*_15); - _30 = copy (*_17); - _14 = >::eq(move _29, move _30) -> [return: bb24, unwind: bb22]; + StorageLive(_52); + StorageLive(_53); + _52 = copy (*_15); + _53 = copy (*_17); + StorageLive(_54); + StorageLive(_60); + StorageLive(_55); + StorageLive(_59); + StorageLive(_57); + _59 = copy ((((((*_52).0: std::vec::Vec).0: alloc::raw_vec::RawVec).0: alloc::raw_vec::RawVecInner).0: std::ptr::Unique).0: std::ptr::NonNull); + _57 = copy _59 as *const u8 (Transmute); + StorageLive(_58); + _58 = copy (((*_52).0: std::vec::Vec).1: usize); + switchInt(UbChecks) -> [0: bb33, otherwise: bb31]; } bb7: { StorageDead(_5); StorageDead(_6); - goto -> bb19; -+ goto -> bb25; ++ goto -> bb43; } bb8: { @@ -154,14 +354,14 @@ StorageDead(_13); _1 = chained_conditions::BacktraceStyle::Short; - goto -> bb19; -+ goto -> bb27; ++ goto -> bb41; } bb10: { StorageDead(_12); StorageDead(_13); - goto -> bb19; -+ goto -> bb25; ++ goto -> bb43; } bb11: { @@ -223,33 +423,223 @@ } bb23: { + StorageLive(_36); + _36 = copy _34 as *mut () (Transmute); + _35 = std::slice::from_raw_parts::precondition_check(move _36, const ::SIZE, const ::ALIGN, copy _33) -> [return: bb24, unwind unreachable]; + } + + bb24: { + StorageDead(_36); + goto -> bb25; + } + + bb25: { + StorageLive(_37); + _37 = *const [u8] from (copy _32, copy _33); + _30 = &(*_37); + StorageDead(_37); + StorageDead(_33); + StorageDead(_32); + StorageDead(_34); + _29 = copy _30 as &str (Transmute); + StorageDead(_30); + StorageLive(_39); + StorageLive(_41); + _39 = copy _29 as &[u8] (Transmute); + _41 = copy _28 as &[u8] (Transmute); + StorageLive(_45); + StorageLive(_50); + StorageLive(_51); + StorageLive(_42); + StorageLive(_43); + _43 = PtrMetadata(copy _39); + StorageLive(_44); + _44 = PtrMetadata(copy _41); + _42 = Ne(move _43, move _44); + switchInt(move _42) -> [0: bb28, otherwise: bb27]; + } + + bb26: { + StorageDead(_51); + StorageDead(_50); + StorageDead(_45); + StorageDead(_41); + StorageDead(_39); + StorageDead(_35); + StorageDead(_29); StorageDead(_28); StorageDead(_27); switchInt(move _7) -> [0: bb6, otherwise: bb5]; } - bb24: { - StorageDead(_30); - StorageDead(_29); + bb27: { + StorageDead(_44); + StorageDead(_43); + _7 = const false; + StorageDead(_42); +- goto -> bb26; ++ goto -> bb39; + } + + bb28: { + StorageDead(_44); + StorageDead(_43); + StorageDead(_42); + StorageLive(_49); + _49 = &raw const (*_39); + _45 = std::intrinsics::size_of_val::<[u8]>(move _49) -> [return: bb30, unwind unreachable]; + } + + bb29: { + StorageDead(_48); + StorageDead(_47); + _7 = Eq(move _46, const 0_i32); + StorageDead(_46); + goto -> bb26; + } + + bb30: { + StorageDead(_49); + StorageLive(_46); + StorageLive(_47); + _50 = &raw const (*_39); + _47 = copy _50 as *const u8 (PtrToPtr); + StorageLive(_48); + _51 = &raw const (*_41); + _48 = copy _51 as *const u8 (PtrToPtr); + _46 = compare_bytes(move _47, move _48, move _45) -> [return: bb29, unwind unreachable]; + } + + bb31: { + StorageLive(_61); + _61 = copy _59 as *mut () (Transmute); + _60 = std::slice::from_raw_parts::precondition_check(move _61, const ::SIZE, const ::ALIGN, copy _58) -> [return: bb32, unwind unreachable]; + } + + bb32: { + StorageDead(_61); + goto -> bb33; + } + + bb33: { + StorageLive(_62); + _62 = *const [u8] from (copy _57, copy _58); + _55 = &(*_62); + StorageDead(_62); + StorageDead(_58); + StorageDead(_57); + StorageDead(_59); + _54 = copy _55 as &str (Transmute); + StorageDead(_55); + StorageLive(_64); + StorageLive(_66); + _64 = copy _54 as &[u8] (Transmute); + _66 = copy _53 as &[u8] (Transmute); + StorageLive(_70); + StorageLive(_75); + StorageLive(_76); + StorageLive(_67); + StorageLive(_68); + _68 = PtrMetadata(copy _64); + StorageLive(_69); + _69 = PtrMetadata(copy _66); + _67 = Ne(move _68, move _69); + switchInt(move _67) -> [0: bb36, otherwise: bb35]; + } + + bb34: { + StorageDead(_76); + StorageDead(_75); + StorageDead(_70); + StorageDead(_66); + StorageDead(_64); + StorageDead(_60); + StorageDead(_54); + StorageDead(_53); + StorageDead(_52); switchInt(move _14) -> [0: bb9, otherwise: bb8]; + } + + bb35: { + StorageDead(_69); + StorageDead(_68); + _14 = const false; + StorageDead(_67); +- goto -> bb34; ++ goto -> bb40; + } + + bb36: { + StorageDead(_69); + StorageDead(_68); + StorageDead(_67); + StorageLive(_74); + _74 = &raw const (*_64); + _70 = std::intrinsics::size_of_val::<[u8]>(move _74) -> [return: bb38, unwind unreachable]; + } + + bb37: { + StorageDead(_73); + StorageDead(_72); + _14 = Eq(move _71, const 0_i32); + StorageDead(_71); + goto -> bb34; + } + + bb38: { + StorageDead(_74); + StorageLive(_71); + StorageLive(_72); + _75 = &raw const (*_64); + _72 = copy _75 as *const u8 (PtrToPtr); + StorageLive(_73); + _76 = &raw const (*_66); + _73 = copy _76 as *const u8 (PtrToPtr); + _71 = compare_bytes(move _72, move _73, move _70) -> [return: bb37, unwind unreachable]; + } + -+ bb25: { ++ bb39: { ++ StorageDead(_51); ++ StorageDead(_50); ++ StorageDead(_45); ++ StorageDead(_41); ++ StorageDead(_39); ++ StorageDead(_35); ++ StorageDead(_29); ++ StorageDead(_28); ++ StorageDead(_27); ++ goto -> bb6; ++ } ++ ++ bb40: { ++ StorageDead(_76); ++ StorageDead(_75); ++ StorageDead(_70); ++ StorageDead(_66); ++ StorageDead(_64); ++ StorageDead(_60); ++ StorageDead(_54); ++ StorageDead(_53); ++ StorageDead(_52); ++ goto -> bb9; ++ } ++ ++ bb41: { + _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb26, otherwise: bb16]; ++ switchInt(move _24) -> [1: bb42, otherwise: bb16]; + } + -+ bb26: { -+ goto -> bb16; -+ } -+ -+ bb27: { -+ _24 = discriminant(_2); -+ switchInt(move _24) -> [1: bb28, otherwise: bb16]; -+ } -+ -+ bb28: { ++ bb42: { + goto -> bb18; ++ } ++ ++ bb43: { ++ _24 = discriminant(_2); ++ switchInt(move _24) -> [1: bb44, otherwise: bb16]; ++ } ++ ++ bb44: { ++ goto -> bb16; } } From ae6e2098f27e7ce1572cbd5239a8f4d18b1eff82 Mon Sep 17 00:00:00 2001 From: The Miri Cronjob Bot Date: Sun, 21 Dec 2025 04:58:31 +0000 Subject: [PATCH 075/126] Prepare for merging from rust-lang/rust This updates the rust-version file to cb79c42008b970269f6a06b257e5f04b93f24d03. --- 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 de0270f31fe5..024cbd285207 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -f51d1bcdc69f9bba47cc1656260ff76e6ff5fba3 +cb79c42008b970269f6a06b257e5f04b93f24d03 From 685e4b6d0283a532daff9bf994e1d34bd853180f Mon Sep 17 00:00:00 2001 From: Brian Campbell Date: Sun, 21 Dec 2025 00:54:42 -0500 Subject: [PATCH 076/126] Add comment with link to issue and open tags --- tests/rustdoc/extern/pub-extern-crate-150176.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/rustdoc/extern/pub-extern-crate-150176.rs b/tests/rustdoc/extern/pub-extern-crate-150176.rs index b68619c5a02d..e557b1607182 100644 --- a/tests/rustdoc/extern/pub-extern-crate-150176.rs +++ b/tests/rustdoc/extern/pub-extern-crate-150176.rs @@ -1,5 +1,9 @@ //@ aux-build:pub-extern-crate.rs +// A refactor had left us missing the closing tags, +// ensure that they are present. +// https://github.com/rust-lang/rust/issues/150176 + //@ has pub_extern_crate_150176/index.html -//@ hasraw - 'pub extern crate inner;' +//@ hasraw - '
pub extern crate inner;
' pub extern crate inner; From 08c396b91e245a0c9a596dc3f7053e7cb2038299 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 20 Dec 2025 23:44:06 -0700 Subject: [PATCH 077/126] rustdoc: upgrade to stringdex 0.0.4 - code cleanup - smaller encoding for runs - fast path for the common encoding case --- Cargo.lock | 4 +- src/librustdoc/Cargo.toml | 2 +- src/librustdoc/html/static/js/stringdex.js | 139 +++++++++++++++++---- 3 files changed, 119 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1cd998a0bd2f..2c5053f0c2b7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5357,9 +5357,9 @@ dependencies = [ [[package]] name = "stringdex" -version = "0.0.3" +version = "0.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556a6126952cb2f5150057c98a77cc6c771027dea2825bf7fa03d3d638b0a4f8" +checksum = "c6204af9e1e433f1ef9b6d44475c7089be33c91111d896463b9dfa20464b87f1" dependencies = [ "stacker", ] diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index dcfc1ffc251e..ab75d2dfa429 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -22,7 +22,7 @@ rustdoc-json-types = { path = "../rustdoc-json-types" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = "1.8.1" -stringdex = "=0.0.3" +stringdex = "=0.0.4" tempfile = "3" threadpool = "1.8.1" tracing = "0.1" diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js index 2a73ae50e720..d04fd6c0e451 100644 --- a/src/librustdoc/html/static/js/stringdex.js +++ b/src/librustdoc/html/static/js/stringdex.js @@ -54,6 +54,52 @@ class RoaringBitmap { } this.consumed_len_bytes = pspecial - i; return this; + } else if (u8array[i] > 0xe0) { + // Special representation of tiny sets that are runs + const lspecial = u8array[i] & 0x0f; + this.keysAndCardinalities = new Uint8Array(lspecial * 4); + i += 1; + const key = u8array[i + 2] | (u8array[i + 3] << 8); + const value = u8array[i] | (u8array[i + 1] << 8); + const container = new RoaringBitmapRun(1, new Uint8Array(4)); + container.array[0] = value & 0xFF; + container.array[1] = (value >> 8) & 0xFF; + container.array[2] = lspecial - 1; + this.containers.push(container); + this.keysAndCardinalities[0] = key & 0xFF; + this.keysAndCardinalities[1] = (key >> 8) & 0xFF; + this.keysAndCardinalities[2] = lspecial - 1; + this.consumed_len_bytes = 5; + return this; + } else if (u8array[i] > 0xd0) { + // Special representation of tiny sets that are close together + const lspecial = u8array[i] & 0x0f; + this.keysAndCardinalities = new Uint8Array(lspecial * 4); + let pspecial = i + 1; + let key = u8array[pspecial + 2] | (u8array[pspecial + 3] << 8); + let value = u8array[pspecial] | (u8array[pspecial + 1] << 8); + let entry = (key << 16) | value; + let container; + container = new RoaringBitmapArray(1, new Uint8Array(4)); + container.array[0] = value & 0xFF; + container.array[1] = (value >> 8) & 0xFF; + this.containers.push(container); + this.keysAndCardinalities[0] = key; + this.keysAndCardinalities[1] = key >> 8; + pspecial += 4; + for (let ispecial = 1; ispecial < lspecial; ispecial += 1) { + entry += u8array[pspecial]; + value = entry & 0xffff; + key = entry >> 16; + container = this.addToArrayAt(key); + const cardinalityOld = container.cardinality; + container.array[cardinalityOld * 2] = value & 0xFF; + container.array[(cardinalityOld * 2) + 1] = (value >> 8) & 0xFF; + container.cardinality = cardinalityOld + 1; + pspecial += 1; + } + this.consumed_len_bytes = pspecial - i; + return this; } else if (u8array[i] < 0x3a) { // Special representation of tiny sets with arbitrary 32-bit integers const lspecial = u8array[i]; @@ -2282,7 +2328,7 @@ function loadDatabase(hooks) { */ class InlineNeighborsTree { /** - * @param {Uint8Array} encoded + * @param {Uint8Array} encoded * @param {number} start */ constructor( @@ -2301,7 +2347,8 @@ function loadDatabase(hooks) { const has_branches = (encoded[i] & 0x04) !== 0; /** @type {boolean} */ const is_suffixes_only = (encoded[i] & 0x01) !== 0; - let leaves_count = ((encoded[i] >> 4) & 0x0f) + 1; + let leaves_count = ((encoded[i] >> 4) & 0x07) + 1; + let leaves_is_run = (encoded[i] >> 7) !== 0; i += 1; let branch_count = 0; if (has_branches) { @@ -2311,8 +2358,10 @@ function loadDatabase(hooks) { const dlen = encoded[i] & 0x3f; if ((encoded[i] & 0x80) !== 0) { leaves_count = 0; + leaves_is_run = false; } i += 1; + /** @type {Uint8Array} */ let data = EMPTY_UINT8; if (!is_suffixes_only && dlen !== 0) { data = encoded.subarray(i, i + dlen); @@ -2324,8 +2373,10 @@ function loadDatabase(hooks) { const branch_nodes = []; for (let j = 0; j < branch_count; j += 1) { const branch_dlen = encoded[i] & 0x0f; - const branch_leaves_count = ((encoded[i] >> 4) & 0x0f) + 1; + const branch_leaves_count = ((encoded[i] >> 4) & 0x07) + 1; + const branch_leaves_is_run = (encoded[i] >> 7) !== 0; i += 1; + /** @type {Uint8Array} */ let branch_data = EMPTY_UINT8; if (!is_suffixes_only && branch_dlen !== 0) { branch_data = encoded.subarray(i, i + branch_dlen); @@ -2338,13 +2389,28 @@ function loadDatabase(hooks) { (branch_leaves_count - 1) & 0xff, ((branch_leaves_count - 1) >> 8) & 0xff, ); - branch_leaves.containers = [ - new RoaringBitmapArray( - branch_leaves_count, - encoded.subarray(i, i + (branch_leaves_count * 2)), - ), - ]; - i += branch_leaves_count * 2; + if (branch_leaves_is_run) { + branch_leaves.containers = [ + new RoaringBitmapRun( + 1, + Uint8Array.of( + encoded[i], + encoded[i + 1], + branch_leaves_count - 1, + 0, + ), + ), + ]; + i += 2; + } else { + branch_leaves.containers = [ + new RoaringBitmapArray( + branch_leaves_count, + encoded.subarray(i, i + (branch_leaves_count * 2)), + ), + ]; + i += branch_leaves_count * 2; + } branch_nodes.push(Promise.resolve( is_suffixes_only ? new SuffixSearchTree( @@ -2379,13 +2445,28 @@ function loadDatabase(hooks) { (leaves_count - 1) & 0xff, ((leaves_count - 1) >> 8) & 0xff, ); - leaves.containers = [ - new RoaringBitmapArray( - leaves_count, - encoded.subarray(i, i + (leaves_count * 2)), - ), - ]; - i += leaves_count * 2; + if (leaves_is_run) { + leaves.containers = [ + new RoaringBitmapRun( + 1, + Uint8Array.of( + encoded[i], + encoded[i + 1], + leaves_count - 1, + 0, + ), + ), + ]; + i += 2; + } else { + leaves.containers = [ + new RoaringBitmapArray( + leaves_count, + encoded.subarray(i, i + (leaves_count * 2)), + ), + ]; + i += leaves_count * 2; + } } return is_suffixes_only ? new SuffixSearchTree( @@ -2654,7 +2735,7 @@ function loadDatabase(hooks) { /** * @param {string} inputBase64 - * @returns {[Uint8Array, SearchTree]} + * @returns {[Uint8Array, SearchTree]} */ function makeSearchTreeFromBase64(inputBase64) { const input = makeUint8ArrayFromBase64(inputBase64); @@ -2972,7 +3053,10 @@ function loadDatabase(hooks) { // node with packed leaves and common 16bit prefix const leaves_count = no_leaves_flag !== 0 ? 0 : - ((compression_tag >> 4) & 0x0f) + 1; + ((compression_tag >> 4) & 0x07) + 1; + const leaves_is_run = no_leaves_flag !== 0 ? + false : + ((compression_tag >> 4) & 0x08) !== 0; const branch_count = is_long_compressed ? ((compression_tag >> 8) & 0xff) + 1 : 0; @@ -2994,16 +3078,25 @@ function loadDatabase(hooks) { for (let j = 0; j < branch_count; j += 1) { const branch_dlen = input[i] & 0x0f; const branch_leaves_count = ((input[i] >> 4) & 0x0f) + 1; + const branch_leaves_is_run = (input[i] >> 7) !== 0; i += 1; if (!is_pure_suffixes_only_node) { i += branch_dlen; } - i += branch_leaves_count * 2; + if (branch_leaves_is_run) { + i += 2; + } else { + i += branch_leaves_count * 2; + } } // branch keys i += branch_count; // leaves - i += leaves_count * 2; + if (leaves_is_run) { + i += 2; + } else { + i += leaves_count * 2; + } if (is_data_compressed) { const clen = ( 1 + // first compression header byte @@ -3305,7 +3398,7 @@ if (typeof window !== "undefined") { // eslint-disable-next-line max-len // polyfill https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array/fromBase64 /** - * @type {function(string): Uint8Array} base64 + * @type {function(string): Uint8Array} base64 */ //@ts-expect-error const makeUint8ArrayFromBase64 = Uint8Array.fromBase64 ? Uint8Array.fromBase64 : (string => { @@ -3318,7 +3411,7 @@ const makeUint8ArrayFromBase64 = Uint8Array.fromBase64 ? Uint8Array.fromBase64 : return bytes; }); /** - * @type {function(string): Uint8Array} base64 + * @type {function(string): Uint8Array} base64 */ //@ts-expect-error const makeUint8ArrayFromHex = Uint8Array.fromHex ? Uint8Array.fromHex : (string => { From bd051c485e05e59598433fe1f2c634dc5cde8524 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Dec 2025 14:02:20 +0100 Subject: [PATCH 078/126] re-bless genmc test --- .../miri/tests/genmc/fail/shims/exit.stderr | 112 +----------------- 1 file changed, 1 insertion(+), 111 deletions(-) diff --git a/src/tools/miri/tests/genmc/fail/shims/exit.stderr b/src/tools/miri/tests/genmc/fail/shims/exit.stderr index dead5faaa514..f27860b82fe7 100644 --- a/src/tools/miri/tests/genmc/fail/shims/exit.stderr +++ b/src/tools/miri/tests/genmc/fail/shims/exit.stderr @@ -1,114 +1,4 @@ Running GenMC Verification... -warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/std/src/thread/mod.rs:LL:CC - | -LL | match COUNTER.compare_exchange_weak(last, id, Ordering::Relaxed, Ordering::Relaxed) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code - | - = note: BACKTRACE: - = note: inside `std::thread::ThreadId::new` at RUSTLIB/std/src/thread/mod.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/current.rs:LL:CC - = note: inside `std::thread::current::id::get_or_init` at RUSTLIB/std/src/thread/current.rs:LL:CC - = note: inside `std::thread::current_id` at RUSTLIB/std/src/thread/current.rs:LL:CC - = note: inside `std::rt::init` at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `std::panicking::catch_unwind::do_call::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panicking::catch_unwind::` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::panic::catch_unwind::<{closure@std::rt::lang_start_internal::{closure#0}}, isize>` at RUSTLIB/std/src/panic.rs:LL:CC - = note: inside `std::rt::lang_start_internal` at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `std::rt::lang_start::<()>` at RUSTLIB/std/src/rt.rs:LL:CC - -warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access. - --> RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC - | -LL | || self - | ________________^ -LL | | .state -LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) - | |____________________________________________________________________________________^ GenMC might miss possible behaviors of this code - | - = note: BACKTRACE: - = note: inside `std::sys::sync::PLATFORM::futex::RwLock::read` at RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC - = note: inside `std::sync::RwLock::<()>::read` at RUSTLIB/std/src/sync/poison/rwlock.rs:LL:CC - = note: inside `std::sys::env::PLATFORM::env_read_lock` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::env::PLATFORM::getenv` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside `std::env::_var_os` at RUSTLIB/std/src/env.rs:LL:CC - = note: inside `std::env::var_os::<&str>` at RUSTLIB/std/src/env.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC -note: inside `main` - --> tests/genmc/fail/shims/exit.rs:LL:CC - | -LL | / std::thread::spawn(|| { -LL | | unsafe { std::hint::unreachable_unchecked() }; -LL | | }); - | |______^ - -warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC - | -LL | || self - | ________________^ -LL | | .state -LL | | .compare_exchange_weak(state, state + READ_LOCKED, Acquire, Relaxed) - | |____________________________________________________________________________________^ GenMC might miss possible behaviors of this code - | - = note: BACKTRACE: - = note: inside `std::sys::sync::PLATFORM::futex::RwLock::read` at RUSTLIB/std/src/sys/sync/PLATFORM/futex.rs:LL:CC - = note: inside `std::sync::RwLock::<()>::read` at RUSTLIB/std/src/sync/poison/rwlock.rs:LL:CC - = note: inside `std::sys::env::PLATFORM::env_read_lock` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr_stack::>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::small_c_string::run_with_cstr::>` at RUSTLIB/std/src/sys/pal/PLATFORM/small_c_string.rs:LL:CC - = note: inside `std::sys::env::PLATFORM::getenv` at RUSTLIB/std/src/sys/env/PLATFORM.rs:LL:CC - = note: inside `std::env::_var_os` at RUSTLIB/std/src/env.rs:LL:CC - = note: inside `std::env::var_os::<&str>` at RUSTLIB/std/src/env.rs:LL:CC - = note: inside closure at RUSTLIB/std/src/thread/mod.rs:LL:CC -note: inside `main` - --> tests/genmc/fail/shims/exit.rs:LL:CC - | -LL | / std::thread::spawn(|| { -LL | | unsafe { std::hint::unreachable_unchecked() }; -LL | | }); - | |______^ - -warning: GenMC currently does not model spurious failures of `compare_exchange_weak`. Miri with GenMC might miss bugs related to spurious failures. - --> RUSTLIB/std/src/rt.rs:LL:CC - | -LL | / CLEANUP.call_once(|| unsafe { -LL | | // Flush stdout and disable buffering. -LL | | crate::io::cleanup(); -... | -LL | | }); - | |______^ GenMC might miss possible behaviors of this code - | - = note: BACKTRACE: - = note: inside `std::rt::cleanup` at RUSTLIB/std/src/rt.rs:LL:CC - = note: inside `std::process::exit` at RUSTLIB/std/src/process.rs:LL:CC -note: inside `main` - --> tests/genmc/fail/shims/exit.rs:LL:CC - | -LL | std::process::exit(0); - | ^^^^^^^^^^^^^^^^^^^^^ - -warning: GenMC currently does not model the failure ordering for `compare_exchange`. Due to success ordering 'Acquire', the failure ordering 'Relaxed' is treated like 'Acquire'. Miri with GenMC might miss bugs related to this memory access. - --> RUSTLIB/std/src/sys/exit_guard.rs:LL:CC - | -LL | match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ GenMC might miss possible behaviors of this code - | - = note: BACKTRACE: - = note: inside `std::sys::exit_guard::unique_thread_exit` at RUSTLIB/std/src/sys/exit_guard.rs:LL:CC - = note: inside `std::sys::pal::PLATFORM::os::exit` at RUSTLIB/std/src/sys/pal/PLATFORM/os.rs:LL:CC - = note: inside `std::process::exit` at RUSTLIB/std/src/process.rs:LL:CC -note: inside `main` - --> tests/genmc/fail/shims/exit.rs:LL:CC - | -LL | std::process::exit(0); - | ^^^^^^^^^^^^^^^^^^^^^ - error: Undefined Behavior: entering unreachable code --> tests/genmc/fail/shims/exit.rs:LL:CC | @@ -122,5 +12,5 @@ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a note: add `-Zmiri-genmc-print-genmc-output` to MIRIFLAGS to see the detailed GenMC error report -error: aborting due to 1 previous error; 5 warnings emitted +error: aborting due to 1 previous error From 37af3f647b4f7e464577d8cc3cd5fb080a827ed9 Mon Sep 17 00:00:00 2001 From: dianqk Date: Sun, 21 Dec 2025 21:32:06 +0800 Subject: [PATCH 079/126] GVN: Adds the `insert_unique` method --- compiler/rustc_mir_transform/src/gvn.rs | 43 ++++++++++++------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 526d0e96a36d..0d458402c951 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -420,6 +420,19 @@ fn typing_env(&self) -> ty::TypingEnv<'tcx> { self.ecx.typing_env() } + fn insert_unique( + &mut self, + ty: Ty<'tcx>, + value: impl FnOnce(VnOpaque) -> Value<'a, 'tcx>, + ) -> VnIndex { + let index = self.values.insert_unique(ty, value); + let _index = self.evaluated.push(None); + debug_assert_eq!(index, _index); + let _index = self.rev_locals.push(SmallVec::new()); + debug_assert_eq!(index, _index); + index + } + #[instrument(level = "trace", skip(self), ret)] fn insert(&mut self, ty: Ty<'tcx>, value: Value<'a, 'tcx>) -> VnIndex { let (index, new) = self.values.insert(ty, value); @@ -437,11 +450,8 @@ fn insert(&mut self, ty: Ty<'tcx>, value: Value<'a, 'tcx>) -> VnIndex { /// from all the others. #[instrument(level = "trace", skip(self), ret)] fn new_opaque(&mut self, ty: Ty<'tcx>) -> VnIndex { - let index = self.values.insert_unique(ty, Value::Opaque); - let _index = self.evaluated.push(Some(None)); - debug_assert_eq!(index, _index); - let _index = self.rev_locals.push(SmallVec::new()); - debug_assert_eq!(index, _index); + let index = self.insert_unique(ty, Value::Opaque); + self.evaluated[index] = Some(None); index } @@ -470,42 +480,29 @@ fn new_pointer(&mut self, place: Place<'tcx>, kind: AddressKind) -> Option) -> VnIndex { - let (index, new) = if value.is_deterministic() { + if value.is_deterministic() { // The constant is deterministic, no need to disambiguate. let constant = Value::Constant { value, disambiguator: None }; - self.values.insert(value.ty(), constant) + self.insert(value.ty(), constant) } else { // Multiple mentions of this constant will yield different values, // so assign a different `disambiguator` to ensure they do not get the same `VnIndex`. - let index = self.values.insert_unique(value.ty(), |disambiguator| Value::Constant { + self.insert_unique(value.ty(), |disambiguator| Value::Constant { value, disambiguator: Some(disambiguator), - }); - (index, true) - }; - if new { - let _index = self.evaluated.push(None); - debug_assert_eq!(index, _index); - let _index = self.rev_locals.push(SmallVec::new()); - debug_assert_eq!(index, _index); + }) } - index } #[inline] From 74af408790acb796ece9aee438b87408ee15a240 Mon Sep 17 00:00:00 2001 From: Iris Shi <0.0@owo.li> Date: Sun, 21 Dec 2025 18:24:44 +0800 Subject: [PATCH 080/126] rustdoc: handle macro expansions in types --- compiler/rustc_ast_pretty/src/pprust/mod.rs | 3 +++ src/librustdoc/html/macro_expansion.rs | 12 +++++++-- .../macro-expansion/type-macro-expansion.rs | 27 +++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 tests/rustdoc/macro-expansion/type-macro-expansion.rs diff --git a/compiler/rustc_ast_pretty/src/pprust/mod.rs b/compiler/rustc_ast_pretty/src/pprust/mod.rs index a766e2006e59..74ed0405498d 100644 --- a/compiler/rustc_ast_pretty/src/pprust/mod.rs +++ b/compiler/rustc_ast_pretty/src/pprust/mod.rs @@ -33,6 +33,9 @@ pub fn where_bound_predicate_to_string(where_bound_predicate: &ast::WhereBoundPr State::new().where_bound_predicate_to_string(where_bound_predicate) } +/// # Panics +/// +/// Panics if `pat.kind` is `PatKind::Missing`. pub fn pat_to_string(pat: &ast::Pat) -> String { State::new().pat_to_string(pat) } diff --git a/src/librustdoc/html/macro_expansion.rs b/src/librustdoc/html/macro_expansion.rs index 9098e92a5cd4..d3c91be3a280 100644 --- a/src/librustdoc/html/macro_expansion.rs +++ b/src/librustdoc/html/macro_expansion.rs @@ -1,5 +1,5 @@ -use rustc_ast::visit::{Visitor, walk_crate, walk_expr, walk_item, walk_pat, walk_stmt}; -use rustc_ast::{Crate, Expr, Item, Pat, Stmt}; +use rustc_ast::visit::{Visitor, walk_crate, walk_expr, walk_item, walk_pat, walk_stmt, walk_ty}; +use rustc_ast::{Crate, Expr, Item, Pat, Stmt, Ty}; use rustc_data_structures::fx::FxHashMap; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Span}; @@ -153,4 +153,12 @@ fn visit_pat(&mut self, pat: &'ast Pat) { walk_pat(self, pat); } } + + fn visit_ty(&mut self, ty: &'ast Ty) { + if ty.span.from_expansion() { + self.handle_new_span(ty.span, || rustc_ast_pretty::pprust::ty_to_string(ty)); + } else { + walk_ty(self, ty); + } + } } diff --git a/tests/rustdoc/macro-expansion/type-macro-expansion.rs b/tests/rustdoc/macro-expansion/type-macro-expansion.rs new file mode 100644 index 000000000000..d7d28fdac666 --- /dev/null +++ b/tests/rustdoc/macro-expansion/type-macro-expansion.rs @@ -0,0 +1,27 @@ +// Ensure macro invocations at type position are expanded correctly + +//@ compile-flags: -Zunstable-options --generate-macro-expansion + +#![crate_name = "foo"] + +//@ has 'src/foo/type-macro-expansion.rs.html' + +macro_rules! foo { + () => { + fn(()) + }; + ($_arg:expr) => { + [(); 1] + }; +} + +fn bar() { + //@ has - '//*[@class="expansion"]/*[@class="original"]/*[@class="macro"]' 'foo!' + //@ has - '//*[@class="expansion"]/*[@class="original"]' 'foo!()' + //@ has - '//*[@class="expansion"]/*[@class="expanded"]' 'fn(())' + let _: foo!(); + //@ has - '//*[@class="expansion"]/*[@class="original"]/*[@class="macro"]' 'foo!' + //@ has - '//*[@class="expansion"]/*[@class="original"]' 'foo!(42)' + //@ has - '//*[@class="expansion"]/*[@class="expanded"]' '[(); 1]' + let _: foo!(42); +} From d2eaec9e258f4e02989b23cfecda681e05101307 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 21 Dec 2025 08:46:13 -0700 Subject: [PATCH 081/126] Clean up needlessly complex math and conditions Co-authored-by: Guillaume Gomez --- src/librustdoc/html/static/js/stringdex.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js index d04fd6c0e451..e45c8bcd653b 100644 --- a/src/librustdoc/html/static/js/stringdex.js +++ b/src/librustdoc/html/static/js/stringdex.js @@ -57,7 +57,7 @@ class RoaringBitmap { } else if (u8array[i] > 0xe0) { // Special representation of tiny sets that are runs const lspecial = u8array[i] & 0x0f; - this.keysAndCardinalities = new Uint8Array(lspecial * 4); + this.keysAndCardinalities = new Uint8Array(lspecial << 2); i += 1; const key = u8array[i + 2] | (u8array[i + 3] << 8); const value = u8array[i] | (u8array[i + 1] << 8); @@ -74,7 +74,7 @@ class RoaringBitmap { } else if (u8array[i] > 0xd0) { // Special representation of tiny sets that are close together const lspecial = u8array[i] & 0x0f; - this.keysAndCardinalities = new Uint8Array(lspecial * 4); + this.keysAndCardinalities = new Uint8Array(lspecial << 2); let pspecial = i + 1; let key = u8array[pspecial + 2] | (u8array[pspecial + 3] << 8); let value = u8array[pspecial] | (u8array[pspecial + 1] << 8); @@ -93,8 +93,8 @@ class RoaringBitmap { key = entry >> 16; container = this.addToArrayAt(key); const cardinalityOld = container.cardinality; - container.array[cardinalityOld * 2] = value & 0xFF; - container.array[(cardinalityOld * 2) + 1] = (value >> 8) & 0xFF; + container.array[cardinalityOld << 1] = value & 0xFF; + container.array[(cardinalityOld << 1) + 1] = (value >> 8) & 0xFF; container.cardinality = cardinalityOld + 1; pspecial += 1; } @@ -2409,7 +2409,7 @@ function loadDatabase(hooks) { encoded.subarray(i, i + (branch_leaves_count * 2)), ), ]; - i += branch_leaves_count * 2; + i += branch_leaves_count << 1; } branch_nodes.push(Promise.resolve( is_suffixes_only ? @@ -2465,7 +2465,7 @@ function loadDatabase(hooks) { encoded.subarray(i, i + (leaves_count * 2)), ), ]; - i += leaves_count * 2; + i += leaves_count << 1; } } return is_suffixes_only ? @@ -3054,8 +3054,7 @@ function loadDatabase(hooks) { const leaves_count = no_leaves_flag !== 0 ? 0 : ((compression_tag >> 4) & 0x07) + 1; - const leaves_is_run = no_leaves_flag !== 0 ? - false : + const leaves_is_run = no_leaves_flag === 0 && ((compression_tag >> 4) & 0x08) !== 0; const branch_count = is_long_compressed ? ((compression_tag >> 8) & 0xff) + 1 : @@ -3086,7 +3085,7 @@ function loadDatabase(hooks) { if (branch_leaves_is_run) { i += 2; } else { - i += branch_leaves_count * 2; + i += branch_leaves_count << 1; } } // branch keys @@ -3095,7 +3094,7 @@ function loadDatabase(hooks) { if (leaves_is_run) { i += 2; } else { - i += leaves_count * 2; + i += leaves_count << 1; } if (is_data_compressed) { const clen = ( From 38c667265b18caa3b0d0ac2b281c4ea928ee3459 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 21 Dec 2025 21:35:10 +0100 Subject: [PATCH 082/126] add `expected_non_empty_string_literal` to attribute parser Signed-off-by: Edvin Bryntesson --- compiler/rustc_attr_parsing/src/context.rs | 4 ++++ compiler/rustc_attr_parsing/src/session_diagnostics.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index df4970d8aa90..9aa0729c5790 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -498,6 +498,10 @@ pub(crate) fn expected_nv_or_no_args(&self, span: Span) -> ErrorGuaranteed { self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValueOrNoArgs) } + pub(crate) fn expected_non_empty_string_literal(&self, span: Span) -> ErrorGuaranteed { + self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNonEmptyStringLiteral) + } + pub(crate) fn expected_no_args(&self, span: Span) -> ErrorGuaranteed { self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNoArgs) } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 73b65193fd34..d9998a15f233 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -521,6 +521,7 @@ pub(crate) enum AttributeParseErrorReason<'a> { ExpectedList, ExpectedListOrNoArgs, ExpectedNameValueOrNoArgs, + ExpectedNonEmptyStringLiteral, UnexpectedLiteral, ExpectedNameValue(Option), DuplicateKey(Symbol), @@ -599,6 +600,9 @@ fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { AttributeParseErrorReason::ExpectedNameValueOrNoArgs => { diag.span_label(self.span, "didn't expect a list here"); } + AttributeParseErrorReason::ExpectedNonEmptyStringLiteral => { + diag.span_label(self.span, "string is not allowed to be empty"); + } AttributeParseErrorReason::DuplicateKey(key) => { diag.span_label(self.span, format!("found `{key}` used as a key more than once")); diag.code(E0538); From d719a49b28a0da4d91c4fd0fd8ccd71cbfa0d491 Mon Sep 17 00:00:00 2001 From: Edvin Bryntesson Date: Sun, 21 Dec 2025 21:45:15 +0100 Subject: [PATCH 083/126] Port `#[cfi_encoding]` to attribute parser --- .../src/attributes/cfi_encoding.rs | 33 +++++++++ .../rustc_attr_parsing/src/attributes/mod.rs | 1 + compiler/rustc_attr_parsing/src/context.rs | 2 + .../rustc_hir/src/attrs/data_structures.rs | 3 + .../rustc_hir/src/attrs/encode_cross_crate.rs | 1 + compiler/rustc_passes/src/check_attr.rs | 2 +- .../src/cfi/typeid/itanium_cxx_abi/encode.rs | 68 ++++++------------- .../cfi/typeid/itanium_cxx_abi/transform.rs | 11 +-- tests/ui/attributes/malformed-attrs.rs | 2 +- tests/ui/attributes/malformed-attrs.stderr | 15 ++-- .../cfi/invalid-attr-encoding.stderr | 8 ++- 11 files changed, 83 insertions(+), 63 deletions(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs b/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs new file mode 100644 index 000000000000..df1e569743c0 --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs @@ -0,0 +1,33 @@ +use super::prelude::*; +pub(crate) struct CfiEncodingParser; +impl SingleAttributeParser for CfiEncodingParser { + const PATH: &[Symbol] = &[sym::cfi_encoding]; + const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowListWarnRest(&[ + Allow(Target::Struct), + Allow(Target::ForeignTy), + Allow(Target::Enum), + Allow(Target::Union), + ]); + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "encoding"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser) -> Option { + let Some(name_value) = args.name_value() else { + cx.expected_name_value(cx.attr_span, Some(sym::cfi_encoding)); + return None; + }; + + let Some(value_str) = name_value.value_as_str() else { + cx.expected_string_literal(name_value.value_span, None); + return None; + }; + + if value_str.as_str().trim().is_empty() { + cx.expected_non_empty_string_literal(name_value.value_span); + return None; + } + + Some(AttributeKind::CfiEncoding { encoding: value_str }) + } +} diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index f7290bd7e6f2..c39c60ea7e39 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -33,6 +33,7 @@ pub(crate) mod body; pub(crate) mod cfg; pub(crate) mod cfg_select; +pub(crate) mod cfi_encoding; pub(crate) mod codegen_attrs; pub(crate) mod confusables; pub(crate) mod crate_level; diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 9aa0729c5790..9a443dfbb842 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -19,6 +19,7 @@ AllowConstFnUnstableParser, AllowInternalUnstableParser, UnstableFeatureBoundParser, }; use crate::attributes::body::CoroutineParser; +use crate::attributes::cfi_encoding::CfiEncodingParser; use crate::attributes::codegen_attrs::{ ColdParser, CoverageParser, EiiExternItemParser, ExportNameParser, ForceTargetFeatureParser, NakedParser, NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, @@ -187,6 +188,7 @@ mod late { // tidy-alphabetical-end // tidy-alphabetical-start + Single, Single, Single, Single, diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index e9f9b2445deb..39530f5c3f8b 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -703,6 +703,9 @@ pub enum AttributeKind { span: Span, }, + /// Represents `#[cfi_encoding]` + CfiEncoding { encoding: Symbol }, + /// Represents `#[rustc_coinductive]`. Coinductive(Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 68456dfe4c29..6d159a6ee68a 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -26,6 +26,7 @@ pub fn encode_cross_crate(&self) -> EncodeCrossCrate { AsPtr(..) => Yes, AutomaticallyDerived(..) => Yes, BodyStability { .. } => No, + CfiEncoding { .. } => Yes, Coinductive(..) => No, Cold(..) => No, Confusables { .. } => Yes, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 7822614a05cb..fae269bfdcf1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -298,6 +298,7 @@ fn check_attributes( | AttributeKind::PinV2(..) | AttributeKind::WindowsSubsystem(..) | AttributeKind::ThreadLocal + | AttributeKind::CfiEncoding { .. } ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); @@ -336,7 +337,6 @@ fn check_attributes( | sym::cfg_trace | sym::cfg_attr_trace // need to be fixed - | sym::cfi_encoding // FIXME(cfi_encoding) | sym::instruction_set // broken on stable!!! | sym::patchable_function_entry // FIXME(patchable_function_entry) | sym::deprecated_safe // FIXME(deprecated_safe) diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs index 60b3b42989b7..5505fe82cea6 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/encode.rs @@ -11,6 +11,8 @@ use rustc_data_structures::base_n::{ALPHANUMERIC_ONLY, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::find_attr; use rustc_middle::bug; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{ @@ -18,7 +20,6 @@ IntTy, List, Region, RegionKind, TermKind, Ty, TyCtxt, TypeFoldable, UintTy, }; use rustc_span::def_id::DefId; -use rustc_span::sym; use tracing::instrument; use crate::cfi::typeid::TypeIdOptions; @@ -446,36 +447,20 @@ pub(crate) fn encode_ty<'tcx>( ty::Adt(adt_def, args) => { let mut s = String::new(); let def_id = adt_def.did(); - if let Some(cfi_encoding) = tcx.get_attr(def_id, sym::cfi_encoding) { + if let Some(encoding) = find_attr!(tcx.get_all_attrs(def_id), AttributeKind::CfiEncoding { encoding } => encoding) + { + let encoding = encoding.as_str().trim(); // Use user-defined CFI encoding for type - if let Some(value_str) = cfi_encoding.value_str() { - let value_str = value_str.as_str().trim(); - if !value_str.is_empty() { - s.push_str(value_str); - // Don't compress user-defined builtin types (see - // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-builtin and - // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression). - let builtin_types = [ - "v", "w", "b", "c", "a", "h", "s", "t", "i", "j", "l", "m", "x", "y", - "n", "o", "f", "d", "e", "g", "z", "Dh", - ]; - if !builtin_types.contains(&value_str) { - compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); - } - } else { - #[allow( - rustc::diagnostic_outside_of_impl, - rustc::untranslatable_diagnostic - )] - tcx.dcx() - .struct_span_err( - cfi_encoding.span(), - format!("invalid `cfi_encoding` for `{:?}`", ty.kind()), - ) - .emit(); - } - } else { - bug!("encode_ty: invalid `cfi_encoding` for `{:?}`", ty.kind()); + s.push_str(&encoding); + // Don't compress user-defined builtin types (see + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-builtin and + // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-compression). + let builtin_types = [ + "v", "w", "b", "c", "a", "h", "s", "t", "i", "j", "l", "m", "x", "y", "n", "o", + "f", "d", "e", "g", "z", "Dh", + ]; + if !builtin_types.contains(&encoding) { + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); } } else if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() { // For cross-language LLVM CFI support, the encoding must be compatible at the FFI @@ -508,26 +493,11 @@ pub(crate) fn encode_ty<'tcx>( ty::Foreign(def_id) => { // , where is let mut s = String::new(); - if let Some(cfi_encoding) = tcx.get_attr(*def_id, sym::cfi_encoding) { + + if let Some(encoding) = find_attr!(tcx.get_all_attrs(*def_id), AttributeKind::CfiEncoding {encoding} => encoding) + { // Use user-defined CFI encoding for type - if let Some(value_str) = cfi_encoding.value_str() { - if !value_str.to_string().trim().is_empty() { - s.push_str(value_str.to_string().trim()); - } else { - #[allow( - rustc::diagnostic_outside_of_impl, - rustc::untranslatable_diagnostic - )] - tcx.dcx() - .struct_span_err( - cfi_encoding.span(), - format!("invalid `cfi_encoding` for `{:?}`", ty.kind()), - ) - .emit(); - } - } else { - bug!("encode_ty: invalid `cfi_encoding` for `{:?}`", ty.kind()); - } + s.push_str(encoding.as_str().trim()); } else { let name = tcx.item_name(*def_id).to_string(); let _ = write!(s, "{}{}", name.len(), name); diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 28481f3dcdb3..9cea681fcb57 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -6,15 +6,15 @@ use std::iter; -use rustc_hir as hir; -use rustc_hir::LangItem; +use rustc_hir::attrs::AttributeKind; +use rustc_hir::{self as hir, LangItem, find_attr}; use rustc_middle::bug; use rustc_middle::ty::{ self, AssocContainer, ExistentialPredicateStableCmpExt as _, Instance, IntTy, List, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, UintTy, }; +use rustc_span::DUMMY_SP; use rustc_span::def_id::DefId; -use rustc_span::{DUMMY_SP, sym}; use rustc_trait_selection::traits; use tracing::{debug, instrument}; @@ -138,7 +138,10 @@ fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { { // Don't transform repr(transparent) types with an user-defined CFI encoding to // preserve the user-defined CFI encoding. - if let Some(_) = self.tcx.get_attr(adt_def.did(), sym::cfi_encoding) { + if find_attr!( + self.tcx.get_all_attrs(adt_def.did()), + AttributeKind::CfiEncoding { .. } + ) { return t; } let variant = adt_def.non_enum_variant(); diff --git a/tests/ui/attributes/malformed-attrs.rs b/tests/ui/attributes/malformed-attrs.rs index 37ccf9faa1a3..b0d8fd774f74 100644 --- a/tests/ui/attributes/malformed-attrs.rs +++ b/tests/ui/attributes/malformed-attrs.rs @@ -137,7 +137,7 @@ pub fn test3() {} //~^ ERROR malformed #[must_not_suspend()] //~^ ERROR malformed -#[cfi_encoding] +#[cfi_encoding = ""] //~^ ERROR malformed struct Test; diff --git a/tests/ui/attributes/malformed-attrs.stderr b/tests/ui/attributes/malformed-attrs.stderr index d0e5cb631c1e..860dcdb349bf 100644 --- a/tests/ui/attributes/malformed-attrs.stderr +++ b/tests/ui/attributes/malformed-attrs.stderr @@ -55,12 +55,6 @@ LL - #[must_not_suspend()] LL + #[must_not_suspend] | -error: malformed `cfi_encoding` attribute input - --> $DIR/malformed-attrs.rs:140:1 - | -LL | #[cfi_encoding] - | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]` - error: malformed `allow` attribute input --> $DIR/malformed-attrs.rs:184:1 | @@ -530,6 +524,15 @@ LL | #[rustc_layout_scalar_valid_range_end] | expected this to be a list | help: must be of the form: `#[rustc_layout_scalar_valid_range_end(end)]` +error[E0539]: malformed `cfi_encoding` attribute input + --> $DIR/malformed-attrs.rs:140:1 + | +LL | #[cfi_encoding = ""] + | ^^^^^^^^^^^^^^^^^--^ + | | | + | | string is not allowed to be empty + | help: must be of the form: `#[cfi_encoding = "encoding"]` + error[E0565]: malformed `marker` attribute input --> $DIR/malformed-attrs.rs:161:1 | diff --git a/tests/ui/sanitizer/cfi/invalid-attr-encoding.stderr b/tests/ui/sanitizer/cfi/invalid-attr-encoding.stderr index 1aa6bef17b1e..e95006c0ef61 100644 --- a/tests/ui/sanitizer/cfi/invalid-attr-encoding.stderr +++ b/tests/ui/sanitizer/cfi/invalid-attr-encoding.stderr @@ -1,8 +1,12 @@ -error: malformed `cfi_encoding` attribute input +error[E0539]: malformed `cfi_encoding` attribute input --> $DIR/invalid-attr-encoding.rs:10:1 | LL | #[cfi_encoding] - | ^^^^^^^^^^^^^^^ help: must be of the form: `#[cfi_encoding = "encoding"]` + | ^^^^^^^^^^^^^^^ + | | + | expected this to be of the form `cfi_encoding = "..."` + | help: must be of the form: `#[cfi_encoding = "encoding"]` error: aborting due to 1 previous error +For more information about this error, try `rustc --explain E0539`. From 5fc00306a8ed6eb40b470773988c57d494b2596d Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Mon, 22 Dec 2025 09:40:21 +0800 Subject: [PATCH 084/126] tidy: skip target-specific check for run-make-cargo too I forgot to change this when implementing the run-make fission. --- src/tools/tidy/src/target_specific_tests.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/tools/tidy/src/target_specific_tests.rs b/src/tools/tidy/src/target_specific_tests.rs index 159d7278bb62..11138de5de76 100644 --- a/src/tools/tidy/src/target_specific_tests.rs +++ b/src/tools/tidy/src/target_specific_tests.rs @@ -52,8 +52,12 @@ pub fn check(tests_path: &Path, tidy_ctx: TidyCtx) { } }); - // Skip run-make tests as revisions are not supported. - if entry.path().strip_prefix(tests_path).is_ok_and(|rest| rest.starts_with("run-make")) { + // Skip run-make/run-make-cargo tests as revisions are not supported. + if entry + .path() + .strip_prefix(tests_path) + .is_ok_and(|rest| rest.starts_with("run-make") || rest.starts_with("run-make-cargo")) + { return; } From 059655298692949f33754ce62c339b84418ed9ff Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sun, 21 Dec 2025 19:35:57 -0700 Subject: [PATCH 085/126] Use arithmetic instead of bitshifts Co-authored-by: Yotam Ofek --- src/librustdoc/html/static/js/stringdex.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/librustdoc/html/static/js/stringdex.js b/src/librustdoc/html/static/js/stringdex.js index e45c8bcd653b..720ac58e76e0 100644 --- a/src/librustdoc/html/static/js/stringdex.js +++ b/src/librustdoc/html/static/js/stringdex.js @@ -57,7 +57,7 @@ class RoaringBitmap { } else if (u8array[i] > 0xe0) { // Special representation of tiny sets that are runs const lspecial = u8array[i] & 0x0f; - this.keysAndCardinalities = new Uint8Array(lspecial << 2); + this.keysAndCardinalities = new Uint8Array(lspecial * 4); i += 1; const key = u8array[i + 2] | (u8array[i + 3] << 8); const value = u8array[i] | (u8array[i + 1] << 8); @@ -74,7 +74,7 @@ class RoaringBitmap { } else if (u8array[i] > 0xd0) { // Special representation of tiny sets that are close together const lspecial = u8array[i] & 0x0f; - this.keysAndCardinalities = new Uint8Array(lspecial << 2); + this.keysAndCardinalities = new Uint8Array(lspecial * 4); let pspecial = i + 1; let key = u8array[pspecial + 2] | (u8array[pspecial + 3] << 8); let value = u8array[pspecial] | (u8array[pspecial + 1] << 8); @@ -93,8 +93,8 @@ class RoaringBitmap { key = entry >> 16; container = this.addToArrayAt(key); const cardinalityOld = container.cardinality; - container.array[cardinalityOld << 1] = value & 0xFF; - container.array[(cardinalityOld << 1) + 1] = (value >> 8) & 0xFF; + container.array[cardinalityOld * 2] = value & 0xFF; + container.array[(cardinalityOld * 2) + 1] = (value >> 8) & 0xFF; container.cardinality = cardinalityOld + 1; pspecial += 1; } @@ -2409,7 +2409,7 @@ function loadDatabase(hooks) { encoded.subarray(i, i + (branch_leaves_count * 2)), ), ]; - i += branch_leaves_count << 1; + i += branch_leaves_count * 2; } branch_nodes.push(Promise.resolve( is_suffixes_only ? @@ -2465,7 +2465,7 @@ function loadDatabase(hooks) { encoded.subarray(i, i + (leaves_count * 2)), ), ]; - i += leaves_count << 1; + i += leaves_count * 2; } } return is_suffixes_only ? @@ -3085,7 +3085,7 @@ function loadDatabase(hooks) { if (branch_leaves_is_run) { i += 2; } else { - i += branch_leaves_count << 1; + i += branch_leaves_count * 2; } } // branch keys @@ -3094,7 +3094,7 @@ function loadDatabase(hooks) { if (leaves_is_run) { i += 2; } else { - i += leaves_count << 1; + i += leaves_count * 2; } if (is_data_compressed) { const clen = ( From de0945b2a714673a94e068d0cfad72dc40a0e6c8 Mon Sep 17 00:00:00 2001 From: Jieyou Xu Date: Wed, 10 Dec 2025 17:16:36 +0800 Subject: [PATCH 086/126] bootstrap: update comment for `STAGE0_MISSING_TARGETS` --- src/bootstrap/src/core/sanity.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 932a58c954df..67f4eb37b2c1 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -28,11 +28,13 @@ pub struct Finder { path: OsString, } -// During sanity checks, we search for target names to determine if they exist in the compiler's built-in -// target list (`rustc --print target-list`). While a target name may be present in the stage2 compiler, -// it might not yet be included in stage0. In such cases, we handle the targets missing from stage0 in this list. -// -// Targets can be removed from this list once they are present in the stage0 compiler (usually by updating the beta compiler of the bootstrap). +/// During sanity checks, we search for target tuples to determine if they exist in the compiler's +/// built-in target list (`rustc --print target-list`). While a target tuple may be present in the +/// in-tree compiler, the stage 0 compiler might not yet know about it (assuming not operating with +/// local-rebuild). In such cases, we handle the targets missing from stage 0 in this list. +/// +/// Targets can be removed from this list during the usual release process bootstrap compiler bumps, +/// when the newly-bumped stage 0 compiler now knows about the formerly-missing targets. const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined "riscv64im-unknown-none-elf", From 42ec5c7b324f2754453691d93561c2738407db2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 12 Dec 2025 19:52:23 +0000 Subject: [PATCH 087/126] Detail expectation on non-`()` block tail in `if` then condition with no `else` When encountering an `if` expression with no `else` where the then block has a tail expression, we emit an E0308 type error. We now explain why `()` was expected. --- compiler/rustc_hir_typeck/src/coercion.rs | 15 ++++++++++++++- ...e-for-type-mismatch-in-closure-in-async.stderr | 2 +- .../missing-return-in-async-block.stderr | 4 ++-- .../unused/unused-doc-comments-edge-cases.stderr | 2 +- .../ui/loops/dont-suggest-break-thru-item.stderr | 8 ++++---- .../struct-literals-in-invalid-places.stderr | 2 +- .../issue-82612-return-mutable-reference.stderr | 2 +- .../return/tail-expr-as-potential-return.stderr | 6 +++--- tests/ui/return/tail-expr-if-as-return.stderr | 2 +- .../try-operator-dont-suggest-semicolon.rs | 2 +- .../try-operator-dont-suggest-semicolon.stderr | 2 +- 11 files changed, 30 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs index b4a43548dcda..5e1e567d103e 100644 --- a/compiler/rustc_hir_typeck/src/coercion.rs +++ b/compiler/rustc_hir_typeck/src/coercion.rs @@ -1838,7 +1838,20 @@ fn report_return_mismatched_types<'infcx>( hir::ExprKind::Match(.., hir::MatchSource::TryDesugar(_)) ) { - err.span_label(cond_expr.span, "expected this to be `()`"); + if let ObligationCauseCode::BlockTailExpression(hir_id, hir::MatchSource::Normal) = + cause.code() + && let hir::Node::Block(block) = fcx.tcx.hir_node(*hir_id) + && let hir::Node::Expr(expr) = fcx.tcx.parent_hir_node(block.hir_id) + && let hir::Node::Expr(if_expr) = fcx.tcx.parent_hir_node(expr.hir_id) + && let hir::ExprKind::If(_cond, _then, None) = if_expr.kind + { + err.span_label( + cond_expr.span, + "`if` expressions without `else` arms expect their inner expression to be `()`", + ); + } else { + err.span_label(cond_expr.span, "expected this to be `()`"); + } if expr.can_have_side_effects() { fcx.suggest_semicolon_at_end(cond_expr.span, &mut err); } diff --git a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr index ce023397db90..928e1fcaa578 100644 --- a/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr +++ b/tests/ui/async-await/dont-ice-for-type-mismatch-in-closure-in-async.stderr @@ -6,7 +6,7 @@ LL | | false | | ^^^^^ expected `()`, found `bool` LL | | LL | | } - | |_________- expected this to be `()` + | |_________- `if` expressions without `else` arms expect their inner expression to be `()` error[E0308]: mismatched types --> $DIR/dont-ice-for-type-mismatch-in-closure-in-async.rs:12:9 diff --git a/tests/ui/async-await/missing-return-in-async-block.stderr b/tests/ui/async-await/missing-return-in-async-block.stderr index 5ea76e5f7bf9..a7d72ab5f33c 100644 --- a/tests/ui/async-await/missing-return-in-async-block.stderr +++ b/tests/ui/async-await/missing-return-in-async-block.stderr @@ -5,7 +5,7 @@ LL | / if true { LL | | Ok(S) | | ^^^^^ expected `()`, found `Result` LL | | } - | |_________- expected this to be `()` + | |_________- `if` expressions without `else` arms expect their inner expression to be `()` | = note: expected unit type `()` found enum `Result` @@ -21,7 +21,7 @@ LL | / if true { LL | | Ok(S) | | ^^^^^ expected `()`, found `Result` LL | | } - | |_________- expected this to be `()` + | |_________- `if` expressions without `else` arms expect their inner expression to be `()` | = note: expected unit type `()` found enum `Result` diff --git a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr index c07411745549..0f0288c6def6 100644 --- a/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr +++ b/tests/ui/lint/unused/unused-doc-comments-edge-cases.stderr @@ -105,7 +105,7 @@ LL | / if num == 3 { LL | | true | | ^^^^ expected `()`, found `bool` LL | | } - | |_____- expected this to be `()` + | |_____- `if` expressions without `else` arms expect their inner expression to be `()` | help: you might have meant to return this value | diff --git a/tests/ui/loops/dont-suggest-break-thru-item.stderr b/tests/ui/loops/dont-suggest-break-thru-item.stderr index e7ed7ae15015..576bd353520f 100644 --- a/tests/ui/loops/dont-suggest-break-thru-item.stderr +++ b/tests/ui/loops/dont-suggest-break-thru-item.stderr @@ -6,7 +6,7 @@ LL | | Err(1) | | ^^^^^^ expected `()`, found `Result<_, {integer}>` ... | LL | | } - | |_____________- expected this to be `()` + | |_____________- `if` expressions without `else` arms expect their inner expression to be `()` | = note: expected unit type `()` found enum `Result<_, {integer}>` @@ -23,7 +23,7 @@ LL | | Err(1) | | ^^^^^^ expected `()`, found `Result<_, {integer}>` ... | LL | | } - | |_____________- expected this to be `()` + | |_____________- `if` expressions without `else` arms expect their inner expression to be `()` | = note: expected unit type `()` found enum `Result<_, {integer}>` @@ -40,7 +40,7 @@ LL | | Err(1) | | ^^^^^^ expected `()`, found `Result<_, {integer}>` LL | | LL | | } - | |_____________- expected this to be `()` + | |_____________- `if` expressions without `else` arms expect their inner expression to be `()` | = note: expected unit type `()` found enum `Result<_, {integer}>` @@ -53,7 +53,7 @@ LL | | Err(1) | | ^^^^^^ expected `()`, found `Result<_, {integer}>` LL | | LL | | } - | |_____________- expected this to be `()` + | |_____________- `if` expressions without `else` arms expect their inner expression to be `()` | = note: expected unit type `()` found enum `Result<_, {integer}>` diff --git a/tests/ui/parser/struct-literals-in-invalid-places.stderr b/tests/ui/parser/struct-literals-in-invalid-places.stderr index 39dc2d2efb75..380ecf94d824 100644 --- a/tests/ui/parser/struct-literals-in-invalid-places.stderr +++ b/tests/ui/parser/struct-literals-in-invalid-places.stderr @@ -200,7 +200,7 @@ LL | if x == E::V { field } {} | ---------------^^^^^-- | | | | | expected `()`, found `bool` - | expected this to be `()` + | `if` expressions without `else` arms expect their inner expression to be `()` | help: you might have meant to return this value | diff --git a/tests/ui/return/issue-82612-return-mutable-reference.stderr b/tests/ui/return/issue-82612-return-mutable-reference.stderr index 59a6bb85d0fd..632f366c7551 100644 --- a/tests/ui/return/issue-82612-return-mutable-reference.stderr +++ b/tests/ui/return/issue-82612-return-mutable-reference.stderr @@ -6,7 +6,7 @@ LL | | let value = unsafe { self.values.get_unchecked_mut(index) }; LL | | value.get_or_insert_with(func) | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `&mut V` LL | | } - | |_________- expected this to be `()` + | |_________- `if` expressions without `else` arms expect their inner expression to be `()` | = note: expected unit type `()` found mutable reference `&mut V` diff --git a/tests/ui/return/tail-expr-as-potential-return.stderr b/tests/ui/return/tail-expr-as-potential-return.stderr index 8105b2df3fea..be3d4b5116f2 100644 --- a/tests/ui/return/tail-expr-as-potential-return.stderr +++ b/tests/ui/return/tail-expr-as-potential-return.stderr @@ -6,7 +6,7 @@ LL | | Err(42) | | ^^^^^^^ expected `()`, found `Result<_, {integer}>` ... | LL | | } - | |_____- expected this to be `()` + | |_____- `if` expressions without `else` arms expect their inner expression to be `()` | = note: expected unit type `()` found enum `Result<_, {integer}>` @@ -23,7 +23,7 @@ LL | | 1i32 | | ^^^^ expected `()`, found `i32` ... | LL | | } - | |_____- expected this to be `()` + | |_____- `if` expressions without `else` arms expect their inner expression to be `()` | help: you might have meant to return this value | @@ -38,7 +38,7 @@ LL | | Err(42) | | ^^^^^^^ expected `()`, found `Result<_, {integer}>` ... | LL | | } - | |_____- expected this to be `()` + | |_____- `if` expressions without `else` arms expect their inner expression to be `()` | = note: expected unit type `()` found enum `Result<_, {integer}>` diff --git a/tests/ui/return/tail-expr-if-as-return.stderr b/tests/ui/return/tail-expr-if-as-return.stderr index 2631f1e426de..68acde416bc7 100644 --- a/tests/ui/return/tail-expr-if-as-return.stderr +++ b/tests/ui/return/tail-expr-if-as-return.stderr @@ -5,7 +5,7 @@ LL | / if true { LL | | "" | | ^^ expected `()`, found `&str` LL | | } - | |_____- expected this to be `()` + | |_____- `if` expressions without `else` arms expect their inner expression to be `()` error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs index f882a159f983..fdd5dfc8307a 100644 --- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs +++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.rs @@ -12,7 +12,7 @@ fn main() -> Result<(), ()> { // Here, we do want to suggest a semicolon: let x = Ok(42); if true { - //~^ NOTE: expected this to be `()` + //~^ NOTE: `if` expressions without `else` arms expect their inner expression to be `()` x? //~^ ERROR: mismatched types [E0308] //~| NOTE: expected `()`, found integer diff --git a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr index a275f0c2fa89..25cd27488c8c 100644 --- a/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr +++ b/tests/ui/suggestions/try-operator-dont-suggest-semicolon.stderr @@ -15,7 +15,7 @@ LL | | x? | | ^^ expected `()`, found integer ... | LL | | } - | |_____- expected this to be `()` + | |_____- `if` expressions without `else` arms expect their inner expression to be `()` | help: consider using a semicolon here | From 7eeaa7ad4841b8e0e63bfd2dff5e2fba7d1fadf7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lauren=C8=9Biu=20Nicola?= Date: Mon, 22 Dec 2025 16:31:05 +0200 Subject: [PATCH 088/126] Fix name collision warning --- src/tools/rust-analyzer/crates/hir/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 90a0c2b402c0..9fc29de4a11c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -2624,7 +2624,7 @@ pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> { let callable_sig = db.callable_item_signature(self.func.into()).instantiate_identity().skip_binder(); let environment = param_env_from_has_crate(db, self.func); - let ty = callable_sig.inputs().as_slice()[0]; + let ty = rustc_type_ir::inherent::SliceLike::as_slice(&callable_sig.inputs())[0]; Type { env: environment, ty } } @@ -2639,7 +2639,7 @@ pub fn ty_with_args<'db>( let callable_sig = db.callable_item_signature(self.func.into()).instantiate(interner, args).skip_binder(); let environment = param_env_from_has_crate(db, self.func); - let ty = callable_sig.inputs().as_slice()[0]; + let ty = rustc_type_ir::inherent::SliceLike::as_slice(&callable_sig.inputs())[0]; Type { env: environment, ty } } } From 26ef77a94a1ae929c80573509c69117e5b2c3c2b Mon Sep 17 00:00:00 2001 From: Roy Ammerschuber Date: Tue, 2 Dec 2025 17:46:44 +0100 Subject: [PATCH 089/126] tree borrows: detect no_valid_exposed_references errors accurately --- .../src/borrow_tracker/tree_borrows/perms.rs | 12 ++--- .../src/borrow_tracker/tree_borrows/tree.rs | 33 +++++++++++-- .../borrow_tracker/tree_borrows/wildcard.rs | 14 +++++- ...cross_tree_update_main_invalid_exposed2.rs | 48 +++++++++++++++++++ ...s_tree_update_main_invalid_exposed2.stderr | 14 ++++++ 5 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed2.rs create mode 100644 src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed2.stderr diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs index bd4573f94013..064c1cc5b95f 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs @@ -374,9 +374,9 @@ pub fn strongest_idempotent_foreign_access(&self, prot: bool) -> IdempotentForei self.inner.strongest_idempotent_foreign_access(prot) } - /// Returns the strongest access allowed from a child to this node without + /// Returns the strongest access allowed that is local to this node without /// causing UB (only considers possible transitions to this permission). - pub fn strongest_allowed_child_access(&self, protected: bool) -> WildcardAccessLevel { + pub fn strongest_allowed_local_access(&self, protected: bool) -> WildcardAccessLevel { match self.inner { // Everything except disabled can be accessed by read access. Disabled => WildcardAccessLevel::None, @@ -794,9 +794,9 @@ fn permissionpriv_partialord_is_reachability() { /// Checks that `strongest_allowed_child_access` correctly /// represents which transitions are possible. #[test] - fn strongest_allowed_child_access() { + fn strongest_allowed_local_access() { for (permission, protected) in <(Permission, bool)>::exhaustive() { - let strongest_child_access = permission.strongest_allowed_child_access(protected); + let strongest_local_access = permission.strongest_allowed_local_access(protected); let is_read_valid = Permission::perform_access( AccessKind::Read, @@ -814,8 +814,8 @@ fn strongest_allowed_child_access() { ) .is_some(); - assert_eq!(is_read_valid, strongest_child_access >= WildcardAccessLevel::Read); - assert_eq!(is_write_valid, strongest_child_access >= WildcardAccessLevel::Write); + assert_eq!(is_read_valid, strongest_local_access >= WildcardAccessLevel::Read); + assert_eq!(is_write_valid, strongest_local_access >= WildcardAccessLevel::Write); } } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs index 900e9c3729c8..c8e27ebf0ff3 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs @@ -111,7 +111,7 @@ fn perform_transition( // We need to update the wildcard state, if the permission // of an exposed pointer changes. if node.is_exposed { - let access_type = self.permission.strongest_allowed_child_access(protected); + let access_type = self.permission.strongest_allowed_local_access(protected); WildcardState::update_exposure(idx, access_type, nodes, wildcard_accesses); } } @@ -1034,6 +1034,9 @@ fn perform_wildcard_access( wildcard_state.access_relatedness(access_kind, only_foreign) }; + // Whether there is an exposed node in this tree that allows this access. + let mut has_valid_exposed = false; + // This does a traversal across the tree updating children before their parents. The // difference to `perform_normal_access` is that we take the access relatedness from // the wildcard tracking state of the node instead of from the visitor itself. @@ -1082,6 +1085,17 @@ fn perform_wildcard_access( return Err(no_valid_exposed_references_error(diagnostics)); }; + let mut entry = args.data.perms.entry(args.idx); + let perm = entry.or_insert(node.default_location_state()); + + // We only count exposed nodes through which an access could happen. + if node.is_exposed + && perm.permission.strongest_allowed_local_access(protected).allows(access_kind) + && max_local_tag.is_none_or(|max_local_tag| max_local_tag >= node.tag) + { + has_valid_exposed = true; + } + let Some(relatedness) = wildcard_relatedness.to_relatedness() else { // If the access type is Either, then we do not apply any transition // to this node, but we still update each of its children. @@ -1090,8 +1104,6 @@ fn perform_wildcard_access( return Ok(()); }; - let mut entry = args.data.perms.entry(args.idx); - let perm = entry.or_insert(node.default_location_state()); // We know the exact relatedness, so we can actually do precise checks. perm.perform_transition( args.idx, @@ -1115,6 +1127,21 @@ fn perform_wildcard_access( }) }, )?; + // If there is no exposed node in this tree that allows this access, then the + // access *must* be foreign. So we check if the root of this tree would allow this + // as a foreign access, and if not, then we can error. + // In practice, all wildcard trees accept foreign accesses, but the main tree does + // not, so this catches UB when none of the nodes in the main tree allows this access. + if !has_valid_exposed + && self + .wildcard_accesses + .get(root) + .unwrap() + .access_relatedness(access_kind, /* only_foreign */ true) + .is_none() + { + return Err(no_valid_exposed_references_error(diagnostics)).into(); + } interp_ok(()) } } diff --git a/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs b/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs index 3b55a9e36ea6..b5ae0ee4c7d3 100644 --- a/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs +++ b/src/tools/miri/src/borrow_tracker/tree_borrows/wildcard.rs @@ -20,6 +20,16 @@ pub enum WildcardAccessLevel { Read, Write, } +impl WildcardAccessLevel { + /// Weather this access kind is allowed at this level. + pub fn allows(self, kind: AccessKind) -> bool { + let required_level = match kind { + AccessKind::Read => Self::Read, + AccessKind::Write => Self::Write, + }; + required_level <= self + } +} /// Where the access happened relative to the current node. #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -430,7 +440,7 @@ pub fn expose_tag(&mut self, tag: BorTag, protected: bool) { .map(|p| p.permission()) .unwrap_or_else(|| node.default_location_state().permission()); - let access_type = perm.strongest_allowed_child_access(protected); + let access_type = perm.strongest_allowed_local_access(protected); WildcardState::update_exposure( id, access_type, @@ -480,7 +490,7 @@ pub fn verify_wildcard_consistency(&self, global: &GlobalState) { perms.get(id).copied().unwrap_or_else(|| node.default_location_state()); perm.permission() - .strongest_allowed_child_access(protected_tags.contains_key(&node.tag)) + .strongest_allowed_local_access(protected_tags.contains_key(&node.tag)) } else { WildcardAccessLevel::None }; diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed2.rs b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed2.rs new file mode 100644 index 000000000000..ca430cad1670 --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed2.rs @@ -0,0 +1,48 @@ +//@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance +use std::cell::Cell; + +/// Checks how accesses from one subtree affect other subtrees. +/// This test checks that an access from a subtree performs a +/// wildcard access on all earlier trees, and that local +/// accesses are treated as access errors for tags that are +/// larger than the root of the accessed subtree. +/// This tests the case were we have multiple exposed nodes on +/// the main tree that are invalid because their tag is too large. +pub fn main() { + let mut x: u32 = 42; + + let ptr_base = &mut x as *mut u32; + let ref1 = unsafe { &mut *ptr_base }; + let int1 = ref1 as *mut u32 as usize; + let wild = int1 as *mut u32; + + // Activates ref1. + *ref1 = 4; + + let ref2 = unsafe { &mut *wild }; + + // Freezes ref1. + let ref3 = unsafe { &mut *(ptr_base as *mut Cell) }; + let _int3 = ref3 as *mut Cell as usize; + let ref4 = unsafe { &mut *(ptr_base as *mut Cell) }; + let _int4 = ref4 as *mut Cell as usize; + + // ┌──────────────┐ + // │ │ + // │ptr_base(Act) ├───────────┬──────────────────┐ * + // │ │ │ │ │ + // └──────┬───────┘ │ │ │ + // │ │ │ │ + // │ │ │ │ + // ▼ ▼ ▼ ▼ + // ┌─────────────┐ ┌────────────┐ ┌────────────┐ ┌───────────┐ + // │ │ │ │ │ │ │ │ + // │ ref1(Frz)* │ │ ref3(ReIM)*│ │ ref4(ReIM)*│ │ ref2(Res) │ + // │ │ │ │ │ │ │ │ + // └─────────────┘ └────────────┘ └────────────┘ └───────────┘ + + // Performs a wildcard access on the main root. However, as there are + // no exposed tags with write permissions and a tag smaller than ref2 + // this access fails. + *ref2 = 13; //~ ERROR: /write access through .* is forbidden/ +} diff --git a/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed2.stderr b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed2.stderr new file mode 100644 index 000000000000..1f7a3d61829c --- /dev/null +++ b/src/tools/miri/tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed2.stderr @@ -0,0 +1,14 @@ +error: Undefined Behavior: write access through at ALLOC[0x0] is forbidden + --> tests/fail/tree_borrows/wildcard/cross_tree_update_main_invalid_exposed2.rs:LL:CC + | +LL | *ref2 = 13; + | ^^^^^^^^^^ Undefined Behavior occurred here + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information + = help: there are no exposed tags which may perform this access here + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From 3f8b25771d1074abb391c55dc2c33df3a8278043 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova <58857108+ada4a@users.noreply.github.com> Date: Mon, 22 Dec 2025 16:50:41 +0100 Subject: [PATCH 090/126] Fix typo --- compiler/rustc_ast/src/ast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 1ea9e0ae7718..7c922417ee29 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1810,7 +1810,7 @@ pub enum ExprKind { /// or a `gen` block (`gen move { ... }`). /// /// The span is the "decl", which is the header before the body `{ }` - /// including the `asyng`/`gen` keywords and possibly `move`. + /// including the `async`/`gen` keywords and possibly `move`. Gen(CaptureBy, Box, GenBlockKind, Span), /// An await expression (`my_future.await`). Span is of await keyword. Await(Box, Span), From 9ae46aa9a3fd63877b04d2d240fc6ff5fe20a38b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Dec 2025 17:23:53 +0100 Subject: [PATCH 091/126] readme: update android state --- src/tools/miri/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/miri/README.md b/src/tools/miri/README.md index 86f190134d45..2832ef50adef 100644 --- a/src/tools/miri/README.md +++ b/src/tools/miri/README.md @@ -219,7 +219,7 @@ degree documented below): - We have unofficial support (not maintained by the Miri team itself) for some further operating systems. - `solaris` / `illumos`: maintained by @devnexen. Supports the entire test suite. - `freebsd`: maintained by @YohDeadfall and @LorrensP-2158466. Supports the entire test suite. - - `android`: **maintainer wanted**. Support very incomplete, but a basic "hello world" works. + - `android`: **maintainer wanted**. Basic OS APIs and concurrency work, but file system access is not supported. - For targets on other operating systems, Miri might fail before even reaching the `main` function. However, even for targets that we do support, the degree of support for accessing platform APIs From dfbb0fd7dc3e4f02e4102cf0b7f87958a8ca4d0e Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 22 Dec 2025 13:13:50 -0800 Subject: [PATCH 092/126] std: Use `usleep` temporarily on WASI targets This fixes some fallout from 147572 where the `thread::sleep` function is is broken on `wasm32-wasip2` after that PR. The cause for this is a broken implementation of `nanosleep` in wasi-libc itself which is being fixed in WebAssembly/wasi-libc/696. Similar to 149999 this avoids the problematic function for now while the wasi-libc changes take some time to propagate into a wasi-sdk release. --- library/std/src/sys/thread/unix.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/thread/unix.rs b/library/std/src/sys/thread/unix.rs index 18cdea0e1b1b..d0396ed71300 100644 --- a/library/std/src/sys/thread/unix.rs +++ b/library/std/src/sys/thread/unix.rs @@ -520,7 +520,7 @@ pub fn set_name(name: &CStr) { debug_assert_eq!(res, libc::OK); } -#[cfg(not(target_os = "espidf"))] +#[cfg(not(any(target_os = "espidf", target_os = "wasi")))] pub fn sleep(dur: Duration) { let mut secs = dur.as_secs(); let mut nsecs = dur.subsec_nanos() as _; @@ -546,7 +546,13 @@ pub fn sleep(dur: Duration) { } } -#[cfg(target_os = "espidf")] +#[cfg(any( + target_os = "espidf", + // wasi-libc prior to WebAssembly/wasi-libc#696 has a broken implementation + // of `nanosleep`, used above by most platforms, so use `usleep` until + // that fix propagates throughout the ecosystem. + target_os = "wasi", +))] pub fn sleep(dur: Duration) { // ESP-IDF does not have `nanosleep`, so we use `usleep` instead. // As per the documentation of `usleep`, it is expected to support From 54062cff4cf06334bc49288afc2391b7dc204e65 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Mon, 22 Dec 2025 12:51:59 -0500 Subject: [PATCH 093/126] move a ui test to coretests unit test It only tests the usage and formatting of `fmt::Pointer`. --- library/coretests/tests/fmt/mod.rs | 19 +++++++++++++++++++ tests/ui/traits/fmt-pointer-trait.rs | 24 ------------------------ 2 files changed, 19 insertions(+), 24 deletions(-) delete mode 100644 tests/ui/traits/fmt-pointer-trait.rs diff --git a/library/coretests/tests/fmt/mod.rs b/library/coretests/tests/fmt/mod.rs index 0fb099ef4191..67ba49db4d91 100644 --- a/library/coretests/tests/fmt/mod.rs +++ b/library/coretests/tests/fmt/mod.rs @@ -76,6 +76,25 @@ fn test_fmt_debug_of_mut_reference() { assert_eq!(format!("{:?}", &mut x), "0"); } +#[test] +fn test_fmt_pointer() { + use std::rc::Rc; + use std::sync::Arc; + let p: *const u8 = std::ptr::null(); + let rc = Rc::new(1usize); + let arc = Arc::new(1usize); + let b = Box::new("hi"); + + let _ = format!("{rc:p}{arc:p}{b:p}"); + + if cfg!(target_pointer_width = "32") { + assert_eq!(format!("{:#p}", p), "0x00000000"); + } else { + assert_eq!(format!("{:#p}", p), "0x0000000000000000"); + } + assert_eq!(format!("{:p}", p), "0x0"); +} + #[test] fn test_default_write_impls() { use core::fmt::Write; diff --git a/tests/ui/traits/fmt-pointer-trait.rs b/tests/ui/traits/fmt-pointer-trait.rs deleted file mode 100644 index edf734597f50..000000000000 --- a/tests/ui/traits/fmt-pointer-trait.rs +++ /dev/null @@ -1,24 +0,0 @@ -//@ run-pass -use std::ptr; -use std::rc::Rc; -use std::sync::Arc; - -fn main() { - let p: *const u8 = ptr::null(); - let rc = Rc::new(1usize); - let arc = Arc::new(1usize); - let b = Box::new("hi"); - - let _ = format!("{:p}{:p}{:p}", - rc, arc, b); - - if cfg!(target_pointer_width = "32") { - assert_eq!(format!("{:#p}", p), - "0x00000000"); - } else { - assert_eq!(format!("{:#p}", p), - "0x0000000000000000"); - } - assert_eq!(format!("{:p}", p), - "0x0"); -} From 2c0f14cb0c108ac72ea23645694a4abee75babd8 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Tue, 23 Dec 2025 03:33:20 +0000 Subject: [PATCH 094/126] bugfix: Fix compilation error in hermit-abi time.rs Fixes time.rs by updating the MIN and MAX structs appropriately. Signed-off-by: John Nunley --- library/std/src/sys/pal/hermit/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/hermit/time.rs b/library/std/src/sys/pal/hermit/time.rs index 53b1f9292b3d..734ad2540a18 100644 --- a/library/std/src/sys/pal/hermit/time.rs +++ b/library/std/src/sys/pal/hermit/time.rs @@ -213,9 +213,9 @@ fn sub(self, other: Instant) -> Duration { pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero()); impl SystemTime { - pub const MAX: SystemTime = SystemTime { t: Timespec::MAX }; + pub const MAX: SystemTime = SystemTime(Timespec::MAX); - pub const MIN: SystemTime = SystemTime { t: Timespec::MIN }; + pub const MIN: SystemTime = SystemTime(Timespec::MIN); pub fn new(tv_sec: i64, tv_nsec: i32) -> SystemTime { SystemTime(Timespec::new(tv_sec, tv_nsec)) From d2f42b0ab7c5df475788f908b55e01dbaeff6681 Mon Sep 17 00:00:00 2001 From: John Nunley Date: Mon, 22 Dec 2025 19:58:33 -0800 Subject: [PATCH 095/126] bugfix: Fix compile issue in Vita libstd Unfortunately it looks like the Vita libc does not support the "utimensat" function, which is needed for setting file times. To fix the build, this commit marks Vita as unsupported for the function that sets the file times. Signed-off-by: John Nunley --- library/std/src/sys/fs/unix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index ee3cb54a5ee6..de80f2ed053f 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -2166,7 +2166,7 @@ fn open_from(from: &Path) -> io::Result<(crate::fs::File, crate::fs::Metadata)> fn set_times_impl(p: &CStr, times: FileTimes, follow_symlinks: bool) -> io::Result<()> { cfg_select! { - any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx") => { + any(target_os = "redox", target_os = "espidf", target_os = "horizon", target_os = "nuttx", target_os = "vita") => { let _ = (p, times, follow_symlinks); Err(io::const_error!( io::ErrorKind::Unsupported, From ffd4da296e9238db0379433f111de2a38a50200f Mon Sep 17 00:00:00 2001 From: Tropical <42101043+tropicaaal@users.noreply.github.com> Date: Mon, 22 Dec 2025 23:33:04 -0600 Subject: [PATCH 096/126] remove unsupported pipe module from VEXos pal --- library/std/src/sys/pal/vexos/mod.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/std/src/sys/pal/vexos/mod.rs b/library/std/src/sys/pal/vexos/mod.rs index 3a37c8f2d488..049b435905d4 100644 --- a/library/std/src/sys/pal/vexos/mod.rs +++ b/library/std/src/sys/pal/vexos/mod.rs @@ -1,6 +1,4 @@ pub mod os; -#[path = "../unsupported/pipe.rs"] -pub mod pipe; pub mod time; #[expect(dead_code)] From ffbb9a59322f57f1e38fe7b992e7b03ad2d00edd Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 20 Dec 2025 18:42:41 +0100 Subject: [PATCH 097/126] compiletest: Add `LineNumber` newtype to avoid `+1` magic here and there Start small. If it works well we can increase usage bit by bit as time passes. Note that we keep using "0" to represent "no specific line" because changing to `Option` everywhere is much bigger and noisier change. That can be done later if wanted. --- src/tools/compiletest/src/directives.rs | 4 +++- src/tools/compiletest/src/directives/file.rs | 3 ++- src/tools/compiletest/src/directives/line.rs | 6 ++++-- .../compiletest/src/directives/line_number.rs | 21 +++++++++++++++++++ src/tools/compiletest/src/directives/tests.rs | 7 ++++--- src/tools/compiletest/src/runtest/debugger.rs | 18 +++++++--------- 6 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 src/tools/compiletest/src/directives/line_number.rs diff --git a/src/tools/compiletest/src/directives.rs b/src/tools/compiletest/src/directives.rs index c154886ebcde..d1e0c5d95001 100644 --- a/src/tools/compiletest/src/directives.rs +++ b/src/tools/compiletest/src/directives.rs @@ -29,6 +29,8 @@ mod file; mod handlers; mod line; +mod line_number; +pub(crate) use line_number::LineNumber; mod needs; #[cfg(test)] mod tests; @@ -591,7 +593,7 @@ fn iter_directives( ]; // Process the extra implied directives, with a dummy line number of 0. for directive_str in extra_directives { - let directive_line = line_directive(testfile, 0, directive_str) + let directive_line = line_directive(testfile, LineNumber::ZERO, directive_str) .unwrap_or_else(|| panic!("bad extra-directive line: {directive_str:?}")); it(&directive_line); } diff --git a/src/tools/compiletest/src/directives/file.rs b/src/tools/compiletest/src/directives/file.rs index 82819ac0c8f0..57186faa56b8 100644 --- a/src/tools/compiletest/src/directives/file.rs +++ b/src/tools/compiletest/src/directives/file.rs @@ -1,5 +1,6 @@ use camino::Utf8Path; +use crate::directives::LineNumber; use crate::directives::line::{DirectiveLine, line_directive}; pub(crate) struct FileDirectives<'a> { @@ -11,7 +12,7 @@ impl<'a> FileDirectives<'a> { pub(crate) fn from_file_contents(path: &'a Utf8Path, file_contents: &'a str) -> Self { let mut lines = vec![]; - for (line_number, ln) in (1..).zip(file_contents.lines()) { + for (line_number, ln) in LineNumber::enumerate().zip(file_contents.lines()) { let ln = ln.trim(); if let Some(directive_line) = line_directive(path, line_number, ln) { diff --git a/src/tools/compiletest/src/directives/line.rs b/src/tools/compiletest/src/directives/line.rs index 16dd9a8de1c0..9cc24c98a859 100644 --- a/src/tools/compiletest/src/directives/line.rs +++ b/src/tools/compiletest/src/directives/line.rs @@ -2,13 +2,15 @@ use camino::Utf8Path; +use crate::directives::LineNumber; + const COMPILETEST_DIRECTIVE_PREFIX: &str = "//@"; /// If the given line begins with the appropriate comment prefix for a directive, /// returns a struct containing various parts of the directive. pub(crate) fn line_directive<'a>( file_path: &'a Utf8Path, - line_number: usize, + line_number: LineNumber, original_line: &'a str, ) -> Option> { // Ignore lines that don't start with the comment prefix. @@ -60,7 +62,7 @@ pub(crate) struct DirectiveLine<'a> { /// Mostly used for diagnostics, but some directives (e.g. `//@ pp-exact`) /// also use it to compute a value based on the filename. pub(crate) file_path: &'a Utf8Path, - pub(crate) line_number: usize, + pub(crate) line_number: LineNumber, /// Some test directives start with a revision name in square brackets /// (e.g. `[foo]`), and only apply to that revision of the test. diff --git a/src/tools/compiletest/src/directives/line_number.rs b/src/tools/compiletest/src/directives/line_number.rs new file mode 100644 index 000000000000..ce5f200f470c --- /dev/null +++ b/src/tools/compiletest/src/directives/line_number.rs @@ -0,0 +1,21 @@ +/// A line number in a file. Internally the first line has index 1. +/// If it is 0 it means "no specific line" (used e.g. for implied directives). +/// When `Display`:ed, the first line is `1`. +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub(crate) struct LineNumber(usize); + +impl LineNumber { + /// This represents "no specific line" (used e.g. for implied directives). + pub(crate) const ZERO: Self = Self(0); + + /// A never ending iterator over line numbers starting from the first line. + pub(crate) fn enumerate() -> impl Iterator { + (1..).map(LineNumber) + } +} + +impl std::fmt::Display for LineNumber { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} diff --git a/src/tools/compiletest/src/directives/tests.rs b/src/tools/compiletest/src/directives/tests.rs index 90e2cb77e304..dfc733cf4e32 100644 --- a/src/tools/compiletest/src/directives/tests.rs +++ b/src/tools/compiletest/src/directives/tests.rs @@ -6,8 +6,8 @@ use crate::common::{Config, Debugger, TestMode}; use crate::directives::{ self, AuxProps, DIRECTIVE_HANDLERS_MAP, DirectivesCache, EarlyProps, Edition, EditionRange, - FileDirectives, KNOWN_DIRECTIVE_NAMES_SET, extract_llvm_version, extract_version_range, - line_directive, parse_edition, parse_normalize_rule, + FileDirectives, KNOWN_DIRECTIVE_NAMES_SET, LineNumber, extract_llvm_version, + extract_version_range, line_directive, parse_edition, parse_normalize_rule, }; use crate::executor::{CollectedTestDesc, ShouldFail}; @@ -1000,7 +1000,8 @@ fn parse_edition_range(line: &str) -> Option { let config = cfg().build(); let line_with_comment = format!("//@ {line}"); - let line = line_directive(Utf8Path::new("tmp.rs"), 0, &line_with_comment).unwrap(); + let line = + line_directive(Utf8Path::new("tmp.rs"), LineNumber::ZERO, &line_with_comment).unwrap(); super::parse_edition_range(&config, &line) } diff --git a/src/tools/compiletest/src/runtest/debugger.rs b/src/tools/compiletest/src/runtest/debugger.rs index 00935ab57d1c..c83e00c1006e 100644 --- a/src/tools/compiletest/src/runtest/debugger.rs +++ b/src/tools/compiletest/src/runtest/debugger.rs @@ -4,6 +4,7 @@ use camino::{Utf8Path, Utf8PathBuf}; +use crate::directives::LineNumber; use crate::runtest::ProcRes; /// Representation of information to invoke a debugger and check its output @@ -11,9 +12,9 @@ pub(super) struct DebuggerCommands { /// Commands for the debuuger pub commands: Vec, /// Lines to insert breakpoints at - pub breakpoint_lines: Vec, + pub breakpoint_lines: Vec, /// Contains the source line number to check and the line itself - check_lines: Vec<(usize, String)>, + check_lines: Vec<(LineNumber, String)>, /// Source file name file: Utf8PathBuf, } @@ -26,15 +27,13 @@ pub fn parse_from(file: &Utf8Path, debugger_prefix: &str) -> Result Result Result<(), String> ); for (src_lineno, err_line) in missing { - write!(msg, "\n ({fname}:{num}) `{err_line}`", num = src_lineno + 1).unwrap(); + write!(msg, "\n ({fname}:{src_lineno}) `{err_line}`").unwrap(); } if !found.is_empty() { let init = "\nthe following subset of check directive(s) was found successfully:"; msg.push_str(init); for (src_lineno, found_line) in found { - write!(msg, "\n ({fname}:{num}) `{found_line}`", num = src_lineno + 1) - .unwrap(); + write!(msg, "\n ({fname}:{src_lineno}) `{found_line}`").unwrap(); } } From 1de1885a63804bd5e0538ba76ab27278b6acf01f Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Tue, 23 Dec 2025 10:34:23 +0300 Subject: [PATCH 098/126] Support syntax for one-line trait reuse --- compiler/rustc_parse/messages.ftl | 2 + compiler/rustc_parse/src/errors.rs | 7 + compiler/rustc_parse/src/parser/item.rs | 144 +++++++-- tests/pretty/delegation-impl-reuse.pp | 46 +++ tests/pretty/delegation-impl-reuse.rs | 18 ++ tests/ui/delegation/impl-reuse-bad-path.rs | 31 ++ .../ui/delegation/impl-reuse-bad-path.stderr | 52 ++++ tests/ui/delegation/impl-reuse-empty-glob.rs | 14 + .../delegation/impl-reuse-empty-glob.stderr | 8 + .../delegation/impl-reuse-illegal-places.rs | 51 +++ .../impl-reuse-illegal-places.stderr | 92 ++++++ .../delegation/impl-reuse-negative-traits.rs | 19 ++ .../impl-reuse-negative-traits.stderr | 9 + .../delegation/impl-reuse-non-reuse-items.rs | 32 ++ .../impl-reuse-non-reuse-items.stderr | 60 ++++ .../impl-reuse-non-trait-impl-cfg-false.rs | 10 + ...impl-reuse-non-trait-impl-cfg-false.stderr | 8 + .../delegation/impl-reuse-non-trait-impl.rs | 9 + .../impl-reuse-non-trait-impl.stderr | 8 + tests/ui/delegation/impl-reuse-pass.rs | 292 ++++++++++++++++++ 20 files changed, 879 insertions(+), 33 deletions(-) create mode 100644 tests/pretty/delegation-impl-reuse.pp create mode 100644 tests/pretty/delegation-impl-reuse.rs create mode 100644 tests/ui/delegation/impl-reuse-bad-path.rs create mode 100644 tests/ui/delegation/impl-reuse-bad-path.stderr create mode 100644 tests/ui/delegation/impl-reuse-empty-glob.rs create mode 100644 tests/ui/delegation/impl-reuse-empty-glob.stderr create mode 100644 tests/ui/delegation/impl-reuse-illegal-places.rs create mode 100644 tests/ui/delegation/impl-reuse-illegal-places.stderr create mode 100644 tests/ui/delegation/impl-reuse-negative-traits.rs create mode 100644 tests/ui/delegation/impl-reuse-negative-traits.stderr create mode 100644 tests/ui/delegation/impl-reuse-non-reuse-items.rs create mode 100644 tests/ui/delegation/impl-reuse-non-reuse-items.stderr create mode 100644 tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.rs create mode 100644 tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.stderr create mode 100644 tests/ui/delegation/impl-reuse-non-trait-impl.rs create mode 100644 tests/ui/delegation/impl-reuse-non-trait-impl.stderr create mode 100644 tests/ui/delegation/impl-reuse-pass.rs diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 87d1173c0d48..747895c80469 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -162,6 +162,8 @@ parse_default_not_followed_by_item = `default` is not followed by an item .label = the `default` qualifier .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default` +parse_delegation_non_trait_impl_reuse = only trait impls can be reused + parse_do_catch_syntax_removed = found removed `do catch` syntax .note = following RFC #2388, the new non-placeholder syntax is `try` .suggestion = replace with the new syntax diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 698d8f76aaa6..3b72c9802afd 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -3671,3 +3671,10 @@ pub(crate) struct VarargsWithoutPattern { #[suggestion(code = "_: ...", applicability = "machine-applicable")] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(parse_delegation_non_trait_impl_reuse)] +pub(crate) struct ImplReuseInherentImpl { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 33913fd351a1..fb8b76e32209 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -117,6 +117,11 @@ pub fn parse_mod( } } +enum ReuseKind { + Path, + Impl, +} + impl<'a> Parser<'a> { pub fn parse_item(&mut self, force_collect: ForceCollect) -> PResult<'a, Option>> { let fn_parse_mode = @@ -249,9 +254,9 @@ fn parse_item_kind( } else if self.check_keyword_case(exp!(Trait), case) || self.check_trait_front_matter() { // TRAIT ITEM self.parse_item_trait(attrs, lo)? - } else if self.check_impl_frontmatter() { + } else if self.check_impl_frontmatter(0) { // IMPL ITEM - self.parse_item_impl(attrs, def_())? + self.parse_item_impl(attrs, def_(), false)? } else if let Const::Yes(const_span) = self.parse_constness(case) { // CONST ITEM self.recover_const_mut(const_span); @@ -265,8 +270,8 @@ fn parse_item_kind( rhs, define_opaque: None, })) - } else if self.is_reuse_path_item() { - self.parse_item_delegation()? + } else if let Some(kind) = self.is_reuse_item() { + self.parse_item_delegation(attrs, def_(), kind)? } else if self.check_keyword_case(exp!(Mod), case) || self.check_keyword_case(exp!(Unsafe), case) && self.is_keyword_ahead(1, &[kw::Mod]) { @@ -367,16 +372,25 @@ fn parse_use_item(&mut self) -> PResult<'a, ItemKind> { /// When parsing a statement, would the start of a path be an item? pub(super) fn is_path_start_item(&mut self) -> bool { self.is_kw_followed_by_ident(kw::Union) // no: `union::b`, yes: `union U { .. }` - || self.is_reuse_path_item() + || self.is_reuse_item().is_some() // yes: `reuse impl Trait for Struct { self.0 }`, yes: `reuse some_path::foo;` || self.check_trait_front_matter() // no: `auto::b`, yes: `auto trait X { .. }` || self.is_async_fn() // no(2015): `async::b`, yes: `async fn` || matches!(self.is_macro_rules_item(), IsMacroRulesItem::Yes{..}) // no: `macro_rules::b`, yes: `macro_rules! mac` } - fn is_reuse_path_item(&mut self) -> bool { + fn is_reuse_item(&mut self) -> Option { + if !self.token.is_keyword(kw::Reuse) { + return None; + } + // no: `reuse ::path` for compatibility reasons with macro invocations - self.token.is_keyword(kw::Reuse) - && self.look_ahead(1, |t| t.is_path_start() && *t != token::PathSep) + if self.look_ahead(1, |t| t.is_path_start() && *t != token::PathSep) { + Some(ReuseKind::Path) + } else if self.check_impl_frontmatter(1) { + Some(ReuseKind::Impl) + } else { + None + } } /// Are we sure this could not possibly be a macro invocation? @@ -560,6 +574,7 @@ fn parse_item_impl( &mut self, attrs: &mut AttrVec, defaultness: Defaultness, + is_reuse: bool, ) -> PResult<'a, ItemKind> { let mut constness = self.parse_constness(Case::Sensitive); let safety = self.parse_safety(Case::Sensitive); @@ -628,7 +643,11 @@ fn parse_item_impl( generics.where_clause = self.parse_where_clause()?; - let impl_items = self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))?; + let impl_items = if is_reuse { + Default::default() + } else { + self.parse_item_list(attrs, |p| p.parse_impl_item(ForceCollect::No))? + }; let (of_trait, self_ty) = match ty_second { Some(ty_second) => { @@ -699,10 +718,76 @@ fn parse_item_impl( Ok(ItemKind::Impl(Impl { generics, of_trait, self_ty, items: impl_items, constness })) } - fn parse_item_delegation(&mut self) -> PResult<'a, ItemKind> { + fn parse_item_delegation( + &mut self, + attrs: &mut AttrVec, + defaultness: Defaultness, + kind: ReuseKind, + ) -> PResult<'a, ItemKind> { let span = self.token.span; self.expect_keyword(exp!(Reuse))?; + let item_kind = match kind { + ReuseKind::Path => self.parse_path_like_delegation(), + ReuseKind::Impl => self.parse_impl_delegation(span, attrs, defaultness), + }?; + + self.psess.gated_spans.gate(sym::fn_delegation, span.to(self.prev_token.span)); + + Ok(item_kind) + } + + fn parse_delegation_body(&mut self) -> PResult<'a, Option>> { + Ok(if self.check(exp!(OpenBrace)) { + Some(self.parse_block()?) + } else { + self.expect(exp!(Semi))?; + None + }) + } + + fn parse_impl_delegation( + &mut self, + span: Span, + attrs: &mut AttrVec, + defaultness: Defaultness, + ) -> PResult<'a, ItemKind> { + let mut impl_item = self.parse_item_impl(attrs, defaultness, true)?; + let ItemKind::Impl(Impl { items, of_trait, .. }) = &mut impl_item else { unreachable!() }; + + let until_expr_span = span.to(self.prev_token.span); + + let Some(of_trait) = of_trait else { + return Err(self + .dcx() + .create_err(errors::ImplReuseInherentImpl { span: until_expr_span })); + }; + + let body = self.parse_delegation_body()?; + let whole_reuse_span = span.to(self.prev_token.span); + + items.push(Box::new(AssocItem { + id: DUMMY_NODE_ID, + attrs: Default::default(), + span: whole_reuse_span, + tokens: None, + vis: Visibility { + kind: VisibilityKind::Inherited, + span: whole_reuse_span, + tokens: None, + }, + kind: AssocItemKind::DelegationMac(Box::new(DelegationMac { + qself: None, + prefix: of_trait.trait_ref.path.clone(), + suffixes: None, + body, + })), + })); + + Ok(impl_item) + } + + fn parse_path_like_delegation(&mut self) -> PResult<'a, ItemKind> { let (qself, path) = if self.eat_lt() { let (qself, path) = self.parse_qpath(PathStyle::Expr)?; (Some(qself), path) @@ -713,43 +798,35 @@ fn parse_item_delegation(&mut self) -> PResult<'a, ItemKind> { let rename = |this: &mut Self| { Ok(if this.eat_keyword(exp!(As)) { Some(this.parse_ident()?) } else { None }) }; - let body = |this: &mut Self| { - Ok(if this.check(exp!(OpenBrace)) { - Some(this.parse_block()?) - } else { - this.expect(exp!(Semi))?; - None - }) - }; - let item_kind = if self.eat_path_sep() { + Ok(if self.eat_path_sep() { let suffixes = if self.eat(exp!(Star)) { None } else { let parse_suffix = |p: &mut Self| Ok((p.parse_path_segment_ident()?, rename(p)?)); Some(self.parse_delim_comma_seq(exp!(OpenBrace), exp!(CloseBrace), parse_suffix)?.0) }; - let deleg = DelegationMac { qself, prefix: path, suffixes, body: body(self)? }; - ItemKind::DelegationMac(Box::new(deleg)) + + ItemKind::DelegationMac(Box::new(DelegationMac { + qself, + prefix: path, + suffixes, + body: self.parse_delegation_body()?, + })) } else { let rename = rename(self)?; let ident = rename.unwrap_or_else(|| path.segments.last().unwrap().ident); - let deleg = Delegation { + + ItemKind::Delegation(Box::new(Delegation { id: DUMMY_NODE_ID, qself, path, ident, rename, - body: body(self)?, + body: self.parse_delegation_body()?, from_glob: false, - }; - ItemKind::Delegation(Box::new(deleg)) - }; - - let span = span.to(self.prev_token.span); - self.psess.gated_spans.gate(sym::fn_delegation, span); - - Ok(item_kind) + })) + }) } fn parse_item_list( @@ -2594,7 +2671,7 @@ fn parse_fn_body( Ok(body) } - fn check_impl_frontmatter(&mut self) -> bool { + fn check_impl_frontmatter(&mut self, look_ahead: usize) -> bool { const ALL_QUALS: &[Symbol] = &[kw::Const, kw::Unsafe]; // In contrast to the loop below, this call inserts `impl` into the // list of expected tokens shown in diagnostics. @@ -2603,7 +2680,7 @@ fn check_impl_frontmatter(&mut self) -> bool { } let mut i = 0; while i < ALL_QUALS.len() { - let action = self.look_ahead(i, |token| { + let action = self.look_ahead(i + look_ahead, |token| { if token.is_keyword(kw::Impl) { return Some(true); } @@ -2618,6 +2695,7 @@ fn check_impl_frontmatter(&mut self) -> bool { } i += 1; } + self.is_keyword_ahead(i, &[kw::Impl]) } diff --git a/tests/pretty/delegation-impl-reuse.pp b/tests/pretty/delegation-impl-reuse.pp new file mode 100644 index 000000000000..72f62de0eacb --- /dev/null +++ b/tests/pretty/delegation-impl-reuse.pp @@ -0,0 +1,46 @@ +#![feature(prelude_import)] +#![no_std] +//@ pretty-compare-only +//@ pretty-mode:expanded +//@ pp-exact:delegation-impl-reuse.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#[macro_use] +extern crate std; +#[prelude_import] +use ::std::prelude::rust_2015::*; + +trait Trait { + fn foo(&self) {} + fn bar(&self) {} + fn baz(&self) {} +} + +struct S; + +impl Trait<{ + struct S; + 0 + }> for S { + reuse Trait<{ + struct S; + 0 + }>::foo { + self.0 + } + reuse Trait<{ + struct S; + 0 + }>::bar { + self.0 + } + reuse Trait<{ + struct S; + 0 + }>::baz { + self.0 + } +} + +fn main() {} diff --git a/tests/pretty/delegation-impl-reuse.rs b/tests/pretty/delegation-impl-reuse.rs new file mode 100644 index 000000000000..9265ea18a76f --- /dev/null +++ b/tests/pretty/delegation-impl-reuse.rs @@ -0,0 +1,18 @@ +//@ pretty-compare-only +//@ pretty-mode:expanded +//@ pp-exact:delegation-impl-reuse.pp + +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +trait Trait { + fn foo(&self) {} + fn bar(&self) {} + fn baz(&self) {} +} + +struct S; + +reuse impl Trait<{ struct S; 0 }> for S { self.0 } + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-bad-path.rs b/tests/ui/delegation/impl-reuse-bad-path.rs new file mode 100644 index 000000000000..19eb51153468 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-bad-path.rs @@ -0,0 +1,31 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +mod unresolved { + struct S; + reuse impl unresolved for S { self.0 } + //~^ ERROR failed to resolve: use of unresolved module or unlinked crate `unresolved` + //~| ERROR cannot find trait `unresolved` in this scope + + trait T {} + reuse impl T for unresolved { self.0 } + //~^ ERROR empty glob delegation is not supported + //~| ERROR cannot find type `unresolved` in this scope +} + +mod wrong_entities { + trait T {} + struct Trait; + struct S; + + reuse impl Trait for S { self.0 } + //~^ ERROR expected trait, found struct `Trait` + //~| ERROR expected trait, found struct `Trait` + + mod TraitModule {} + reuse impl TraitModule for S { self.0 } + //~^ ERROR expected trait, found module `TraitModule` + //~| ERROR expected trait, found module `TraitModule` +} + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-bad-path.stderr b/tests/ui/delegation/impl-reuse-bad-path.stderr new file mode 100644 index 000000000000..5fadd719ae4d --- /dev/null +++ b/tests/ui/delegation/impl-reuse-bad-path.stderr @@ -0,0 +1,52 @@ +error: empty glob delegation is not supported + --> $DIR/impl-reuse-bad-path.rs:11:5 + | +LL | reuse impl T for unresolved { self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: expected trait, found struct `Trait` + --> $DIR/impl-reuse-bad-path.rs:21:16 + | +LL | reuse impl Trait for S { self.0 } + | ^^^^^ not a trait + +error: expected trait, found module `TraitModule` + --> $DIR/impl-reuse-bad-path.rs:26:16 + | +LL | reuse impl TraitModule for S { self.0 } + | ^^^^^^^^^^^ not a trait + +error[E0433]: failed to resolve: use of unresolved module or unlinked crate `unresolved` + --> $DIR/impl-reuse-bad-path.rs:6:16 + | +LL | reuse impl unresolved for S { self.0 } + | ^^^^^^^^^^ use of unresolved module or unlinked crate `unresolved` + +error[E0405]: cannot find trait `unresolved` in this scope + --> $DIR/impl-reuse-bad-path.rs:6:16 + | +LL | reuse impl unresolved for S { self.0 } + | ^^^^^^^^^^ not found in this scope + +error[E0425]: cannot find type `unresolved` in this scope + --> $DIR/impl-reuse-bad-path.rs:11:22 + | +LL | reuse impl T for unresolved { self.0 } + | ^^^^^^^^^^ not found in this scope + +error[E0404]: expected trait, found struct `Trait` + --> $DIR/impl-reuse-bad-path.rs:21:16 + | +LL | reuse impl Trait for S { self.0 } + | ^^^^^ not a trait + +error[E0404]: expected trait, found module `TraitModule` + --> $DIR/impl-reuse-bad-path.rs:26:16 + | +LL | reuse impl TraitModule for S { self.0 } + | ^^^^^^^^^^^ not a trait + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0404, E0405, E0425, E0433. +For more information about an error, try `rustc --explain E0404`. diff --git a/tests/ui/delegation/impl-reuse-empty-glob.rs b/tests/ui/delegation/impl-reuse-empty-glob.rs new file mode 100644 index 000000000000..3f1314c47da6 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-empty-glob.rs @@ -0,0 +1,14 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +mod empty_glob { + trait T {} + + struct S; + + reuse impl T for S { self.0 } + //~^ ERROR empty glob delegation is not supported +} + + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-empty-glob.stderr b/tests/ui/delegation/impl-reuse-empty-glob.stderr new file mode 100644 index 000000000000..bf6bb5876351 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-empty-glob.stderr @@ -0,0 +1,8 @@ +error: empty glob delegation is not supported + --> $DIR/impl-reuse-empty-glob.rs:9:5 + | +LL | reuse impl T for S { self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/impl-reuse-illegal-places.rs b/tests/ui/delegation/impl-reuse-illegal-places.rs new file mode 100644 index 000000000000..361331d41315 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-illegal-places.rs @@ -0,0 +1,51 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +trait T { + fn f(&self) {} +} + +struct S; +impl T for S {} + +struct F(S); + +struct X { + reuse impl T for F { self.0 } + //~^ ERROR expected `:`, found keyword `impl` +} + +impl X { + reuse impl T for F { self.0 } + //~^ ERROR implementation is not supported in `trait`s or `impl`s +} + +trait Trait { + reuse impl T for F { self.0 } + //~^ ERROR implementation is not supported in `trait`s or `impl`s +} + +extern "C" { + reuse impl T for F { self.0 } + //~^ ERROR implementation is not supported in `extern` blocks +} + +mod m { + mod inner { + pub fn foo() {} + } + + reuse inner::{ + reuse impl T for F { self.0 } + //~^ ERROR expected identifier, found keyword `impl` + //~| ERROR expected one of `,`, `as`, or `}`, found keyword `impl` + //~| ERROR expected one of `,`, `as`, or `}`, found `T` + //~| ERROR expected identifier, found keyword `for` + //~| ERROR expected one of `,`, `as`, or `}`, found keyword `for` + //~| ERROR expected one of `,`, `as`, or `}`, found `F` + //~| ERROR expected one of `,`, `as`, or `}`, found `{` + } +} +//~^ ERROR expected item, found `}` + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-illegal-places.stderr b/tests/ui/delegation/impl-reuse-illegal-places.stderr new file mode 100644 index 000000000000..fb17ebdd6cee --- /dev/null +++ b/tests/ui/delegation/impl-reuse-illegal-places.stderr @@ -0,0 +1,92 @@ +error: expected `:`, found keyword `impl` + --> $DIR/impl-reuse-illegal-places.rs:14:11 + | +LL | struct X { + | - while parsing this struct +LL | reuse impl T for F { self.0 } + | ^^^^ expected `:` + +error: implementation is not supported in `trait`s or `impl`s + --> $DIR/impl-reuse-illegal-places.rs:19:5 + | +LL | reuse impl T for F { self.0 } + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider moving the implementation out to a nearby module scope + +error: implementation is not supported in `trait`s or `impl`s + --> $DIR/impl-reuse-illegal-places.rs:24:5 + | +LL | reuse impl T for F { self.0 } + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider moving the implementation out to a nearby module scope + +error: implementation is not supported in `extern` blocks + --> $DIR/impl-reuse-illegal-places.rs:29:5 + | +LL | reuse impl T for F { self.0 } + | ^^^^^^^^^^^^^^^^^^ + | + = help: consider moving the implementation out to a nearby module scope + +error: expected identifier, found keyword `impl` + --> $DIR/impl-reuse-illegal-places.rs:39:15 + | +LL | reuse impl T for F { self.0 } + | ^^^^ expected identifier, found keyword + +error: expected one of `,`, `as`, or `}`, found keyword `impl` + --> $DIR/impl-reuse-illegal-places.rs:39:15 + | +LL | reuse impl T for F { self.0 } + | -^^^^ expected one of `,`, `as`, or `}` + | | + | help: missing `,` + +error: expected one of `,`, `as`, or `}`, found `T` + --> $DIR/impl-reuse-illegal-places.rs:39:20 + | +LL | reuse impl T for F { self.0 } + | -^ expected one of `,`, `as`, or `}` + | | + | help: missing `,` + +error: expected identifier, found keyword `for` + --> $DIR/impl-reuse-illegal-places.rs:39:22 + | +LL | reuse impl T for F { self.0 } + | ^^^ expected identifier, found keyword + +error: expected one of `,`, `as`, or `}`, found keyword `for` + --> $DIR/impl-reuse-illegal-places.rs:39:22 + | +LL | reuse impl T for F { self.0 } + | -^^^ expected one of `,`, `as`, or `}` + | | + | help: missing `,` + +error: expected one of `,`, `as`, or `}`, found `F` + --> $DIR/impl-reuse-illegal-places.rs:39:26 + | +LL | reuse impl T for F { self.0 } + | -^ expected one of `,`, `as`, or `}` + | | + | help: missing `,` + +error: expected one of `,`, `as`, or `}`, found `{` + --> $DIR/impl-reuse-illegal-places.rs:39:28 + | +LL | reuse impl T for F { self.0 } + | ^ expected one of `,`, `as`, or `}` + +error: expected item, found `}` + --> $DIR/impl-reuse-illegal-places.rs:48:1 + | +LL | } + | ^ expected item + | + = note: for a full list of items that can appear in modules, see + +error: aborting due to 12 previous errors + diff --git a/tests/ui/delegation/impl-reuse-negative-traits.rs b/tests/ui/delegation/impl-reuse-negative-traits.rs new file mode 100644 index 000000000000..7bcbc82f03db --- /dev/null +++ b/tests/ui/delegation/impl-reuse-negative-traits.rs @@ -0,0 +1,19 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#![feature(negative_impls)] + +trait Trait { + fn foo(&self); + //~^ ERROR negative impls cannot have any items [E0749] +} + +struct S; +impl Trait for S { + fn foo(&self) {} +} + +struct F(S); + +reuse impl !Trait for F { &self.0 } + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-negative-traits.stderr b/tests/ui/delegation/impl-reuse-negative-traits.stderr new file mode 100644 index 000000000000..1be6ef715920 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-negative-traits.stderr @@ -0,0 +1,9 @@ +error[E0749]: negative impls cannot have any items + --> $DIR/impl-reuse-negative-traits.rs:6:8 + | +LL | fn foo(&self); + | ^^^ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0749`. diff --git a/tests/ui/delegation/impl-reuse-non-reuse-items.rs b/tests/ui/delegation/impl-reuse-non-reuse-items.rs new file mode 100644 index 000000000000..de7c92279218 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-reuse-items.rs @@ -0,0 +1,32 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +mod non_delegatable_items { + trait Trait { + fn method(&self); + const CONST: u8; + type Type; + #[allow(non_camel_case_types)] + type method; + } + + struct F; + impl Trait for F { + fn method(&self) {} + const CONST: u8 = 0; + type Type = u8; + type method = u8; + } + + struct S(F); + + reuse impl Trait for S { &self.0 } + //~^ ERROR item `CONST` is an associated method, which doesn't match its trait `Trait` + //~| ERROR item `Type` is an associated method, which doesn't match its trait `Trait` + //~| ERROR duplicate definitions with name `method` + //~| ERROR expected function, found associated constant `Trait::CONST` + //~| ERROR expected function, found associated type `Trait::Type` + //~| ERROR not all trait items implemented, missing: `CONST`, `Type`, `method` +} + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-non-reuse-items.stderr b/tests/ui/delegation/impl-reuse-non-reuse-items.stderr new file mode 100644 index 000000000000..9d6b0f638136 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-reuse-items.stderr @@ -0,0 +1,60 @@ +error[E0324]: item `CONST` is an associated method, which doesn't match its trait `Trait` + --> $DIR/impl-reuse-non-reuse-items.rs:23:5 + | +LL | const CONST: u8; + | ---------------- item in trait +... +LL | reuse impl Trait for S { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait + +error[E0324]: item `Type` is an associated method, which doesn't match its trait `Trait` + --> $DIR/impl-reuse-non-reuse-items.rs:23:5 + | +LL | type Type; + | ---------- item in trait +... +LL | reuse impl Trait for S { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ does not match trait + +error[E0201]: duplicate definitions with name `method`: + --> $DIR/impl-reuse-non-reuse-items.rs:23:5 + | +LL | fn method(&self); + | ----------------- item in trait +... +LL | reuse impl Trait for S { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | duplicate definition + | previous definition here + +error[E0423]: expected function, found associated constant `Trait::CONST` + --> $DIR/impl-reuse-non-reuse-items.rs:23:16 + | +LL | reuse impl Trait for S { &self.0 } + | ^^^^^ not a function + +error[E0423]: expected function, found associated type `Trait::Type` + --> $DIR/impl-reuse-non-reuse-items.rs:23:16 + | +LL | reuse impl Trait for S { &self.0 } + | ^^^^^ not a function + +error[E0046]: not all trait items implemented, missing: `CONST`, `Type`, `method` + --> $DIR/impl-reuse-non-reuse-items.rs:23:5 + | +LL | const CONST: u8; + | --------------- `CONST` from trait +LL | type Type; + | --------- `Type` from trait +LL | #[allow(non_camel_case_types)] +LL | type method; + | ----------- `method` from trait +... +LL | reuse impl Trait for S { &self.0 } + | ^^^^^^^^^^^^^^^^^^^^^^ missing `CONST`, `Type`, `method` in implementation + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0046, E0201, E0324, E0423. +For more information about an error, try `rustc --explain E0046`. diff --git a/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.rs b/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.rs new file mode 100644 index 000000000000..51ef1dc14ba8 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.rs @@ -0,0 +1,10 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +struct Trait(usize); + +#[cfg(false)] +reuse impl Trait { self.0 } +//~^ ERROR only trait impls can be reused + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.stderr b/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.stderr new file mode 100644 index 000000000000..24a138016116 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-trait-impl-cfg-false.stderr @@ -0,0 +1,8 @@ +error: only trait impls can be reused + --> $DIR/impl-reuse-non-trait-impl-cfg-false.rs:7:1 + | +LL | reuse impl Trait { self.0 } + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/impl-reuse-non-trait-impl.rs b/tests/ui/delegation/impl-reuse-non-trait-impl.rs new file mode 100644 index 000000000000..c7a9813250db --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-trait-impl.rs @@ -0,0 +1,9 @@ +#![allow(incomplete_features)] +#![feature(fn_delegation)] + +struct Trait(usize); + +reuse impl Trait { self.0 } +//~^ ERROR only trait impls can be reused + +fn main() {} diff --git a/tests/ui/delegation/impl-reuse-non-trait-impl.stderr b/tests/ui/delegation/impl-reuse-non-trait-impl.stderr new file mode 100644 index 000000000000..3987042104c3 --- /dev/null +++ b/tests/ui/delegation/impl-reuse-non-trait-impl.stderr @@ -0,0 +1,8 @@ +error: only trait impls can be reused + --> $DIR/impl-reuse-non-trait-impl.rs:6:1 + | +LL | reuse impl Trait { self.0 } + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/delegation/impl-reuse-pass.rs b/tests/ui/delegation/impl-reuse-pass.rs new file mode 100644 index 000000000000..90060b03f9ef --- /dev/null +++ b/tests/ui/delegation/impl-reuse-pass.rs @@ -0,0 +1,292 @@ +//@ check-pass + +#![allow(incomplete_features)] +#![feature(fn_delegation)] +#![feature(const_trait_impl)] +#![allow(warnings)] + +mod default { + trait T { + fn foo(&self) {} + fn bar(&self) {} + fn goo(&self) {} + } + + struct S; + impl T for S {} + + struct F(S); + reuse impl T for F { self.0 } + + fn f() { + let f = F(S{}); + + f.foo(); + f.bar(); + f.goo(); + } +} + +mod dyn_traits { + trait T { + fn foo(&self) -> Box; + } + + trait SecondTrait { + fn bar(&self); + } + + reuse impl SecondTrait for dyn T { self.foo().as_ref() } +} + +mod complex_path { + pub mod first { + pub mod second { + pub trait T { + fn foo(&self, x: usize); + } + } + } + + struct S; + impl first::second::T for S { + fn foo(&self, x: usize) { } + } + + struct F(S); + reuse impl first::second::T for F { self.0 } + + fn f() { + use complex_path::first::second::T; + + let f = F(S{}); + + f.foo(1); + } +} + +mod no_body_reuse { + trait T { + fn foo(&self) {} + fn bar(&mut self) {} + } + + struct F; + + reuse impl T for F; + + fn foo() { + let mut f = F{}; + + f.foo(); + f.bar(); + } +} + +mod unsafe_trait { + unsafe trait UnsafeTrait { + fn foo(&self) {} + fn bar(&self) {} + fn goo(&self) {} + } + + struct S; + unsafe impl UnsafeTrait for S {} + + struct F(S); + reuse unsafe impl UnsafeTrait for F { self.0 } + + fn f() { + let f = F(S{}); + + f.foo(); + f.bar(); + f.goo(); + } +} + +mod const_trait { + const trait ConstTrait { + fn foo(&self) -> usize { 0 } + fn bar(&self) -> usize { 1 } + } + + struct S; + const impl ConstTrait for S {} + + struct F(S); + reuse const impl ConstTrait for F { self.0 } + + fn f() { + let f = F(S{}); + + f.foo(); + f.bar(); + } +} + +mod different_selves { + trait T: Sized { + fn foo(&self) {} + fn boo(self) {} + fn goo(&mut self) {} + } + + struct S; + impl T for S {} + + struct F(S); + reuse impl T for F { self.0 } + + struct D(S); + macro_rules! self_0 { ($self:ident) => { $self.0 } } + + reuse impl T for D { self_0!(self) } + + fn f() { + let mut f = F(S{}); + f.foo(); + f.goo(); + f.boo(); + + let mut d = D(S{}); + d.foo(); + d.goo(); + d.boo(); + } +} + +mod macros { + trait Trait { + fn foo(&self) -> u8 { 0 } + fn bar(&self) -> u8 { 1 } + } + + impl Trait for u8 {} + struct S(u8); + + macro_rules! self_0_ref { ($self:ident) => { &$self.0 } } + + reuse impl Trait for S { self_0_ref!(self) } + + struct M(u8); + macro_rules! m { () => { M } } + reuse impl Trait for m!() { self_0_ref!(self) } + + struct S1(u8); + macro_rules! one_line_reuse { ($self:ident) => { reuse impl Trait for S1 { $self.0 } } } + one_line_reuse!(self); + + struct S2(u8); + macro_rules! one_line_reuse_expr { ($x:expr) => { reuse impl Trait for S2 { $x } } } + one_line_reuse_expr!(self.0); + + struct S3(u8); + macro_rules! s3 { () => { S3 } } + macro_rules! one_line_reuse_expr2 { ($x:expr) => { reuse impl Trait for s3!() { $x } } } + one_line_reuse_expr2!(self.0); + + fn f() { + let s = S(1); + s.foo(); + s.bar(); + + let m = M(41); + m.foo(); + m.bar(); + + let s1 = S1(2); + s1.foo(); + s1.bar(); + + let s2 = S2(4); + s2.foo(); + s2.bar(); + + let s3 = S3(5); + s3.foo(); + s3.bar(); + } +} + +mod generics { + trait Trait<'a, 'b, A, B, C> { + fn foo(&self, a: &A) {} + fn bar(&self, b: &B) {} + fn goo(&self, c: &C) {} + } + + struct S; + impl<'a, 'b, A, B, C> Trait<'a, 'b, A, B, C> for S {} + + struct F(S); + reuse impl<'a, 'b, A, B, C> Trait<'a, 'b, A, B, C> for F { &self.0 } + + struct S1; + struct F1(S1); + impl<'c, B> Trait<'static, 'c, usize, B, String> for S1 {} + reuse impl<'d, B> Trait<'static, 'd, usize, B, String> for F1 { &self.0 } + + struct S2; + struct F2(S2); + impl Trait<'static, 'static, u8, u16, u32> for S2 {} + reuse impl Trait<'static, 'static, u8, u16, u32> for F2 { &self.0 } + + fn f<'a, 'b, 'c, A, B, C>(a: A, b: B, c: C) { + let f = F(S{}); + + >::foo(&f, &a); + >::bar(&f, &b); + >::goo(&f, &c); + + let f = F1(S1{}); + >::foo(&f, &123); + >::bar(&f, &b); + >::goo(&f, &"s".to_string()); + + let f = F2(S2{}); + >::foo(&f, &1); + >::bar(&f, &2); + >::goo(&f, &3); + } +} + +mod reuse_in_different_places { + trait T { + fn foo(&self, x: usize) {} + } + + struct S; + impl T for S {} + + struct F1(S); + reuse impl T for F1 { + struct F2(S, S, S); + reuse impl T for F2 { self.1 } + + let f2 = F2(S{}, S{}, S{}); + f2.foo(123); + + &self.0 + } + + fn foo() { + struct F(S); + reuse impl T for F { self.0 } + + let f = F(S{}); + f.foo(1); + } + + fn bar() { + || { + struct F(S); + reuse impl T for F { self.0 } + + let f = F(S{}); + f.foo(1); + }; + } +} + +fn main() {} From f289ccf207ede543f23d5998bf5ee6a0b793bdf2 Mon Sep 17 00:00:00 2001 From: Daniel Scherzer Date: Mon, 22 Dec 2025 23:49:11 -0800 Subject: [PATCH 099/126] `target_features::Stability`: tweak docs of `requires_nightly()` * No method named `allow_toggle()` exists on the type, but based on the documentation of both `requires_nightly()` and `toggle_allowed()` it seems that `toggle_allowed()` is the intended method to mention. * Add `()` to the mention of `in_cfg()` to make it clear that a method is being referred to, and to match the presence of `()` in the mention of `toggle_allowed()`. --- compiler/rustc_target/src/target_features.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index 35cfeba2bffd..85c473c5abb2 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -62,8 +62,8 @@ pub fn in_cfg(&self) -> bool { /// the feature gate to actually be enabled when using a nightly compiler.) /// /// Before calling this, ensure the feature is even permitted for this use: - /// - for `#[target_feature]`/`-Ctarget-feature`, check `allow_toggle()` - /// - for `cfg(target_feature)`, check `in_cfg` + /// - for `#[target_feature]`/`-Ctarget-feature`, check `toggle_allowed()` + /// - for `cfg(target_feature)`, check `in_cfg()` pub fn requires_nightly(&self) -> Option { match *self { Stability::Unstable(nightly_feature) => Some(nightly_feature), From 82499bac52fe6367b0da4a161d6cc9b6b49d2cc4 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Tue, 23 Dec 2025 10:06:02 +0000 Subject: [PATCH 100/126] Correct terminology in Clone --- library/core/src/clone.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index bf8875098edf..e3d4b5c3331c 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -52,12 +52,12 @@ /// original. /// /// Differs from [`Copy`] in that [`Copy`] is implicit and an inexpensive bit-wise copy, while -/// `Clone` is always explicit and may or may not be expensive. In order to enforce -/// these characteristics, Rust does not allow you to reimplement [`Copy`], but you -/// may reimplement `Clone` and run arbitrary code. +/// `Clone` is always explicit and may or may not be expensive. [`Copy`] has no methods, so you +/// cannot change its behavior, but when implementing `Clone`, the `clone` method you provide +/// may run arbitrary code. /// -/// Since `Clone` is more general than [`Copy`], you can automatically make anything -/// [`Copy`] be `Clone` as well. +/// Since `Clone` is a supertrait of [`Copy`], any type that implements `Copy` must also implement +/// `Clone`. /// /// ## Derivable /// From 7ca2eb9c6f67e694cfc7d762f722c3a510fe59b0 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sat, 20 Dec 2025 23:37:09 +0900 Subject: [PATCH 101/126] moved test --- .../issue-50581.rs => array-slice-vec/array-break-length-2.rs} | 0 .../array-break-length-2.stderr} | 0 .../issue-36400.rs => borrowck/borrow-immutable-deref-box.rs} | 0 .../borrow-immutable-deref-box.stderr} | 0 .../issue-18423.rs => box/box-lifetime-argument-not-allowed.rs} | 0 .../box-lifetime-argument-not-allowed.stderr} | 0 .../cast-rfc0401.rs => cast/cast-rfc0401-fail.rs} | 0 .../cast-rfc0401.stderr => cast/cast-rfc0401-fail.stderr} | 0 tests/ui/{issues/issue-22289.rs => cast/cast-to-dyn-any.rs} | 0 .../ui/{issues/issue-22289.stderr => cast/cast-to-dyn-any.stderr} | 0 .../closure-array-break-length-2.rs} | 0 .../closure-array-break-length-2.stderr} | 0 .../closure-move-use-after-move-diagnostic.rs} | 0 .../closure-move-use-after-move-diagnostic.stderr} | 0 .../{issues/issue-38458.rs => consts/const-return-outside-fn.rs} | 0 .../issue-38458.stderr => consts/const-return-outside-fn.stderr} | 0 .../ui/{issues/issue-28568.rs => drop/drop-conflicting-impls.rs} | 0 .../issue-28568.stderr => drop/drop-conflicting-impls.stderr} | 0 .../issue-23217.rs => enum/enum-discriminant-missing-variant.rs} | 0 .../enum-discriminant-missing-variant.stderr} | 0 .../{issues/issue-21554.rs => mismatched_types/cast-rfc0401-2.rs} | 0 .../issue-21554.stderr => mismatched_types/cast-rfc0401-2.stderr} | 0 .../issue-47184.rs => nll/borrowck-annotate-static-lifetime.rs} | 0 .../borrowck-annotate-static-lifetime.stderr} | 0 tests/ui/{issues/issue-46983.rs => nll/nll-anon-to-static.rs} | 0 .../{issues/issue-46983.stderr => nll/nll-anon-to-static.stderr} | 0 .../issue-45965.rs => parser/missing-operator-after-float.rs} | 0 .../missing-operator-after-float.stderr} | 0 .../{issues/issue-44078.rs => parser/unbalanced-doublequote-2.rs} | 0 .../issue-44078.stderr => parser/unbalanced-doublequote-2.stderr} | 0 .../issue-23173.rs => resolve/missing-associated-items.rs} | 0 .../missing-associated-items.stderr} | 0 tests/ui/{issues/issue-50582.rs => typeck/for-in-const-eval.rs} | 0 .../issue-50582.stderr => typeck/for-in-const-eval.stderr} | 0 34 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-50581.rs => array-slice-vec/array-break-length-2.rs} (100%) rename tests/ui/{issues/issue-50581.stderr => array-slice-vec/array-break-length-2.stderr} (100%) rename tests/ui/{issues/issue-36400.rs => borrowck/borrow-immutable-deref-box.rs} (100%) rename tests/ui/{issues/issue-36400.stderr => borrowck/borrow-immutable-deref-box.stderr} (100%) rename tests/ui/{issues/issue-18423.rs => box/box-lifetime-argument-not-allowed.rs} (100%) rename tests/ui/{issues/issue-18423.stderr => box/box-lifetime-argument-not-allowed.stderr} (100%) rename tests/ui/{mismatched_types/cast-rfc0401.rs => cast/cast-rfc0401-fail.rs} (100%) rename tests/ui/{mismatched_types/cast-rfc0401.stderr => cast/cast-rfc0401-fail.stderr} (100%) rename tests/ui/{issues/issue-22289.rs => cast/cast-to-dyn-any.rs} (100%) rename tests/ui/{issues/issue-22289.stderr => cast/cast-to-dyn-any.stderr} (100%) rename tests/ui/{array-slice-vec/array-break-length.rs => closures/closure-array-break-length-2.rs} (100%) rename tests/ui/{array-slice-vec/array-break-length.stderr => closures/closure-array-break-length-2.stderr} (100%) rename tests/ui/{issues/issue-24357.rs => closures/closure-move-use-after-move-diagnostic.rs} (100%) rename tests/ui/{issues/issue-24357.stderr => closures/closure-move-use-after-move-diagnostic.stderr} (100%) rename tests/ui/{issues/issue-38458.rs => consts/const-return-outside-fn.rs} (100%) rename tests/ui/{issues/issue-38458.stderr => consts/const-return-outside-fn.stderr} (100%) rename tests/ui/{issues/issue-28568.rs => drop/drop-conflicting-impls.rs} (100%) rename tests/ui/{issues/issue-28568.stderr => drop/drop-conflicting-impls.stderr} (100%) rename tests/ui/{issues/issue-23217.rs => enum/enum-discriminant-missing-variant.rs} (100%) rename tests/ui/{issues/issue-23217.stderr => enum/enum-discriminant-missing-variant.stderr} (100%) rename tests/ui/{issues/issue-21554.rs => mismatched_types/cast-rfc0401-2.rs} (100%) rename tests/ui/{issues/issue-21554.stderr => mismatched_types/cast-rfc0401-2.stderr} (100%) rename tests/ui/{issues/issue-47184.rs => nll/borrowck-annotate-static-lifetime.rs} (100%) rename tests/ui/{issues/issue-47184.stderr => nll/borrowck-annotate-static-lifetime.stderr} (100%) rename tests/ui/{issues/issue-46983.rs => nll/nll-anon-to-static.rs} (100%) rename tests/ui/{issues/issue-46983.stderr => nll/nll-anon-to-static.stderr} (100%) rename tests/ui/{issues/issue-45965.rs => parser/missing-operator-after-float.rs} (100%) rename tests/ui/{issues/issue-45965.stderr => parser/missing-operator-after-float.stderr} (100%) rename tests/ui/{issues/issue-44078.rs => parser/unbalanced-doublequote-2.rs} (100%) rename tests/ui/{issues/issue-44078.stderr => parser/unbalanced-doublequote-2.stderr} (100%) rename tests/ui/{issues/issue-23173.rs => resolve/missing-associated-items.rs} (100%) rename tests/ui/{issues/issue-23173.stderr => resolve/missing-associated-items.stderr} (100%) rename tests/ui/{issues/issue-50582.rs => typeck/for-in-const-eval.rs} (100%) rename tests/ui/{issues/issue-50582.stderr => typeck/for-in-const-eval.stderr} (100%) diff --git a/tests/ui/issues/issue-50581.rs b/tests/ui/array-slice-vec/array-break-length-2.rs similarity index 100% rename from tests/ui/issues/issue-50581.rs rename to tests/ui/array-slice-vec/array-break-length-2.rs diff --git a/tests/ui/issues/issue-50581.stderr b/tests/ui/array-slice-vec/array-break-length-2.stderr similarity index 100% rename from tests/ui/issues/issue-50581.stderr rename to tests/ui/array-slice-vec/array-break-length-2.stderr diff --git a/tests/ui/issues/issue-36400.rs b/tests/ui/borrowck/borrow-immutable-deref-box.rs similarity index 100% rename from tests/ui/issues/issue-36400.rs rename to tests/ui/borrowck/borrow-immutable-deref-box.rs diff --git a/tests/ui/issues/issue-36400.stderr b/tests/ui/borrowck/borrow-immutable-deref-box.stderr similarity index 100% rename from tests/ui/issues/issue-36400.stderr rename to tests/ui/borrowck/borrow-immutable-deref-box.stderr diff --git a/tests/ui/issues/issue-18423.rs b/tests/ui/box/box-lifetime-argument-not-allowed.rs similarity index 100% rename from tests/ui/issues/issue-18423.rs rename to tests/ui/box/box-lifetime-argument-not-allowed.rs diff --git a/tests/ui/issues/issue-18423.stderr b/tests/ui/box/box-lifetime-argument-not-allowed.stderr similarity index 100% rename from tests/ui/issues/issue-18423.stderr rename to tests/ui/box/box-lifetime-argument-not-allowed.stderr diff --git a/tests/ui/mismatched_types/cast-rfc0401.rs b/tests/ui/cast/cast-rfc0401-fail.rs similarity index 100% rename from tests/ui/mismatched_types/cast-rfc0401.rs rename to tests/ui/cast/cast-rfc0401-fail.rs diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/cast/cast-rfc0401-fail.stderr similarity index 100% rename from tests/ui/mismatched_types/cast-rfc0401.stderr rename to tests/ui/cast/cast-rfc0401-fail.stderr diff --git a/tests/ui/issues/issue-22289.rs b/tests/ui/cast/cast-to-dyn-any.rs similarity index 100% rename from tests/ui/issues/issue-22289.rs rename to tests/ui/cast/cast-to-dyn-any.rs diff --git a/tests/ui/issues/issue-22289.stderr b/tests/ui/cast/cast-to-dyn-any.stderr similarity index 100% rename from tests/ui/issues/issue-22289.stderr rename to tests/ui/cast/cast-to-dyn-any.stderr diff --git a/tests/ui/array-slice-vec/array-break-length.rs b/tests/ui/closures/closure-array-break-length-2.rs similarity index 100% rename from tests/ui/array-slice-vec/array-break-length.rs rename to tests/ui/closures/closure-array-break-length-2.rs diff --git a/tests/ui/array-slice-vec/array-break-length.stderr b/tests/ui/closures/closure-array-break-length-2.stderr similarity index 100% rename from tests/ui/array-slice-vec/array-break-length.stderr rename to tests/ui/closures/closure-array-break-length-2.stderr diff --git a/tests/ui/issues/issue-24357.rs b/tests/ui/closures/closure-move-use-after-move-diagnostic.rs similarity index 100% rename from tests/ui/issues/issue-24357.rs rename to tests/ui/closures/closure-move-use-after-move-diagnostic.rs diff --git a/tests/ui/issues/issue-24357.stderr b/tests/ui/closures/closure-move-use-after-move-diagnostic.stderr similarity index 100% rename from tests/ui/issues/issue-24357.stderr rename to tests/ui/closures/closure-move-use-after-move-diagnostic.stderr diff --git a/tests/ui/issues/issue-38458.rs b/tests/ui/consts/const-return-outside-fn.rs similarity index 100% rename from tests/ui/issues/issue-38458.rs rename to tests/ui/consts/const-return-outside-fn.rs diff --git a/tests/ui/issues/issue-38458.stderr b/tests/ui/consts/const-return-outside-fn.stderr similarity index 100% rename from tests/ui/issues/issue-38458.stderr rename to tests/ui/consts/const-return-outside-fn.stderr diff --git a/tests/ui/issues/issue-28568.rs b/tests/ui/drop/drop-conflicting-impls.rs similarity index 100% rename from tests/ui/issues/issue-28568.rs rename to tests/ui/drop/drop-conflicting-impls.rs diff --git a/tests/ui/issues/issue-28568.stderr b/tests/ui/drop/drop-conflicting-impls.stderr similarity index 100% rename from tests/ui/issues/issue-28568.stderr rename to tests/ui/drop/drop-conflicting-impls.stderr diff --git a/tests/ui/issues/issue-23217.rs b/tests/ui/enum/enum-discriminant-missing-variant.rs similarity index 100% rename from tests/ui/issues/issue-23217.rs rename to tests/ui/enum/enum-discriminant-missing-variant.rs diff --git a/tests/ui/issues/issue-23217.stderr b/tests/ui/enum/enum-discriminant-missing-variant.stderr similarity index 100% rename from tests/ui/issues/issue-23217.stderr rename to tests/ui/enum/enum-discriminant-missing-variant.stderr diff --git a/tests/ui/issues/issue-21554.rs b/tests/ui/mismatched_types/cast-rfc0401-2.rs similarity index 100% rename from tests/ui/issues/issue-21554.rs rename to tests/ui/mismatched_types/cast-rfc0401-2.rs diff --git a/tests/ui/issues/issue-21554.stderr b/tests/ui/mismatched_types/cast-rfc0401-2.stderr similarity index 100% rename from tests/ui/issues/issue-21554.stderr rename to tests/ui/mismatched_types/cast-rfc0401-2.stderr diff --git a/tests/ui/issues/issue-47184.rs b/tests/ui/nll/borrowck-annotate-static-lifetime.rs similarity index 100% rename from tests/ui/issues/issue-47184.rs rename to tests/ui/nll/borrowck-annotate-static-lifetime.rs diff --git a/tests/ui/issues/issue-47184.stderr b/tests/ui/nll/borrowck-annotate-static-lifetime.stderr similarity index 100% rename from tests/ui/issues/issue-47184.stderr rename to tests/ui/nll/borrowck-annotate-static-lifetime.stderr diff --git a/tests/ui/issues/issue-46983.rs b/tests/ui/nll/nll-anon-to-static.rs similarity index 100% rename from tests/ui/issues/issue-46983.rs rename to tests/ui/nll/nll-anon-to-static.rs diff --git a/tests/ui/issues/issue-46983.stderr b/tests/ui/nll/nll-anon-to-static.stderr similarity index 100% rename from tests/ui/issues/issue-46983.stderr rename to tests/ui/nll/nll-anon-to-static.stderr diff --git a/tests/ui/issues/issue-45965.rs b/tests/ui/parser/missing-operator-after-float.rs similarity index 100% rename from tests/ui/issues/issue-45965.rs rename to tests/ui/parser/missing-operator-after-float.rs diff --git a/tests/ui/issues/issue-45965.stderr b/tests/ui/parser/missing-operator-after-float.stderr similarity index 100% rename from tests/ui/issues/issue-45965.stderr rename to tests/ui/parser/missing-operator-after-float.stderr diff --git a/tests/ui/issues/issue-44078.rs b/tests/ui/parser/unbalanced-doublequote-2.rs similarity index 100% rename from tests/ui/issues/issue-44078.rs rename to tests/ui/parser/unbalanced-doublequote-2.rs diff --git a/tests/ui/issues/issue-44078.stderr b/tests/ui/parser/unbalanced-doublequote-2.stderr similarity index 100% rename from tests/ui/issues/issue-44078.stderr rename to tests/ui/parser/unbalanced-doublequote-2.stderr diff --git a/tests/ui/issues/issue-23173.rs b/tests/ui/resolve/missing-associated-items.rs similarity index 100% rename from tests/ui/issues/issue-23173.rs rename to tests/ui/resolve/missing-associated-items.rs diff --git a/tests/ui/issues/issue-23173.stderr b/tests/ui/resolve/missing-associated-items.stderr similarity index 100% rename from tests/ui/issues/issue-23173.stderr rename to tests/ui/resolve/missing-associated-items.stderr diff --git a/tests/ui/issues/issue-50582.rs b/tests/ui/typeck/for-in-const-eval.rs similarity index 100% rename from tests/ui/issues/issue-50582.rs rename to tests/ui/typeck/for-in-const-eval.rs diff --git a/tests/ui/issues/issue-50582.stderr b/tests/ui/typeck/for-in-const-eval.stderr similarity index 100% rename from tests/ui/issues/issue-50582.stderr rename to tests/ui/typeck/for-in-const-eval.stderr From 4578082361406cdf6836301c127534f1a2317135 Mon Sep 17 00:00:00 2001 From: reddevilmidzy Date: Sun, 21 Dec 2025 09:13:49 +0900 Subject: [PATCH 102/126] Cleaned up some tests add comment to closure-move-use-after-move-diagnostic.rs add comment to missing-operator-after-float.rs add comment to closure-array-break-length.rs add comment to box-lifetime-argument-not-allowed.rs add comment to const-return-outside-fn.rs add comment to drop-conflicting-impls.rs add comment to unbalanced-doublequote-2.rs add comment to borrow-immutable-deref-box.rs add comment to for-in-const-eval.rs add comment to borrowck-annotated-static-lifetime.rs cleaned up cast-rfc0401.rs add comment to nll-anon-to-static.rs add comment to cast-to-dyn-any.rs add comment to missing-associated-items.rs add comment to enum-discriminant-missing-variant.rs --- .../array-slice-vec/array-break-length-2.rs | 3 - .../array-break-length-2.stderr | 9 --- .../ui/borrowck/borrow-immutable-deref-box.rs | 1 + .../borrow-immutable-deref-box.stderr | 2 +- .../box/box-lifetime-argument-not-allowed.rs | 7 +- .../box-lifetime-argument-not-allowed.stderr | 4 +- tests/ui/cast/cast-rfc0401-2.rs | 8 -- tests/ui/cast/cast-rfc0401-2.stderr | 15 ---- tests/ui/cast/cast-rfc0401-fail.rs | 29 ++++--- tests/ui/cast/cast-rfc0401-fail.stderr | 76 ++++++++++--------- tests/ui/cast/cast-to-dyn-any.rs | 1 + tests/ui/cast/cast-to-dyn-any.stderr | 2 +- .../closures/closure-array-break-length-2.rs | 9 --- .../closure-array-break-length-2.stderr | 15 ---- .../ui/closures/closure-array-break-length.rs | 11 +++ .../closure-array-break-length.stderr | 26 ++++++- .../closure-move-use-after-move-diagnostic.rs | 21 ++--- ...sure-move-use-after-move-diagnostic.stderr | 25 +++--- tests/ui/consts/const-return-outside-fn.rs | 1 + .../ui/consts/const-return-outside-fn.stderr | 2 +- tests/ui/drop/drop-conflicting-impls.rs | 7 +- tests/ui/drop/drop-conflicting-impls.stderr | 2 +- .../enum/enum-discriminant-missing-variant.rs | 1 + .../enum-discriminant-missing-variant.stderr | 2 +- tests/ui/mismatched_types/cast-rfc0401-2.rs | 6 -- .../ui/mismatched_types/cast-rfc0401-2.stderr | 9 --- .../nll/borrowck-annotate-static-lifetime.rs | 1 + .../borrowck-annotate-static-lifetime.stderr | 2 +- tests/ui/nll/nll-anon-to-static.rs | 1 + tests/ui/nll/nll-anon-to-static.stderr | 2 +- .../ui/parser/missing-operator-after-float.rs | 1 + .../missing-operator-after-float.stderr | 2 +- tests/ui/parser/unbalanced-doublequote-2.rs | 1 + .../ui/parser/unbalanced-doublequote-2.stderr | 2 +- tests/ui/resolve/missing-associated-items.rs | 12 ++- .../resolve/missing-associated-items.stderr | 10 +-- tests/ui/typeck/for-in-const-eval.rs | 1 + tests/ui/typeck/for-in-const-eval.stderr | 2 +- 38 files changed, 160 insertions(+), 171 deletions(-) delete mode 100644 tests/ui/array-slice-vec/array-break-length-2.rs delete mode 100644 tests/ui/array-slice-vec/array-break-length-2.stderr delete mode 100644 tests/ui/cast/cast-rfc0401-2.rs delete mode 100644 tests/ui/cast/cast-rfc0401-2.stderr delete mode 100644 tests/ui/closures/closure-array-break-length-2.rs delete mode 100644 tests/ui/closures/closure-array-break-length-2.stderr delete mode 100644 tests/ui/mismatched_types/cast-rfc0401-2.rs delete mode 100644 tests/ui/mismatched_types/cast-rfc0401-2.stderr diff --git a/tests/ui/array-slice-vec/array-break-length-2.rs b/tests/ui/array-slice-vec/array-break-length-2.rs deleted file mode 100644 index 12bb9930eca4..000000000000 --- a/tests/ui/array-slice-vec/array-break-length-2.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - |_: [u8; break]| (); //~ ERROR [E0268] -} diff --git a/tests/ui/array-slice-vec/array-break-length-2.stderr b/tests/ui/array-slice-vec/array-break-length-2.stderr deleted file mode 100644 index bac1ade3b0c8..000000000000 --- a/tests/ui/array-slice-vec/array-break-length-2.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0268]: `break` outside of a loop or labeled block - --> $DIR/issue-50581.rs:2:14 - | -LL | |_: [u8; break]| (); - | ^^^^^ cannot `break` outside of a loop or labeled block - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/borrowck/borrow-immutable-deref-box.rs b/tests/ui/borrowck/borrow-immutable-deref-box.rs index a405f9b11352..6d4932b5b4b5 100644 --- a/tests/ui/borrowck/borrow-immutable-deref-box.rs +++ b/tests/ui/borrowck/borrow-immutable-deref-box.rs @@ -1,3 +1,4 @@ +//! regression test for issue fn f(x: &mut u32) {} fn main() { diff --git a/tests/ui/borrowck/borrow-immutable-deref-box.stderr b/tests/ui/borrowck/borrow-immutable-deref-box.stderr index 522fb36e1434..6456dc8a0e5a 100644 --- a/tests/ui/borrowck/borrow-immutable-deref-box.stderr +++ b/tests/ui/borrowck/borrow-immutable-deref-box.stderr @@ -1,5 +1,5 @@ error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable - --> $DIR/issue-36400.rs:5:7 + --> $DIR/borrow-immutable-deref-box.rs:6:7 | LL | f(&mut *x); | ^^^^^^^ cannot borrow as mutable diff --git a/tests/ui/box/box-lifetime-argument-not-allowed.rs b/tests/ui/box/box-lifetime-argument-not-allowed.rs index 675fd041154b..647fe0917d0a 100644 --- a/tests/ui/box/box-lifetime-argument-not-allowed.rs +++ b/tests/ui/box/box-lifetime-argument-not-allowed.rs @@ -1,8 +1,9 @@ -// Test that `Box` cannot be used with a lifetime argument. +//! Test that `Box` cannot be used with a lifetime argument. +//! regression test for issue struct Foo<'a> { - x: Box<'a, isize> + x: Box<'a, isize>, //~^ ERROR struct takes 0 lifetime arguments but 1 lifetime argument was supplied } -fn main() { } +fn main() {} diff --git a/tests/ui/box/box-lifetime-argument-not-allowed.stderr b/tests/ui/box/box-lifetime-argument-not-allowed.stderr index b5f19b5c9b23..a597a03023af 100644 --- a/tests/ui/box/box-lifetime-argument-not-allowed.stderr +++ b/tests/ui/box/box-lifetime-argument-not-allowed.stderr @@ -1,7 +1,7 @@ error[E0107]: struct takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/issue-18423.rs:4:8 + --> $DIR/box-lifetime-argument-not-allowed.rs:5:8 | -LL | x: Box<'a, isize> +LL | x: Box<'a, isize>, | ^^^ -- help: remove the lifetime argument | | | expected 0 lifetime arguments diff --git a/tests/ui/cast/cast-rfc0401-2.rs b/tests/ui/cast/cast-rfc0401-2.rs deleted file mode 100644 index 70604a587ea1..000000000000 --- a/tests/ui/cast/cast-rfc0401-2.rs +++ /dev/null @@ -1,8 +0,0 @@ -// RFC 401 test extracted into distinct file. This is because some the -// change to suppress "derived" errors wound up suppressing this error -// message, since the fallback for `3` doesn't occur. - -fn main() { - let _ = 3 as bool; - //~^ ERROR cannot cast `i32` as `bool` -} diff --git a/tests/ui/cast/cast-rfc0401-2.stderr b/tests/ui/cast/cast-rfc0401-2.stderr deleted file mode 100644 index f2956cdfa335..000000000000 --- a/tests/ui/cast/cast-rfc0401-2.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0054]: cannot cast `i32` as `bool` - --> $DIR/cast-rfc0401-2.rs:6:13 - | -LL | let _ = 3 as bool; - | ^^^^^^^^^ - | -help: compare with zero instead - | -LL - let _ = 3 as bool; -LL + let _ = 3 != 0; - | - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0054`. diff --git a/tests/ui/cast/cast-rfc0401-fail.rs b/tests/ui/cast/cast-rfc0401-fail.rs index b2ff5b4a0c06..fb04e3f5f9a0 100644 --- a/tests/ui/cast/cast-rfc0401-fail.rs +++ b/tests/ui/cast/cast-rfc0401-fail.rs @@ -1,29 +1,33 @@ -fn illegal_cast(u: *const U) -> *const V -{ +fn illegal_cast(u: *const U) -> *const V { u as *const V //~ ERROR is invalid } -fn illegal_cast_2(u: *const U) -> *const str -{ +fn illegal_cast_2(u: *const U) -> *const str { u as *const str //~ ERROR is invalid } -trait Foo { fn foo(&self) {} } +trait Foo { + fn foo(&self) {} +} impl Foo for T {} -trait Bar { fn foo(&self) {} } +trait Bar { + fn foo(&self) {} +} impl Bar for T {} enum E { - A, B + A, + B, } -fn main() -{ +struct Inches(i32); + +fn main() { let f: f32 = 1.2; let v = core::ptr::null::(); - let fat_v : *const [u8] = unsafe { &*core::ptr::null::<[u8; 1]>()}; - let fat_sv : *const [i8] = unsafe { &*core::ptr::null::<[i8; 1]>()}; + let fat_v: *const [u8] = unsafe { &*core::ptr::null::<[u8; 1]>() }; + let fat_sv: *const [i8] = unsafe { &*core::ptr::null::<[i8; 1]>() }; let foo: &dyn Foo = &f; let _ = v as &u8; //~ ERROR non-primitive cast @@ -39,6 +43,7 @@ fn main() let _ = 3_i32 as bool; //~ ERROR cannot cast let _ = E::A as bool; //~ ERROR cannot cast let _ = 0x61u32 as char; //~ ERROR can be cast as + let _ = Inches as f32; //~ ERROR is invalid let _ = false as f32; //~ ERROR is invalid let _ = E::A as f32; //~ ERROR is invalid @@ -58,7 +63,7 @@ fn main() let _ = &f as *const f64; //~ ERROR is invalid let _ = fat_sv as usize; //~ ERROR is invalid - let a : *const str = "hello"; + let a: *const str = "hello"; let _ = a as *const dyn Foo; //~ ERROR the size for values of type // check no error cascade diff --git a/tests/ui/cast/cast-rfc0401-fail.stderr b/tests/ui/cast/cast-rfc0401-fail.stderr index a188b7791fdc..c41e6e3612dd 100644 --- a/tests/ui/cast/cast-rfc0401-fail.stderr +++ b/tests/ui/cast/cast-rfc0401-fail.stderr @@ -1,5 +1,5 @@ error[E0606]: casting `*const U` as `*const V` is invalid - --> $DIR/cast-rfc0401.rs:3:5 + --> $DIR/cast-rfc0401-fail.rs:2:5 | LL | u as *const V | ^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | u as *const V = note: the pointers may have different metadata error[E0606]: casting `*const U` as `*const str` is invalid - --> $DIR/cast-rfc0401.rs:8:5 + --> $DIR/cast-rfc0401-fail.rs:6:5 | LL | u as *const str | ^^^^^^^^^^^^^^^ @@ -15,13 +15,13 @@ LL | u as *const str = note: the pointers may have different metadata error[E0609]: no field `f` on type `fn() {main}` - --> $DIR/cast-rfc0401.rs:65:18 + --> $DIR/cast-rfc0401-fail.rs:70:18 | LL | let _ = main.f as *const u32; | ^ unknown field error[E0605]: non-primitive cast: `*const u8` as `&u8` - --> $DIR/cast-rfc0401.rs:29:13 + --> $DIR/cast-rfc0401-fail.rs:33:13 | LL | let _ = v as &u8; | ^^^^^^^^ invalid cast @@ -33,43 +33,43 @@ LL + let _ = &*v; | error[E0605]: non-primitive cast: `*const u8` as `E` - --> $DIR/cast-rfc0401.rs:30:13 + --> $DIR/cast-rfc0401-fail.rs:34:13 | LL | let _ = v as E; | ^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `*const u8` as `fn()` - --> $DIR/cast-rfc0401.rs:31:13 + --> $DIR/cast-rfc0401-fail.rs:35:13 | LL | let _ = v as fn(); | ^^^^^^^^^ invalid cast error[E0605]: non-primitive cast: `*const u8` as `(u32,)` - --> $DIR/cast-rfc0401.rs:32:13 + --> $DIR/cast-rfc0401-fail.rs:36:13 | LL | let _ = v as (u32,); | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0605]: non-primitive cast: `Option<&*const u8>` as `*const u8` - --> $DIR/cast-rfc0401.rs:33:13 + --> $DIR/cast-rfc0401-fail.rs:37:13 | LL | let _ = Some(&v) as *const u8; | ^^^^^^^^^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object error[E0606]: casting `*const u8` as `f32` is invalid - --> $DIR/cast-rfc0401.rs:35:13 + --> $DIR/cast-rfc0401-fail.rs:39:13 | LL | let _ = v as f32; | ^^^^^^^^ error[E0606]: casting `fn() {main}` as `f64` is invalid - --> $DIR/cast-rfc0401.rs:36:13 + --> $DIR/cast-rfc0401-fail.rs:40:13 | LL | let _ = main as f64; | ^^^^^^^^^^^ error[E0606]: casting `&*const u8` as `usize` is invalid - --> $DIR/cast-rfc0401.rs:37:13 + --> $DIR/cast-rfc0401-fail.rs:41:13 | LL | let _ = &v as usize; | ^^^^^^^^^^^ @@ -77,13 +77,13 @@ LL | let _ = &v as usize; = help: cast through a raw pointer first error[E0606]: casting `f32` as `*const u8` is invalid - --> $DIR/cast-rfc0401.rs:38:13 + --> $DIR/cast-rfc0401-fail.rs:42:13 | LL | let _ = f as *const u8; | ^^^^^^^^^^^^^^ error[E0054]: cannot cast `i32` as `bool` - --> $DIR/cast-rfc0401.rs:39:13 + --> $DIR/cast-rfc0401-fail.rs:43:13 | LL | let _ = 3_i32 as bool; | ^^^^^^^^^^^^^ @@ -95,13 +95,13 @@ LL + let _ = 3_i32 != 0; | error[E0054]: cannot cast `E` as `bool` - --> $DIR/cast-rfc0401.rs:40:13 + --> $DIR/cast-rfc0401-fail.rs:44:13 | LL | let _ = E::A as bool; | ^^^^^^^^^^^^ unsupported cast error[E0604]: only `u8` can be cast as `char`, not `u32` - --> $DIR/cast-rfc0401.rs:41:13 + --> $DIR/cast-rfc0401-fail.rs:45:13 | LL | let _ = 0x61u32 as char; | ^^^^^^^^^^^^^^^ invalid cast @@ -112,8 +112,14 @@ LL - let _ = 0x61u32 as char; LL + let _ = char::from_u32(0x61u32); | +error[E0606]: casting `fn(i32) -> Inches {Inches}` as `f32` is invalid + --> $DIR/cast-rfc0401-fail.rs:46:13 + | +LL | let _ = Inches as f32; + | ^^^^^^^^^^^^^ + error[E0606]: casting `bool` as `f32` is invalid - --> $DIR/cast-rfc0401.rs:43:13 + --> $DIR/cast-rfc0401-fail.rs:48:13 | LL | let _ = false as f32; | ^^^^^^^^^^^^ @@ -121,7 +127,7 @@ LL | let _ = false as f32; = help: cast through an integer first error[E0606]: casting `E` as `f32` is invalid - --> $DIR/cast-rfc0401.rs:44:13 + --> $DIR/cast-rfc0401-fail.rs:49:13 | LL | let _ = E::A as f32; | ^^^^^^^^^^^ @@ -129,7 +135,7 @@ LL | let _ = E::A as f32; = help: cast through an integer first error[E0606]: casting `char` as `f32` is invalid - --> $DIR/cast-rfc0401.rs:45:13 + --> $DIR/cast-rfc0401-fail.rs:50:13 | LL | let _ = 'a' as f32; | ^^^^^^^^^^ @@ -137,25 +143,25 @@ LL | let _ = 'a' as f32; = help: cast through an integer first error[E0606]: casting `bool` as `*const u8` is invalid - --> $DIR/cast-rfc0401.rs:47:13 + --> $DIR/cast-rfc0401-fail.rs:52:13 | LL | let _ = false as *const u8; | ^^^^^^^^^^^^^^^^^^ error[E0606]: casting `E` as `*const u8` is invalid - --> $DIR/cast-rfc0401.rs:48:13 + --> $DIR/cast-rfc0401-fail.rs:53:13 | LL | let _ = E::A as *const u8; | ^^^^^^^^^^^^^^^^^ error[E0606]: casting `char` as `*const u8` is invalid - --> $DIR/cast-rfc0401.rs:49:13 + --> $DIR/cast-rfc0401-fail.rs:54:13 | LL | let _ = 'a' as *const u8; | ^^^^^^^^^^^^^^^^ error[E0606]: cannot cast `usize` to a pointer that is wide - --> $DIR/cast-rfc0401.rs:51:24 + --> $DIR/cast-rfc0401-fail.rs:56:24 | LL | let _ = 42usize as *const [u8]; | ------- ^^^^^^^^^^^ creating a `*const [u8]` requires both an address and a length @@ -163,43 +169,43 @@ LL | let _ = 42usize as *const [u8]; | consider casting this expression to `*const ()`, then using `core::ptr::from_raw_parts` error[E0607]: cannot cast thin pointer `*const u8` to wide pointer `*const [u8]` - --> $DIR/cast-rfc0401.rs:52:13 + --> $DIR/cast-rfc0401-fail.rs:57:13 | LL | let _ = v as *const [u8]; | ^^^^^^^^^^^^^^^^ error[E0606]: casting `&dyn Foo` as `*const str` is invalid - --> $DIR/cast-rfc0401.rs:54:13 + --> $DIR/cast-rfc0401-fail.rs:59:13 | LL | let _ = foo as *const str; | ^^^^^^^^^^^^^^^^^ error[E0606]: casting `&dyn Foo` as `*mut str` is invalid - --> $DIR/cast-rfc0401.rs:55:13 + --> $DIR/cast-rfc0401-fail.rs:60:13 | LL | let _ = foo as *mut str; | ^^^^^^^^^^^^^^^ error[E0606]: casting `fn() {main}` as `*mut str` is invalid - --> $DIR/cast-rfc0401.rs:56:13 + --> $DIR/cast-rfc0401-fail.rs:61:13 | LL | let _ = main as *mut str; | ^^^^^^^^^^^^^^^^ error[E0606]: casting `&f32` as `*mut f32` is invalid - --> $DIR/cast-rfc0401.rs:57:13 + --> $DIR/cast-rfc0401-fail.rs:62:13 | LL | let _ = &f as *mut f32; | ^^^^^^^^^^^^^^ error[E0606]: casting `&f32` as `*const f64` is invalid - --> $DIR/cast-rfc0401.rs:58:13 + --> $DIR/cast-rfc0401-fail.rs:63:13 | LL | let _ = &f as *const f64; | ^^^^^^^^^^^^^^^^ error[E0606]: casting `*const [i8]` as `usize` is invalid - --> $DIR/cast-rfc0401.rs:59:13 + --> $DIR/cast-rfc0401-fail.rs:64:13 | LL | let _ = fat_sv as usize; | ^^^^^^^^^^^^^^^ @@ -207,7 +213,7 @@ LL | let _ = fat_sv as usize; = help: cast through a thin pointer first error[E0606]: casting `*const dyn Foo` as `*const [u16]` is invalid - --> $DIR/cast-rfc0401.rs:68:13 + --> $DIR/cast-rfc0401-fail.rs:73:13 | LL | let _ = cf as *const [u16]; | ^^^^^^^^^^^^^^^^^^ @@ -215,7 +221,7 @@ LL | let _ = cf as *const [u16]; = note: the pointers have different metadata error[E0606]: casting `*const dyn Foo` as `*const dyn Bar` is invalid - --> $DIR/cast-rfc0401.rs:69:13 + --> $DIR/cast-rfc0401-fail.rs:74:13 | LL | let _ = cf as *const dyn Bar; | ^^^^^^^^^^^^^^^^^^^^ @@ -223,7 +229,7 @@ LL | let _ = cf as *const dyn Bar; = note: the trait objects may have different vtables error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/cast-rfc0401.rs:53:13 + --> $DIR/cast-rfc0401-fail.rs:58:13 | LL | let _ = fat_v as *const dyn Foo; | ^^^^^ doesn't have a size known at compile-time @@ -232,7 +238,7 @@ LL | let _ = fat_v as *const dyn Foo; = note: required for the cast from `*const [u8]` to `*const dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time - --> $DIR/cast-rfc0401.rs:62:13 + --> $DIR/cast-rfc0401-fail.rs:67:13 | LL | let _ = a as *const dyn Foo; | ^ doesn't have a size known at compile-time @@ -241,7 +247,7 @@ LL | let _ = a as *const dyn Foo; = note: required for the cast from `*const str` to `*const dyn Foo` error[E0606]: casting `&{float}` as `f32` is invalid - --> $DIR/cast-rfc0401.rs:71:30 + --> $DIR/cast-rfc0401-fail.rs:76:30 | LL | vec![0.0].iter().map(|s| s as f32).collect::>(); | ^^^^^^^^ @@ -251,7 +257,7 @@ help: dereference the expression LL | vec![0.0].iter().map(|s| *s as f32).collect::>(); | + -error: aborting due to 34 previous errors +error: aborting due to 35 previous errors Some errors have detailed explanations: E0054, E0277, E0604, E0605, E0606, E0607, E0609. For more information about an error, try `rustc --explain E0054`. diff --git a/tests/ui/cast/cast-to-dyn-any.rs b/tests/ui/cast/cast-to-dyn-any.rs index e1b3dfe5b61b..3180c530209e 100644 --- a/tests/ui/cast/cast-to-dyn-any.rs +++ b/tests/ui/cast/cast-to-dyn-any.rs @@ -1,3 +1,4 @@ +//! regression test for issue fn main() { 0 as &dyn std::any::Any; //~ ERROR non-primitive cast } diff --git a/tests/ui/cast/cast-to-dyn-any.stderr b/tests/ui/cast/cast-to-dyn-any.stderr index 560fbc73bbdc..6ee1098fcf40 100644 --- a/tests/ui/cast/cast-to-dyn-any.stderr +++ b/tests/ui/cast/cast-to-dyn-any.stderr @@ -1,5 +1,5 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn Any + 'static)` - --> $DIR/issue-22289.rs:2:5 + --> $DIR/cast-to-dyn-any.rs:3:5 | LL | 0 as &dyn std::any::Any; | ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast diff --git a/tests/ui/closures/closure-array-break-length-2.rs b/tests/ui/closures/closure-array-break-length-2.rs deleted file mode 100644 index 60589f7c264a..000000000000 --- a/tests/ui/closures/closure-array-break-length-2.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - loop { - |_: [_; break]| {} //~ ERROR: `break` outside of a loop - } - - loop { - |_: [_; continue]| {} //~ ERROR: `continue` outside of a loop - } -} diff --git a/tests/ui/closures/closure-array-break-length-2.stderr b/tests/ui/closures/closure-array-break-length-2.stderr deleted file mode 100644 index 2df7b6d7f63c..000000000000 --- a/tests/ui/closures/closure-array-break-length-2.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0268]: `break` outside of a loop or labeled block - --> $DIR/array-break-length.rs:3:17 - | -LL | |_: [_; break]| {} - | ^^^^^ cannot `break` outside of a loop or labeled block - -error[E0268]: `continue` outside of a loop - --> $DIR/array-break-length.rs:7:17 - | -LL | |_: [_; continue]| {} - | ^^^^^^^^ cannot `continue` outside of a loop - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/closures/closure-array-break-length.rs b/tests/ui/closures/closure-array-break-length.rs index fda590fda022..c90ae6585dca 100644 --- a/tests/ui/closures/closure-array-break-length.rs +++ b/tests/ui/closures/closure-array-break-length.rs @@ -1,7 +1,18 @@ +//! regression test for issue fn main() { |_: [_; continue]| {}; //~ ERROR: `continue` outside of a loop + |_: [_; break]| (); //~ ERROR: `break` outside of a loop or labeled block + while |_: [_; continue]| {} {} //~ ERROR: `continue` outside of a loop while |_: [_; break]| {} {} //~ ERROR: `break` outside of a loop + + loop { + |_: [_; break]| {} //~ ERROR: `break` outside of a loop + } + + loop { + |_: [_; continue]| {} //~ ERROR: `continue` outside of a loop + } } diff --git a/tests/ui/closures/closure-array-break-length.stderr b/tests/ui/closures/closure-array-break-length.stderr index 7e0b0027a6f0..3256c50bb906 100644 --- a/tests/ui/closures/closure-array-break-length.stderr +++ b/tests/ui/closures/closure-array-break-length.stderr @@ -1,21 +1,39 @@ error[E0268]: `continue` outside of a loop - --> $DIR/closure-array-break-length.rs:2:13 + --> $DIR/closure-array-break-length.rs:3:13 | LL | |_: [_; continue]| {}; | ^^^^^^^^ cannot `continue` outside of a loop +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/closure-array-break-length.rs:5:13 + | +LL | |_: [_; break]| (); + | ^^^^^ cannot `break` outside of a loop or labeled block + error[E0268]: `continue` outside of a loop - --> $DIR/closure-array-break-length.rs:4:19 + --> $DIR/closure-array-break-length.rs:7:19 | LL | while |_: [_; continue]| {} {} | ^^^^^^^^ cannot `continue` outside of a loop error[E0268]: `break` outside of a loop or labeled block - --> $DIR/closure-array-break-length.rs:6:19 + --> $DIR/closure-array-break-length.rs:9:19 | LL | while |_: [_; break]| {} {} | ^^^^^ cannot `break` outside of a loop or labeled block -error: aborting due to 3 previous errors +error[E0268]: `break` outside of a loop or labeled block + --> $DIR/closure-array-break-length.rs:12:17 + | +LL | |_: [_; break]| {} + | ^^^^^ cannot `break` outside of a loop or labeled block + +error[E0268]: `continue` outside of a loop + --> $DIR/closure-array-break-length.rs:16:17 + | +LL | |_: [_; continue]| {} + | ^^^^^^^^ cannot `continue` outside of a loop + +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0268`. diff --git a/tests/ui/closures/closure-move-use-after-move-diagnostic.rs b/tests/ui/closures/closure-move-use-after-move-diagnostic.rs index 63c061594d87..3326af7486c5 100644 --- a/tests/ui/closures/closure-move-use-after-move-diagnostic.rs +++ b/tests/ui/closures/closure-move-use-after-move-diagnostic.rs @@ -1,13 +1,16 @@ +//! regression test for struct NoCopy; //~ NOTE if `NoCopy` implemented `Clone`, you could clone the value //~^ NOTE consider implementing `Clone` for this type fn main() { - let x = NoCopy; - //~^ NOTE move occurs because `x` has type `NoCopy` - let f = move || { let y = x; }; - //~^ NOTE value moved into closure here - //~| NOTE variable moved due to use in closure - //~| NOTE you could clone this value - let z = x; - //~^ ERROR use of moved value: `x` - //~| NOTE value used here after move + let x = NoCopy; + //~^ NOTE move occurs because `x` has type `NoCopy` + let f = move || { + //~^ NOTE value moved into closure here + let y = x; + //~^ NOTE variable moved due to use in closure + //~| NOTE you could clone this value + }; + let z = x; + //~^ ERROR use of moved value: `x` + //~| NOTE value used here after move } diff --git a/tests/ui/closures/closure-move-use-after-move-diagnostic.stderr b/tests/ui/closures/closure-move-use-after-move-diagnostic.stderr index 2d85077fe4c2..94f80da1b10a 100644 --- a/tests/ui/closures/closure-move-use-after-move-diagnostic.stderr +++ b/tests/ui/closures/closure-move-use-after-move-diagnostic.stderr @@ -1,25 +1,26 @@ error[E0382]: use of moved value: `x` - --> $DIR/issue-24357.rs:10:12 + --> $DIR/closure-move-use-after-move-diagnostic.rs:13:13 | -LL | let x = NoCopy; - | - move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait +LL | let x = NoCopy; + | - move occurs because `x` has type `NoCopy`, which does not implement the `Copy` trait LL | -LL | let f = move || { let y = x; }; - | ------- - variable moved due to use in closure - | | - | value moved into closure here +LL | let f = move || { + | ------- value moved into closure here +LL | +LL | let y = x; + | - variable moved due to use in closure ... -LL | let z = x; - | ^ value used here after move +LL | let z = x; + | ^ value used here after move | note: if `NoCopy` implemented `Clone`, you could clone the value - --> $DIR/issue-24357.rs:1:1 + --> $DIR/closure-move-use-after-move-diagnostic.rs:2:1 | LL | struct NoCopy; | ^^^^^^^^^^^^^ consider implementing `Clone` for this type ... -LL | let f = move || { let y = x; }; - | - you could clone this value +LL | let y = x; + | - you could clone this value error: aborting due to 1 previous error diff --git a/tests/ui/consts/const-return-outside-fn.rs b/tests/ui/consts/const-return-outside-fn.rs index 665a8fdf8e26..c2ee8642bf4b 100644 --- a/tests/ui/consts/const-return-outside-fn.rs +++ b/tests/ui/consts/const-return-outside-fn.rs @@ -1,3 +1,4 @@ +//! regression test for issue const x: () = { return; //~ ERROR return statement outside of function body }; diff --git a/tests/ui/consts/const-return-outside-fn.stderr b/tests/ui/consts/const-return-outside-fn.stderr index fbf88d503397..131d577a2547 100644 --- a/tests/ui/consts/const-return-outside-fn.stderr +++ b/tests/ui/consts/const-return-outside-fn.stderr @@ -1,5 +1,5 @@ error[E0572]: return statement outside of function body - --> $DIR/issue-38458.rs:2:5 + --> $DIR/const-return-outside-fn.rs:3:5 | LL | return; | ^^^^^^ diff --git a/tests/ui/drop/drop-conflicting-impls.rs b/tests/ui/drop/drop-conflicting-impls.rs index ce511158f005..fba3462a24b2 100644 --- a/tests/ui/drop/drop-conflicting-impls.rs +++ b/tests/ui/drop/drop-conflicting-impls.rs @@ -1,12 +1,13 @@ +//! regression test for issue struct MyStruct; impl Drop for MyStruct { - fn drop(&mut self) { } + fn drop(&mut self) {} } impl Drop for MyStruct { -//~^ ERROR conflicting implementations of trait - fn drop(&mut self) { } + //~^ ERROR conflicting implementations of trait + fn drop(&mut self) {} } fn main() {} diff --git a/tests/ui/drop/drop-conflicting-impls.stderr b/tests/ui/drop/drop-conflicting-impls.stderr index c8db0403e59a..ee310f498d37 100644 --- a/tests/ui/drop/drop-conflicting-impls.stderr +++ b/tests/ui/drop/drop-conflicting-impls.stderr @@ -1,5 +1,5 @@ error[E0119]: conflicting implementations of trait `Drop` for type `MyStruct` - --> $DIR/issue-28568.rs:7:1 + --> $DIR/drop-conflicting-impls.rs:8:1 | LL | impl Drop for MyStruct { | ---------------------- first implementation here diff --git a/tests/ui/enum/enum-discriminant-missing-variant.rs b/tests/ui/enum/enum-discriminant-missing-variant.rs index 09f9ebccf250..1bdbfb1fbcd4 100644 --- a/tests/ui/enum/enum-discriminant-missing-variant.rs +++ b/tests/ui/enum/enum-discriminant-missing-variant.rs @@ -1,3 +1,4 @@ +//! regression test for issue pub enum SomeEnum { B = SomeEnum::A, //~ ERROR no variant or associated item named `A` found } diff --git a/tests/ui/enum/enum-discriminant-missing-variant.stderr b/tests/ui/enum/enum-discriminant-missing-variant.stderr index 830d260f99d7..ef98a93e86f6 100644 --- a/tests/ui/enum/enum-discriminant-missing-variant.stderr +++ b/tests/ui/enum/enum-discriminant-missing-variant.stderr @@ -1,5 +1,5 @@ error[E0599]: no variant or associated item named `A` found for enum `SomeEnum` in the current scope - --> $DIR/issue-23217.rs:2:19 + --> $DIR/enum-discriminant-missing-variant.rs:3:19 | LL | pub enum SomeEnum { | ----------------- variant or associated item `A` not found for this enum diff --git a/tests/ui/mismatched_types/cast-rfc0401-2.rs b/tests/ui/mismatched_types/cast-rfc0401-2.rs deleted file mode 100644 index c176b1247cea..000000000000 --- a/tests/ui/mismatched_types/cast-rfc0401-2.rs +++ /dev/null @@ -1,6 +0,0 @@ -struct Inches(i32); - -fn main() { - Inches as f32; - //~^ ERROR casting -} diff --git a/tests/ui/mismatched_types/cast-rfc0401-2.stderr b/tests/ui/mismatched_types/cast-rfc0401-2.stderr deleted file mode 100644 index b1b59af6ec2b..000000000000 --- a/tests/ui/mismatched_types/cast-rfc0401-2.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0606]: casting `fn(i32) -> Inches {Inches}` as `f32` is invalid - --> $DIR/issue-21554.rs:4:5 - | -LL | Inches as f32; - | ^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0606`. diff --git a/tests/ui/nll/borrowck-annotate-static-lifetime.rs b/tests/ui/nll/borrowck-annotate-static-lifetime.rs index 2f78ce0002ba..9d849db9b4f3 100644 --- a/tests/ui/nll/borrowck-annotate-static-lifetime.rs +++ b/tests/ui/nll/borrowck-annotate-static-lifetime.rs @@ -1,3 +1,4 @@ +//! regression test for issue fn main() { let _vec: Vec<&'static String> = vec![&String::new()]; //~^ ERROR temporary value dropped while borrowed [E0716] diff --git a/tests/ui/nll/borrowck-annotate-static-lifetime.stderr b/tests/ui/nll/borrowck-annotate-static-lifetime.stderr index d25c6eda9c34..9cb9007d9131 100644 --- a/tests/ui/nll/borrowck-annotate-static-lifetime.stderr +++ b/tests/ui/nll/borrowck-annotate-static-lifetime.stderr @@ -1,5 +1,5 @@ error[E0716]: temporary value dropped while borrowed - --> $DIR/issue-47184.rs:2:44 + --> $DIR/borrowck-annotate-static-lifetime.rs:3:44 | LL | let _vec: Vec<&'static String> = vec![&String::new()]; | -------------------- ^^^^^^^^^^^^^ - temporary value is freed at the end of this statement diff --git a/tests/ui/nll/nll-anon-to-static.rs b/tests/ui/nll/nll-anon-to-static.rs index 4bd49a8796b3..3dc79950056c 100644 --- a/tests/ui/nll/nll-anon-to-static.rs +++ b/tests/ui/nll/nll-anon-to-static.rs @@ -1,3 +1,4 @@ +//! regression test for issue fn foo(x: &u32) -> &'static u32 { &*x //~^ ERROR lifetime may not live long enough diff --git a/tests/ui/nll/nll-anon-to-static.stderr b/tests/ui/nll/nll-anon-to-static.stderr index f47df306ab84..e431dfd992e1 100644 --- a/tests/ui/nll/nll-anon-to-static.stderr +++ b/tests/ui/nll/nll-anon-to-static.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/issue-46983.rs:2:5 + --> $DIR/nll-anon-to-static.rs:3:5 | LL | fn foo(x: &u32) -> &'static u32 { | - let's call the lifetime of this reference `'1` diff --git a/tests/ui/parser/missing-operator-after-float.rs b/tests/ui/parser/missing-operator-after-float.rs index 15649f777e09..8868689ff81f 100644 --- a/tests/ui/parser/missing-operator-after-float.rs +++ b/tests/ui/parser/missing-operator-after-float.rs @@ -1,3 +1,4 @@ +//! regression test for issue fn main() { let a = |r: f64| if r != 0.0(r != 0.0) { 1.0 } else { 0.0 }; //~^ ERROR expected function, found `{float}` diff --git a/tests/ui/parser/missing-operator-after-float.stderr b/tests/ui/parser/missing-operator-after-float.stderr index 95a39b1d1980..08878cf098a7 100644 --- a/tests/ui/parser/missing-operator-after-float.stderr +++ b/tests/ui/parser/missing-operator-after-float.stderr @@ -1,5 +1,5 @@ error[E0618]: expected function, found `{float}` - --> $DIR/issue-45965.rs:2:30 + --> $DIR/missing-operator-after-float.rs:3:30 | LL | let a = |r: f64| if r != 0.0(r != 0.0) { 1.0 } else { 0.0 }; | ^^^---------- diff --git a/tests/ui/parser/unbalanced-doublequote-2.rs b/tests/ui/parser/unbalanced-doublequote-2.rs index b8c0e285ffca..1906f96f6c9b 100644 --- a/tests/ui/parser/unbalanced-doublequote-2.rs +++ b/tests/ui/parser/unbalanced-doublequote-2.rs @@ -1,3 +1,4 @@ +//! regression test for issue fn main() { "😊""; //~ ERROR unterminated double quote } diff --git a/tests/ui/parser/unbalanced-doublequote-2.stderr b/tests/ui/parser/unbalanced-doublequote-2.stderr index 3e12de34e11e..3a6efaf7d4ec 100644 --- a/tests/ui/parser/unbalanced-doublequote-2.stderr +++ b/tests/ui/parser/unbalanced-doublequote-2.stderr @@ -1,5 +1,5 @@ error[E0765]: unterminated double quote string - --> $DIR/issue-44078.rs:2:8 + --> $DIR/unbalanced-doublequote-2.rs:3:8 | LL | "😊""; | _________^ diff --git a/tests/ui/resolve/missing-associated-items.rs b/tests/ui/resolve/missing-associated-items.rs index 92f4c546440a..72d6cbb3f149 100644 --- a/tests/ui/resolve/missing-associated-items.rs +++ b/tests/ui/resolve/missing-associated-items.rs @@ -1,9 +1,17 @@ -enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ } +//! regression test for issue +enum Token { + LeftParen, + RightParen, + Plus, + Minus, /* etc */ +} struct Struct { a: usize, } -fn use_token(token: &Token) { unimplemented!() } +fn use_token(token: &Token) { + unimplemented!() +} fn main() { use_token(&Token::Homura); //~ ERROR no variant or associated item named `Homura` diff --git a/tests/ui/resolve/missing-associated-items.stderr b/tests/ui/resolve/missing-associated-items.stderr index d07d1a7caaf2..d27a3a644aee 100644 --- a/tests/ui/resolve/missing-associated-items.stderr +++ b/tests/ui/resolve/missing-associated-items.stderr @@ -1,14 +1,14 @@ error[E0599]: no variant or associated item named `Homura` found for enum `Token` in the current scope - --> $DIR/issue-23173.rs:9:23 + --> $DIR/missing-associated-items.rs:17:23 | -LL | enum Token { LeftParen, RightParen, Plus, Minus, /* etc */ } +LL | enum Token { | ---------- variant or associated item `Homura` not found for this enum ... LL | use_token(&Token::Homura); | ^^^^^^ variant or associated item not found in `Token` error[E0599]: no function or associated item named `method` found for struct `Struct` in the current scope - --> $DIR/issue-23173.rs:10:13 + --> $DIR/missing-associated-items.rs:18:13 | LL | struct Struct { | ------------- function or associated item `method` not found for this struct @@ -17,7 +17,7 @@ LL | Struct::method(); | ^^^^^^ function or associated item not found in `Struct` error[E0599]: no function or associated item named `method` found for struct `Struct` in the current scope - --> $DIR/issue-23173.rs:11:13 + --> $DIR/missing-associated-items.rs:19:13 | LL | struct Struct { | ------------- function or associated item `method` not found for this struct @@ -26,7 +26,7 @@ LL | Struct::method; | ^^^^^^ function or associated item not found in `Struct` error[E0599]: no associated item named `Assoc` found for struct `Struct` in the current scope - --> $DIR/issue-23173.rs:12:13 + --> $DIR/missing-associated-items.rs:20:13 | LL | struct Struct { | ------------- associated item `Assoc` not found for this struct diff --git a/tests/ui/typeck/for-in-const-eval.rs b/tests/ui/typeck/for-in-const-eval.rs index 1358e0bde4c8..f187a9ef3077 100644 --- a/tests/ui/typeck/for-in-const-eval.rs +++ b/tests/ui/typeck/for-in-const-eval.rs @@ -1,3 +1,4 @@ +//! regression test for issue fn main() { Vec::<[(); 1 + for x in 0..1 {}]>::new(); //~^ ERROR cannot add diff --git a/tests/ui/typeck/for-in-const-eval.stderr b/tests/ui/typeck/for-in-const-eval.stderr index 168f5894fb03..e7a255849581 100644 --- a/tests/ui/typeck/for-in-const-eval.stderr +++ b/tests/ui/typeck/for-in-const-eval.stderr @@ -1,5 +1,5 @@ error[E0277]: cannot add `()` to `{integer}` - --> $DIR/issue-50582.rs:2:18 + --> $DIR/for-in-const-eval.rs:3:18 | LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); | ^ no implementation for `{integer} + ()` From ac448c987d2ed4b8ef50bb2f5422c093c1e161a5 Mon Sep 17 00:00:00 2001 From: delta17920 Date: Tue, 9 Dec 2025 09:36:58 +0000 Subject: [PATCH 103/126] Fix ICE in normalization during closure capture analysis --- compiler/rustc_middle/src/ty/util.rs | 6 +- .../normalization-ice-issue-149746.rs | 17 ++++ .../normalization-ice-issue-149746.stderr | 80 +++++++++++++++++++ 3 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 tests/ui/associated-types/normalization-ice-issue-149746.rs create mode 100644 tests/ui/associated-types/normalization-ice-issue-149746.stderr diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index fc03ad52b4bf..2797f2fcdb72 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1394,8 +1394,10 @@ pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<' // This doesn't depend on regions, so try to minimize distinct // query keys used. - let erased = tcx.normalize_erasing_regions(typing_env, query_ty); - tcx.has_significant_drop_raw(typing_env.as_query_input(erased)) + // FIX: Use try_normalize to avoid crashing. If it fails, return true. + tcx.try_normalize_erasing_regions(typing_env, query_ty) + .map(|erased| tcx.has_significant_drop_raw(typing_env.as_query_input(erased))) + .unwrap_or(true) } } } diff --git a/tests/ui/associated-types/normalization-ice-issue-149746.rs b/tests/ui/associated-types/normalization-ice-issue-149746.rs new file mode 100644 index 000000000000..8932d321b7e5 --- /dev/null +++ b/tests/ui/associated-types/normalization-ice-issue-149746.rs @@ -0,0 +1,17 @@ +//@ edition: 2015..2021 +#![warn(rust_2021_incompatible_closure_captures)] +trait Owner { type Ty; } +impl Owner for () { type Ty = T; } +pub struct Warns { + _significant_drop: <() as Owner>::Ty, + //~^ ERROR expected a `FnMut()` closure, found `T` + field: String, +} +pub fn test(w: Warns) { + //~^ ERROR expected a `FnMut()` closure, found `T` + _ = || w.field + //~^ ERROR expected a `FnMut()` closure, found `T` + //~| ERROR expected a `FnMut()` closure, found `T` + //~| WARN: changes to closure capture in Rust 2021 will affect drop order +} +fn main() {} diff --git a/tests/ui/associated-types/normalization-ice-issue-149746.stderr b/tests/ui/associated-types/normalization-ice-issue-149746.stderr new file mode 100644 index 000000000000..7f983d6e14ae --- /dev/null +++ b/tests/ui/associated-types/normalization-ice-issue-149746.stderr @@ -0,0 +1,80 @@ +error[E0277]: expected a `FnMut()` closure, found `T` + --> $DIR/normalization-ice-issue-149746.rs:6:24 + | +LL | _significant_drop: <() as Owner>::Ty, + | ^^^^^^^^^^^^^^^^^^^^ expected an `FnMut()` closure, found `T` + | + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `Owner::Ty` + --> $DIR/normalization-ice-issue-149746.rs:3:26 + | +LL | trait Owner { type Ty; } + | ^^^^^^^ required by this bound in `Owner::Ty` +help: consider restricting type parameter `T` with trait `FnMut` + | +LL | pub struct Warns { + | +++++++++ + +warning: changes to closure capture in Rust 2021 will affect drop order + --> $DIR/normalization-ice-issue-149746.rs:12:9 + | +LL | _ = || w.field + | ^^ ------- + | | | + | | in Rust 2018, `w` is dropped here, but in Rust 2021, only `w.field` will be dropped here as part of the closure + | in Rust 2018, this closure captures all of `w`, but in Rust 2021, it will only capture `w.field` + | + = note: for more information, see +note: the lint level is defined here + --> $DIR/normalization-ice-issue-149746.rs:2:9 + | +LL | #![warn(rust_2021_incompatible_closure_captures)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: add a dummy let to cause `w` to be fully captured + | +LL | _ = || { let _ = &w; w.field } + | +++++++++++++ + + +error[E0277]: expected a `FnMut()` closure, found `T` + --> $DIR/normalization-ice-issue-149746.rs:12:9 + | +LL | _ = || w.field + | ^^^^^^^^^^ expected an `FnMut()` closure, found `T` + | + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `Owner::Ty` + --> $DIR/normalization-ice-issue-149746.rs:3:26 + | +LL | trait Owner { type Ty; } + | ^^^^^^^ required by this bound in `Owner::Ty` + +error[E0277]: expected a `FnMut()` closure, found `T` + --> $DIR/normalization-ice-issue-149746.rs:10:16 + | +LL | pub fn test(w: Warns) { + | ^ expected an `FnMut()` closure, found `T` + | + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `Owner::Ty` + --> $DIR/normalization-ice-issue-149746.rs:3:26 + | +LL | trait Owner { type Ty; } + | ^^^^^^^ required by this bound in `Owner::Ty` + +error[E0277]: expected a `FnMut()` closure, found `T` + --> $DIR/normalization-ice-issue-149746.rs:12:9 + | +LL | _ = || w.field + | ^^^^^^^^^^ expected an `FnMut()` closure, found `T` + | + = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` +note: required by a bound in `Owner::Ty` + --> $DIR/normalization-ice-issue-149746.rs:3:26 + | +LL | trait Owner { type Ty; } + | ^^^^^^^ required by this bound in `Owner::Ty` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. From 75f53dd70e23b09e2557ca7c73bcaa22b9d1a8ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 23 Dec 2025 14:16:25 +0100 Subject: [PATCH 104/126] Update bors configuration --- rust-bors.toml | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/rust-bors.toml b/rust-bors.toml index e813c6c4b116..996b50b2ea27 100644 --- a/rust-bors.toml +++ b/rust-bors.toml @@ -25,3 +25,42 @@ labels_blocking_approval = [ "S-waiting-on-t-rustdoc-frontend", "S-waiting-on-t-clippy" ] + +# If CI runs quicker than this duration, consider it to be a failure +min_ci_time = 600 + +[labels] +approved = [ + "+S-waiting-on-bors", + "-S-blocked", + "-S-waiting-on-author", + "-S-waiting-on-crater", + "-S-waiting-on-review", + "-S-waiting-on-team" +] +unapproved = [ + "+S-waiting-on-author", + "-S-blocked", + "-S-waiting-on-bors", + "-S-waiting-on-crater", + "-S-waiting-on-review", + "-S-waiting-on-team" +] +try_failed = [ + "+S-waiting-on-author", + "-S-waiting-on-review", + "-S-waiting-on-crater" +] +auto_build_succeeded = ["+merged-by-bors"] +auto_build_failed = [ + "+S-waiting-on-review", + "-S-blocked", + "-S-waiting-on-bors", + "-S-waiting-on-author", + "-S-waiting-on-crater", + "-S-waiting-on-team" +] + +# Flip this two once new bors is used for actual merges on this repository +merge_queue_enabled = false +report_merge_conflicts = true From dfef2e96fe0216e243f458b8fe04a8b82a07065a Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 9 Dec 2025 07:50:30 -0800 Subject: [PATCH 105/126] Remove the need to call clang for std::offload usages --- compiler/rustc_codegen_llvm/src/back/write.rs | 74 ++++++++++++++++++- compiler/rustc_codegen_llvm/src/base.rs | 6 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 8 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 22 +++++- compiler/rustc_interface/src/tests.rs | 2 +- .../rustc_llvm/llvm-wrapper/RustWrapper.cpp | 32 ++++++-- compiler/rustc_session/src/config.rs | 12 +-- compiler/rustc_session/src/options.rs | 23 +++++- 8 files changed, 149 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index e8da7f68136d..a649ee4bff1c 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -703,10 +703,9 @@ fn handle_offload<'ll>(cx: &'ll SimpleCx<'_>, old_fn: &llvm::Value) { llvm::set_value_name(new_fn, &name); } - if cgcx.target_is_like_gpu && config.offload.contains(&config::Offload::Enable) { + if cgcx.target_is_like_gpu && config.offload.contains(&config::Offload::Device) { let cx = SimpleCx::new(module.module_llvm.llmod(), module.module_llvm.llcx, cgcx.pointer_size); - for func in cx.get_functions() { let offload_kernel = "offload-kernel"; if attributes::has_string_attr(func, offload_kernel) { @@ -775,12 +774,79 @@ fn handle_offload<'ll>(cx: &'ll SimpleCx<'_>, old_fn: &llvm::Value) { ) }; - if cgcx.target_is_like_gpu && config.offload.contains(&config::Offload::Enable) { + if cgcx.target_is_like_gpu && config.offload.contains(&config::Offload::Device) { + let device_path = cgcx.output_filenames.path(OutputType::Object); + let device_dir = device_path.parent().unwrap(); + let device_out = device_dir.join("host.out"); + let device_out_c = path_to_c_string(device_out.as_path()); unsafe { - llvm::LLVMRustBundleImages(module.module_llvm.llmod(), module.module_llvm.tm.raw()); + // 1) Bundle device module into offload image host.out (device TM) + let ok = llvm::LLVMRustBundleImages( + module.module_llvm.llmod(), + module.module_llvm.tm.raw(), + device_out_c.as_ptr(), + ); + assert!(ok, "LLVMRustBundleImages (device -> host.out) failed"); + if !device_out.exists() { + panic!("BundleImages failed, `host.out` was not created!"); + } } } + // This assumes that we previously compiled our kernels for a gpu target, which created a + // `host.out` artifact. The user is supposed to provide us with a path to this artifact, we + // don't need any other artifacts from the previous run. We will embed this artifact into our + // LLVM-IR host module, to create a `host.o` ObjectFile, which we will write to disk. + // The last, not yet automated steps uses the `clang-linker-wrapper` to process `host.o`. + if !cgcx.target_is_like_gpu { + if let Some(device_path) = config + .offload + .iter() + .find_map(|o| if let config::Offload::Host(path) = o { Some(path) } else { None }) + { + let device_pathbuf = PathBuf::from(device_path); + if device_pathbuf.is_relative() { + panic!("Absolute path is needed"); + } else if device_pathbuf + .file_name() + .and_then(|n| n.to_str()) + .is_some_and(|n| n != "host.out") + { + panic!("Need path to the host.out file"); + } + assert!(device_pathbuf.exists()); + let host_path = cgcx.output_filenames.path(OutputType::Object); + let host_dir = host_path.parent().unwrap(); + let out_obj = host_dir.join("host.o"); + let host_out_c = path_to_c_string(device_pathbuf.as_path()); + + // 2) Finalize host: lib.bc + host.out -> host.o (host TM) + // We create a full clone of our LLVM host module, since we will embed the device IR + // into it, and this might break caching or incremental compilation otherwise. + let llmod2 = llvm::LLVMCloneModule(module.module_llvm.llmod()); + let ok = + unsafe { llvm::LLVMRustOffloadEmbedBufferInModule(llmod2, host_out_c.as_ptr()) }; + assert!(ok, "LLVMRustOffloadEmbedBufferInModule failed"); + write_output_file( + dcx, + module.module_llvm.tm.raw(), + config.no_builtins, + llmod2, + &out_obj, + None, + llvm::FileType::ObjectFile, + &cgcx.prof, + true, + ); + if !out_obj.exists() { + dbg!("{:?} does not exist!", out_obj); + panic!("FinalizeOffload failed!"); + } + // We ignore cgcx.save_temps here and unconditionally always keep our `host.out` artifact. + // Otherwise, recompiling the host code would fail since we deleted that device artifact + // in the previous host compilation, which would be confusing at best. + } + } result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::RunLlvmPasses)) } diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 16455b4c79cd..388118f9b4f1 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -93,9 +93,9 @@ fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen { - if !tcx - .sess - .opts - .unstable_opts - .offload - .contains(&rustc_session::config::Offload::Enable) - { + if tcx.sess.opts.unstable_opts.offload.is_empty() { let _ = tcx.dcx().emit_almost_fatal(OffloadWithoutEnable); } diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index a86b4cc38915..75b3e5955b78 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -1666,7 +1666,15 @@ mod Offload { use super::*; unsafe extern "C" { /// Processes the module and writes it in an offload compatible way into a "host.out" file. - pub(crate) fn LLVMRustBundleImages<'a>(M: &'a Module, TM: &'a TargetMachine) -> bool; + pub(crate) fn LLVMRustBundleImages<'a>( + M: &'a Module, + TM: &'a TargetMachine, + host_out: *const c_char, + ) -> bool; + pub(crate) unsafe fn LLVMRustOffloadEmbedBufferInModule<'a>( + _M: &'a Module, + _host_out: *const c_char, + ) -> bool; pub(crate) fn LLVMRustOffloadMapper<'a>(OldFn: &'a Value, NewFn: &'a Value); } } @@ -1680,7 +1688,17 @@ mod Offload_fallback { /// Processes the module and writes it in an offload compatible way into a "host.out" file. /// Marked as unsafe to match the real offload wrapper which is unsafe due to FFI. #[allow(unused_unsafe)] - pub(crate) unsafe fn LLVMRustBundleImages<'a>(_M: &'a Module, _TM: &'a TargetMachine) -> bool { + pub(crate) unsafe fn LLVMRustBundleImages<'a>( + _M: &'a Module, + _TM: &'a TargetMachine, + _host_out: *const c_char, + ) -> bool { + unimplemented!("This rustc version was not built with LLVM Offload support!"); + } + pub(crate) unsafe fn LLVMRustOffloadEmbedBufferInModule<'a>( + _M: &'a Module, + _host_out: *const c_char, + ) -> bool { unimplemented!("This rustc version was not built with LLVM Offload support!"); } #[allow(unused_unsafe)] diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 8dab3a7f37f5..d075f94ef850 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -837,7 +837,7 @@ macro_rules! tracked { tracked!(no_profiler_runtime, true); tracked!(no_trait_vptr, true); tracked!(no_unique_section_names, true); - tracked!(offload, vec![Offload::Enable]); + tracked!(offload, vec![Offload::Device]); tracked!(on_broken_pipe, OnBrokenPipe::Kill); tracked!(osx_rpath_install_name, true); tracked!(packed_bundled_libs, true); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 0720af0eb7e0..02e6abf24627 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -43,8 +43,10 @@ // available. As such, we only try to build it in the first place, if // llvm.offload is enabled. #ifdef OFFLOAD +#include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Object/OffloadBinary.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" #endif // for raw `write` in the bad-alloc handler @@ -174,12 +176,13 @@ static Error writeFile(StringRef Filename, StringRef Data) { // --image=file=device.bc,triple=amdgcn-amd-amdhsa,arch=gfx90a,kind=openmp // The input module is the rust code compiled for a gpu target like amdgpu. // Based on clang/tools/clang-offload-packager/ClangOffloadPackager.cpp -extern "C" bool LLVMRustBundleImages(LLVMModuleRef M, TargetMachine &TM) { +extern "C" bool LLVMRustBundleImages(LLVMModuleRef M, TargetMachine &TM, + const char *HostOutPath) { std::string Storage; llvm::raw_string_ostream OS1(Storage); llvm::WriteBitcodeToFile(*unwrap(M), OS1); OS1.flush(); - auto MB = llvm::MemoryBuffer::getMemBufferCopy(Storage, "module.bc"); + auto MB = llvm::MemoryBuffer::getMemBufferCopy(Storage, "device.bc"); SmallVector BinaryData; raw_svector_ostream OS2(BinaryData); @@ -188,19 +191,38 @@ extern "C" bool LLVMRustBundleImages(LLVMModuleRef M, TargetMachine &TM) { ImageBinary.TheImageKind = object::IMG_Bitcode; ImageBinary.Image = std::move(MB); ImageBinary.TheOffloadKind = object::OFK_OpenMP; - ImageBinary.StringData["triple"] = TM.getTargetTriple().str(); - ImageBinary.StringData["arch"] = TM.getTargetCPU(); + + std::string TripleStr = TM.getTargetTriple().str(); + llvm::StringRef CPURef = TM.getTargetCPU(); + ImageBinary.StringData["triple"] = TripleStr; + ImageBinary.StringData["arch"] = CPURef; llvm::SmallString<0> Buffer = OffloadBinary::write(ImageBinary); if (Buffer.size() % OffloadBinary::getAlignment() != 0) // Offload binary has invalid size alignment return false; OS2 << Buffer; - if (Error E = writeFile("host.out", + if (Error E = writeFile(HostOutPath, StringRef(BinaryData.begin(), BinaryData.size()))) return false; return true; } +extern "C" bool LLVMRustOffloadEmbedBufferInModule(LLVMModuleRef HostM, + const char *HostOutPath) { + auto MBOrErr = MemoryBuffer::getFile(HostOutPath); + if (!MBOrErr) { + auto E = MBOrErr.getError(); + auto _B = errorCodeToError(E); + return false; + } + MemoryBufferRef Buf = (*MBOrErr)->getMemBufferRef(); + Module *M = unwrap(HostM); + StringRef SectionName = ".llvm.offloading"; + Align Alignment = Align(8); + llvm::embedBufferInModule(*M, Buf, SectionName, Alignment); + return true; +} + extern "C" void LLVMRustOffloadMapper(LLVMValueRef OldFn, LLVMValueRef NewFn) { llvm::Function *oldFn = llvm::unwrap(OldFn); llvm::Function *newFn = llvm::unwrap(NewFn); diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index a3a97dfec61d..2774333573f6 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -190,10 +190,12 @@ pub enum CoverageLevel { } // The different settings that the `-Z offload` flag can have. -#[derive(Clone, Copy, PartialEq, Hash, Debug)] +#[derive(Clone, PartialEq, Hash, Debug)] pub enum Offload { - /// Enable the llvm offload pipeline - Enable, + /// Entry point for `std::offload`, enables kernel compilation for a gpu device + Device, + /// Second step in the offload pipeline, generates the host code to call kernels. + Host(String), } /// The different settings that the `-Z autodiff` flag can have. @@ -2578,9 +2580,7 @@ pub fn build_session_options(early_dcx: &mut EarlyDiagCtxt, matches: &getopts::M ) } - if !nightly_options::is_unstable_enabled(matches) - && unstable_opts.offload.contains(&Offload::Enable) - { + if !nightly_options::is_unstable_enabled(matches) && !unstable_opts.offload.is_empty() { early_dcx.early_fatal( "`-Zoffload=Enable` also requires `-Zunstable-options` \ and a nightly compiler", diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index aea0b73ee927..2b83d1225c97 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1451,8 +1451,27 @@ pub(crate) fn parse_offload(slot: &mut Vec, v: Option<&str>) -> bool { let mut v: Vec<&str> = v.split(",").collect(); v.sort_unstable(); for &val in v.iter() { - let variant = match val { - "Enable" => Offload::Enable, + // Split each entry on '=' if it has an argument + let (key, arg) = match val.split_once('=') { + Some((k, a)) => (k, Some(a)), + None => (val, None), + }; + + let variant = match key { + "Host" => { + if let Some(p) = arg { + Offload::Host(p.to_string()) + } else { + return false; + } + } + "Device" => { + if let Some(_) = arg { + // Device does not accept a value + return false; + } + Offload::Device + } _ => { // FIXME(ZuseZ4): print an error saying which value is not recognized return false; From 3fdc6da2aad13909f02754d32db85ac69ca86102 Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 9 Dec 2025 07:51:04 -0800 Subject: [PATCH 106/126] adding proper error handling for offload --- compiler/rustc_codegen_llvm/messages.ftl | 7 ++++++- compiler/rustc_codegen_llvm/src/back/write.rs | 20 +++++++++---------- compiler/rustc_codegen_llvm/src/errors.rs | 20 +++++++++++++++++++ 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl index b3ef9840f5dc..a637ae8184b4 100644 --- a/compiler/rustc_codegen_llvm/messages.ftl +++ b/compiler/rustc_codegen_llvm/messages.ftl @@ -19,7 +19,12 @@ codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for codegen_llvm_mismatch_data_layout = data-layout for target `{$rustc_target}`, `{$rustc_layout}`, differs from LLVM target's `{$llvm_target}` default layout, `{$llvm_layout}` -codegen_llvm_offload_without_enable = using the offload feature requires -Z offload=Enable +codegen_llvm_offload_bundleimages_failed = call to BundleImages failed, `host.out` was not created +codegen_llvm_offload_embed_failed = call to EmbedBufferInModule failed, `host.o` was not created +codegen_llvm_offload_no_abs_path = using the `-Z offload=Host=/absolute/path/to/host.out` flag requires an absolute path +codegen_llvm_offload_no_host_out = using the `-Z offload=Host=/absolute/path/to/host.out` flag must point to a `host.out` file +codegen_llvm_offload_nonexisting = the given path/file to `host.out` does not exist. Did you forget to run the device compilation first? +codegen_llvm_offload_without_enable = using the offload feature requires -Z offload= codegen_llvm_offload_without_fat_lto = using the offload feature requires -C lto=fat codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index a649ee4bff1c..d87de8b38467 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -786,9 +786,8 @@ fn handle_offload<'ll>(cx: &'ll SimpleCx<'_>, old_fn: &llvm::Value) { module.module_llvm.tm.raw(), device_out_c.as_ptr(), ); - assert!(ok, "LLVMRustBundleImages (device -> host.out) failed"); - if !device_out.exists() { - panic!("BundleImages failed, `host.out` was not created!"); + if !ok || !device_out.exists() { + dcx.emit_err(crate::errors::OffloadBundleImagesFailed); } } } @@ -806,15 +805,16 @@ fn handle_offload<'ll>(cx: &'ll SimpleCx<'_>, old_fn: &llvm::Value) { { let device_pathbuf = PathBuf::from(device_path); if device_pathbuf.is_relative() { - panic!("Absolute path is needed"); + dcx.emit_err(crate::errors::OffloadWithoutAbsPath); } else if device_pathbuf .file_name() .and_then(|n| n.to_str()) .is_some_and(|n| n != "host.out") { - panic!("Need path to the host.out file"); + dcx.emit_err(crate::errors::OffloadWrongFileName); + } else if !device_pathbuf.exists() { + dcx.emit_err(crate::errors::OffloadNonexistingPath); } - assert!(device_pathbuf.exists()); let host_path = cgcx.output_filenames.path(OutputType::Object); let host_dir = host_path.parent().unwrap(); let out_obj = host_dir.join("host.o"); @@ -826,7 +826,9 @@ fn handle_offload<'ll>(cx: &'ll SimpleCx<'_>, old_fn: &llvm::Value) { let llmod2 = llvm::LLVMCloneModule(module.module_llvm.llmod()); let ok = unsafe { llvm::LLVMRustOffloadEmbedBufferInModule(llmod2, host_out_c.as_ptr()) }; - assert!(ok, "LLVMRustOffloadEmbedBufferInModule failed"); + if !ok { + dcx.emit_err(crate::errors::OffloadEmbedFailed); + } write_output_file( dcx, module.module_llvm.tm.raw(), @@ -838,10 +840,6 @@ fn handle_offload<'ll>(cx: &'ll SimpleCx<'_>, old_fn: &llvm::Value) { &cgcx.prof, true, ); - if !out_obj.exists() { - dbg!("{:?} does not exist!", out_obj); - panic!("FinalizeOffload failed!"); - } // We ignore cgcx.save_temps here and unconditionally always keep our `host.out` artifact. // Otherwise, recompiling the host code would fail since we deleted that device artifact // in the previous host compilation, which would be confusing at best. diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs index b59067b9745b..c73140e041b6 100644 --- a/compiler/rustc_codegen_llvm/src/errors.rs +++ b/compiler/rustc_codegen_llvm/src/errors.rs @@ -52,6 +52,26 @@ fn into_diag(self, dcx: DiagCtxtHandle<'_>, level: Level) -> Diag<'_, G> { #[diag(codegen_llvm_offload_without_fat_lto)] pub(crate) struct OffloadWithoutFatLTO; +#[derive(Diagnostic)] +#[diag(codegen_llvm_offload_no_abs_path)] +pub(crate) struct OffloadWithoutAbsPath; + +#[derive(Diagnostic)] +#[diag(codegen_llvm_offload_no_host_out)] +pub(crate) struct OffloadWrongFileName; + +#[derive(Diagnostic)] +#[diag(codegen_llvm_offload_nonexisting)] +pub(crate) struct OffloadNonexistingPath; + +#[derive(Diagnostic)] +#[diag(codegen_llvm_offload_bundleimages_failed)] +pub(crate) struct OffloadBundleImagesFailed; + +#[derive(Diagnostic)] +#[diag(codegen_llvm_offload_embed_failed)] +pub(crate) struct OffloadEmbedFailed; + #[derive(Diagnostic)] #[diag(codegen_llvm_lto_bitcode_from_rlib)] pub(crate) struct LtoBitcodeFromRlib { From 8e1d80305fd98ee7da1cb422d5da2495502e995d Mon Sep 17 00:00:00 2001 From: Manuel Drehwald Date: Tue, 9 Dec 2025 07:50:48 -0800 Subject: [PATCH 107/126] Update offloading docs to account for simplified usage --- src/doc/rustc-dev-guide/src/offload/usage.md | 23 +++++++++----------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/doc/rustc-dev-guide/src/offload/usage.md b/src/doc/rustc-dev-guide/src/offload/usage.md index d934de9049be..062534a4b655 100644 --- a/src/doc/rustc-dev-guide/src/offload/usage.md +++ b/src/doc/rustc-dev-guide/src/offload/usage.md @@ -77,28 +77,25 @@ pub extern "gpu-kernel" fn kernel_1(x: *mut [f64; 256]) { ## Compile instructions It is important to use a clang compiler build on the same llvm as rustc. Just calling clang without the full path will likely use your system clang, which probably will be incompatible. So either substitute clang/lld invocations below with absolute path, or set your `PATH` accordingly. -First we generate the host (cpu) code. The first build is just to compile libc, take note of the hashed path. Then we call rustc directly to build our host code, while providing the libc artifact to rustc. +First we generate the device (gpu) code. Replace the target-cpu with the right code for your gpu. ``` -cargo +offload build -r -v -rustc +offload --edition 2024 src/lib.rs -g --crate-type cdylib -C opt-level=3 -C panic=abort -C lto=fat -L dependency=/absolute_path_to/target/release/deps --extern libc=/absolute_path_to/target/release/deps/liblibc-.rlib --emit=llvm-bc,llvm-ir -Zoffload=Enable -Zunstable-options +RUSTFLAGS="-Ctarget-cpu=gfx90a --emit=llvm-bc,llvm-ir -Zoffload=Device -Csave-temps -Zunstable-options" cargo +offload build -Zunstable-options -r -v --target amdgcn-amd-amdhsa -Zbuild-std=core ``` +You might afterwards need to copy your target/release/deps/.bc to lib.bc for now, before the next step. -Now we generate the device code. Replace the target-cpu with the right code for your gpu. +Now we generate the host (cpu) code. ``` -RUSTFLAGS="-Ctarget-cpu=gfx90a --emit=llvm-bc,llvm-ir -Zoffload=Enable -Zunstable-options" cargo +offload build -Zunstable-options -r -v --target amdgcn-amd-amdhsa -Zbuild-std=core +RUSTFLAGS="--emit=llvm-bc,llvm-ir -Csave-temps -Zoffload=Host=/p/lustre1/drehwald1/prog/offload/r/target/amdgcn-amd-amdhsa/release/deps/host.out -Zunstable-options" cargo +offload build -r ``` - +This call also does a lot of work and generates multiple intermediate files for llvm offload. +While we integrated most offload steps into rustc by now, one binary invocation still remains for now: ``` -"clang-21" "-cc1" "-triple" "x86_64-unknown-linux-gnu" "-S" "-save-temps=cwd" "-disable-free" "-clear-ast-before-backend" "-main-file-name" "lib.rs" "-mrelocation-model" "pic" "-pic-level" "2" "-pic-is-pie" "-mframe-pointer=all" "-fmath-errno" "-ffp-contract=on" "-fno-rounding-math" "-mconstructor-aliases" "-funwind-tables=2" "-target-cpu" "x86-64" "-tune-cpu" "generic" "-resource-dir" "//rust/build/x86_64-unknown-linux-gnu/llvm/lib/clang/21" "-ferror-limit" "19" "-fopenmp" "-fopenmp-offload-mandatory" "-fgnuc-version=4.2.1" "-fskip-odr-check-in-gmf" "-fembed-offload-object=host.out" "-fopenmp-targets=amdgcn-amd-amdhsa" "-faddrsig" "-D__GCC_HAVE_DWARF2_CFI_ASM=1" "-o" "host.s" "-x" "ir" "lib.bc" - -"clang-21" "-cc1as" "-triple" "x86_64-unknown-linux-gnu" "-filetype" "obj" "-main-file-name" "lib.rs" "-target-cpu" "x86-64" "-mrelocation-model" "pic" "-o" "host.o" "host.s" - -"clang-linker-wrapper" "--should-extract=gfx90a" "--device-compiler=amdgcn-amd-amdhsa=-g" "--device-compiler=amdgcn-amd-amdhsa=-save-temps=cwd" "--device-linker=amdgcn-amd-amdhsa=-lompdevice" "--host-triple=x86_64-unknown-linux-gnu" "--save-temps" "--linker-path=/ABSOlUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/lld/bin/ld.lld" "--hash-style=gnu" "--eh-frame-hdr" "-m" "elf_x86_64" "-pie" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-o" "bare" "/lib/../lib64/Scrt1.o" "/lib/../lib64/crti.o" "/ABSOLUTE_PATH_TO/crtbeginS.o" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/bin/../lib/x86_64-unknown-linux-gnu" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib/clang/21/lib/x86_64-unknown-linux-gnu" "-L/lib/../lib64" "-L/usr/lib64" "-L/lib" "-L/usr/lib" "host.o" "-lstdc++" "-lm" "-lomp" "-lomptarget" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib" "-lgcc_s" "-lgcc" "-lpthread" "-lc" "-lgcc_s" "-lgcc" "/ABSOLUTE_PATH_TO/crtendS.o" "/lib/../lib64/crtn.o" +"clang-linker-wrapper" "--should-extract=gfx90a" "--device-compiler=amdgcn-amd-amdhsa=-g" "--device-compiler=amdgcn-amd-amdhsa=-save-temps=cwd" "--device-linker=amdgcn-amd-amdhsa=-lompdevice" "--host-triple=x86_64-unknown-linux-gnu" "--save-temps" "--linker-path=/ABSOlUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/lld/bin/ld.lld" "--hash-style=gnu" "--eh-frame-hdr" "-m" "elf_x86_64" "-pie" "-dynamic-linker" "/lib64/ld-linux-x86-64.so.2" "-o" "bare" "/lib/../lib64/Scrt1.o" "/lib/../lib64/crti.o" "/ABSOLUTE_PATH_TO/crtbeginS.o" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/bin/../lib/x86_64-unknown-linux-gnu" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib/clang/21/lib/x86_64-unknown-linux-gnu" "-L/lib/../lib64" "-L/usr/lib64" "-L/lib" "-L/usr/lib" "target//release/host.o" "-lstdc++" "-lm" "-lomp" "-lomptarget" "-L/ABSOLUTE_PATH_TO/rust/build/x86_64-unknown-linux-gnu/llvm/lib" "-lgcc_s" "-lgcc" "-lpthread" "-lc" "-lgcc_s" "-lgcc" "/ABSOLUTE_PATH_TO/crtendS.o" "/lib/../lib64/crtn.o" ``` -Especially for the last three commands I recommend to not fix the paths, but rather just re-generate them by copying a bare-mode openmp example and compiling it with your clang. By adding `-###` to your clang invocation, you can see the invidual steps. -You can ignore other steps, e.g. the invocation of a "clang-offload-packager". +You can try to find the paths to those files on your system. However, I recommend to not fix the paths, but rather just re-generate them by copying a bare-mode openmp example and compiling it with your clang. By adding `-###` to your clang invocation, you can see the invidual steps. +It will show multiple steps, just look for the clang-linker-wrapper example. Make sure to still include the path to the `host.o` file, and not whatever tmp file you got when compiling your c++ example with the following call. ``` myclang++ -fuse-ld=lld -O3 -fopenmp -fopenmp-offload-mandatory --offload-arch=gfx90a omp_bare.cpp -o main -### ``` From 8f3a76bd38f903503f29e895c78bab4a685d64ec Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Fri, 14 Nov 2025 08:57:41 +0000 Subject: [PATCH 108/126] mgca always resolve params --- .../src/hir_ty_lowering/mod.rs | 10 ++ compiler/rustc_hir_typeck/src/lib.rs | 12 ++ compiler/rustc_middle/src/hir/map.rs | 48 ++++++++ compiler/rustc_resolve/src/late.rs | 12 +- .../mgca/explicit_anon_consts.rs | 1 + .../mgca/explicit_anon_consts.stderr | 112 ++++++++---------- .../mgca/type_const-on-generic-expr.rs | 1 + .../mgca/type_const-on-generic-expr.stderr | 41 +++---- 8 files changed, 145 insertions(+), 92 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 4db9a4c2bcdd..f7c7cf6634fd 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2378,6 +2378,16 @@ fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> { let expr = &tcx.hir_body(anon.body).value; debug!(?expr); + // If the rhs is an anon const naming generics it shouldn't have + // access to then we lower to `ConstKind::Error`. This prevents + // `try_lower_anon_const_lit` from ICEing on anon consts such as + // `const { N }` which aren't supposed to be legal. + if let ty::AnonConstKind::MCG = tcx.anon_const_kind(anon.def_id) + && let Err(e) = tcx.check_anon_const_invalid_param_uses(anon.def_id) + { + return ty::Const::new_error(tcx, e); + } + // FIXME(generic_const_parameter_types): We should use the proper generic args // here. It's only used as a hint for literals so doesn't matter too much to use the right // generic arguments, just weaker type inference. diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 39c28c4f4e99..b8a587016427 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -115,6 +115,18 @@ fn typeck_with_inspect<'tcx>( return tcx.typeck(typeck_root_def_id); } + // We can't handle bodies containing generic parameters even though + // these generic parameters aren't part of its `generics_of` right now. + // + // See the FIXME on `check_anon_const_invalid_param_uses`. + if tcx.features().min_generic_const_args() + && let DefKind::AnonConst = tcx.def_kind(def_id) + && let ty::AnonConstKind::MCG = tcx.anon_const_kind(def_id) + && let Err(e) = tcx.check_anon_const_invalid_param_uses(def_id) + { + e.raise_fatal(); + } + let id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir_node(id); let span = tcx.def_span(def_id); diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 5da762ef8565..9e639b243f28 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -2,6 +2,8 @@ //! eliminated, and all its methods are now on `TyCtxt`. But the module name //! stays as `map` because there isn't an obviously better name for it. +use std::ops::ControlFlow; + use rustc_abi::ExternAbi; use rustc_ast::visit::{VisitorResult, walk_list}; use rustc_data_structures::fingerprint::Fingerprint; @@ -1086,6 +1088,52 @@ pub fn hir_maybe_get_struct_pattern_shorthand_field(self, expr: &Expr<'_>) -> Op None } + + // FIXME(mgca): this is pretty iffy. In the long term we should make + // HIR ty lowering able to return `Error` versions of types/consts when + // lowering them in contexts that aren't supposed to use generic parameters. + // + // This current impl strategy is incomplete and doesn't handle `Self` ty aliases. + pub fn check_anon_const_invalid_param_uses( + self, + anon: LocalDefId, + ) -> Result<(), ErrorGuaranteed> { + struct GenericParamVisitor<'tcx>(TyCtxt<'tcx>); + impl<'tcx> Visitor<'tcx> for GenericParamVisitor<'tcx> { + type NestedFilter = nested_filter::OnlyBodies; + type Result = ControlFlow; + + fn maybe_tcx(&mut self) -> TyCtxt<'tcx> { + self.0 + } + + fn visit_path( + &mut self, + path: &crate::hir::Path<'tcx>, + _id: HirId, + ) -> ControlFlow { + if let Res::Def( + DefKind::TyParam | DefKind::ConstParam | DefKind::LifetimeParam, + _, + ) = path.res + { + let e = self.0.dcx().struct_span_err( + path.span, + "generic parameters may not be used in const operations", + ); + return ControlFlow::Break(e.emit()); + } + + intravisit::walk_path(self, path) + } + } + + let body = self.hir_maybe_body_owned_by(anon).unwrap(); + match GenericParamVisitor(self).visit_expr(&body.value) { + ControlFlow::Break(e) => Err(e), + ControlFlow::Continue(()) => Ok(()), + } + } } impl<'tcx> intravisit::HirTyCtxt<'tcx> for TyCtxt<'tcx> { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index d3428a4af348..4fefcc66b588 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -4879,12 +4879,7 @@ fn resolve_anon_const(&mut self, constant: &'ast AnonConst, anon_const_kind: Ano constant, anon_const_kind ); - let is_trivial_const_arg = if self.r.tcx.features().min_generic_const_args() { - matches!(constant.mgca_disambiguation, MgcaDisambiguation::Direct) - } else { - constant.value.is_potential_trivial_const_arg() - }; - + let is_trivial_const_arg = constant.value.is_potential_trivial_const_arg(); self.resolve_anon_const_manual(is_trivial_const_arg, anon_const_kind, |this| { this.resolve_expr(&constant.value, None) }) @@ -4914,7 +4909,10 @@ fn resolve_anon_const_manual( AnonConstKind::FieldDefaultValue => ConstantHasGenerics::Yes, AnonConstKind::InlineConst => ConstantHasGenerics::Yes, AnonConstKind::ConstArg(_) => { - if self.r.tcx.features().generic_const_exprs() || is_trivial_const_arg { + if self.r.tcx.features().generic_const_exprs() + || self.r.tcx.features().min_generic_const_args() + || is_trivial_const_arg + { ConstantHasGenerics::Yes } else { ConstantHasGenerics::No(NoConstantGenericsReason::NonTrivialConstArg) diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs index 31391b023bfe..ef17222ebc91 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -10,6 +10,7 @@ type Adt2 = Foo<{ N }>; type Adt3 = Foo; //~^ ERROR: generic parameters may not be used in const operations +//~^^ ERROR generic parameters may not be used in const operations type Adt4 = Foo<{ 1 + 1 }>; //~^ ERROR: complex const arguments must be placed inside of a `const` block type Adt5 = Foo; diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr index b3d960e315ea..eb200aae3396 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -1,92 +1,82 @@ -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:11:41 - | -LL | type Adt3 = Foo; - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:19:42 - | -LL | type Arr3 = [(); const { N }]; - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:28:27 - | -LL | let _3 = [(); const { N }]; - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:40:46 - | -LL | const ITEM3: usize = const { N }; - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:58:31 - | -LL | T3: Trait, - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:67:58 - | -LL | struct Default3; - | ^ cannot perform const operation using `N` - | - = help: const parameters may only be used as standalone arguments here, i.e. `N` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions - error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:13:33 + --> $DIR/explicit_anon_consts.rs:14:33 | LL | type Adt4 = Foo<{ 1 + 1 }>; | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:21:34 + --> $DIR/explicit_anon_consts.rs:22:34 | LL | type Arr4 = [(); 1 + 1]; | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:30:19 + --> $DIR/explicit_anon_consts.rs:31:19 | LL | let _4 = [(); 1 + 1]; | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:43:38 + --> $DIR/explicit_anon_consts.rs:44:38 | LL | const ITEM4: usize = { 1 + 1 }; | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:60:23 + --> $DIR/explicit_anon_consts.rs:61:23 | LL | T4: Trait, | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:69:50 + --> $DIR/explicit_anon_consts.rs:70:50 | LL | struct Default4; | ^^^^^^^^^ -error: aborting due to 12 previous errors +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:11:41 + | +LL | type Adt3 = Foo; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:20:42 + | +LL | type Arr3 = [(); const { N }]; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:41:46 + | +LL | const ITEM3: usize = const { N }; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:59:31 + | +LL | T3: Trait, + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:68:58 + | +LL | struct Default3; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:29:27 + | +LL | let _3 = [(); const { N }]; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts.rs:11:41 + | +LL | type Adt3 = Foo; + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 13 previous errors diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs index 577fee084dbd..a1008fae9d16 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs @@ -4,6 +4,7 @@ #[type_const] const FREE1: usize = const { std::mem::size_of::() }; //~^ ERROR generic parameters may not be used in const operations +//~^^ ERROR generic parameters may not be used in const operations #[type_const] const FREE2: usize = const { I + 1 }; //~^ ERROR generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr index 8cef77e5b229..c77be158d0ef 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr @@ -2,46 +2,39 @@ error: generic parameters may not be used in const operations --> $DIR/type_const-on-generic-expr.rs:5:53 | LL | const FREE1: usize = const { std::mem::size_of::() }; - | ^ cannot perform const operation using `T` - | - = note: type parameters may not be used in const expressions - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + | ^ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:8:46 + --> $DIR/type_const-on-generic-expr.rs:9:46 | LL | const FREE2: usize = const { I + 1 }; - | ^ cannot perform const operation using `I` - | - = help: const parameters may only be used as standalone arguments here, i.e. `I` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + | ^ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:24:54 + --> $DIR/type_const-on-generic-expr.rs:25:54 | LL | const N1: usize = const { std::mem::size_of::() }; - | ^ cannot perform const operation using `T` - | - = note: type parameters may not be used in const expressions - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + | ^ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:27:47 + --> $DIR/type_const-on-generic-expr.rs:28:47 | LL | const N2: usize = const { I + 1 }; - | ^ cannot perform const operation using `I` - | - = help: const parameters may only be used as standalone arguments here, i.e. `I` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions + | ^ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:30:35 + --> $DIR/type_const-on-generic-expr.rs:31:35 | LL | const N3: usize = const { 2 & X }; - | ^ cannot perform const operation using `X` + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/type_const-on-generic-expr.rs:5:53 | - = help: const parameters may only be used as standalone arguments here, i.e. `X` - = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions +LL | const FREE1: usize = const { std::mem::size_of::() }; + | ^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors From c65551e835f42d6b3cc28ebe37257ae7cfcbfe06 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Thu, 20 Nov 2025 02:16:43 +0000 Subject: [PATCH 109/126] Introduce `hir::ConstArgKind::Struct` --- compiler/rustc_ast_lowering/src/index.rs | 7 ++ compiler/rustc_ast_lowering/src/lib.rs | 41 +++++++++ compiler/rustc_hir/src/hir.rs | 13 +++ compiler/rustc_hir/src/intravisit.rs | 23 +++++ .../src/hir_ty_lowering/mod.rs | 3 + compiler/rustc_hir_pretty/src/lib.rs | 4 + compiler/rustc_metadata/src/rmeta/encoder.rs | 1 + compiler/rustc_middle/src/hir/map.rs | 2 + compiler/rustc_middle/src/hir/mod.rs | 1 + compiler/rustc_resolve/src/def_collector.rs | 89 +++++++++++++++---- compiler/rustc_resolve/src/lib.rs | 9 ++ .../mgca/struct_expr_with_macros.rs | 31 +++++++ 12 files changed, 205 insertions(+), 19 deletions(-) create mode 100644 tests/ui/const-generics/mgca/struct_expr_with_macros.rs diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 8d7351d3a510..f6edcaa64dfe 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -281,6 +281,13 @@ fn visit_expr_field(&mut self, field: &'hir ExprField<'hir>) { }); } + fn visit_const_arg_expr_field(&mut self, field: &'hir ConstArgExprField<'hir>) { + self.insert(field.span, field.hir_id, Node::ConstArgExprField(field)); + self.with_parent(field.hir_id, |this| { + intravisit::walk_const_arg_expr_field(this, field); + }) + } + fn visit_stmt(&mut self, stmt: &'hir Stmt<'hir>) { self.insert(stmt.span, stmt.hir_id, Node::Stmt(stmt)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1bc8d7c25bb5..416fef8e3af3 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2410,6 +2410,47 @@ fn lower_expr_to_const_arg_direct(&mut self, expr: &Expr) -> hir::ConstArg<'hir> ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Path(qpath) } } + ExprKind::Struct(se) => { + let path = self.lower_qpath( + expr.id, + &se.qself, + &se.path, + // FIXME(mgca): we may want this to be `Optional` instead, but + // we would also need to make sure that HIR ty lowering errors + // when these paths wind up in signatures. + ParamMode::Explicit, + AllowReturnTypeNotation::No, + ImplTraitContext::Disallowed(ImplTraitPosition::Path), + None, + ); + + let fields = self.arena.alloc_from_iter(se.fields.iter().map(|f| { + let hir_id = self.lower_node_id(f.id); + // FIXME(mgca): This might result in lowering attributes that + // then go unused as the `Target::ExprField` is not actually + // corresponding to `Node::ExprField`. + self.lower_attrs(hir_id, &f.attrs, f.span, Target::ExprField); + + let expr = if let ExprKind::ConstBlock(anon_const) = &f.expr.kind { + let def_id = self.local_def_id(anon_const.id); + let def_kind = self.tcx.def_kind(def_id); + assert_eq!(DefKind::AnonConst, def_kind); + + self.lower_anon_const_to_const_arg_direct(anon_const) + } else { + self.lower_expr_to_const_arg_direct(&f.expr) + }; + + &*self.arena.alloc(hir::ConstArgExprField { + hir_id, + field: self.lower_ident(f.ident), + expr: self.arena.alloc(expr), + span: self.lower_span(f.span), + }) + })); + + ConstArg { hir_id: self.next_id(), kind: hir::ConstArgKind::Struct(path, fields) } + } ExprKind::Underscore => ConstArg { hir_id: self.lower_node_id(expr.id), kind: hir::ConstArgKind::Infer(expr.span, ()), diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index c60471848c89..e176c703b33e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -494,6 +494,7 @@ pub fn anon_const_hir_id(&self) -> Option { pub fn span(&self) -> Span { match self.kind { + ConstArgKind::Struct(path, _) => path.span(), ConstArgKind::Path(path) => path.span(), ConstArgKind::Anon(anon) => anon.span, ConstArgKind::Error(span, _) => span, @@ -513,6 +514,8 @@ pub enum ConstArgKind<'hir, Unambig = ()> { /// However, in the future, we'll be using it for all of those. Path(QPath<'hir>), Anon(&'hir AnonConst), + /// Represents construction of struct/struct variants + Struct(QPath<'hir>, &'hir [&'hir ConstArgExprField<'hir>]), /// Error const Error(Span, ErrorGuaranteed), /// This variant is not always used to represent inference consts, sometimes @@ -520,6 +523,14 @@ pub enum ConstArgKind<'hir, Unambig = ()> { Infer(Span, Unambig), } +#[derive(Clone, Copy, Debug, HashStable_Generic)] +pub struct ConstArgExprField<'hir> { + pub hir_id: HirId, + pub span: Span, + pub field: Ident, + pub expr: &'hir ConstArg<'hir>, +} + #[derive(Clone, Copy, Debug, HashStable_Generic)] pub struct InferArg { #[stable_hasher(ignore)] @@ -4714,6 +4725,7 @@ pub enum Node<'hir> { ConstArg(&'hir ConstArg<'hir>), Expr(&'hir Expr<'hir>), ExprField(&'hir ExprField<'hir>), + ConstArgExprField(&'hir ConstArgExprField<'hir>), Stmt(&'hir Stmt<'hir>), PathSegment(&'hir PathSegment<'hir>), Ty(&'hir Ty<'hir>), @@ -4773,6 +4785,7 @@ pub fn ident(&self) -> Option { Node::AssocItemConstraint(c) => Some(c.ident), Node::PatField(f) => Some(f.ident), Node::ExprField(f) => Some(f.ident), + Node::ConstArgExprField(f) => Some(f.field), Node::PreciseCapturingNonLifetimeArg(a) => Some(a.ident), Node::Param(..) | Node::AnonConst(..) diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index be3cab6461ef..e63f51f8e6a4 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -396,6 +396,9 @@ fn visit_expr(&mut self, ex: &'v Expr<'v>) -> Self::Result { fn visit_expr_field(&mut self, field: &'v ExprField<'v>) -> Self::Result { walk_expr_field(self, field) } + fn visit_const_arg_expr_field(&mut self, field: &'v ConstArgExprField<'v>) -> Self::Result { + walk_const_arg_expr_field(self, field) + } fn visit_pattern_type_pattern(&mut self, p: &'v TyPat<'v>) -> Self::Result { walk_ty_pat(self, p) } @@ -954,6 +957,17 @@ pub fn walk_expr_field<'v, V: Visitor<'v>>(visitor: &mut V, field: &'v ExprField try_visit!(visitor.visit_ident(*ident)); visitor.visit_expr(*expr) } + +pub fn walk_const_arg_expr_field<'v, V: Visitor<'v>>( + visitor: &mut V, + field: &'v ConstArgExprField<'v>, +) -> V::Result { + let ConstArgExprField { hir_id, field, expr, span: _ } = field; + try_visit!(visitor.visit_id(*hir_id)); + try_visit!(visitor.visit_ident(*field)); + visitor.visit_const_arg_unambig(*expr) +} + /// We track whether an infer var is from a [`Ty`], [`ConstArg`], or [`GenericArg`] so that /// HIR visitors overriding [`Visitor::visit_infer`] can determine what kind of infer is being visited pub enum InferKind<'hir> { @@ -1068,6 +1082,15 @@ pub fn walk_const_arg<'v, V: Visitor<'v>>( let ConstArg { hir_id, kind } = const_arg; try_visit!(visitor.visit_id(*hir_id)); match kind { + ConstArgKind::Struct(qpath, field_exprs) => { + try_visit!(visitor.visit_qpath(qpath, *hir_id, qpath.span())); + + for field_expr in *field_exprs { + try_visit!(visitor.visit_const_arg_expr_field(field_expr)); + } + + V::Result::output() + } ConstArgKind::Path(qpath) => visitor.visit_qpath(qpath, *hir_id, qpath.span()), ConstArgKind::Anon(anon) => visitor.visit_anon_const(*anon), ConstArgKind::Error(_, _) => V::Result::output(), // errors and spans are not important diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index f7c7cf6634fd..3c1200c812bc 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2263,6 +2263,9 @@ pub fn lower_const_arg( ) .unwrap_or_else(|guar| Const::new_error(tcx, guar)) } + hir::ConstArgKind::Struct(..) => { + span_bug!(const_arg.span(), "lowering `{:?}` is not yet implemented", const_arg) + } hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon), hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e), diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index b3b416955230..f99533922110 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -180,6 +180,8 @@ fn print_node(&mut self, node: Node<'_>) { Node::ConstArg(a) => self.print_const_arg(a), Node::Expr(a) => self.print_expr(a), Node::ExprField(a) => self.print_expr_field(a), + // FIXME(mgca): proper printing for struct exprs + Node::ConstArgExprField(_) => self.word("/* STRUCT EXPR */"), Node::Stmt(a) => self.print_stmt(a), Node::PathSegment(a) => self.print_path_segment(a), Node::Ty(a) => self.print_type(a), @@ -1135,6 +1137,8 @@ fn print_const_item_rhs(&mut self, ct_rhs: hir::ConstItemRhs<'_>) { fn print_const_arg(&mut self, const_arg: &hir::ConstArg<'_>) { match &const_arg.kind { + // FIXME(mgca): proper printing for struct exprs + ConstArgKind::Struct(..) => self.word("/* STRUCT EXPR */"), ConstArgKind::Path(qpath) => self.print_qpath(qpath, true), ConstArgKind::Anon(anon) => self.print_anon_const(anon), ConstArgKind::Error(_, _) => self.word("/*ERROR*/"), diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 94bc4d3fa530..920c896d5a47 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1440,6 +1440,7 @@ fn encode_def_ids(&mut self) { hir::Node::ConstArg(hir::ConstArg { kind, .. }) => match kind { // Skip encoding defs for these as they should not have had a `DefId` created hir::ConstArgKind::Error(..) + | hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) | hir::ConstArgKind::Infer(..) => true, hir::ConstArgKind::Anon(..) => false, diff --git a/compiler/rustc_middle/src/hir/map.rs b/compiler/rustc_middle/src/hir/map.rs index 9e639b243f28..d62ddc915d17 100644 --- a/compiler/rustc_middle/src/hir/map.rs +++ b/compiler/rustc_middle/src/hir/map.rs @@ -739,6 +739,7 @@ pub fn hir_id_to_string(self, id: HirId) -> String { Node::ConstArg(_) => node_str("const"), Node::Expr(_) => node_str("expr"), Node::ExprField(_) => node_str("expr field"), + Node::ConstArgExprField(_) => node_str("const arg expr field"), Node::Stmt(_) => node_str("stmt"), Node::PathSegment(_) => node_str("path segment"), Node::Ty(_) => node_str("type"), @@ -1007,6 +1008,7 @@ pub fn hir_span_with_body(self, hir_id: HirId) -> Span { Node::ConstArg(const_arg) => const_arg.span(), Node::Expr(expr) => expr.span, Node::ExprField(field) => field.span, + Node::ConstArgExprField(field) => field.span, Node::Stmt(stmt) => stmt.span, Node::PathSegment(seg) => { let ident_span = seg.ident.span; diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 217ecbab059e..ba2d8febad7c 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -359,6 +359,7 @@ pub fn expr_guaranteed_to_constitute_read_for_never(self, expr: &Expr<'_>) -> bo | Node::Infer(_) | Node::WherePredicate(_) | Node::PreciseCapturingNonLifetimeArg(_) + | Node::ConstArgExprField(_) | Node::OpaqueTy(_) => { unreachable!("no sub-expr expected for {parent_node:?}") } diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 71bbd64ddc6c..b50fc201bdb8 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -11,9 +11,9 @@ use rustc_middle::span_bug; use rustc_span::hygiene::LocalExpnId; use rustc_span::{Span, Symbol, sym}; -use tracing::debug; +use tracing::{debug, instrument}; -use crate::{ImplTraitContext, InvocationParent, Resolver}; +use crate::{ConstArgContext, ImplTraitContext, InvocationParent, Resolver}; pub(crate) fn collect_definitions( resolver: &mut Resolver<'_, '_>, @@ -21,6 +21,7 @@ pub(crate) fn collect_definitions( expansion: LocalExpnId, ) { let invocation_parent = resolver.invocation_parents[&expansion]; + debug!("new fragment to visit with invocation_parent: {invocation_parent:?}"); let mut visitor = DefCollector { resolver, expansion, invocation_parent }; fragment.visit_with(&mut visitor); } @@ -74,6 +75,12 @@ fn with_impl_trait( self.invocation_parent.impl_trait_context = orig_itc; } + fn with_const_arg(&mut self, ctxt: ConstArgContext, f: F) { + let orig = mem::replace(&mut self.invocation_parent.const_arg_context, ctxt); + f(self); + self.invocation_parent.const_arg_context = orig; + } + fn collect_field(&mut self, field: &'a FieldDef, index: Option) { let index = |this: &Self| { index.unwrap_or_else(|| { @@ -93,7 +100,10 @@ fn collect_field(&mut self, field: &'a FieldDef, index: Option) { } } + #[instrument(level = "debug", skip(self))] fn visit_macro_invoc(&mut self, id: NodeId) { + debug!(?self.invocation_parent); + let id = id.placeholder_to_expn_id(); let old_parent = self.resolver.invocation_parents.insert(id, self.invocation_parent); assert!(old_parent.is_none(), "parent `LocalDefId` is reset for an invocation"); @@ -360,36 +370,77 @@ fn visit_anon_const(&mut self, constant: &'a AnonConst) { // `MgcaDisambiguation::Direct` is set even when MGCA is disabled, so // to avoid affecting stable we have to feature gate the not creating // anon consts - if let MgcaDisambiguation::Direct = constant.mgca_disambiguation - && self.resolver.tcx.features().min_generic_const_args() - { - visit::walk_anon_const(self, constant); - return; + if !self.resolver.tcx.features().min_generic_const_args() { + let parent = + self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span); + return self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); } - let parent = self.create_def(constant.id, None, DefKind::AnonConst, constant.value.span); - self.with_parent(parent, |this| visit::walk_anon_const(this, constant)); + match constant.mgca_disambiguation { + MgcaDisambiguation::Direct => self.with_const_arg(ConstArgContext::Direct, |this| { + visit::walk_anon_const(this, constant); + }), + MgcaDisambiguation::AnonConst => { + self.with_const_arg(ConstArgContext::NonDirect, |this| { + let parent = + this.create_def(constant.id, None, DefKind::AnonConst, constant.value.span); + this.with_parent(parent, |this| visit::walk_anon_const(this, constant)); + }) + } + }; } + #[instrument(level = "debug", skip(self))] fn visit_expr(&mut self, expr: &'a Expr) { - let parent_def = match expr.kind { + debug!(?self.invocation_parent); + + let parent_def = match &expr.kind { ExprKind::MacCall(..) => return self.visit_macro_invoc(expr.id), ExprKind::Closure(..) | ExprKind::Gen(..) => { self.create_def(expr.id, None, DefKind::Closure, expr.span) } - ExprKind::ConstBlock(ref constant) => { - for attr in &expr.attrs { - visit::walk_attribute(self, attr); - } - let def = - self.create_def(constant.id, None, DefKind::InlineConst, constant.value.span); - self.with_parent(def, |this| visit::walk_anon_const(this, constant)); - return; + ExprKind::ConstBlock(constant) => { + // Under `min_generic_const_args` a `const { }` block sometimes + // corresponds to an anon const rather than an inline const. + let def_kind = match self.invocation_parent.const_arg_context { + ConstArgContext::Direct => DefKind::AnonConst, + ConstArgContext::NonDirect => DefKind::InlineConst, + }; + + return self.with_const_arg(ConstArgContext::NonDirect, |this| { + for attr in &expr.attrs { + visit::walk_attribute(this, attr); + } + + let def = this.create_def(constant.id, None, def_kind, constant.value.span); + this.with_parent(def, |this| visit::walk_anon_const(this, constant)); + }); } + + // Avoid overwriting `const_arg_context` as we may want to treat const blocks + // as being anon consts if we are inside a const argument. + ExprKind::Struct(_) => return visit::walk_expr(self, expr), + // FIXME(mgca): we may want to handle block labels in some manner + ExprKind::Block(block, _) if let [stmt] = block.stmts.as_slice() => match stmt.kind { + // FIXME(mgca): this probably means that mac calls that expand + // to semi'd const blocks are handled differently to just writing + // out a semi'd const block. + StmtKind::Expr(..) | StmtKind::MacCall(..) => return visit::walk_expr(self, expr), + + // Fallback to normal behaviour + StmtKind::Let(..) | StmtKind::Item(..) | StmtKind::Semi(..) | StmtKind::Empty => { + self.invocation_parent.parent_def + } + }, + _ => self.invocation_parent.parent_def, }; - self.with_parent(parent_def, |this| visit::walk_expr(this, expr)) + self.with_const_arg(ConstArgContext::NonDirect, |this| { + // Note in some cases the `parent_def` here may be the existing parent + // and this is actually a no-op `with_parent` call. + this.with_parent(parent_def, |this| visit::walk_expr(this, expr)) + }) } fn visit_ty(&mut self, ty: &'a Ty) { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c981abe67c1f..57f19f7ea398 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -187,6 +187,7 @@ struct InvocationParent { parent_def: LocalDefId, impl_trait_context: ImplTraitContext, in_attr: bool, + const_arg_context: ConstArgContext, } impl InvocationParent { @@ -194,6 +195,7 @@ impl InvocationParent { parent_def: CRATE_DEF_ID, impl_trait_context: ImplTraitContext::Existential, in_attr: false, + const_arg_context: ConstArgContext::NonDirect, }; } @@ -204,6 +206,13 @@ enum ImplTraitContext { InBinding, } +#[derive(Copy, Clone, Debug)] +enum ConstArgContext { + Direct, + /// Either inside of an `AnonConst` or not inside a const argument at all. + NonDirect, +} + /// Used for tracking import use types which will be used for redundant import checking. /// /// ### Used::Scope Example diff --git a/tests/ui/const-generics/mgca/struct_expr_with_macros.rs b/tests/ui/const-generics/mgca/struct_expr_with_macros.rs new file mode 100644 index 000000000000..b59a73066488 --- /dev/null +++ b/tests/ui/const-generics/mgca/struct_expr_with_macros.rs @@ -0,0 +1,31 @@ +//@ check-pass + +// Test that the def collector makes `AnonConst`s not `InlineConst`s even +// when the const block is obscured via macros. + +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +macro_rules! const_block { + ($e:expr) => { const { + $e + } } +} + +macro_rules! foo_expr { + ($e:expr) => { Foo { + field: $e, + } } +} + +use std::marker::ConstParamTy; + +#[derive(PartialEq, Eq, ConstParamTy)] +struct Foo { field: u32 } + +fn foo() {} + +fn main() { + foo::<{ Foo { field: const_block!{ 1 + 1 }} }>(); + foo::<{ foo_expr! { const_block! { 1 + 1 }} }>(); +} From 6722805cdc9f0a73aaad56729383510047788320 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 19 Nov 2025 19:30:09 +0000 Subject: [PATCH 110/126] Make `ValTree` recurse through `ty::Const` --- .../src/intrinsics/simd.rs | 17 +- compiler/rustc_codegen_llvm/src/intrinsic.rs | 14 +- .../rustc_codegen_ssa/src/mir/constant.rs | 19 +-- .../rustc_codegen_ssa/src/mir/intrinsic.rs | 2 +- .../src/const_eval/valtrees.rs | 31 ++-- .../src/interpret/intrinsics/simd.rs | 12 +- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/mir/consts.rs | 27 +-- compiler/rustc_middle/src/thir.rs | 8 +- compiler/rustc_middle/src/ty/consts.rs | 42 ++++- .../rustc_middle/src/ty/consts/valtree.rs | 157 +++++++++--------- compiler/rustc_middle/src/ty/context.rs | 5 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- compiler/rustc_middle/src/ty/pattern.rs | 2 +- .../rustc_middle/src/ty/structural_impls.rs | 33 +++- .../src/builder/custom/parse/instruction.rs | 2 +- .../src/builder/matches/mod.rs | 15 +- .../src/builder/matches/test.rs | 2 +- compiler/rustc_mir_build/src/builder/scope.rs | 9 +- compiler/rustc_mir_build/src/thir/constant.rs | 2 +- .../src/thir/pattern/const_to_pat.rs | 28 ++-- compiler/rustc_pattern_analysis/src/rustc.rs | 20 +-- compiler/rustc_symbol_mangling/src/legacy.rs | 2 +- compiler/rustc_transmute/src/lib.rs | 9 +- compiler/rustc_ty_utils/src/consts.rs | 14 +- compiler/rustc_type_ir/src/const_kind.rs | 73 ++++++++ compiler/rustc_type_ir/src/flags.rs | 12 +- compiler/rustc_type_ir/src/inherent.rs | 6 + compiler/rustc_type_ir/src/interner.rs | 3 +- compiler/rustc_type_ir/src/relate.rs | 16 +- ...transmute_infinitely_recursive_type.stderr | 2 +- 31 files changed, 371 insertions(+), 217 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 0bce31beb8b8..38e8d2fa9368 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -143,7 +143,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let total_len = lane_count * 2; - let indexes = idx.iter().map(|idx| idx.unwrap_leaf().to_u32()).collect::>(); + let indexes = idx.iter().map(|idx| idx.to_leaf().to_u32()).collect::>(); for &idx in &indexes { assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len); @@ -961,9 +961,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap(); let ptr_val = ptr.load_scalar(fx); - let alignment = generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] - .unwrap_leaf() - .to_simd_alignment(); + let alignment = + generic_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(); let memflags = match alignment { SimdAlign::Unaligned => MemFlags::new().with_notrap(), @@ -1006,9 +1005,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap(); let ret_lane_layout = fx.layout_of(ret_lane_ty); - let alignment = generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] - .unwrap_leaf() - .to_simd_alignment(); + let alignment = + generic_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(); let memflags = match alignment { SimdAlign::Unaligned => MemFlags::new().with_notrap(), @@ -1059,9 +1057,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let ret_lane_layout = fx.layout_of(ret_lane_ty); let ptr_val = ptr.load_scalar(fx); - let alignment = generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] - .unwrap_leaf() - .to_simd_alignment(); + let alignment = + generic_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(); let memflags = match alignment { SimdAlign::Unaligned => MemFlags::new().with_notrap(), diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 3bc890310cc8..215738828c98 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -351,7 +351,7 @@ fn codegen_intrinsic_call( _ => bug!(), }; let ptr = args[0].immediate(); - let locality = fn_args.const_at(1).to_value().valtree.unwrap_leaf().to_i32(); + let locality = fn_args.const_at(1).to_leaf().to_i32(); self.call_intrinsic( "llvm.prefetch", &[self.val_ty(ptr)], @@ -1533,7 +1533,7 @@ fn vector_mask_to_bitmask<'a, 'll, 'tcx>( } if name == sym::simd_shuffle_const_generic { - let idx = fn_args[2].expect_const().to_value().valtree.unwrap_branch(); + let idx = fn_args[2].expect_const().to_branch(); let n = idx.len() as u64; let (out_len, out_ty) = require_simd!(ret_ty, SimdReturn); @@ -1552,7 +1552,7 @@ fn vector_mask_to_bitmask<'a, 'll, 'tcx>( .iter() .enumerate() .map(|(arg_idx, val)| { - let idx = val.unwrap_leaf().to_i32(); + let idx = val.to_leaf().to_i32(); if idx >= i32::try_from(total_len).unwrap() { bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds { span, @@ -1964,9 +1964,7 @@ fn llvm_alignment<'ll, 'tcx>( // those lanes whose `mask` bit is enabled. // The memory addresses corresponding to the “off” lanes are not accessed. - let alignment = fn_args[3].expect_const().to_value().valtree.unwrap_branch()[0] - .unwrap_leaf() - .to_simd_alignment(); + let alignment = fn_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(); // The element type of the "mask" argument must be a signed integer type of any width let mask_ty = in_ty; @@ -2059,9 +2057,7 @@ fn llvm_alignment<'ll, 'tcx>( // those lanes whose `mask` bit is enabled. // The memory addresses corresponding to the “off” lanes are not accessed. - let alignment = fn_args[3].expect_const().to_value().valtree.unwrap_branch()[0] - .unwrap_leaf() - .to_simd_alignment(); + let alignment = fn_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(); // The element type of the "mask" argument must be a signed integer type of any width let mask_ty = in_ty; diff --git a/compiler/rustc_codegen_ssa/src/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs index 11b6ab3cdf1a..abdac4c7c372 100644 --- a/compiler/rustc_codegen_ssa/src/mir/constant.rs +++ b/compiler/rustc_codegen_ssa/src/mir/constant.rs @@ -77,22 +77,21 @@ pub fn immediate_const_vector( .flatten() .map(|val| { // A SIMD type has a single field, which is an array. - let fields = val.unwrap_branch(); + let fields = val.to_branch(); assert_eq!(fields.len(), 1); - let array = fields[0].unwrap_branch(); + let array = fields[0].to_branch(); // Iterate over the array elements to obtain the values in the vector. let values: Vec<_> = array .iter() .map(|field| { - if let Some(prim) = field.try_to_scalar() { - let layout = bx.layout_of(field_ty); - let BackendRepr::Scalar(scalar) = layout.backend_repr else { - bug!("from_const: invalid ByVal layout: {:#?}", layout); - }; - bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout)) - } else { + let Some(prim) = field.try_to_scalar() else { bug!("field is not a scalar {:?}", field) - } + }; + let layout = bx.layout_of(field_ty); + let BackendRepr::Scalar(scalar) = layout.backend_repr else { + bug!("from_const: invalid ByVal layout: {:#?}", layout); + }; + bx.scalar_to_backend(prim, scalar, bx.immediate_backend_type(layout)) }) .collect(); bx.const_vector(&values) diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs index aeb740118234..f4fae40d8828 100644 --- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -102,7 +102,7 @@ pub fn codegen_intrinsic_call( }; let parse_atomic_ordering = |ord: ty::Value<'tcx>| { - let discr = ord.valtree.unwrap_branch()[0].unwrap_leaf(); + let discr = ord.to_branch()[0].to_leaf(); discr.to_atomic_ordering() }; diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 7c41258ebfe5..b771addb8df5 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -36,13 +36,17 @@ fn branches<'tcx>( // For enums, we prepend their variant index before the variant's fields so we can figure out // the variant again when just seeing a valtree. if let Some(variant) = variant { - branches.push(ty::ValTree::from_scalar_int(*ecx.tcx, variant.as_u32().into())); + branches.push(ty::Const::new_value( + *ecx.tcx, + ty::ValTree::from_scalar_int(*ecx.tcx, variant.as_u32().into()), + ecx.tcx.types.u32, + )); } for i in 0..field_count { let field = ecx.project_field(&place, FieldIdx::from_usize(i)).unwrap(); let valtree = const_to_valtree_inner(ecx, &field, num_nodes)?; - branches.push(valtree); + branches.push(ty::Const::new_value(*ecx.tcx, valtree, field.layout.ty)); } // Have to account for ZSTs here @@ -65,7 +69,7 @@ fn slice_branches<'tcx>( for i in 0..n { let place_elem = ecx.project_index(place, i).unwrap(); let valtree = const_to_valtree_inner(ecx, &place_elem, num_nodes)?; - elems.push(valtree); + elems.push(ty::Const::new_value(*ecx.tcx, valtree, place_elem.layout.ty)); } Ok(ty::ValTree::from_branches(*ecx.tcx, elems)) @@ -200,8 +204,8 @@ fn reconstruct_place_meta<'tcx>( &ObligationCause::dummy(), |ty| ty, || { - let branches = last_valtree.unwrap_branch(); - last_valtree = *branches.last().unwrap(); + let branches = last_valtree.to_branch(); + last_valtree = branches.last().unwrap().to_value().valtree; debug!(?branches, ?last_valtree); }, ); @@ -212,7 +216,7 @@ fn reconstruct_place_meta<'tcx>( }; // Get the number of elements in the unsized field. - let num_elems = last_valtree.unwrap_branch().len(); + let num_elems = last_valtree.to_branch().len(); MemPlaceMeta::Meta(Scalar::from_target_usize(num_elems as u64, &tcx)) } @@ -274,7 +278,7 @@ pub fn valtree_to_const_value<'tcx>( mir::ConstValue::ZeroSized } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(_, _) => { - mir::ConstValue::Scalar(Scalar::Int(cv.valtree.unwrap_leaf())) + mir::ConstValue::Scalar(Scalar::Int(cv.to_leaf())) } ty::Pat(ty, _) => { let cv = ty::Value { valtree: cv.valtree, ty }; @@ -301,12 +305,13 @@ pub fn valtree_to_const_value<'tcx>( || matches!(cv.ty.kind(), ty::Adt(def, _) if def.is_struct())) { // A Scalar tuple/struct; we can avoid creating an allocation. - let branches = cv.valtree.unwrap_branch(); + let branches = cv.to_branch(); // Find the non-ZST field. (There can be aligned ZST!) for (i, &inner_valtree) in branches.iter().enumerate() { let field = layout.field(&LayoutCx::new(tcx, typing_env), i); if !field.is_zst() { - let cv = ty::Value { valtree: inner_valtree, ty: field.ty }; + let cv = + ty::Value { valtree: inner_valtree.to_value().valtree, ty: field.ty }; return valtree_to_const_value(tcx, typing_env, cv); } } @@ -381,7 +386,7 @@ fn valtree_into_mplace<'tcx>( // Zero-sized type, nothing to do. } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(..) => { - let scalar_int = valtree.unwrap_leaf(); + let scalar_int = valtree.to_leaf(); debug!("writing trivial valtree {:?} to place {:?}", scalar_int, place); ecx.write_immediate(Immediate::Scalar(scalar_int.into()), place).unwrap(); } @@ -391,13 +396,13 @@ fn valtree_into_mplace<'tcx>( ecx.write_immediate(imm, place).unwrap(); } ty::Adt(_, _) | ty::Tuple(_) | ty::Array(_, _) | ty::Str | ty::Slice(_) => { - let branches = valtree.unwrap_branch(); + let branches = valtree.to_branch(); // Need to downcast place for enums let (place_adjusted, branches, variant_idx) = match ty.kind() { ty::Adt(def, _) if def.is_enum() => { // First element of valtree corresponds to variant - let scalar_int = branches[0].unwrap_leaf(); + let scalar_int = branches[0].to_leaf(); let variant_idx = VariantIdx::from_u32(scalar_int.to_u32()); let variant = def.variant(variant_idx); debug!(?variant); @@ -425,7 +430,7 @@ fn valtree_into_mplace<'tcx>( }; debug!(?place_inner); - valtree_into_mplace(ecx, &place_inner, *inner_valtree); + valtree_into_mplace(ecx, &place_inner, inner_valtree.to_value().valtree); dump_place(ecx, &place_inner); } diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs index 20de47683122..33a115384a88 100644 --- a/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs +++ b/compiler/rustc_const_eval/src/interpret/intrinsics/simd.rs @@ -545,7 +545,7 @@ enum Op { let (right, right_len) = self.project_to_simd(&args[1])?; let (dest, dest_len) = self.project_to_simd(&dest)?; - let index = generic_args[2].expect_const().to_value().valtree.unwrap_branch(); + let index = generic_args[2].expect_const().to_branch(); let index_len = index.len(); assert_eq!(left_len, right_len); @@ -553,7 +553,7 @@ enum Op { for i in 0..dest_len { let src_index: u64 = - index[usize::try_from(i).unwrap()].unwrap_leaf().to_u32().into(); + index[usize::try_from(i).unwrap()].to_leaf().to_u32().into(); let dest = self.project_index(&dest, i)?; let val = if src_index < left_len { @@ -657,9 +657,7 @@ enum Op { self.check_simd_ptr_alignment( ptr, dest_layout, - generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] - .unwrap_leaf() - .to_simd_alignment(), + generic_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(), )?; for i in 0..dest_len { @@ -689,9 +687,7 @@ enum Op { self.check_simd_ptr_alignment( ptr, args[2].layout, - generic_args[3].expect_const().to_value().valtree.unwrap_branch()[0] - .unwrap_leaf() - .to_simd_alignment(), + generic_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(), )?; for i in 0..vals_len { diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index d1d4c32184ee..4fa39eb83e9e 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -92,7 +92,7 @@ macro_rules! arena_types { [] name_set: rustc_data_structures::unord::UnordSet, [] autodiff_item: rustc_ast::expand::autodiff_attrs::AutoDiffItem, [] ordered_name_set: rustc_data_structures::fx::FxIndexSet, - [] valtree: rustc_middle::ty::ValTreeKind<'tcx>, + [] valtree: rustc_middle::ty::ValTreeKind>, [] stable_order_of_exportable_impls: rustc_data_structures::fx::FxIndexMap, diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index fe352df3b9f0..afe39e4481ef 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -302,15 +302,7 @@ pub fn is_required_const(&self) -> bool { #[inline] pub fn try_to_scalar(self) -> Option { match self { - Const::Ty(_, c) => match c.kind() { - ty::ConstKind::Value(cv) if cv.ty.is_primitive() => { - // A valtree of a type where leaves directly represent the scalar const value. - // Just checking whether it is a leaf is insufficient as e.g. references are leafs - // but the leaf value is the value they point to, not the reference itself! - Some(cv.valtree.unwrap_leaf().into()) - } - _ => None, - }, + Const::Ty(_, c) => c.try_to_scalar(), Const::Val(val, _) => val.try_to_scalar(), Const::Unevaluated(..) => None, } @@ -321,10 +313,7 @@ pub fn try_to_scalar_int(self) -> Option { // This is equivalent to `self.try_to_scalar()?.try_to_int().ok()`, but measurably faster. match self { Const::Val(ConstValue::Scalar(Scalar::Int(x)), _) => Some(x), - Const::Ty(_, c) => match c.kind() { - ty::ConstKind::Value(cv) if cv.ty.is_primitive() => Some(cv.valtree.unwrap_leaf()), - _ => None, - }, + Const::Ty(_, c) => c.try_to_leaf(), _ => None, } } @@ -377,14 +366,10 @@ pub fn try_eval_scalar( tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, ) -> Option { - if let Const::Ty(_, c) = self - && let ty::ConstKind::Value(cv) = c.kind() - && cv.ty.is_primitive() - { - // Avoid the `valtree_to_const_val` query. Can only be done on primitive types that - // are valtree leaves, and *not* on references. (References should return the - // pointer here, which valtrees don't represent.) - Some(cv.valtree.unwrap_leaf().into()) + if let Const::Ty(_, c) = self { + // We don't evaluate anything for type system constants as normalizing + // the MIR will handle this for us + c.try_to_scalar() } else { self.eval(tcx, typing_env, DUMMY_SP).ok()?.try_to_scalar() } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index 3d893bf75e0b..31745cae3c06 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -928,7 +928,7 @@ pub fn is_full_range(&self, tcx: TyCtxt<'tcx>) -> Option { let lo_is_min = match self.lo { PatRangeBoundary::NegInfinity => true, PatRangeBoundary::Finite(value) => { - let lo = value.try_to_scalar_int().unwrap().to_bits(size) ^ bias; + let lo = value.to_leaf().to_bits(size) ^ bias; lo <= min } PatRangeBoundary::PosInfinity => false, @@ -937,7 +937,7 @@ pub fn is_full_range(&self, tcx: TyCtxt<'tcx>) -> Option { let hi_is_max = match self.hi { PatRangeBoundary::NegInfinity => false, PatRangeBoundary::Finite(value) => { - let hi = value.try_to_scalar_int().unwrap().to_bits(size) ^ bias; + let hi = value.to_leaf().to_bits(size) ^ bias; hi > max || hi == max && self.end == RangeEnd::Included } PatRangeBoundary::PosInfinity => true, @@ -1029,7 +1029,7 @@ pub fn as_finite(self) -> Option> { } pub fn to_bits(self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> u128 { match self { - Self::Finite(value) => value.try_to_scalar_int().unwrap().to_bits_unchecked(), + Self::Finite(value) => value.to_leaf().to_bits_unchecked(), Self::NegInfinity => { // Unwrap is ok because the type is known to be numeric. ty.numeric_min_and_max_as_bits(tcx).unwrap().0 @@ -1057,7 +1057,7 @@ pub fn compare_with(self, other: Self, ty: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Optio // many ranges such as '\u{037A}'..='\u{037F}', and chars can be compared // in this way. (Finite(a), Finite(b)) if matches!(ty.kind(), ty::Int(_) | ty::Uint(_) | ty::Char) => { - if let (Some(a), Some(b)) = (a.try_to_scalar_int(), b.try_to_scalar_int()) { + if let (Some(a), Some(b)) = (a.try_to_leaf(), b.try_to_leaf()) { let sz = ty.primitive_size(tcx); let cmp = match ty.kind() { ty::Uint(_) | ty::Char => a.to_uint(sz).cmp(&b.to_uint(sz)), diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 787ea5f9363d..da3caf0bb210 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -6,6 +6,7 @@ use rustc_type_ir::walk::TypeWalker; use rustc_type_ir::{self as ir, TypeFlags, WithCachedTypeInfo}; +use crate::mir::interpret::Scalar; use crate::ty::{self, Ty, TyCtxt}; mod int; @@ -260,7 +261,7 @@ pub fn to_value(self) -> ty::Value<'tcx> { /// Attempts to convert to a value. /// - /// Note that this does not evaluate the constant. + /// Note that this does not normalize the constant. pub fn try_to_value(self) -> Option> { match self.kind() { ty::ConstKind::Value(cv) => Some(cv), @@ -268,6 +269,45 @@ pub fn try_to_value(self) -> Option> { } } + /// Converts to a `ValTreeKind::Leaf` value, `panic`'ing + /// if this constant is some other kind. + /// + /// Note that this does not normalize the constant. + #[inline] + pub fn to_leaf(self) -> ScalarInt { + self.to_value().to_leaf() + } + + /// Converts to a `ValTreeKind::Branch` value, `panic`'ing + /// if this constant is some other kind. + /// + /// Note that this does not normalize the constant. + #[inline] + pub fn to_branch(self) -> &'tcx [ty::Const<'tcx>] { + self.to_value().to_branch() + } + + /// Attempts to convert to a `ValTreeKind::Leaf` value. + /// + /// Note that this does not normalize the constant. + pub fn try_to_leaf(self) -> Option { + self.try_to_value()?.try_to_leaf() + } + + /// Attempts to convert to a `ValTreeKind::Leaf` value. + /// + /// Note that this does not normalize the constant. + pub fn try_to_scalar(self) -> Option { + self.try_to_leaf().map(Scalar::Int) + } + + /// Attempts to convert to a `ValTreeKind::Branch` value. + /// + /// Note that this does not normalize the constant. + pub fn try_to_branch(self) -> Option<&'tcx [ty::Const<'tcx>]> { + self.try_to_value()?.try_to_branch() + } + /// Convenience method to extract the value of a usize constant, /// useful to get the length of an array type. /// diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index a14e47d70821..8afee2dfe3bc 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -3,89 +3,38 @@ use rustc_data_structures::intern::Interned; use rustc_hir::def::Namespace; -use rustc_macros::{HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable}; +use rustc_macros::{ + HashStable, Lift, TyDecodable, TyEncodable, TypeFoldable, TypeVisitable, extension, +}; use super::ScalarInt; use crate::mir::interpret::{ErrorHandled, Scalar}; use crate::ty::print::{FmtPrinter, PrettyPrinter}; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::{self, Ty, TyCtxt, ValTreeKind}; -/// This datastructure is used to represent the value of constants used in the type system. -/// -/// We explicitly choose a different datastructure from the way values are processed within -/// CTFE, as in the type system equal values (according to their `PartialEq`) must also have -/// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa. -/// Since CTFE uses `AllocId` to represent pointers, it often happens that two different -/// `AllocId`s point to equal values. So we may end up with different representations for -/// two constants whose value is `&42`. Furthermore any kind of struct that has padding will -/// have arbitrary values within that padding, even if the values of the struct are the same. -/// -/// `ValTree` does not have this problem with representation, as it only contains integers or -/// lists of (nested) `ValTree`. -#[derive(Clone, Debug, Hash, Eq, PartialEq)] -#[derive(HashStable, TyEncodable, TyDecodable)] -pub enum ValTreeKind<'tcx> { - /// integers, `bool`, `char` are represented as scalars. - /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values - /// of these types have the same representation. - Leaf(ScalarInt), - - //SliceOrStr(ValSlice<'tcx>), - // don't use SliceOrStr for now - /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by - /// listing their fields' values in order. - /// - /// Enums are represented by storing their variant index as a u32 field, followed by all - /// the fields of the variant. - /// - /// ZST types are represented as an empty slice. - Branch(Box<[ValTree<'tcx>]>), -} - -impl<'tcx> ValTreeKind<'tcx> { - #[inline] - pub fn unwrap_leaf(&self) -> ScalarInt { - match self { - Self::Leaf(s) => *s, - _ => bug!("expected leaf, got {:?}", self), - } - } - - #[inline] - pub fn unwrap_branch(&self) -> &[ValTree<'tcx>] { - match self { - Self::Branch(branch) => &**branch, - _ => bug!("expected branch, got {:?}", self), - } - } - - pub fn try_to_scalar(&self) -> Option { - self.try_to_scalar_int().map(Scalar::Int) - } - - pub fn try_to_scalar_int(&self) -> Option { - match self { - Self::Leaf(s) => Some(*s), - Self::Branch(_) => None, - } - } - - pub fn try_to_branch(&self) -> Option<&[ValTree<'tcx>]> { - match self { - Self::Branch(branch) => Some(&**branch), - Self::Leaf(_) => None, - } +#[extension(pub trait ValTreeKindExt<'tcx>)] +impl<'tcx> ty::ValTreeKind> { + fn try_to_scalar(&self) -> Option { + self.try_to_leaf().map(Scalar::Int) } } /// An interned valtree. Use this rather than `ValTreeKind`, whenever possible. /// -/// See the docs of [`ValTreeKind`] or the [dev guide] for an explanation of this type. +/// See the docs of [`ty::ValTreeKind`] or the [dev guide] for an explanation of this type. /// /// [dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html#valtrees #[derive(Copy, Clone, Hash, Eq, PartialEq)] #[derive(HashStable)] -pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ValTreeKind<'tcx>>); +// FIXME(mgca): Try not interning here. We already intern `ty::Const` which `ValTreeKind` +// recurses through +pub struct ValTree<'tcx>(pub(crate) Interned<'tcx, ty::ValTreeKind>>); + +impl<'tcx> rustc_type_ir::inherent::ValTree> for ValTree<'tcx> { + fn kind(&self) -> &ty::ValTreeKind> { + &self + } +} impl<'tcx> ValTree<'tcx> { /// Returns the zero-sized valtree: `Branch([])`. @@ -94,28 +43,33 @@ pub fn zst(tcx: TyCtxt<'tcx>) -> Self { } pub fn is_zst(self) -> bool { - matches!(*self, ValTreeKind::Branch(box [])) + matches!(*self, ty::ValTreeKind::Branch(box [])) } pub fn from_raw_bytes(tcx: TyCtxt<'tcx>, bytes: &[u8]) -> Self { - let branches = bytes.iter().map(|&b| Self::from_scalar_int(tcx, b.into())); + let branches = bytes.iter().map(|&b| { + ty::Const::new_value(tcx, Self::from_scalar_int(tcx, b.into()), tcx.types.u8) + }); Self::from_branches(tcx, branches) } - pub fn from_branches(tcx: TyCtxt<'tcx>, branches: impl IntoIterator) -> Self { - tcx.intern_valtree(ValTreeKind::Branch(branches.into_iter().collect())) + pub fn from_branches( + tcx: TyCtxt<'tcx>, + branches: impl IntoIterator>, + ) -> Self { + tcx.intern_valtree(ty::ValTreeKind::Branch(branches.into_iter().collect())) } pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt) -> Self { - tcx.intern_valtree(ValTreeKind::Leaf(i)) + tcx.intern_valtree(ty::ValTreeKind::Leaf(i)) } } impl<'tcx> Deref for ValTree<'tcx> { - type Target = &'tcx ValTreeKind<'tcx>; + type Target = &'tcx ty::ValTreeKind>; #[inline] - fn deref(&self) -> &&'tcx ValTreeKind<'tcx> { + fn deref(&self) -> &&'tcx ty::ValTreeKind> { &self.0.0 } } @@ -154,7 +108,7 @@ pub fn try_to_bits(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> let (ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Float(_)) = self.ty.kind() else { return None; }; - let scalar = self.valtree.try_to_scalar_int()?; + let scalar = self.try_to_leaf()?; let input = typing_env.with_post_analysis_normalized(tcx).as_query_input(self.ty); let size = tcx.layout_of(input).ok()?.size; Some(scalar.to_bits(size)) @@ -164,14 +118,14 @@ pub fn try_to_bool(self) -> Option { if !self.ty.is_bool() { return None; } - self.valtree.try_to_scalar_int()?.try_to_bool().ok() + self.try_to_leaf()?.try_to_bool().ok() } pub fn try_to_target_usize(self, tcx: TyCtxt<'tcx>) -> Option { if !self.ty.is_usize() { return None; } - self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx)) + self.try_to_leaf().map(|s| s.to_target_usize(tcx)) } /// Get the values inside the ValTree as a slice of bytes. This only works for @@ -192,9 +146,48 @@ pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>) -> Option<&'tcx [u8]> { _ => return None, } - Some(tcx.arena.alloc_from_iter( - self.valtree.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().to_u8()), - )) + Some(tcx.arena.alloc_from_iter(self.to_branch().into_iter().map(|ct| ct.to_leaf().to_u8()))) + } + + /// Converts to a `ValTreeKind::Leaf` value, `panic`'ing + /// if this constant is some other kind. + #[inline] + pub fn to_leaf(self) -> ScalarInt { + match &**self.valtree { + ValTreeKind::Leaf(s) => *s, + ValTreeKind::Branch(..) => bug!("expected leaf, got {:?}", self), + } + } + + /// Converts to a `ValTreeKind::Branch` value, `panic`'ing + /// if this constant is some other kind. + #[inline] + pub fn to_branch(self) -> &'tcx [ty::Const<'tcx>] { + match &**self.valtree { + ValTreeKind::Branch(branch) => &**branch, + ValTreeKind::Leaf(..) => bug!("expected branch, got {:?}", self), + } + } + + /// Attempts to convert to a `ValTreeKind::Leaf` value. + pub fn try_to_leaf(self) -> Option { + match &**self.valtree { + ValTreeKind::Leaf(s) => Some(*s), + ValTreeKind::Branch(_) => None, + } + } + + /// Attempts to convert to a `ValTreeKind::Leaf` value. + pub fn try_to_scalar(&self) -> Option { + self.try_to_leaf().map(Scalar::Int) + } + + /// Attempts to convert to a `ValTreeKind::Branch` value. + pub fn try_to_branch(self) -> Option<&'tcx [ty::Const<'tcx>]> { + match &**self.valtree { + ValTreeKind::Branch(branch) => Some(&**branch), + ValTreeKind::Leaf(_) => None, + } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 9e4692b96418..000e7c16098e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -165,6 +165,7 @@ fn with_cached_task(self, task: impl FnOnce() -> T) -> (T, DepNodeIndex) { type ValueConst = ty::Value<'tcx>; type ExprConst = ty::Expr<'tcx>; type ValTree = ty::ValTree<'tcx>; + type ScalarInt = ty::ScalarInt; type Region = Region<'tcx>; type EarlyParamRegion = ty::EarlyParamRegion; @@ -954,7 +955,7 @@ pub struct CtxtInterners<'tcx> { fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, captures: InternedSet<'tcx, List<&'tcx ty::CapturedPlace<'tcx>>>, - valtree: InternedSet<'tcx, ty::ValTreeKind<'tcx>>, + valtree: InternedSet<'tcx, ty::ValTreeKind>>, patterns: InternedSet<'tcx, List>>, outlives: InternedSet<'tcx, List>>, } @@ -2777,7 +2778,7 @@ impl<'tcx> TyCtxt<'tcx> { // crate only, and have a corresponding `mk_` function. direct_interners! { region: pub(crate) intern_region(RegionKind<'tcx>): Region -> Region<'tcx>, - valtree: pub(crate) intern_valtree(ValTreeKind<'tcx>): ValTree -> ValTree<'tcx>, + valtree: pub(crate) intern_valtree(ValTreeKind>): ValTree -> ValTree<'tcx>, pat: pub mk_pat(PatternKind<'tcx>): Pattern -> Pattern<'tcx>, const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutData): Layout -> Layout<'tcx>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 60b6b7024dcd..5cc5ab0d5268 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -77,7 +77,7 @@ }; pub use self::consts::{ AnonConstKind, AtomicOrdering, Const, ConstInt, ConstKind, ConstToValTreeResult, Expr, - ExprKind, ScalarInt, SimdAlign, UnevaluatedConst, ValTree, ValTreeKind, Value, + ExprKind, ScalarInt, SimdAlign, UnevaluatedConst, ValTree, ValTreeKindExt, Value, }; pub use self::context::{ CtxtInterners, CurrentGcx, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, tls, diff --git a/compiler/rustc_middle/src/ty/pattern.rs b/compiler/rustc_middle/src/ty/pattern.rs index 335e5c064743..6acf0aff800f 100644 --- a/compiler/rustc_middle/src/ty/pattern.rs +++ b/compiler/rustc_middle/src/ty/pattern.rs @@ -72,7 +72,7 @@ fn print(t: &PatternKind<'tcx>, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{start}")?; if let Some(c) = end.try_to_value() { - let end = c.valtree.unwrap_leaf(); + let end = c.to_leaf(); let size = end.size(); let max = match c.ty.kind() { ty::Int(_) => { diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 5126d902a6d5..1a5a3f3965fa 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -256,8 +256,8 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { crate::ty::AssocItem, crate::ty::AssocKind, crate::ty::BoundRegion, + crate::ty::ScalarInt, crate::ty::UserTypeAnnotationIndex, - crate::ty::ValTree<'tcx>, crate::ty::abstract_const::NotConstEvaluatable, crate::ty::adjustment::AutoBorrowMutability, crate::ty::adjustment::PointerCoercion, @@ -697,6 +697,37 @@ fn super_visit_with>>(&self, visitor: &mut V) -> V:: } } +impl<'tcx> TypeVisitable> for ty::ValTree<'tcx> { + fn visit_with>>(&self, visitor: &mut V) -> V::Result { + let inner: &ty::ValTreeKind> = &*self; + inner.visit_with(visitor) + } +} + +impl<'tcx> TypeFoldable> for ty::ValTree<'tcx> { + fn try_fold_with>>( + self, + folder: &mut F, + ) -> Result { + let inner: &ty::ValTreeKind> = &*self; + let new_inner = inner.clone().try_fold_with(folder)?; + + if inner == &new_inner { + Ok(self) + } else { + let valtree = folder.cx().intern_valtree(new_inner); + Ok(valtree) + } + } + + fn fold_with>>(self, folder: &mut F) -> Self { + let inner: &ty::ValTreeKind> = &*self; + let new_inner = inner.clone().fold_with(folder); + + if inner == &new_inner { self } else { folder.cx().intern_valtree(new_inner) } + } +} + impl<'tcx> TypeVisitable> for rustc_span::ErrorGuaranteed { fn visit_with>>(&self, visitor: &mut V) -> V::Result { visitor.visit_error(*self) diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index b221318bf0b1..ddaa61c6cc91 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -157,7 +157,7 @@ fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult { }); } }; - values.push(value.valtree.unwrap_leaf().to_bits_unchecked()); + values.push(value.to_leaf().to_bits_unchecked()); targets.push(self.parse_block(arm.body)?); } diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 8897ca7c7210..465b1db9a164 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -2935,7 +2935,8 @@ fn static_pattern_match_inner( bug!("malformed valtree for an enum") }; - let ValTreeKind::Leaf(actual_variant_idx) = ***actual_variant_idx else { + let ValTreeKind::Leaf(actual_variant_idx) = *actual_variant_idx.to_value().valtree + else { bug!("malformed valtree for an enum") }; @@ -2943,7 +2944,7 @@ fn static_pattern_match_inner( } Constructor::IntRange(int_range) => { let size = pat.ty().primitive_size(self.tcx); - let actual_int = valtree.unwrap_leaf().to_bits(size); + let actual_int = valtree.to_leaf().to_bits(size); let actual_int = if pat.ty().is_signed() { MaybeInfiniteInt::new_finite_int(actual_int, size.bits()) } else { @@ -2951,33 +2952,33 @@ fn static_pattern_match_inner( }; IntRange::from_singleton(actual_int).is_subrange(int_range) } - Constructor::Bool(pattern_value) => match valtree.unwrap_leaf().try_to_bool() { + Constructor::Bool(pattern_value) => match valtree.to_leaf().try_to_bool() { Ok(actual_value) => *pattern_value == actual_value, Err(()) => bug!("bool value with invalid bits"), }, Constructor::F16Range(l, h, end) => { - let actual = valtree.unwrap_leaf().to_f16(); + let actual = valtree.to_leaf().to_f16(); match end { RangeEnd::Included => (*l..=*h).contains(&actual), RangeEnd::Excluded => (*l..*h).contains(&actual), } } Constructor::F32Range(l, h, end) => { - let actual = valtree.unwrap_leaf().to_f32(); + let actual = valtree.to_leaf().to_f32(); match end { RangeEnd::Included => (*l..=*h).contains(&actual), RangeEnd::Excluded => (*l..*h).contains(&actual), } } Constructor::F64Range(l, h, end) => { - let actual = valtree.unwrap_leaf().to_f64(); + let actual = valtree.to_leaf().to_f64(); match end { RangeEnd::Included => (*l..=*h).contains(&actual), RangeEnd::Excluded => (*l..*h).contains(&actual), } } Constructor::F128Range(l, h, end) => { - let actual = valtree.unwrap_leaf().to_f128(); + let actual = valtree.to_leaf().to_f128(); match end { RangeEnd::Included => (*l..=*h).contains(&actual), RangeEnd::Excluded => (*l..*h).contains(&actual), diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 402587bff7e8..2401bc6648ed 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -116,7 +116,7 @@ pub(super) fn perform_test( let switch_targets = SwitchTargets::new( target_blocks.iter().filter_map(|(&branch, &block)| { if let TestBranch::Constant(value) = branch { - let bits = value.valtree.unwrap_leaf().to_bits_unchecked(); + let bits = value.to_leaf().to_bits_unchecked(); Some((bits, block)) } else { None diff --git a/compiler/rustc_mir_build/src/builder/scope.rs b/compiler/rustc_mir_build/src/builder/scope.rs index a176f3e49a50..981704052536 100644 --- a/compiler/rustc_mir_build/src/builder/scope.rs +++ b/compiler/rustc_mir_build/src/builder/scope.rs @@ -897,7 +897,14 @@ pub(crate) fn break_const_continuable_scope( self.tcx, ValTree::from_branches( self.tcx, - [ValTree::from_scalar_int(self.tcx, variant_index.as_u32().into())], + [ty::Const::new_value( + self.tcx, + ValTree::from_scalar_int( + self.tcx, + variant_index.as_u32().into(), + ), + self.tcx.types.u32, + )], ), self.thir[value].ty, ), diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index 6e071fb344c4..563212a51f31 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -63,7 +63,7 @@ pub(crate) fn lit_to_const<'tcx>( // A CStr is a newtype around a byte slice, so we create the inner slice here. // We need a branch for each "level" of the data structure. let bytes = ty::ValTree::from_raw_bytes(tcx, byte_sym.as_byte_str()); - ty::ValTree::from_branches(tcx, [bytes]) + ty::ValTree::from_branches(tcx, [ty::Const::new_value(tcx, bytes, *inner_ty)]) } (ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => { let scalar_int = trunc(n.get(), *ui); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index c3c4c455b965..ce4c89a8eb2e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -239,14 +239,14 @@ fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box> { return self.mk_err(tcx.dcx().create_err(err), ty); } ty::Adt(adt_def, args) if adt_def.is_enum() => { - let (&variant_index, fields) = cv.unwrap_branch().split_first().unwrap(); - let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().to_u32()); + let (&variant_index, fields) = cv.to_branch().split_first().unwrap(); + let variant_index = VariantIdx::from_u32(variant_index.to_leaf().to_u32()); PatKind::Variant { adt_def: *adt_def, args, variant_index, subpatterns: self.field_pats( - fields.iter().copied().zip( + fields.iter().map(|ct| ct.to_value().valtree).zip( adt_def.variants()[variant_index] .fields .iter() @@ -258,28 +258,32 @@ fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box> { ty::Adt(def, args) => { assert!(!def.is_union()); // Valtree construction would never succeed for unions. PatKind::Leaf { - subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip( - def.non_enum_variant().fields.iter().map(|field| field.ty(tcx, args)), - )), + subpatterns: self.field_pats( + cv.to_branch().iter().map(|ct| ct.to_value().valtree).zip( + def.non_enum_variant().fields.iter().map(|field| field.ty(tcx, args)), + ), + ), } } ty::Tuple(fields) => PatKind::Leaf { - subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(fields.iter())), + subpatterns: self.field_pats( + cv.to_branch().iter().map(|ct| ct.to_value().valtree).zip(fields.iter()), + ), }, ty::Slice(elem_ty) => PatKind::Slice { prefix: cv - .unwrap_branch() + .to_branch() .iter() - .map(|val| *self.valtree_to_pat(*val, *elem_ty)) + .map(|val| *self.valtree_to_pat(val.to_value().valtree, *elem_ty)) .collect(), slice: None, suffix: Box::new([]), }, ty::Array(elem_ty, _) => PatKind::Array { prefix: cv - .unwrap_branch() + .to_branch() .iter() - .map(|val| *self.valtree_to_pat(*val, *elem_ty)) + .map(|val| *self.valtree_to_pat(val.to_value().valtree, *elem_ty)) .collect(), slice: None, suffix: Box::new([]), @@ -312,7 +316,7 @@ fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box> { } }, ty::Float(flt) => { - let v = cv.unwrap_leaf(); + let v = cv.to_leaf(); let is_nan = match flt { ty::FloatTy::F16 => v.to_f16().is_nan(), ty::FloatTy::F32 => v.to_f32().is_nan(), diff --git a/compiler/rustc_pattern_analysis/src/rustc.rs b/compiler/rustc_pattern_analysis/src/rustc.rs index df86233c2b05..d66c303b1726 100644 --- a/compiler/rustc_pattern_analysis/src/rustc.rs +++ b/compiler/rustc_pattern_analysis/src/rustc.rs @@ -440,7 +440,7 @@ pub(crate) fn lower_pat_range_bdy( match bdy { PatRangeBoundary::NegInfinity => MaybeInfiniteInt::NegInfinity, PatRangeBoundary::Finite(value) => { - let bits = value.try_to_scalar_int().unwrap().to_bits_unchecked(); + let bits = value.to_leaf().to_bits_unchecked(); match *ty.kind() { ty::Int(ity) => { let size = Integer::from_int_ty(&self.tcx, ity).size().bits(); @@ -540,7 +540,7 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> { } ty::Char | ty::Int(_) | ty::Uint(_) => { ctor = { - let bits = value.valtree.unwrap_leaf().to_bits_unchecked(); + let bits = value.to_leaf().to_bits_unchecked(); let x = match *ty.kind() { ty::Int(ity) => { let size = Integer::from_int_ty(&cx.tcx, ity).size().bits(); @@ -555,7 +555,7 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> { } ty::Float(ty::FloatTy::F16) => { use rustc_apfloat::Float; - let bits = value.valtree.unwrap_leaf().to_u16(); + let bits = value.to_leaf().to_u16(); let value = rustc_apfloat::ieee::Half::from_bits(bits.into()); ctor = F16Range(value, value, RangeEnd::Included); fields = vec![]; @@ -563,7 +563,7 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> { } ty::Float(ty::FloatTy::F32) => { use rustc_apfloat::Float; - let bits = value.valtree.unwrap_leaf().to_u32(); + let bits = value.to_leaf().to_u32(); let value = rustc_apfloat::ieee::Single::from_bits(bits.into()); ctor = F32Range(value, value, RangeEnd::Included); fields = vec![]; @@ -571,7 +571,7 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> { } ty::Float(ty::FloatTy::F64) => { use rustc_apfloat::Float; - let bits = value.valtree.unwrap_leaf().to_u64(); + let bits = value.to_leaf().to_u64(); let value = rustc_apfloat::ieee::Double::from_bits(bits.into()); ctor = F64Range(value, value, RangeEnd::Included); fields = vec![]; @@ -579,7 +579,7 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> { } ty::Float(ty::FloatTy::F128) => { use rustc_apfloat::Float; - let bits = value.valtree.unwrap_leaf().to_u128(); + let bits = value.to_leaf().to_u128(); let value = rustc_apfloat::ieee::Quad::from_bits(bits); ctor = F128Range(value, value, RangeEnd::Included); fields = vec![]; @@ -623,12 +623,8 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> { } ty::Float(fty) => { use rustc_apfloat::Float; - let lo = lo - .as_finite() - .map(|c| c.try_to_scalar_int().unwrap().to_bits_unchecked()); - let hi = hi - .as_finite() - .map(|c| c.try_to_scalar_int().unwrap().to_bits_unchecked()); + let lo = lo.as_finite().map(|c| c.to_leaf().to_bits_unchecked()); + let hi = hi.as_finite().map(|c| c.to_leaf().to_bits_unchecked()); match fty { ty::FloatTy::F16 => { use rustc_apfloat::ieee::Half; diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index ee2621af8428..ea16231880e2 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -293,7 +293,7 @@ fn print_const(&mut self, ct: ty::Const<'tcx>) -> Result<(), PrintError> { ty::ConstKind::Value(cv) if cv.ty.is_integral() => { // The `pretty_print_const` formatting depends on -Zverbose-internals // flag, so we cannot reuse it here. - let scalar = cv.valtree.unwrap_leaf(); + let scalar = cv.to_leaf(); let signed = matches!(cv.ty.kind(), ty::Int(_)); write!( self, diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs index 36281ff16bce..58cb2eb6556e 100644 --- a/compiler/rustc_transmute/src/lib.rs +++ b/compiler/rustc_transmute/src/lib.rs @@ -129,10 +129,7 @@ pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option { use rustc_middle::ty::ScalarInt; use rustc_span::sym; - let Some(cv) = ct.try_to_value() else { - return None; - }; - + let cv = ct.try_to_value()?; let adt_def = cv.ty.ty_adt_def()?; if !tcx.is_lang_item(adt_def.did(), LangItem::TransmuteOpts) { @@ -149,7 +146,7 @@ pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option { } let variant = adt_def.non_enum_variant(); - let fields = cv.valtree.unwrap_branch(); + let fields = cv.to_branch(); let get_field = |name| { let (field_idx, _) = variant @@ -158,7 +155,7 @@ pub fn from_const<'tcx>(tcx: TyCtxt<'tcx>, ct: Const<'tcx>) -> Option { .enumerate() .find(|(_, field_def)| name == field_def.name) .unwrap_or_else(|| panic!("There were no fields named `{name}`.")); - fields[field_idx].unwrap_leaf() == ScalarInt::TRUE + fields[field_idx].to_leaf() == ScalarInt::TRUE }; Some(Self { diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 4b19d0f16d78..d8d5b7fc75cc 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -25,15 +25,14 @@ fn destructure_const<'tcx>( let ty::ConstKind::Value(cv) = const_.kind() else { bug!("cannot destructure constant {:?}", const_) }; - - let branches = cv.valtree.unwrap_branch(); + let branches = cv.to_branch(); let (fields, variant) = match cv.ty.kind() { ty::Array(inner_ty, _) | ty::Slice(inner_ty) => { // construct the consts for the elements of the array/slice let field_consts = branches .iter() - .map(|b| ty::Const::new_value(tcx, *b, *inner_ty)) + .map(|b| ty::Const::new_value(tcx, b.to_value().valtree, *inner_ty)) .collect::>(); debug!(?field_consts); @@ -43,7 +42,7 @@ fn destructure_const<'tcx>( ty::Adt(def, args) => { let (variant_idx, branches) = if def.is_enum() { let (head, rest) = branches.split_first().unwrap(); - (VariantIdx::from_u32(head.unwrap_leaf().to_u32()), rest) + (VariantIdx::from_u32(head.to_leaf().to_u32()), rest) } else { (FIRST_VARIANT, branches) }; @@ -52,7 +51,8 @@ fn destructure_const<'tcx>( for (field, field_valtree) in iter::zip(fields, branches) { let field_ty = field.ty(tcx, args); - let field_const = ty::Const::new_value(tcx, *field_valtree, field_ty); + let field_const = + ty::Const::new_value(tcx, field_valtree.to_value().valtree, field_ty); field_consts.push(field_const); } debug!(?field_consts); @@ -61,7 +61,9 @@ fn destructure_const<'tcx>( } ty::Tuple(elem_tys) => { let fields = iter::zip(*elem_tys, branches) - .map(|(elem_ty, elem_valtree)| ty::Const::new_value(tcx, *elem_valtree, elem_ty)) + .map(|(elem_ty, elem_valtree)| { + ty::Const::new_value(tcx, elem_valtree.to_value().valtree, elem_ty) + }) .collect::>(); (fields, None) diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index f315e8b3e11c..a5c40d4eb199 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -127,3 +127,76 @@ fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { } } } + +/// This datastructure is used to represent the value of constants used in the type system. +/// +/// We explicitly choose a different datastructure from the way values are processed within +/// CTFE, as in the type system equal values (according to their `PartialEq`) must also have +/// equal representation (`==` on the rustc data structure, e.g. `ValTree`) and vice versa. +/// Since CTFE uses `AllocId` to represent pointers, it often happens that two different +/// `AllocId`s point to equal values. So we may end up with different representations for +/// two constants whose value is `&42`. Furthermore any kind of struct that has padding will +/// have arbitrary values within that padding, even if the values of the struct are the same. +/// +/// `ValTree` does not have this problem with representation, as it only contains integers or +/// lists of (nested) `ty::Const`s (which may indirectly contain more `ValTree`s). +#[derive_where(Clone, Debug, Hash, Eq, PartialEq; I: Interner)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr( + feature = "nightly", + derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) +)] +pub enum ValTreeKind { + /// integers, `bool`, `char` are represented as scalars. + /// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values + /// of these types have the same representation. + Leaf(I::ScalarInt), + + /// The fields of any kind of aggregate. Structs, tuples and arrays are represented by + /// listing their fields' values in order. + /// + /// Enums are represented by storing their variant index as a u32 field, followed by all + /// the fields of the variant. + /// + /// ZST types are represented as an empty slice. + // FIXME(mgca): Use a `List` here instead of a boxed slice + Branch(Box<[I::Const]>), +} + +impl ValTreeKind { + /// Converts to a `ValTreeKind::Leaf` value, `panic`'ing + /// if this valtree is some other kind. + #[inline] + pub fn to_leaf(&self) -> I::ScalarInt { + match self { + ValTreeKind::Leaf(s) => *s, + ValTreeKind::Branch(..) => panic!("expected leaf, got {:?}", self), + } + } + + /// Converts to a `ValTreeKind::Branch` value, `panic`'ing + /// if this valtree is some other kind. + #[inline] + pub fn to_branch(&self) -> &[I::Const] { + match self { + ValTreeKind::Branch(branch) => &**branch, + ValTreeKind::Leaf(..) => panic!("expected branch, got {:?}", self), + } + } + + /// Attempts to convert to a `ValTreeKind::Leaf` value. + pub fn try_to_leaf(&self) -> Option { + match self { + ValTreeKind::Leaf(s) => Some(*s), + ValTreeKind::Branch(_) => None, + } + } + + /// Attempts to convert to a `ValTreeKind::Branch` value. + pub fn try_to_branch(&self) -> Option<&[I::Const]> { + match self { + ValTreeKind::Branch(branch) => Some(&**branch), + ValTreeKind::Leaf(_) => None, + } + } +} diff --git a/compiler/rustc_type_ir/src/flags.rs b/compiler/rustc_type_ir/src/flags.rs index 34b030ee768b..2c1fc7decc3e 100644 --- a/compiler/rustc_type_ir/src/flags.rs +++ b/compiler/rustc_type_ir/src/flags.rs @@ -477,7 +477,17 @@ fn add_const_kind(&mut self, c: &ty::ConstKind) { ty::ConstKind::Placeholder(_) => { self.add_flags(TypeFlags::HAS_CT_PLACEHOLDER); } - ty::ConstKind::Value(cv) => self.add_ty(cv.ty()), + ty::ConstKind::Value(cv) => { + self.add_ty(cv.ty()); + match cv.valtree().kind() { + ty::ValTreeKind::Leaf(_) => (), + ty::ValTreeKind::Branch(cts) => { + for ct in cts { + self.add_const(*ct); + } + } + } + } ty::ConstKind::Expr(e) => self.add_args(e.args().as_slice()), ty::ConstKind::Error(_) => self.add_flags(TypeFlags::HAS_ERROR), } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 75ba0231d98c..16f837141e97 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -292,6 +292,12 @@ pub trait ValueConst>: Copy + Debug + Hash + Eq { fn valtree(self) -> I::ValTree; } +// FIXME(mgca): This trait can be removed once we're not using a `Box` in `Branch` +pub trait ValTree>: Copy + Debug + Hash + Eq { + // This isnt' `IntoKind` because then we can't return a reference + fn kind(&self) -> &ty::ValTreeKind; +} + pub trait ExprConst>: Copy + Debug + Hash + Eq + Relate { fn args(self) -> I::GenericArgs; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 3884f29a4fc8..03cf738c0598 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -153,7 +153,8 @@ fn mk_tracked( type PlaceholderConst: PlaceholderConst; type ValueConst: ValueConst; type ExprConst: ExprConst; - type ValTree: Copy + Debug + Hash + Eq; + type ValTree: ValTree; + type ScalarInt: Copy + Debug + Hash + Eq; // Kinds of regions type Region: Region; diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 4f843503d1af..4954ebc51cfc 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -582,13 +582,27 @@ pub fn structurally_relate_consts>( } (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2, (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => { - a_val.valtree() == b_val.valtree() + match (a_val.valtree().kind(), b_val.valtree().kind()) { + (ty::ValTreeKind::Leaf(scalar_a), ty::ValTreeKind::Leaf(scalar_b)) => { + scalar_a == scalar_b + } + (ty::ValTreeKind::Branch(branches_a), ty::ValTreeKind::Branch(branches_b)) + if branches_a.len() == branches_b.len() => + { + branches_a + .into_iter() + .zip(branches_b) + .all(|(a, b)| relation.relate(*a, *b).is_ok()) + } + _ => false, + } } // While this is slightly incorrect, it shouldn't matter for `min_const_generics` // and is the better alternative to waiting until `generic_const_exprs` can // be stabilized. (ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu)) if au.def == bu.def => { + // FIXME(mgca): remove this if cfg!(debug_assertions) { let a_ty = cx.type_of(au.def.into()).instantiate(cx, au.args); let b_ty = cx.type_of(bu.def.into()).instantiate(cx, bu.args); diff --git a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr index 1a0563b469c1..a96876a2c25a 100644 --- a/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr +++ b/tests/ui/transmutability/structs/repr/transmute_infinitely_recursive_type.stderr @@ -12,7 +12,7 @@ LL | struct ExplicitlyPadded(Box); error[E0391]: cycle detected when computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` | = note: ...which immediately requires computing layout of `should_pad_explicitly_packed_field::ExplicitlyPadded` again - = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::TransmuteFrom` + = note: cycle used when evaluating trait selection obligation `(): core::mem::transmutability::TransmuteFrom` = note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information error: aborting due to 2 previous errors From 484480412e7779d364a4d28be0f4ca6c50d9492b Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 19 Nov 2025 19:31:11 +0000 Subject: [PATCH 111/126] Lower `hir::ConstArgKind::Struct` to a `ValTree` --- .../src/hir_ty_lowering/mod.rs | 134 +++++++++++++++--- tests/crashes/127972.rs | 6 - tests/crashes/137888.rs | 11 -- tests/crashes/140275.rs | 5 - .../mgca/adt_expr_arg_simple.rs | 38 +++++ .../mgca/adt_expr_arg_simple.stderr | 14 ++ .../mgca/adt_expr_erroneuous_inits.rs | 26 ++++ .../mgca/adt_expr_erroneuous_inits.stderr | 49 +++++++ .../mgca/adt_expr_fields_type_check.rs | 17 +++ .../mgca/adt_expr_infers_from_value.rs | 45 ++++++ .../mgca/explicit_anon_consts-2.rs | 10 ++ .../mgca/explicit_anon_consts-2.stderr | 8 ++ .../mgca/explicit_anon_consts-3.rs | 10 ++ .../mgca/explicit_anon_consts-3.stderr | 8 ++ .../mgca/explicit_anon_consts-4.rs | 9 ++ .../mgca/explicit_anon_consts-4.stderr | 8 ++ .../mgca/explicit_anon_consts-5.rs | 16 +++ .../mgca/explicit_anon_consts-5.stderr | 8 ++ .../mgca/explicit_anon_consts-6.rs | 8 ++ .../mgca/explicit_anon_consts-6.stderr | 8 ++ .../mgca/explicit_anon_consts.rs | 25 ++-- .../mgca/explicit_anon_consts.stderr | 54 ++----- .../explicit_anon_consts_literals_hack.rs | 18 ++- .../explicit_anon_consts_literals_hack.stderr | 8 ++ .../mgca/type_const-on-generic-expr.rs | 24 ---- .../mgca/type_const-on-generic-expr.stderr | 30 +--- .../mgca/type_const-on-generic_expr-2.rs | 27 ++++ .../mgca/type_const-on-generic_expr-2.stderr | 20 +++ .../bad_const_generics_args_on_const_param.rs | 15 -- ..._const_generics_args_on_const_param.stderr | 21 --- 30 files changed, 491 insertions(+), 189 deletions(-) delete mode 100644 tests/crashes/127972.rs delete mode 100644 tests/crashes/137888.rs delete mode 100644 tests/crashes/140275.rs create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_simple.rs create mode 100644 tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr create mode 100644 tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.rs create mode 100644 tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr create mode 100644 tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs create mode 100644 tests/ui/const-generics/mgca/adt_expr_infers_from_value.rs create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-2.rs create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-2.stderr create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-3.rs create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-3.stderr create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-4.rs create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-4.stderr create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-5.rs create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-5.stderr create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-6.rs create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts-6.stderr create mode 100644 tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr create mode 100644 tests/ui/const-generics/mgca/type_const-on-generic_expr-2.rs create mode 100644 tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr delete mode 100644 tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs delete mode 100644 tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs index 3c1200c812bc..23110d2c5c87 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs @@ -2263,15 +2263,120 @@ pub fn lower_const_arg( ) .unwrap_or_else(|guar| Const::new_error(tcx, guar)) } - hir::ConstArgKind::Struct(..) => { - span_bug!(const_arg.span(), "lowering `{:?}` is not yet implemented", const_arg) + hir::ConstArgKind::Struct(qpath, inits) => { + self.lower_const_arg_struct(hir_id, qpath, inits, const_arg.span()) } - hir::ConstArgKind::Anon(anon) => self.lower_anon_const(anon), + hir::ConstArgKind::Anon(anon) => self.lower_const_arg_anon(anon), hir::ConstArgKind::Infer(span, ()) => self.ct_infer(None, span), hir::ConstArgKind::Error(_, e) => ty::Const::new_error(tcx, e), } } + fn lower_const_arg_struct( + &self, + hir_id: HirId, + qpath: hir::QPath<'tcx>, + inits: &'tcx [&'tcx hir::ConstArgExprField<'tcx>], + span: Span, + ) -> Const<'tcx> { + // FIXME(mgca): try to deduplicate this function with + // the equivalent HIR typeck logic. + let tcx = self.tcx(); + + let non_adt_or_variant_res = || { + let e = tcx.dcx().span_err(span, "struct expression with invalid base path"); + ty::Const::new_error(tcx, e) + }; + + let (ty, variant_did) = match qpath { + hir::QPath::Resolved(maybe_qself, path) => { + debug!(?maybe_qself, ?path); + let opt_self_ty = maybe_qself.as_ref().map(|qself| self.lower_ty(qself)); + let ty = + self.lower_resolved_ty_path(opt_self_ty, path, hir_id, PermitVariants::Yes); + let variant_did = match path.res { + Res::Def(DefKind::Variant | DefKind::Struct, did) => did, + _ => return non_adt_or_variant_res(), + }; + + (ty, variant_did) + } + hir::QPath::TypeRelative(hir_self_ty, segment) => { + debug!(?hir_self_ty, ?segment); + let self_ty = self.lower_ty(hir_self_ty); + let opt_res = self.lower_type_relative_ty_path( + self_ty, + hir_self_ty, + segment, + hir_id, + span, + PermitVariants::Yes, + ); + + let (ty, _, res_def_id) = match opt_res { + Ok(r @ (_, DefKind::Variant | DefKind::Struct, _)) => r, + Ok(_) => return non_adt_or_variant_res(), + Err(e) => return ty::Const::new_error(tcx, e), + }; + + (ty, res_def_id) + } + }; + + let ty::Adt(adt_def, adt_args) = ty.kind() else { unreachable!() }; + + let variant_def = adt_def.variant_with_id(variant_did); + let variant_idx = adt_def.variant_index_with_id(variant_did).as_u32(); + + let fields = variant_def + .fields + .iter() + .map(|field_def| { + // FIXME(mgca): we aren't really handling privacy, stability, + // or macro hygeniene but we should. + let mut init_expr = + inits.iter().filter(|init_expr| init_expr.field.name == field_def.name); + + match init_expr.next() { + Some(expr) => { + if let Some(expr) = init_expr.next() { + let e = tcx.dcx().span_err( + expr.span, + format!( + "struct expression with multiple initialisers for `{}`", + field_def.name, + ), + ); + return ty::Const::new_error(tcx, e); + } + + self.lower_const_arg(expr.expr, FeedConstTy::Param(field_def.did, adt_args)) + } + None => { + let e = tcx.dcx().span_err( + span, + format!( + "struct expression with missing field initialiser for `{}`", + field_def.name + ), + ); + ty::Const::new_error(tcx, e) + } + } + }) + .collect::>(); + + let opt_discr_const = if adt_def.is_enum() { + let valtree = ty::ValTree::from_scalar_int(tcx, variant_idx.into()); + Some(ty::Const::new_value(tcx, valtree, tcx.types.u32)) + } else { + None + }; + + let valtree = ty::ValTree::from_branches(tcx, opt_discr_const.into_iter().chain(fields)); + ty::Const::new_value(tcx, valtree, ty) + } + /// Lower a [resolved][hir::QPath::Resolved] path to a (type-level) constant. fn lower_resolved_const_path( &self, @@ -2375,22 +2480,12 @@ fn lower_resolved_const_path( /// Literals are eagerly converted to a constant, everything else becomes `Unevaluated`. #[instrument(skip(self), level = "debug")] - fn lower_anon_const(&self, anon: &AnonConst) -> Const<'tcx> { + fn lower_const_arg_anon(&self, anon: &AnonConst) -> Const<'tcx> { let tcx = self.tcx(); let expr = &tcx.hir_body(anon.body).value; debug!(?expr); - // If the rhs is an anon const naming generics it shouldn't have - // access to then we lower to `ConstKind::Error`. This prevents - // `try_lower_anon_const_lit` from ICEing on anon consts such as - // `const { N }` which aren't supposed to be legal. - if let ty::AnonConstKind::MCG = tcx.anon_const_kind(anon.def_id) - && let Err(e) = tcx.check_anon_const_invalid_param_uses(anon.def_id) - { - return ty::Const::new_error(tcx, e); - } - // FIXME(generic_const_parameter_types): We should use the proper generic args // here. It's only used as a hint for literals so doesn't matter too much to use the right // generic arguments, just weaker type inference. @@ -2416,8 +2511,8 @@ fn try_lower_anon_const_lit( ) -> Option> { let tcx = self.tcx(); - // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments - // currently have to be wrapped in curly brackets, so it's necessary to special-case. + // Unwrap a block, so that e.g. `{ 1 }` is recognised as a literal. This makes the + // performance optimisation of directly lowering anon consts occur more often. let expr = match &expr.kind { hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { block.expr.as_ref().unwrap() @@ -2425,15 +2520,18 @@ fn try_lower_anon_const_lit( _ => expr, }; + // FIXME(mgca): remove this delayed bug once we start checking this + // when lowering `Ty/ConstKind::Param`s more generally. if let hir::ExprKind::Path(hir::QPath::Resolved( _, &hir::Path { res: Res::Def(DefKind::ConstParam, _), .. }, )) = expr.kind { - span_bug!( + let e = tcx.dcx().span_delayed_bug( expr.span, - "try_lower_anon_const_lit: received const param which shouldn't be possible" + "try_lower_anon_const_lit: received const param which shouldn't be possible", ); + return Some(ty::Const::new_error(tcx, e)); }; let lit_input = match expr.kind { diff --git a/tests/crashes/127972.rs b/tests/crashes/127972.rs deleted file mode 100644 index 797dd7e60209..000000000000 --- a/tests/crashes/127972.rs +++ /dev/null @@ -1,6 +0,0 @@ -//@ known-bug: #127962 -#![feature(generic_const_exprs, const_arg_path)] - -fn zero_init() -> Substs1<{ (N) }> { - Substs1([0; { (usize) }]) -} diff --git a/tests/crashes/137888.rs b/tests/crashes/137888.rs deleted file mode 100644 index 6c13ae5fa916..000000000000 --- a/tests/crashes/137888.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: #137888 -#![feature(generic_const_exprs)] -macro_rules! empty { - () => (); -} -fn bar() -> [(); { - empty! {}; - N - }] { -} -fn main() {} diff --git a/tests/crashes/140275.rs b/tests/crashes/140275.rs deleted file mode 100644 index 5ea04af0c8e0..000000000000 --- a/tests/crashes/140275.rs +++ /dev/null @@ -1,5 +0,0 @@ -//@ known-bug: #140275 -#![feature(generic_const_exprs)] -trait T{} -trait V{} -impl T for [i32; N::<&mut V>] {} diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs b/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs new file mode 100644 index 000000000000..ffb763da325c --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_simple.rs @@ -0,0 +1,38 @@ +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +enum Option { + Some(T), + None, +} +use Option::Some; + +fn foo>() {} + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn bar() { + // the initializer of `_0` is a `N` which is a legal const argument + // so this is ok. + foo::<{ Some:: { 0: N } }>(); + + // this is allowed as mgca supports uses of assoc consts in the + // type system. ie `::ASSOC` is a legal const argument + foo::<{ Some:: { 0: ::ASSOC } }>(); + + // this on the other hand is not allowed as `N + 1` is not a legal + // const argument + foo::<{ Some:: { 0: N + 1 } }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block + + // this also is not allowed as generic parameters cannot be used + // in anon const const args + foo::<{ Some:: { 0: const { N + 1 } } }>(); + //~^ ERROR: generic parameters may not be used in const operations +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr b/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr new file mode 100644 index 000000000000..8b9c228c1ee5 --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_arg_simple.stderr @@ -0,0 +1,14 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/adt_expr_arg_simple.rs:29:30 + | +LL | foo::<{ Some:: { 0: N + 1 } }>(); + | ^^^^^ + +error: generic parameters may not be used in const operations + --> $DIR/adt_expr_arg_simple.rs:34:38 + | +LL | foo::<{ Some:: { 0: const { N + 1 } } }>(); + | ^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.rs b/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.rs new file mode 100644 index 000000000000..752844e4328f --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.rs @@ -0,0 +1,26 @@ +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] +#![crate_type = "lib"] + +// Miscellaneous assortment of invalid cases of directly represented +// `ConstArgKind::Struct`'s under mgca. + +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +struct Foo { field: T } + +fn NonStruct() {} + +fn accepts>() {} + +fn bar() { + accepts::<{ Foo:: { }}>(); + //~^ ERROR: struct expression with missing field initialiser for `field` + accepts::<{ Foo:: { field: const { 1 }, field: const { 2} }}>(); + //~^ ERROR: struct expression with multiple initialisers for `field` + accepts::<{ Fooo:: { field: const { 1 } }}>(); + //~^ ERROR: cannot find struct, variant or union type `Fooo` in this scope + //~| ERROR: struct expression with invalid base path + accepts::<{ NonStruct { }}>(); + //~^ ERROR: expected struct, variant or union type, found function `NonStruct` + //~| ERROR: struct expression with invalid base path +} diff --git a/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr b/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr new file mode 100644 index 000000000000..49d3f67003dc --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_erroneuous_inits.stderr @@ -0,0 +1,49 @@ +error[E0422]: cannot find struct, variant or union type `Fooo` in this scope + --> $DIR/adt_expr_erroneuous_inits.rs:20:17 + | +LL | struct Foo { field: T } + | ------------- similarly named struct `Foo` defined here +... +LL | accepts::<{ Fooo:: { field: const { 1 } }}>(); + | ^^^^ + | +help: a struct with a similar name exists + | +LL - accepts::<{ Fooo:: { field: const { 1 } }}>(); +LL + accepts::<{ Foo:: { field: const { 1 } }}>(); + | + +error[E0574]: expected struct, variant or union type, found function `NonStruct` + --> $DIR/adt_expr_erroneuous_inits.rs:23:17 + | +LL | accepts::<{ NonStruct { }}>(); + | ^^^^^^^^^ not a struct, variant or union type + +error: struct expression with missing field initialiser for `field` + --> $DIR/adt_expr_erroneuous_inits.rs:16:17 + | +LL | accepts::<{ Foo:: { }}>(); + | ^^^^^^^^^ + +error: struct expression with multiple initialisers for `field` + --> $DIR/adt_expr_erroneuous_inits.rs:18:49 + | +LL | accepts::<{ Foo:: { field: const { 1 }, field: const { 2} }}>(); + | ^^^^^^^^^^^^^^^^^ + +error: struct expression with invalid base path + --> $DIR/adt_expr_erroneuous_inits.rs:20:17 + | +LL | accepts::<{ Fooo:: { field: const { 1 } }}>(); + | ^^^^^^^^^^ + +error: struct expression with invalid base path + --> $DIR/adt_expr_erroneuous_inits.rs:23:17 + | +LL | accepts::<{ NonStruct { }}>(); + | ^^^^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0422, E0574. +For more information about an error, try `rustc --explain E0422`. diff --git a/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs b/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs new file mode 100644 index 000000000000..eafc8382966b --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_fields_type_check.rs @@ -0,0 +1,17 @@ +//@ check-pass +// FIXME(mgca): This should error + +#![feature(min_generic_const_args, adt_const_params)] +#![expect(incomplete_features)] + +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +struct Foo { field: T } + +fn accepts>() {} + +fn bar() { + // `N` is not of type `u8` but we don't actually check this anywhere yet + accepts::<{ Foo:: { field: N }}>(); +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/adt_expr_infers_from_value.rs b/tests/ui/const-generics/mgca/adt_expr_infers_from_value.rs new file mode 100644 index 000000000000..d3c9b655a9e5 --- /dev/null +++ b/tests/ui/const-generics/mgca/adt_expr_infers_from_value.rs @@ -0,0 +1,45 @@ +//@ check-pass + +#![feature( + generic_const_items, + min_generic_const_args, + adt_const_params, + generic_const_parameter_types, + unsized_const_params, +)] +#![expect(incomplete_features)] + +use std::marker::{PhantomData, ConstParamTy, ConstParamTy_}; + +#[derive(PartialEq, Eq, ConstParamTy)] +struct Foo { + field: T, +} + +#[type_const] +const WRAP: Foo = { Foo:: { + field: N, +} }; + +fn main() { + // What we're trying to accomplish here is winding up with an equality relation + // between two `ty::Const` that looks something like: + // + // ``` + // Foo { field: const { 1 + 2 } } + // eq + // Foo { field: ?x } + // ``` + // + // Note that the `field: _` here means a const argument `_` not a wildcard pattern. + // This tests that we are able to infer `?x=3` even though the first `ty::Const` + // may be a fully evaluated constant, and the latter is not fully evaluatable due + // to inference variables. + let _: PC<_, { WRAP:: }> + = PC::<_, { Foo:: { field: _ }}>; +} + +// "PhantomConst" helper equivalent to "PhantomData" used for testing equalities +// of arbitrarily typed const arguments. +struct PC { _0: PhantomData } +const PC: PC = PC { _0: PhantomData:: }; diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-2.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-2.rs new file mode 100644 index 000000000000..37a3321a291e --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-2.rs @@ -0,0 +1,10 @@ +#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] +#![expect(incomplete_features)] +// library crates exercise weirder code paths around +// DefIds which were created for const args. +#![crate_type = "lib"] + +struct Foo; + +type Alias = Foo; +//~^ ERROR: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-2.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-2.stderr new file mode 100644 index 000000000000..8d8abd9ef313 --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-2.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts-2.rs:9:42 + | +LL | type Alias = Foo; + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-3.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-3.rs new file mode 100644 index 000000000000..ad7ae7c511ff --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-3.rs @@ -0,0 +1,10 @@ +#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] +#![expect(incomplete_features)] +// library crates exercise weirder code paths around +// DefIds which were created for const args. +#![crate_type = "lib"] + +struct Foo; + +type Alias = [(); const { N }]; +//~^ ERROR: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-3.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-3.stderr new file mode 100644 index 000000000000..fe2c40486aeb --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-3.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts-3.rs:9:43 + | +LL | type Alias = [(); const { N }]; + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-4.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-4.rs new file mode 100644 index 000000000000..bcf34bdb13ee --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-4.rs @@ -0,0 +1,9 @@ +#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] +#![expect(incomplete_features)] +// library crates exercise weirder code paths around +// DefIds which were created for const args. +#![crate_type = "lib"] + +#[type_const] +const ITEM3: usize = const { N }; +//~^ ERROR: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-4.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-4.stderr new file mode 100644 index 000000000000..7fc78257aa2c --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-4.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts-4.rs:8:46 + | +LL | const ITEM3: usize = const { N }; + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-5.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-5.rs new file mode 100644 index 000000000000..aa14ec4275e4 --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-5.rs @@ -0,0 +1,16 @@ +#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] +#![expect(incomplete_features)] +// library crates exercise weirder code paths around +// DefIds which were created for const args. +#![crate_type = "lib"] + +trait Trait { + #[type_const] + const ASSOC: usize; +} + +fn ace_bounds< + const N: usize, + T: Trait, + //~^ ERROR: generic parameters may not be used in const operations +>() {} diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-5.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-5.stderr new file mode 100644 index 000000000000..6d2ab078c8cf --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-5.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts-5.rs:14:30 + | +LL | T: Trait, + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-6.rs b/tests/ui/const-generics/mgca/explicit_anon_consts-6.rs new file mode 100644 index 000000000000..600f4b9cd7f9 --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-6.rs @@ -0,0 +1,8 @@ +#![feature(associated_const_equality, generic_const_items, min_generic_const_args)] +#![expect(incomplete_features)] +// library crates exercise weirder code paths around +// DefIds which were created for const args. +#![crate_type = "lib"] + +struct Default3; +//~^ ERROR: generic parameters may not be used in const operations diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts-6.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts-6.stderr new file mode 100644 index 000000000000..727e478bee8e --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts-6.stderr @@ -0,0 +1,8 @@ +error: generic parameters may not be used in const operations + --> $DIR/explicit_anon_consts-6.rs:7:58 + | +LL | struct Default3; + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.rs b/tests/ui/const-generics/mgca/explicit_anon_consts.rs index ef17222ebc91..f7df3eddfa64 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.rs @@ -4,21 +4,22 @@ // DefIds which were created for const args. #![crate_type = "lib"] +// FIXME(mgca): merge the split out parts of this test back in + struct Foo; type Adt1 = Foo; type Adt2 = Foo<{ N }>; -type Adt3 = Foo; -//~^ ERROR: generic parameters may not be used in const operations -//~^^ ERROR generic parameters may not be used in const operations +// explicit_anon_consts-2.rs +// type Adt3 = Foo; type Adt4 = Foo<{ 1 + 1 }>; //~^ ERROR: complex const arguments must be placed inside of a `const` block type Adt5 = Foo; type Arr = [(); N]; type Arr2 = [(); { N }]; -type Arr3 = [(); const { N }]; -//~^ ERROR: generic parameters may not be used in const operations +// explicit_anon_consts-3.rs +// type Arr3 = [(); const { N }]; type Arr4 = [(); 1 + 1]; //~^ ERROR: complex const arguments must be placed inside of a `const` block type Arr5 = [(); const { 1 + 1 }]; @@ -37,9 +38,9 @@ fn repeats() { const ITEM1: usize = N; #[type_const] const ITEM2: usize = { N }; -#[type_const] -const ITEM3: usize = const { N }; -//~^ ERROR: generic parameters may not be used in const operations +// explicit_anon_consts-4.rs +// #[type_const] +// const ITEM3: usize = const { N }; #[type_const] const ITEM4: usize = { 1 + 1 }; //~^ ERROR: complex const arguments must be placed inside of a `const` block @@ -56,8 +57,8 @@ fn ace_bounds< // We skip the T1 case because it doesn't resolve // T1: Trait, T2: Trait, - T3: Trait, - //~^ ERROR: generic parameters may not be used in const operations + // explicit_anon_consts-5.rs + // T3: Trait, T4: Trait, //~^ ERROR: complex const arguments must be placed inside of a `const` block T5: Trait, @@ -65,8 +66,8 @@ fn ace_bounds< struct Default1; struct Default2; -struct Default3; -//~^ ERROR: generic parameters may not be used in const operations +// explicit_anon_consts-6.rs +// struct Default3; struct Default4; //~^ ERROR: complex const arguments must be placed inside of a `const` block struct Default5; diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr index eb200aae3396..1605dd8069d0 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts.stderr +++ b/tests/ui/const-generics/mgca/explicit_anon_consts.stderr @@ -1,82 +1,44 @@ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:14:33 + --> $DIR/explicit_anon_consts.rs:15:33 | LL | type Adt4 = Foo<{ 1 + 1 }>; | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:22:34 + --> $DIR/explicit_anon_consts.rs:23:34 | LL | type Arr4 = [(); 1 + 1]; | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:31:19 + --> $DIR/explicit_anon_consts.rs:32:19 | LL | let _4 = [(); 1 + 1]; | ^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:44:38 + --> $DIR/explicit_anon_consts.rs:45:38 | LL | const ITEM4: usize = { 1 + 1 }; | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:61:23 + --> $DIR/explicit_anon_consts.rs:62:23 | LL | T4: Trait, | ^^^^^^^^^ error: complex const arguments must be placed inside of a `const` block - --> $DIR/explicit_anon_consts.rs:70:50 + --> $DIR/explicit_anon_consts.rs:71:50 | LL | struct Default4; | ^^^^^^^^^ error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:11:41 - | -LL | type Adt3 = Foo; - | ^ - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:20:42 - | -LL | type Arr3 = [(); const { N }]; - | ^ - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:41:46 - | -LL | const ITEM3: usize = const { N }; - | ^ - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:59:31 - | -LL | T3: Trait, - | ^ - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:68:58 - | -LL | struct Default3; - | ^ - -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:29:27 + --> $DIR/explicit_anon_consts.rs:30:27 | LL | let _3 = [(); const { N }]; | ^ -error: generic parameters may not be used in const operations - --> $DIR/explicit_anon_consts.rs:11:41 - | -LL | type Adt3 = Foo; - | ^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 13 previous errors +error: aborting due to 7 previous errors diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs index 979d10331a59..8c8c5c8e8f88 100644 --- a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs +++ b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.rs @@ -1,9 +1,10 @@ -//@ check-pass - // We allow for literals to implicitly be anon consts still regardless // of whether a const block is placed around them or not +// +// However, we don't allow so for const arguments in field init positions. +// This is just harder to implement so we did not do so. -#![feature(min_generic_const_args, associated_const_equality)] +#![feature(min_generic_const_args, adt_const_params, associated_const_equality)] #![expect(incomplete_features)] trait Trait { @@ -19,4 +20,15 @@ fn repeat_count() { struct Foo; type NormalArg = (Foo<1>, Foo<-1>); +#[derive(Eq, PartialEq, std::marker::ConstParamTy)] +struct ADT { field: u8 } + +fn struct_expr() { + fn takes_n() {} + + takes_n::<{ ADT { field: 1 } }>(); + //~^ ERROR: complex const arguments must be placed inside of a `const` block + takes_n::<{ ADT { field: const { 1 } } }>(); +} + fn main() {} diff --git a/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr new file mode 100644 index 000000000000..02647fd808cc --- /dev/null +++ b/tests/ui/const-generics/mgca/explicit_anon_consts_literals_hack.stderr @@ -0,0 +1,8 @@ +error: complex const arguments must be placed inside of a `const` block + --> $DIR/explicit_anon_consts_literals_hack.rs:29:30 + | +LL | takes_n::<{ ADT { field: 1 } }>(); + | ^ + +error: aborting due to 1 previous error + diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs index a1008fae9d16..ac4c4fb59419 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.rs @@ -4,32 +4,8 @@ #[type_const] const FREE1: usize = const { std::mem::size_of::() }; //~^ ERROR generic parameters may not be used in const operations -//~^^ ERROR generic parameters may not be used in const operations #[type_const] const FREE2: usize = const { I + 1 }; //~^ ERROR generic parameters may not be used in const operations -pub trait Tr { - #[type_const] - const N1: usize; - #[type_const] - const N2: usize; - #[type_const] - const N3: usize; -} - -pub struct S; - -impl Tr for S { - #[type_const] - const N1: usize = const { std::mem::size_of::() }; - //~^ ERROR generic parameters may not be used in const operations - #[type_const] - const N2: usize = const { I + 1 }; - //~^ ERROR generic parameters may not be used in const operations - #[type_const] - const N3: usize = const { 2 & X }; - //~^ ERROR generic parameters may not be used in const operations -} - fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr index c77be158d0ef..f339e82beeed 100644 --- a/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr +++ b/tests/ui/const-generics/mgca/type_const-on-generic-expr.stderr @@ -5,36 +5,10 @@ LL | const FREE1: usize = const { std::mem::size_of::() }; | ^ error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:9:46 + --> $DIR/type_const-on-generic-expr.rs:8:46 | LL | const FREE2: usize = const { I + 1 }; | ^ -error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:25:54 - | -LL | const N1: usize = const { std::mem::size_of::() }; - | ^ - -error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:28:47 - | -LL | const N2: usize = const { I + 1 }; - | ^ - -error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:31:35 - | -LL | const N3: usize = const { 2 & X }; - | ^ - -error: generic parameters may not be used in const operations - --> $DIR/type_const-on-generic-expr.rs:5:53 - | -LL | const FREE1: usize = const { std::mem::size_of::() }; - | ^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error: aborting due to 6 previous errors +error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.rs b/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.rs new file mode 100644 index 000000000000..37de4d4a4abb --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.rs @@ -0,0 +1,27 @@ +#![expect(incomplete_features)] +#![feature(min_generic_const_args, generic_const_items)] + +pub trait Tr { + #[type_const] + const N1: usize; + #[type_const] + const N2: usize; + #[type_const] + const N3: usize; +} + +pub struct S; + +impl Tr for S { + #[type_const] + const N1: usize = const { std::mem::size_of::() }; + //~^ ERROR generic parameters may not be used in const operations + #[type_const] + const N2: usize = const { I + 1 }; + //~^ ERROR generic parameters may not be used in const operations + #[type_const] + const N3: usize = const { 2 & X }; + //~^ ERROR generic parameters may not be used in const operations +} + +fn main() {} diff --git a/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr b/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr new file mode 100644 index 000000000000..9d4e99ca0aaf --- /dev/null +++ b/tests/ui/const-generics/mgca/type_const-on-generic_expr-2.stderr @@ -0,0 +1,20 @@ +error: generic parameters may not be used in const operations + --> $DIR/type_const-on-generic_expr-2.rs:17:54 + | +LL | const N1: usize = const { std::mem::size_of::() }; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/type_const-on-generic_expr-2.rs:20:47 + | +LL | const N2: usize = const { I + 1 }; + | ^ + +error: generic parameters may not be used in const operations + --> $DIR/type_const-on-generic_expr-2.rs:23:35 + | +LL | const N3: usize = const { 2 & X }; + | ^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs deleted file mode 100644 index 29f193a4d7f3..000000000000 --- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@known-bug: #127972 -//@ failure-status: 101 -//@ normalize-stderr: "note: .*\n\n" -> "" -//@ normalize-stderr: "thread 'rustc'.*panicked.*\n" -> "" -//@ normalize-stderr: "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " -//@ normalize-stderr: "/rustc(?:-dev)?/[a-z0-9.]+/" -> "" -//@ rustc-env:RUST_BACKTRACE=0 - -#![feature(pattern_types, pattern_type_macro, generic_const_exprs)] -#![allow(internal_features)] - -type Pat = - std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>); - -fn main() {} diff --git a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr b/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr deleted file mode 100644 index d053d8aed062..000000000000 --- a/tests/ui/type/pattern_types/bad_const_generics_args_on_const_param.stderr +++ /dev/null @@ -1,21 +0,0 @@ -warning: the feature `generic_const_exprs` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/bad_const_generics_args_on_const_param.rs:9:47 - | -LL | #![feature(pattern_types, pattern_type_macro, generic_const_exprs)] - | ^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #76560 for more information - = error: internal compiler error: compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs:LL:CC: try_lower_anon_const_lit: received const param which shouldn't be possible - --> $DIR/bad_const_generics_args_on_const_param.rs:13:36 - | -LL | std::pat::pattern_type!(u32 is START::<(), i32, 2>..=END::<_, Assoc = ()>); - | ^^^^^^^^^^^^^^^^^^^ - - -Box -query stack during panic: -#0 [type_of] expanding type alias `Pat` -#1 [check_well_formed] checking that `Pat` is well-formed -... and 2 other queries... use `env RUST_BACKTRACE=1` to see the full query stack -error: aborting due to 1 previous error; 1 warning emitted - From 79fd535473f9a2025ee5d09ce9465969da90ae33 Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Wed, 19 Nov 2025 23:28:50 +0000 Subject: [PATCH 112/126] Fix tools --- .../src/intrinsics/simd.rs | 2 +- src/librustdoc/clean/mod.rs | 6 +++++- src/librustdoc/clean/utils.rs | 2 +- .../clippy/clippy_lints/src/utils/author.rs | 1 + src/tools/clippy/clippy_utils/src/consts.rs | 2 +- .../clippy/clippy_utils/src/hir_utils.rs | 21 +++++++++++++++---- src/tools/miri/src/intrinsics/atomic.rs | 2 +- 7 files changed, 27 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 38e8d2fa9368..15aef60c5af3 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -130,7 +130,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( return; } - let idx = generic_args[2].expect_const().to_value().valtree.unwrap_branch(); + let idx = generic_args[2].expect_const().to_branch(); assert_eq!(x.layout(), y.layout()); let layout = x.layout(); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 764b3a0acdb6..707b48b355ba 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -319,6 +319,10 @@ pub(crate) fn clean_const<'tcx>(constant: &hir::ConstArg<'tcx>) -> ConstantKind hir::ConstArgKind::Path(qpath) => { ConstantKind::Path { path: qpath_to_string(qpath).into() } } + hir::ConstArgKind::Struct(..) => { + // FIXME(mgca): proper printing :3 + ConstantKind::Path { path: "/* STRUCT EXPR */".to_string().into() } + } hir::ConstArgKind::Anon(anon) => ConstantKind::Anonymous { body: anon.body }, hir::ConstArgKind::Infer(..) | hir::ConstArgKind::Error(..) => ConstantKind::Infer, } @@ -1800,7 +1804,7 @@ pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> T let ct = cx.tcx.normalize_erasing_regions(typing_env, ct); print_const(cx, ct) } - hir::ConstArgKind::Path(..) => { + hir::ConstArgKind::Struct(..) | hir::ConstArgKind::Path(..) => { let ct = lower_const_arg_for_rustdoc(cx.tcx, const_arg, FeedConstTy::No); print_const(cx, ct) } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 4c3f26701bab..0f75a332ad6b 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -357,7 +357,7 @@ pub(crate) fn print_const(cx: &DocContext<'_>, n: ty::Const<'_>) -> String { } // array lengths are obviously usize ty::ConstKind::Value(cv) if *cv.ty.kind() == ty::Uint(ty::UintTy::Usize) => { - cv.valtree.unwrap_leaf().to_string() + cv.to_leaf().to_string() } _ => n.to_string(), } diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 03cbb0311c6c..685b0a9c0d60 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -319,6 +319,7 @@ fn const_arg(&self, const_arg: &Binding<&ConstArg<'_>>) { chain!(self, "let ConstArgKind::Anon({anon_const}) = {const_arg}.kind"); self.body(field!(anon_const.body)); }, + ConstArgKind::Struct(..) => chain!(self, "let ConstArgKind::Struct(..) = {const_arg}.kind"), ConstArgKind::Infer(..) => chain!(self, "let ConstArgKind::Infer(..) = {const_arg}.kind"), ConstArgKind::Error(..) => chain!(self, "let ConstArgKind::Error(..) = {const_arg}.kind"), } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 7e3fa4f9909b..e43b0b95d9f7 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1139,7 +1139,7 @@ pub fn const_item_rhs_to_expr<'tcx>(tcx: TyCtxt<'tcx>, ct_rhs: ConstItemRhs<'tcx ConstItemRhs::Body(body_id) => Some(tcx.hir_body(body_id).value), ConstItemRhs::TypeConst(const_arg) => match const_arg.kind { ConstArgKind::Anon(anon) => Some(tcx.hir_body(anon.body).value), - ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => None, + ConstArgKind::Struct(..) | ConstArgKind::Path(_) | ConstArgKind::Error(..) | ConstArgKind::Infer(..) => None, }, } } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index c6d82c0e63fa..5cadf5fbb869 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -477,11 +477,18 @@ fn eq_const_arg(&mut self, left: &ConstArg<'_>, right: &ConstArg<'_>) -> bool { (ConstArgKind::Path(l_p), ConstArgKind::Path(r_p)) => self.eq_qpath(l_p, r_p), (ConstArgKind::Anon(l_an), ConstArgKind::Anon(r_an)) => self.eq_body(l_an.body, r_an.body), (ConstArgKind::Infer(..), ConstArgKind::Infer(..)) => true, + (ConstArgKind::Struct(path_a, inits_a), ConstArgKind::Struct(path_b, inits_b)) => { + self.eq_qpath(path_a, path_b) + && inits_a.iter().zip(*inits_b).all(|(init_a, init_b)| { + self.eq_const_arg(init_a.expr, init_b.expr) + }) + } // Use explicit match for now since ConstArg is undergoing flux. - (ConstArgKind::Path(..), ConstArgKind::Anon(..)) - | (ConstArgKind::Anon(..), ConstArgKind::Path(..)) - | (ConstArgKind::Infer(..) | ConstArgKind::Error(..), _) - | (_, ConstArgKind::Infer(..) | ConstArgKind::Error(..)) => false, + (ConstArgKind::Path(..), _) + | (ConstArgKind::Anon(..), _) + | (ConstArgKind::Infer(..), _) + | (ConstArgKind::Struct(..), _) + | (ConstArgKind::Error(..), _) => false, } } @@ -1332,6 +1339,12 @@ fn hash_const_arg(&mut self, const_arg: &ConstArg<'_>) { match &const_arg.kind { ConstArgKind::Path(path) => self.hash_qpath(path), ConstArgKind::Anon(anon) => self.hash_body(anon.body), + ConstArgKind::Struct(path, inits) => { + self.hash_qpath(path); + for init in *inits { + self.hash_const_arg(init.expr); + } + } ConstArgKind::Infer(..) | ConstArgKind::Error(..) => {}, } } diff --git a/src/tools/miri/src/intrinsics/atomic.rs b/src/tools/miri/src/intrinsics/atomic.rs index 9bb0ab70de23..481b6716c70c 100644 --- a/src/tools/miri/src/intrinsics/atomic.rs +++ b/src/tools/miri/src/intrinsics/atomic.rs @@ -31,7 +31,7 @@ fn emulate_atomic_intrinsic( let get_ord_at = |i: usize| { let ordering = generic_args.const_at(i).to_value(); - ordering.valtree.unwrap_branch()[0].unwrap_leaf().to_atomic_ordering() + ordering.to_branch()[0].to_value().to_leaf().to_atomic_ordering() }; fn read_ord(ord: AtomicOrdering) -> AtomicReadOrd { From bbf4ec3b0fd31a813208791dcce4264ed6bdbae3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Tue, 23 Dec 2025 15:47:03 +0100 Subject: [PATCH 113/126] Add support for `automation/bors/auto` merge branch --- .github/workflows/ci.yml | 7 ++++--- src/ci/citool/src/main.rs | 4 +++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 05aa600e649e..bb6bc325a3bb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,6 +15,7 @@ on: - try - try-perf - automation/bors/try + - automation/bors/auto pull_request: branches: - "**" @@ -56,7 +57,7 @@ jobs: - name: Test citool # Only test citool on the auto branch, to reduce latency of the calculate matrix job # on PR/try builds. - if: ${{ github.ref == 'refs/heads/auto' }} + if: ${{ github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto' }} run: | cd src/ci/citool CARGO_INCREMENTAL=0 cargo test @@ -79,7 +80,7 @@ jobs: # access the environment. # # We only enable the environment for the rust-lang/rust repository, so that CI works on forks. - environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto')) && 'bors') || '' }} + environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} env: CI_JOB_NAME: ${{ matrix.name }} CI_JOB_DOC_URL: ${{ matrix.doc_url }} @@ -313,7 +314,7 @@ jobs: needs: [ calculate_matrix, job ] # !cancelled() executes the job regardless of whether the previous jobs passed or failed if: ${{ !cancelled() && contains(fromJSON('["auto", "try"]'), needs.calculate_matrix.outputs.run_type) }} - environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto')) && 'bors') || '' }} + environment: ${{ ((github.repository == 'rust-lang/rust' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf' || github.ref == 'refs/heads/automation/bors/try' || github.ref == 'refs/heads/auto' || github.ref == 'refs/heads/automation/bors/auto')) && 'bors') || '' }} steps: - name: checkout the source code uses: actions/checkout@v5 diff --git a/src/ci/citool/src/main.rs b/src/ci/citool/src/main.rs index 4fe9cee900ca..d7b491d38f41 100644 --- a/src/ci/citool/src/main.rs +++ b/src/ci/citool/src/main.rs @@ -46,7 +46,9 @@ fn get_run_type(&self) -> Option { let patterns = if !patterns.is_empty() { Some(patterns) } else { None }; Some(RunType::TryJob { job_patterns: patterns }) } - ("push", "refs/heads/auto") => Some(RunType::AutoJob), + ("push", "refs/heads/auto" | "refs/heads/automation/bors/auto") => { + Some(RunType::AutoJob) + } ("push", "refs/heads/main") => Some(RunType::MainJob), _ => None, } From c252af5cbbe576acf5ffefa44687c8cf27a5c294 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 23 Dec 2025 15:30:38 +0000 Subject: [PATCH 114/126] Fix audit workflow --- .github/workflows/audit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/audit.yml b/.github/workflows/audit.yml index 27c95572ef87..274b9504beb0 100644 --- a/.github/workflows/audit.yml +++ b/.github/workflows/audit.yml @@ -12,7 +12,7 @@ jobs: steps: - uses: actions/checkout@v4 - run: | - sed -i 's/components.*/components = []/' rust-toolchain + sed -i 's/components.*/components = []/' rust-toolchain.toml - uses: rustsec/audit-check@v1.4.1 with: token: ${{ secrets.GITHUB_TOKEN }} From 6bb3a40d535634d9004db49d639d900ecf66fc7f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:48:27 +0000 Subject: [PATCH 115/126] Update to Cranelift 0.127 --- Cargo.lock | 173 ++++++++++++++++------------------------------------- Cargo.toml | 24 ++++---- 2 files changed, 63 insertions(+), 134 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 617c7f0e34cd..3d13b5540e19 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,42 +43,42 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cranelift-assembler-x64" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7631e609c97f063f9777aae405e8492abf9bf92336d7aa3f875403dd4ffd7d" +checksum = "8bd963a645179fa33834ba61fa63353998543b07f877e208da9eb47d4a70d1e7" dependencies = [ "cranelift-assembler-x64-meta", ] [[package]] name = "cranelift-assembler-x64-meta" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c030edccdc4a5bbf28fbfe7701b5cd1f9854b4445184dd34af2a7e8f8db6f45" +checksum = "3f6d5739c9dc6b5553ca758d78d87d127dd19f397f776efecf817b8ba8d0bb01" dependencies = [ "cranelift-srcgen", ] [[package]] name = "cranelift-bforest" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb544c1242d0ca98baf01873ebba96c79d5df155d5108d9bb699aefc741f5e6d" +checksum = "ff402c11bb1c9652b67a3e885e84b1b8d00c13472c8fd85211e06a41a63c3e03" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-bitset" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0325aecbafec053d3d3f082edfdca7937e2945e7f09c5ff9672e05198312282" +checksum = "769a0d88c2f5539e9c5536a93a7bf164b0dc68d91e3d00723e5b4ffc1440afdc" [[package]] name = "cranelift-codegen" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb3236fd319ae897ba00c8a25105081de5c1348576def0e96c062ad259f87a7" +checksum = "d4351f721fb3b26add1c180f0a75c7474bab2f903c8b777c6ca65238ded59a78" dependencies = [ "bumpalo", "cranelift-assembler-x64", @@ -102,9 +102,9 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b8791c911a361c539130ace34fb726b16aca4216470ec75d75264b1495c8a3a" +checksum = "61f86c0ba5b96713643f4dd0de0df12844de9c7bb137d6829b174b706939aa74" dependencies = [ "cranelift-assembler-x64-meta", "cranelift-codegen-shared", @@ -114,33 +114,33 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12ead718c2a10990870c19b2497b5a04b8aae6024485e33da25b5d02e35819e0" +checksum = "f08605eee8d51fd976a970bd5b16c9529b51b624f8af68f80649ffb172eb85a4" [[package]] name = "cranelift-control" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0a57fc972b5651047efddccb99440d103d9d8c13393ccebde15ddd5b6a1181b" +checksum = "623aab0a09e40f0cf0b5d35eb7832bae4c4f13e3768228e051a6c1a60e88ef5f" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aae980b4a1678b601eab2f52e372ed0b3c9565a31c17f380008cb97b3a699c5" +checksum = "ea0f066e07e3bcbe38884cc5c94c32c7a90267d69df80f187d9dfe421adaa7c4" dependencies = [ "cranelift-bitset", ] [[package]] name = "cranelift-frontend" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78877016b607982ca1708c0dd4ce23bde04581a39854c9b43a1dca43625b54c" +checksum = "40865b02a0e52ca8e580ad64feef530cb1d05f6bb4972b4eef05e3eaeae81701" dependencies = [ "cranelift-codegen", "log", @@ -150,15 +150,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dc46a68b46d4f53f9f2f02ab8d3a34b00f03a21c124a7a965b8cbf5fdb6773b" +checksum = "104b3c117ae513e9af1d90679842101193a5ccb96ac9f997966d85ea25be2852" [[package]] name = "cranelift-jit" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7df920009af919ad9df52eb7b47b1895145822e0c29da9b715a876fc8ecc6d82" +checksum = "3aa5f855cfb8e4253ed2d0dfc1a0b6ebe4912e67aa8b7ee14026ff55ca17f1fe" dependencies = [ "anyhow", "cranelift-codegen", @@ -171,14 +171,14 @@ dependencies = [ "region", "target-lexicon", "wasmtime-internal-jit-icache-coherence", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "cranelift-module" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddcf313629071ce74de8e59f02092f5453d1a01047607fc4ad36886b8bd1486c" +checksum = "b1d01806b191b59f4fc4680293dd5f554caf2de5b62f95eff5beef7acb46c29c" dependencies = [ "anyhow", "cranelift-codegen", @@ -187,9 +187,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03faa07ec8cf373250a8252eb773d098ff88259fa1c19ee1ecde8012839f4097" +checksum = "e5c54e0a358bc05b48f2032e1c320e7f468da068604f2869b77052eab68eb0fe" dependencies = [ "cranelift-codegen", "libc", @@ -198,9 +198,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cca62c14f3c2e4f438192562bbf82d1a98a59543cc66ba04fb658ba99f515a6" +checksum = "3d17e0216be5daabab616647c1918e06dae0708474ba5f7b7762ac24ea5eb126" dependencies = [ "anyhow", "cranelift-codegen", @@ -213,9 +213,9 @@ dependencies = [ [[package]] name = "cranelift-srcgen" -version = "0.126.0" +version = "0.127.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0484cb32c527a742e1bba09ef174acac0afb1dcf623ef1adda42849200edcd2e" +checksum = "cc6f4b039f453b66c75e9f7886e5a2af96276e151f44dc19b24b58f9a0c98009" [[package]] name = "crc32fast" @@ -293,7 +293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "754ca22de805bb5744484a5b151a9e1a8e837d5dc232c2d7d8c2e3492edc8b60" dependencies = [ "cfg-if", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -469,31 +469,25 @@ checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "wasmtime-internal-jit-icache-coherence" -version = "39.0.0" +version = "40.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f67986f5c499274ae5b2ba5b173bba0b95d1381f5ca70d8eec657f2392117d8" +checksum = "0858b470463f3e7c73acd6049046049e64be17b98901c2db5047450cf83df1fe" dependencies = [ "anyhow", "cfg-if", "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "wasmtime-internal-math" -version = "39.0.0" +version = "40.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a681733e9b5d5d8804ee6cacd59f92c0d87ba2274f42ee1d4e5a943828d0075d" +checksum = "222e1a590ece4e898f20af1e541b61d2cb803f2557e7eaff23e6c1db5434454a" dependencies = [ "libm", ] -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - [[package]] name = "windows-link" version = "0.2.1" @@ -506,16 +500,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] name = "windows-sys" -version = "0.60.2" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets 0.53.3", + "windows-link", ] [[package]] @@ -524,31 +518,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" -dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -557,92 +534,44 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" diff --git a/Cargo.toml b/Cargo.toml index 58e61cd0b9d7..ee4bde477c47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.126.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } -cranelift-frontend = { version = "0.126.0" } -cranelift-module = { version = "0.126.0" } -cranelift-native = { version = "0.126.0" } -cranelift-jit = { version = "0.126.0", optional = true } -cranelift-object = { version = "0.126.0" } +cranelift-codegen = { version = "0.127.0", default-features = false, features = ["std", "timing", "unwind", "all-native-arch"] } +cranelift-frontend = { version = "0.127.0" } +cranelift-module = { version = "0.127.0" } +cranelift-native = { version = "0.127.0" } +cranelift-jit = { version = "0.127.0", optional = true } +cranelift-object = { version = "0.127.0" } target-lexicon = "0.13" gimli = { version = "0.32", default-features = false, features = ["write"] } object = { version = "0.37.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } @@ -24,12 +24,12 @@ smallvec = "1.8.1" [patch.crates-io] # Uncomment to use an unreleased version of cranelift -#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } -#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } -#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } -#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } -#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } -#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-39.0.0" } +#cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-40.0.0" } +#cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-40.0.0" } +#cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-40.0.0" } +#cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-40.0.0" } +#cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-40.0.0" } +#cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "release-40.0.0" } # Uncomment to use local checkout of cranelift #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } From 6f3f6bdacb75571a87f08e0920d9c191b3d65ded Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 23 Dec 2025 16:22:22 +0000 Subject: [PATCH 116/126] Rustup to rustc 1.94.0-nightly (4f14395c3 2025-12-22) --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 6ce49eb4ccf0..b157c5879ba7 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-12-18" +channel = "nightly-2025-12-23" components = ["rust-src", "rustc-dev", "llvm-tools", "rustfmt"] profile = "minimal" From e7965821e8bb671937e59f99894537d436060fc0 Mon Sep 17 00:00:00 2001 From: Tshepang Mbambo Date: Tue, 23 Dec 2025 23:35:58 +0200 Subject: [PATCH 117/126] use new term in description of --target --- compiler/rustc_session/src/config.rs | 2 +- src/doc/man/rustc.1 | 4 ++-- src/doc/rustc/src/command-line-arguments.md | 2 +- tests/run-make/rustc-help/help-v.stdout | 2 +- tests/run-make/rustc-help/help.stdout | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 2774333573f6..f326442c0879 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -1798,7 +1798,7 @@ pub fn rustc_optgroups() -> Vec { "", ), opt(Stable, Flag, "", "test", "Build a test harness", ""), - opt(Stable, Opt, "", "target", "Target triple for which the code is compiled", ""), + opt(Stable, Opt, "", "target", "Target tuple for which the code is compiled", ""), opt(Stable, Multi, "A", "allow", "Set lint allowed", ""), opt(Stable, Multi, "W", "warn", "Set lint warnings", ""), opt(Stable, Multi, "", "force-warn", "Set lint force-warn", ""), diff --git a/src/doc/man/rustc.1 b/src/doc/man/rustc.1 index 534af3f85bb9..2a91774d671a 100644 --- a/src/doc/man/rustc.1 +++ b/src/doc/man/rustc.1 @@ -79,8 +79,8 @@ Provide a detailed explanation of an error message. Build a test harness. .TP \fB\-\-target\fR \fITARGET\fR -Target triple for which the code is compiled. This option defaults to the host’s target -triple. The target triple has the general format \-\-\-, where: +Target tuple for which the code is compiled. This option defaults to the host’s target +tuple. The target tuple has the general format \-\-\-, where: .RS .TP .B diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 0b15fbc24dfc..507af9e2ffef 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -284,7 +284,7 @@ and instead produce a test harness. See the [Tests chapter](tests/index.md) for more information about tests. -## `--target`: select a target triple to build +## `--target`: select a target tuple to build This controls which [target](targets/index.md) to produce. diff --git a/tests/run-make/rustc-help/help-v.stdout b/tests/run-make/rustc-help/help-v.stdout index c41cb5e3bde8..cf055e220c0d 100644 --- a/tests/run-make/rustc-help/help-v.stdout +++ b/tests/run-make/rustc-help/help-v.stdout @@ -51,7 +51,7 @@ Options: --explain Provide a detailed explanation of an error message --test Build a test harness --target - Target triple for which the code is compiled + Target tuple for which the code is compiled -A, --allow Set lint allowed -W, --warn Set lint warnings --force-warn diff --git a/tests/run-make/rustc-help/help.stdout b/tests/run-make/rustc-help/help.stdout index 5e13a900484d..4075dd028299 100644 --- a/tests/run-make/rustc-help/help.stdout +++ b/tests/run-make/rustc-help/help.stdout @@ -51,7 +51,7 @@ Options: --explain Provide a detailed explanation of an error message --test Build a test harness --target - Target triple for which the code is compiled + Target tuple for which the code is compiled -A, --allow Set lint allowed -W, --warn Set lint warnings --force-warn From b7729998d25a158a6925f737f4c164ec0572ff10 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 20 Dec 2025 14:08:21 +1100 Subject: [PATCH 118/126] Classify `TestableCase::Constant` into multiple sub-kinds --- .../src/builder/matches/buckets.rs | 21 ++++++++------- .../src/builder/matches/match_pair.rs | 26 +++++++++++++++++-- .../src/builder/matches/mod.rs | 21 ++++++++++++++- .../src/builder/matches/test.rs | 15 +++++------ 4 files changed, 61 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/buckets.rs b/compiler/rustc_mir_build/src/builder/matches/buckets.rs index 8cbbb8e14095..5275a1bb620e 100644 --- a/compiler/rustc_mir_build/src/builder/matches/buckets.rs +++ b/compiler/rustc_mir_build/src/builder/matches/buckets.rs @@ -6,8 +6,7 @@ use tracing::debug; use crate::builder::Builder; -use crate::builder::matches::test::is_switch_ty; -use crate::builder::matches::{Candidate, Test, TestBranch, TestKind, TestableCase}; +use crate::builder::matches::{Candidate, PatConstKind, Test, TestBranch, TestKind, TestableCase}; /// Output of [`Builder::partition_candidates_into_buckets`]. pub(crate) struct PartitionedCandidates<'tcx, 'b, 'c> { @@ -157,11 +156,10 @@ fn choose_bucket_for_candidate( // // FIXME(#29623) we could use PatKind::Range to rule // things out here, in some cases. - // - // FIXME(Zalathar): Is the `is_switch_ty` test unnecessary? - (TestKind::SwitchInt, &TestableCase::Constant { value }) - if is_switch_ty(match_pair.pattern_ty) => - { + ( + TestKind::SwitchInt, + &TestableCase::Constant { value, kind: PatConstKind::IntOrChar }, + ) => { // An important invariant of candidate bucketing is that a candidate // must not match in multiple branches. For `SwitchInt` tests, adding // a new value might invalidate that property for range patterns that @@ -206,7 +204,7 @@ fn choose_bucket_for_candidate( }) } - (TestKind::If, TestableCase::Constant { value }) => { + (TestKind::If, TestableCase::Constant { value, kind: PatConstKind::Bool }) => { fully_matched = true; let value = value.try_to_bool().unwrap_or_else(|| { span_bug!(test.span, "expected boolean value but got {value:?}") @@ -291,7 +289,7 @@ fn choose_bucket_for_candidate( if !test.overlaps(pat, self.tcx)? { Some(TestBranch::Failure) } else { None } } } - (TestKind::Range(range), &TestableCase::Constant { value }) => { + (TestKind::Range(range), &TestableCase::Constant { value, kind: _ }) => { fully_matched = false; if !range.contains(value, self.tcx)? { // `value` is not contained in the testing range, @@ -302,7 +300,10 @@ fn choose_bucket_for_candidate( } } - (TestKind::Eq { value: test_val, .. }, TestableCase::Constant { value: case_val }) => { + ( + TestKind::Eq { value: test_val, .. }, + TestableCase::Constant { value: case_val, kind: _ }, + ) => { if test_val == case_val { fully_matched = true; Some(TestBranch::Success) diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index 9b9ee1836956..c8e3628ae346 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -7,7 +7,9 @@ use crate::builder::Builder; use crate::builder::expr::as_place::{PlaceBase, PlaceBuilder}; -use crate::builder::matches::{FlatPat, MatchPairTree, PatternExtraData, TestableCase}; +use crate::builder::matches::{ + FlatPat, MatchPairTree, PatConstKind, PatternExtraData, TestableCase, +}; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in @@ -156,7 +158,27 @@ pub(super) fn for_pattern( } } - PatKind::Constant { value } => Some(TestableCase::Constant { value }), + PatKind::Constant { value } => { + // CAUTION: The type of the pattern node (`pattern.ty`) is + // _often_ the same as the type of the const value (`value.ty`), + // but there are some cases where those types differ + // (e.g. when `deref!(..)` patterns interact with `String`). + + // Classify the constant-pattern into further kinds, to + // reduce the number of ad-hoc type tests needed later on. + let pat_ty = pattern.ty; + let const_kind = if pat_ty.is_bool() { + PatConstKind::Bool + } else if pat_ty.is_integral() || pat_ty.is_char() { + PatConstKind::IntOrChar + } else { + // FIXME(Zalathar): This still covers several different + // categories (e.g. raw pointer, string, pattern-type) + // which could be split out into their own kinds. + PatConstKind::Other + }; + Some(TestableCase::Constant { value, kind: const_kind }) + } PatKind::AscribeUserType { ascription: Ascription { ref annotation, variance }, diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 8897ca7c7210..04722bf690c4 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1262,7 +1262,7 @@ struct Ascription<'tcx> { #[derive(Debug, Clone)] enum TestableCase<'tcx> { Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx }, - Constant { value: ty::Value<'tcx> }, + Constant { value: ty::Value<'tcx>, kind: PatConstKind }, Range(Arc>), Slice { len: u64, variable_length: bool }, Deref { temp: Place<'tcx>, mutability: Mutability }, @@ -1276,6 +1276,25 @@ fn as_range(&self) -> Option<&PatRange<'tcx>> { } } +/// Sub-classification of [`TestableCase::Constant`], which helps to avoid +/// some redundant ad-hoc checks when preparing and lowering tests. +#[derive(Debug, Clone)] +enum PatConstKind { + /// The primitive `bool` type, which is like an integer but simpler, + /// having only two values. + Bool, + /// Primitive unsigned/signed integer types, plus `char`. + /// These types interact nicely with `SwitchInt`. + IntOrChar, + /// Any other constant-pattern is usually tested via some kind of equality + /// check. Types that might be encountered here include: + /// - `&str` + /// - floating-point primitives, e.g. `f32`, `f64` + /// - raw pointers derived from integer values + /// - pattern types, e.g. `pattern_type!(u32 is 1..)` + Other, +} + /// Node in a tree of "match pairs", where each pair consists of a place to be /// tested, and a test to perform on that place. /// diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index 402587bff7e8..bc4966404ced 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -19,7 +19,9 @@ use tracing::{debug, instrument}; use crate::builder::Builder; -use crate::builder::matches::{MatchPairTree, Test, TestBranch, TestKind, TestableCase}; +use crate::builder::matches::{ + MatchPairTree, PatConstKind, Test, TestBranch, TestKind, TestableCase, +}; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Identifies what test is needed to decide if `match_pair` is applicable. @@ -32,11 +34,11 @@ pub(super) fn pick_test_for_match_pair( let kind = match match_pair.testable_case { TestableCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def }, - TestableCase::Constant { .. } if match_pair.pattern_ty.is_bool() => TestKind::If, - TestableCase::Constant { .. } if is_switch_ty(match_pair.pattern_ty) => { + TestableCase::Constant { value: _, kind: PatConstKind::Bool } => TestKind::If, + TestableCase::Constant { value: _, kind: PatConstKind::IntOrChar } => { TestKind::SwitchInt } - TestableCase::Constant { value } => { + TestableCase::Constant { value, kind: PatConstKind::Other } => { TestKind::Eq { value, cast_ty: match_pair.pattern_ty } } @@ -491,11 +493,6 @@ fn string_compare( } } -/// Returns true if this type be used with [`TestKind::SwitchInt`]. -pub(crate) fn is_switch_ty(ty: Ty<'_>) -> bool { - ty.is_integral() || ty.is_char() -} - fn trait_method<'tcx>( tcx: TyCtxt<'tcx>, trait_def_id: DefId, From 1296925d1b71fa9dbf636aa540bd7cced80c3054 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 24 Dec 2025 13:38:07 +1100 Subject: [PATCH 119/126] Split out a separate `PatConstKind::Float` Unlike the other types covered by `PatConstKind::Other`, const-float patterns can also interact with range patterns. --- .../rustc_mir_build/src/builder/matches/buckets.rs | 13 +++++++++++-- .../src/builder/matches/match_pair.rs | 2 ++ compiler/rustc_mir_build/src/builder/matches/mod.rs | 5 ++++- .../rustc_mir_build/src/builder/matches/test.rs | 3 +++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_build/src/builder/matches/buckets.rs b/compiler/rustc_mir_build/src/builder/matches/buckets.rs index 5275a1bb620e..f8af50ee52fe 100644 --- a/compiler/rustc_mir_build/src/builder/matches/buckets.rs +++ b/compiler/rustc_mir_build/src/builder/matches/buckets.rs @@ -289,7 +289,13 @@ fn choose_bucket_for_candidate( if !test.overlaps(pat, self.tcx)? { Some(TestBranch::Failure) } else { None } } } - (TestKind::Range(range), &TestableCase::Constant { value, kind: _ }) => { + ( + TestKind::Range(range), + &TestableCase::Constant { + value, + kind: PatConstKind::Bool | PatConstKind::IntOrChar | PatConstKind::Float, + }, + ) => { fully_matched = false; if !range.contains(value, self.tcx)? { // `value` is not contained in the testing range, @@ -302,7 +308,10 @@ fn choose_bucket_for_candidate( ( TestKind::Eq { value: test_val, .. }, - TestableCase::Constant { value: case_val, kind: _ }, + TestableCase::Constant { + value: case_val, + kind: PatConstKind::Float | PatConstKind::Other, + }, ) => { if test_val == case_val { fully_matched = true; diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index c8e3628ae346..798110c8b090 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -171,6 +171,8 @@ pub(super) fn for_pattern( PatConstKind::Bool } else if pat_ty.is_integral() || pat_ty.is_char() { PatConstKind::IntOrChar + } else if pat_ty.is_floating_point() { + PatConstKind::Float } else { // FIXME(Zalathar): This still covers several different // categories (e.g. raw pointer, string, pattern-type) diff --git a/compiler/rustc_mir_build/src/builder/matches/mod.rs b/compiler/rustc_mir_build/src/builder/matches/mod.rs index 04722bf690c4..8128ea946f08 100644 --- a/compiler/rustc_mir_build/src/builder/matches/mod.rs +++ b/compiler/rustc_mir_build/src/builder/matches/mod.rs @@ -1286,10 +1286,13 @@ enum PatConstKind { /// Primitive unsigned/signed integer types, plus `char`. /// These types interact nicely with `SwitchInt`. IntOrChar, + /// Floating-point primitives, e.g. `f32`, `f64`. + /// These types don't support `SwitchInt` and require an equality test, + /// but can also interact with range pattern tests. + Float, /// Any other constant-pattern is usually tested via some kind of equality /// check. Types that might be encountered here include: /// - `&str` - /// - floating-point primitives, e.g. `f32`, `f64` /// - raw pointers derived from integer values /// - pattern types, e.g. `pattern_type!(u32 is 1..)` Other, diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index bc4966404ced..f292a8e79d9d 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -38,6 +38,9 @@ pub(super) fn pick_test_for_match_pair( TestableCase::Constant { value: _, kind: PatConstKind::IntOrChar } => { TestKind::SwitchInt } + TestableCase::Constant { value, kind: PatConstKind::Float } => { + TestKind::Eq { value, cast_ty: match_pair.pattern_ty } + } TestableCase::Constant { value, kind: PatConstKind::Other } => { TestKind::Eq { value, cast_ty: match_pair.pattern_ty } } From b5c473e4141c6b1bc7a1babec3e01f894442f436 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 23 Dec 2025 15:50:33 +0000 Subject: [PATCH 120/126] Avoid using env::temp when linking a binary This keeps all build artefacts (even temporary ones) within the build directory. --- compiler/rustc_codegen_ssa/src/back/link.rs | 11 ++++++----- compiler/rustc_fs_util/src/lib.rs | 6 +----- tests/run-make/invalid-tmpdir-env-var/rmake.rs | 8 ++++---- 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 70db6794742d..ba07345dd43f 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -103,17 +103,18 @@ pub fn link_binary( }); if outputs.outputs.should_link() { - let tmpdir = TempDirBuilder::new() - .prefix("rustc") - .tempdir() - .unwrap_or_else(|error| sess.dcx().emit_fatal(errors::CreateTempDir { error })); - let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps); let output = out_filename( sess, crate_type, outputs, codegen_results.crate_info.local_crate_name, ); + let tmpdir = TempDirBuilder::new() + .prefix("rustc") + .tempdir_in(output.parent().unwrap_or_else(|| Path::new("."))) + .unwrap_or_else(|error| sess.dcx().emit_fatal(errors::CreateTempDir { error })); + let path = MaybeTempDir::new(tmpdir, sess.opts.cg.save_temps); + let crate_name = format!("{}", codegen_results.crate_info.local_crate_name); let out_filename = output.file_for_writing( outputs, diff --git a/compiler/rustc_fs_util/src/lib.rs b/compiler/rustc_fs_util/src/lib.rs index 7a883a13b72d..e21da4cdddf7 100644 --- a/compiler/rustc_fs_util/src/lib.rs +++ b/compiler/rustc_fs_util/src/lib.rs @@ -1,6 +1,6 @@ use std::ffi::{CString, OsStr}; use std::path::{Path, PathBuf, absolute}; -use std::{env, fs, io}; +use std::{fs, io}; use tempfile::TempDir; @@ -139,8 +139,4 @@ pub fn tempdir_in>(&self, dir: P) -> io::Result { } self.builder.tempdir_in(dir) } - - pub fn tempdir(&self) -> io::Result { - self.tempdir_in(env::temp_dir()) - } } diff --git a/tests/run-make/invalid-tmpdir-env-var/rmake.rs b/tests/run-make/invalid-tmpdir-env-var/rmake.rs index c5b9dca33a94..a62592757879 100644 --- a/tests/run-make/invalid-tmpdir-env-var/rmake.rs +++ b/tests/run-make/invalid-tmpdir-env-var/rmake.rs @@ -1,9 +1,7 @@ //@ needs-target-std // // When the TMP (on Windows) or TMPDIR (on Unix) variable is set to an invalid -// or non-existing directory, this used to cause an internal compiler error (ICE). After the -// addition of proper error handling in #28430, this test checks that the expected message is -// printed. +// or non-existing directory, this used to cause an internal compiler error (ICE). // See https://github.com/rust-lang/rust/issues/14698 use run_make_support::{is_windows, rustc}; @@ -18,5 +16,7 @@ fn main() { } else { rustc.env("TMPDIR", "fake"); } - rustc.input("foo.rs").run_fail().assert_stderr_contains("couldn't create a temp dir"); + let result = rustc.input("foo.rs").run_unchecked(); + // Ensure that rustc doesn't ICE by checking the exit code isn't 101. + assert_ne!(result.status().code(), Some(101)); } From 6e354544bfe4bc6ce17265bfb8013631d505f1ac Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Tue, 23 Dec 2025 17:46:09 +0000 Subject: [PATCH 121/126] Rename invalid-tmpdir-env-var to invalid-tmpdir-no-ice --- .../{invalid-tmpdir-env-var => invalid-tmpdir-no-ice}/foo.rs | 0 .../{invalid-tmpdir-env-var => invalid-tmpdir-no-ice}/rmake.rs | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/run-make/{invalid-tmpdir-env-var => invalid-tmpdir-no-ice}/foo.rs (100%) rename tests/run-make/{invalid-tmpdir-env-var => invalid-tmpdir-no-ice}/rmake.rs (100%) diff --git a/tests/run-make/invalid-tmpdir-env-var/foo.rs b/tests/run-make/invalid-tmpdir-no-ice/foo.rs similarity index 100% rename from tests/run-make/invalid-tmpdir-env-var/foo.rs rename to tests/run-make/invalid-tmpdir-no-ice/foo.rs diff --git a/tests/run-make/invalid-tmpdir-env-var/rmake.rs b/tests/run-make/invalid-tmpdir-no-ice/rmake.rs similarity index 100% rename from tests/run-make/invalid-tmpdir-env-var/rmake.rs rename to tests/run-make/invalid-tmpdir-no-ice/rmake.rs From 855281c8871e43980fc41b54d1d5949a9863103d Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Wed, 24 Dec 2025 16:04:58 +0800 Subject: [PATCH 122/126] Disable f16 on LoongArch for LLVM < 21 The `f16` type works on the LoongArch target starting from LLVM 21. However, the current minimum supported external LLVM version is 20, so `f16` must not be enabled on LoongArch for LLVM version < 21. --- compiler/rustc_codegen_llvm/src/llvm_util.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index a5a8f8e6a25e..01181ce26184 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -383,6 +383,7 @@ fn update_target_reliable_float_cfg(sess: &Session, cfg: &mut TargetConfig) { // Infinite recursion (Arch::CSky, _) => false, (Arch::Hexagon, _) if major < 21 => false, // (fixed in llvm21) + (Arch::LoongArch32 | Arch::LoongArch64, _) if major < 21 => false, // (fixed in llvm21) (Arch::PowerPC | Arch::PowerPC64, _) => false, (Arch::Sparc | Arch::Sparc64, _) => false, (Arch::Wasm32 | Arch::Wasm64, _) => false, From 13c6256efe7d426abeb7c86a20b14ba38dc7ad4e Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 24 Dec 2025 10:21:07 +0000 Subject: [PATCH 123/126] Include rustc version in ICE messages Rather than only including them in the ICE file. Not every user includes the ICE file in their bug reports, nor do they always list the rustc version. --- compiler/rustc_driver_impl/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 63fc9c96f450..7820198f2dcf 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -1531,15 +1531,15 @@ fn report_ice( .map(PathBuf::from) .map(|env_var| session_diagnostics::IcePathErrorEnv { env_var }), }); - dcx.emit_note(session_diagnostics::IceVersion { version, triple: tuple }); None } } } else { - dcx.emit_note(session_diagnostics::IceVersion { version, triple: tuple }); None }; + dcx.emit_note(session_diagnostics::IceVersion { version, triple: tuple }); + if let Some((flags, excluded_cargo_defaults)) = rustc_session::utils::extra_compiler_flags() { dcx.emit_note(session_diagnostics::IceFlags { flags: flags.join(" ") }); if excluded_cargo_defaults { From 0e0911b5d8261e1a74158b0a611875521704b0cc Mon Sep 17 00:00:00 2001 From: Boxy Uwu Date: Thu, 18 Dec 2025 18:50:27 +0000 Subject: [PATCH 124/126] Misc cleanups --- compiler/rustc_borrowck/src/lib.rs | 8 +- compiler/rustc_borrowck/src/root_cx.rs | 2 +- .../rustc_borrowck/src/universal_regions.rs | 47 ++--- .../rustc_hir_analysis/src/collect/type_of.rs | 160 +++++++++--------- 4 files changed, 99 insertions(+), 118 deletions(-) diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8d61ffde116c..fa78fb623596 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1,4 +1,4 @@ -//! This query borrow-checks the MIR to (further) ensure it is not broken. +//! This crate implemens MIR typeck and MIR borrowck. // tidy-alphabetical-start #![allow(internal_features)] @@ -111,9 +111,9 @@ pub fn provide(providers: &mut Providers) { *providers = Providers { mir_borrowck, ..*providers }; } -/// Provider for `query mir_borrowck`. Similar to `typeck`, this must -/// only be called for typeck roots which will then borrowck all -/// nested bodies as well. +/// Provider for `query mir_borrowck`. Unlike `typeck`, this must +/// only be called for typeck roots which *similar* to `typeck` will +/// then borrowck all nested bodies as well. fn mir_borrowck( tcx: TyCtxt<'_>, def: LocalDefId, diff --git a/compiler/rustc_borrowck/src/root_cx.rs b/compiler/rustc_borrowck/src/root_cx.rs index c3ff8cba9472..4d42055df168 100644 --- a/compiler/rustc_borrowck/src/root_cx.rs +++ b/compiler/rustc_borrowck/src/root_cx.rs @@ -255,7 +255,7 @@ pub(super) fn do_mir_borrowck(&mut self) { } // We now apply the closure requirements of nested bodies modulo - // regions. In case a body does not depend on opaque types, we + // opaques. In case a body does not depend on opaque types, we // eagerly check its region constraints and use the final closure // requirements. // diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index aee1eb94dc81..a0d5e1ce780d 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -1,13 +1,12 @@ //! Code to extract the universally quantified regions declared on a -//! function and the relationships between them. For example: +//! function. For example: //! //! ``` //! fn foo<'a, 'b, 'c: 'b>() { } //! ``` //! //! here we would return a map assigning each of `{'a, 'b, 'c}` -//! to an index, as well as the `FreeRegionMap` which can compute -//! relationships between them. +//! to an index. //! //! The code in this file doesn't *do anything* with those results; it //! just returns them for other code to use. @@ -271,8 +270,7 @@ impl<'tcx> UniversalRegions<'tcx> { /// Creates a new and fully initialized `UniversalRegions` that /// contains indices for all the free regions found in the given /// MIR -- that is, all the regions that appear in the function's - /// signature. This will also compute the relationships that are - /// known between those regions. + /// signature. pub(crate) fn new(infcx: &BorrowckInferCtxt<'tcx>, mir_def: LocalDefId) -> Self { UniversalRegionsBuilder { infcx, mir_def }.build() } @@ -648,17 +646,14 @@ fn defining_ty(&self) -> DefiningTy<'tcx> { BodyOwnerKind::Const { .. } | BodyOwnerKind::Static(..) => { let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); - if self.mir_def.to_def_id() == typeck_root_def_id - // Do not ICE when checking default_field_values consts with lifetimes (#135649) - && DefKind::Field != tcx.def_kind(tcx.parent(typeck_root_def_id)) - { + if self.mir_def.to_def_id() == typeck_root_def_id { let args = self.infcx.replace_free_regions_with_nll_infer_vars( NllRegionVariableOrigin::FreeRegion, identity_args, ); DefiningTy::Const(self.mir_def.to_def_id(), args) } else { - // FIXME this line creates a dependency between borrowck and typeck. + // FIXME: this line creates a query dependency between borrowck and typeck. // // This is required for `AscribeUserType` canonical query, which will call // `type_of(inline_const_def_id)`. That `type_of` would inject erased lifetimes @@ -699,30 +694,14 @@ fn compute_indices( let tcx = self.infcx.tcx; let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id()); let identity_args = GenericArgs::identity_for_item(tcx, typeck_root_def_id); - let fr_args = match defining_ty { - DefiningTy::Closure(_, args) - | DefiningTy::CoroutineClosure(_, args) - | DefiningTy::Coroutine(_, args) - | DefiningTy::InlineConst(_, args) => { - // In the case of closures, we rely on the fact that - // the first N elements in the ClosureArgs are - // inherited from the `typeck_root_def_id`. - // Therefore, when we zip together (below) with - // `identity_args`, we will get only those regions - // that correspond to early-bound regions declared on - // the `typeck_root_def_id`. - assert!(args.len() >= identity_args.len()); - assert_eq!(args.regions().count(), identity_args.regions().count()); - args - } - - DefiningTy::FnDef(_, args) | DefiningTy::Const(_, args) => args, - - DefiningTy::GlobalAsm(_) => ty::List::empty(), - }; + let renumbered_args = defining_ty.args(); let global_mapping = iter::once((tcx.lifetimes.re_static, fr_static)); - let arg_mapping = iter::zip(identity_args.regions(), fr_args.regions().map(|r| r.as_var())); + // This relies on typeck roots being generics_of parents with their + // parameters at the start of nested bodies' generics. + assert!(renumbered_args.len() >= identity_args.len()); + let arg_mapping = + iter::zip(identity_args.regions(), renumbered_args.regions().map(|r| r.as_var())); UniversalRegionIndices { indices: global_mapping.chain(arg_mapping).collect(), @@ -862,8 +841,8 @@ fn compute_inputs_and_output( }; // FIXME(#129952): We probably want a more principled approach here. - if let Err(terr) = inputs_and_output.skip_binder().error_reported() { - self.infcx.set_tainted_by_errors(terr); + if let Err(e) = inputs_and_output.error_reported() { + self.infcx.set_tainted_by_errors(e); } inputs_and_output diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 180589340b4c..aa0e5c7fd710 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::{self, DefiningScopeKind, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, span_bug}; use rustc_span::{DUMMY_SP, Ident, Span}; +use tracing::instrument; use super::{HirPlaceholderCollector, ItemCtxt, bad_placeholder}; use crate::check::wfcheck::check_static_item; @@ -17,85 +18,7 @@ mod opaque; -fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { - use hir::*; - use rustc_middle::ty::Ty; - let tcx = icx.tcx; - let hir_id = tcx.local_def_id_to_hir_id(def_id); - - let node = tcx.hir_node(hir_id); - let Node::AnonConst(&AnonConst { span, .. }) = node else { - span_bug!( - tcx.def_span(def_id), - "expected anon const in `anon_const_type_of`, got {node:?}" - ); - }; - - let parent_node_id = tcx.parent_hir_id(hir_id); - let parent_node = tcx.hir_node(parent_node_id); - - match parent_node { - // Anon consts "inside" the type system. - Node::ConstArg(&ConstArg { - hir_id: arg_hir_id, - kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }), - .. - }) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span), - - Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => { - tcx.adt_def(tcx.hir_get_parent_item(hir_id)).repr().discr_type().to_ty(tcx) - } - - Node::Field(&hir::FieldDef { default: Some(c), def_id: field_def_id, .. }) - if c.hir_id == hir_id => - { - tcx.type_of(field_def_id).instantiate_identity() - } - - _ => Ty::new_error_with_message( - tcx, - span, - format!("unexpected anon const parent in type_of(): {parent_node:?}"), - ), - } -} - -fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> { - use hir::*; - use rustc_middle::ty::Ty; - - let tcx = icx.tcx; - - match tcx.parent_hir_node(arg_hir_id) { - // Array length const arguments do not have `type_of` fed as there is never a corresponding - // generic parameter definition. - Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. }) - | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) - if constant.hir_id == arg_hir_id => - { - tcx.types.usize - } - - Node::TyPat(pat) => { - let node = match tcx.parent_hir_node(pat.hir_id) { - // Or patterns can be nested one level deep - Node::TyPat(p) => tcx.parent_hir_node(p.hir_id), - other => other, - }; - let hir::TyKind::Pat(ty, _) = node.expect_ty().kind else { bug!() }; - icx.lower_ty(ty) - } - - // This is not a `bug!` as const arguments in path segments that did not resolve to anything - // will result in `type_of` never being fed. - _ => Ty::new_error_with_message( - tcx, - span, - "`type_of` called on const argument's anon const before the const argument was lowered", - ), - } -} - +#[instrument(level = "debug", skip(tcx), ret)] pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<'_, Ty<'_>> { use rustc_hir::*; use rustc_middle::ty::Ty; @@ -408,6 +331,85 @@ pub(super) fn type_of_opaque_hir_typeck( } } +fn anon_const_type_of<'tcx>(icx: &ItemCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { + use hir::*; + use rustc_middle::ty::Ty; + let tcx = icx.tcx; + let hir_id = tcx.local_def_id_to_hir_id(def_id); + + let node = tcx.hir_node(hir_id); + let Node::AnonConst(&AnonConst { span, .. }) = node else { + span_bug!( + tcx.def_span(def_id), + "expected anon const in `anon_const_type_of`, got {node:?}" + ); + }; + + let parent_node_id = tcx.parent_hir_id(hir_id); + let parent_node = tcx.hir_node(parent_node_id); + + match parent_node { + // Anon consts "inside" the type system. + Node::ConstArg(&ConstArg { + hir_id: arg_hir_id, + kind: ConstArgKind::Anon(&AnonConst { hir_id: anon_hir_id, .. }), + .. + }) if anon_hir_id == hir_id => const_arg_anon_type_of(icx, arg_hir_id, span), + + Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => { + tcx.adt_def(tcx.hir_get_parent_item(hir_id)).repr().discr_type().to_ty(tcx) + } + + Node::Field(&hir::FieldDef { default: Some(c), def_id: field_def_id, .. }) + if c.hir_id == hir_id => + { + tcx.type_of(field_def_id).instantiate_identity() + } + + _ => Ty::new_error_with_message( + tcx, + span, + format!("unexpected anon const parent in type_of(): {parent_node:?}"), + ), + } +} + +fn const_arg_anon_type_of<'tcx>(icx: &ItemCtxt<'tcx>, arg_hir_id: HirId, span: Span) -> Ty<'tcx> { + use hir::*; + use rustc_middle::ty::Ty; + + let tcx = icx.tcx; + + match tcx.parent_hir_node(arg_hir_id) { + // Array length const arguments do not have `type_of` fed as there is never a corresponding + // generic parameter definition. + Node::Ty(&hir::Ty { kind: TyKind::Array(_, ref constant), .. }) + | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. }) + if constant.hir_id == arg_hir_id => + { + tcx.types.usize + } + + Node::TyPat(pat) => { + let node = match tcx.parent_hir_node(pat.hir_id) { + // Or patterns can be nested one level deep + Node::TyPat(p) => tcx.parent_hir_node(p.hir_id), + other => other, + }; + let hir::TyKind::Pat(ty, _) = node.expect_ty().kind else { bug!() }; + icx.lower_ty(ty) + } + + // This is not a `bug!` as const arguments in path segments that did not resolve to anything + // will result in `type_of` never being fed. + _ => Ty::new_error_with_message( + tcx, + span, + "`type_of` called on const argument's anon const before the const argument was lowered", + ), + } +} + fn infer_placeholder_type<'tcx>( cx: &dyn HirTyLowerer<'tcx>, def_id: LocalDefId, From a8c9cb5f77f2d66f85758703610b55a2ae8865e0 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Wed, 24 Dec 2025 12:25:30 +0000 Subject: [PATCH 125/126] Fix some divergences with the cg_clif subtree For some reason git-subtree incorrectly synced those changes. --- .../rustc_codegen_cranelift/src/intrinsics/simd.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 15aef60c5af3..bef9c6747457 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -1005,14 +1005,6 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let lane_clif_ty = fx.clif_type(val_lane_ty).unwrap(); let ret_lane_layout = fx.layout_of(ret_lane_ty); - let alignment = - generic_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment(); - - let memflags = match alignment { - SimdAlign::Unaligned => MemFlags::new().with_notrap(), - _ => MemFlags::trusted(), - }; - for lane_idx in 0..ptr_lane_count { let val_lane = val.value_lane(fx, lane_idx).load_scalar(fx); let ptr_lane = ptr.value_lane(fx, lane_idx).load_scalar(fx); @@ -1028,7 +1020,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.bcx.seal_block(if_disabled); fx.bcx.switch_to_block(if_enabled); - let res = fx.bcx.ins().load(lane_clif_ty, memflags, ptr_lane, 0); + let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), ptr_lane, 0); fx.bcx.ins().jump(next, &[res.into()]); fx.bcx.switch_to_block(if_disabled); From faac1b517f59e92b51b176fb0bbec26b82a2a0d6 Mon Sep 17 00:00:00 2001 From: The rustc-josh-sync Cronjob Bot Date: Thu, 25 Dec 2025 04:19:22 +0000 Subject: [PATCH 126/126] Prepare for merging from rust-lang/rust This updates the rust-version file to e7d44143a12a526488e4f0c0d7ea8e62a4fe9354. --- src/tools/rust-analyzer/rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/rust-analyzer/rust-version b/src/tools/rust-analyzer/rust-version index 95e1cd0db37c..5ffe95a0b54f 100644 --- a/src/tools/rust-analyzer/rust-version +++ b/src/tools/rust-analyzer/rust-version @@ -1 +1 @@ -f41f40408d719aa9ae0c6bfa17619d8f3f9e5b99 +e7d44143a12a526488e4f0c0d7ea8e62a4fe9354