From aee14eb9113363529ffd6657c968e817371592b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Aug 2026 08:46:35 +0200 Subject: [PATCH 01/12] declare C and C-unwind as mutually ABI-compatible --- library/core/src/primitive_docs.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs index 4b84a9de4ce72..5099c2fded6b5 100644 --- a/library/core/src/primitive_docs.rs +++ b/library/core/src/primitive_docs.rs @@ -1810,9 +1810,14 @@ const _: () = (); /// `fn name(...) -> ...` implicitly uses the `"Rust"` ABI string and `extern fn name(...) -> ...` /// implicitly uses the `"C"` ABI string. /// -/// The ABI strings are guaranteed to be compatible if they are the same, or if the caller ABI -/// string is `$X-unwind` and the callee ABI string is `$X`, where `$X` is one of the following: -/// "C", "aapcs", "fastcall", "stdcall", "system", "sysv64", "thiscall", "vectorcall", "win64". +/// The ABI strings are guaranteed to be compatible if they are the same, or if one of them is +/// `$X-unwind` and the other one is `$X`, where `$X` is one of the following: "C", "aapcs", +/// "fastcall", "stdcall", "system", "sysv64", "thiscall", "vectorcall", "win64". (Note that [it is +/// undefined behavior][unwind-ub] for a function to unwind unless *both* caller and callee use a +/// signature that permits unwinding, such as "C-unwind". Rust ensures that a function defined with +/// a non-unwinding ABI such as "C" never unwinds due to a panic, so undefined behavior can only +/// arise if the callee ABI is `$X-unwind` and the caller ABI is `$X`, or if a non-Rust unwind +/// occurs.) /// /// The following types are guaranteed to be ABI-compatible: /// @@ -1878,7 +1883,8 @@ const _: () = (); /// Behavior since transmuting `None::>` to `NonZero` violates the non-zero /// requirement. /// -/// [cfi-docs]: https://doc.rust-lang.org/beta/unstable-book/compiler-flags/sanitizer.html#controlflowintegrity +/// [unwind-ub]: ../reference/behavior-considered-undefined.html#r-undefined.call +/// [cfi-docs]: ../unstable-book/compiler-flags/sanitizer.html#controlflowintegrity /// /// ### Trait implementations /// From 3a4c1c0e1196f64a3759bca77908979a4ee4cba7 Mon Sep 17 00:00:00 2001 From: Lucy Menon <168595099+syntactically@users.noreply.github.com> Date: Mon, 21 Sep 2026 19:08:35 +0100 Subject: [PATCH 02/12] Add Tier 3 targets for Hyperlight guests --- .../rustc_target/src/spec/base/hyperlight.rs | 19 +++++ compiler/rustc_target/src/spec/base/mod.rs | 1 + compiler/rustc_target/src/spec/mod.rs | 4 + .../targets/aarch64_unknown_hyperlight.rs | 31 ++++++++ .../spec/targets/x86_64_unknown_hyperlight.rs | 30 ++++++++ src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 + .../rustc/src/platform-support/hyperlight.md | 75 +++++++++++++++++++ src/librustdoc/clean/cfg.rs | 1 + .../src/completions/attribute/cfg.rs | 3 +- tests/assembly-llvm/targets/targets-elf.rs | 6 ++ tests/rustdoc-html/doc-cfg/all-targets.rs | 7 +- tests/ui/check-cfg/cfg-crate-features.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 4 +- 14 files changed, 179 insertions(+), 7 deletions(-) create mode 100644 compiler/rustc_target/src/spec/base/hyperlight.rs create mode 100644 compiler/rustc_target/src/spec/targets/aarch64_unknown_hyperlight.rs create mode 100644 compiler/rustc_target/src/spec/targets/x86_64_unknown_hyperlight.rs create mode 100644 src/doc/rustc/src/platform-support/hyperlight.md diff --git a/compiler/rustc_target/src/spec/base/hyperlight.rs b/compiler/rustc_target/src/spec/base/hyperlight.rs new file mode 100644 index 0000000000000..2865d3eaa35ad --- /dev/null +++ b/compiler/rustc_target/src/spec/base/hyperlight.rs @@ -0,0 +1,19 @@ +use crate::spec::{ + Cc, CodeModel, LinkerFlavor, Lld, Os, PanicStrategy, RelocModel, StackProbeType, TargetOptions, +}; + +pub(crate) fn opts() -> TargetOptions { + TargetOptions { + os: Os::Hyperlight, + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + disable_redzone: true, + panic_strategy: PanicStrategy::Abort, + stack_probes: StackProbeType::Inline, + code_model: Some(CodeModel::Small), + relocation_model: RelocModel::Pic, + position_independent_executables: true, + static_position_independent_executables: true, + ..Default::default() + } +} diff --git a/compiler/rustc_target/src/spec/base/mod.rs b/compiler/rustc_target/src/spec/base/mod.rs index 13f364f3d8258..1fc2deed765f6 100644 --- a/compiler/rustc_target/src/spec/base/mod.rs +++ b/compiler/rustc_target/src/spec/base/mod.rs @@ -13,6 +13,7 @@ pub(crate) mod helenos; pub(crate) mod hermit; pub(crate) mod hurd; pub(crate) mod hurd_gnu; +pub(crate) mod hyperlight; pub(crate) mod illumos; pub(crate) mod l4re; pub(crate) mod linux; diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 42d817c7daa31..31bf200280eb7 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1695,6 +1695,9 @@ supported_targets! { ("i686-oe-linux-gnu", i686_oe_linux_gnu), ("riscv64-oe-linux-gnu", riscv64_oe_linux_gnu), ("x86_64-oe-linux-gnu", x86_64_oe_linux_gnu), + + ("aarch64-unknown-hyperlight", aarch64_unknown_hyperlight), + ("x86_64-unknown-hyperlight", x86_64_unknown_hyperlight), } /// Cow-Vec-Str: Cow<'static, [Cow<'static, str>]> @@ -1850,6 +1853,7 @@ crate::target_spec_enum! { Hermit = "hermit", Horizon = "horizon", Hurd = "hurd", + Hyperlight = "hyperlight", Illumos = "illumos", IOs = "ios", L4Re = "l4re", diff --git a/compiler/rustc_target/src/spec/targets/aarch64_unknown_hyperlight.rs b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hyperlight.rs new file mode 100644 index 0000000000000..651ae753cb59c --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/aarch64_unknown_hyperlight.rs @@ -0,0 +1,31 @@ +// Hyperlight Guest target for AArch64 + +use crate::spec::{Arch, SanitizerSet, Target, TargetMetadata, TargetOptions, base}; + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + features: "+v8.1a,+strict-align,+neon,+fp-armv8".into(), + direct_access_external_data: Some(true), + + supported_sanitizers: SanitizerSet::KCFI + | SanitizerSet::KERNELADDRESS + | SanitizerSet::KERNELHWADDRESS, + max_atomic_width: Some(128), + default_uwtable: true, + supports_xray: true, + ..base::hyperlight::opts() + }; + Target { + llvm_target: "aarch64-unknown-none".into(), + metadata: TargetMetadata { + description: Some("ARM64 Hyperlight guest".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32".into(), + arch: Arch::AArch64, + options: opts, + } +} diff --git a/compiler/rustc_target/src/spec/targets/x86_64_unknown_hyperlight.rs b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hyperlight.rs new file mode 100644 index 0000000000000..373b6995117b0 --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/x86_64_unknown_hyperlight.rs @@ -0,0 +1,30 @@ +// Hyperlight Guest target for x86_64 + +use crate::spec::{Arch, RelroLevel, SanitizerSet, Target, TargetMetadata, TargetOptions, base}; + +pub(crate) fn target() -> Target { + let opts = TargetOptions { + features: "-mmx,+sse,+sse2,-sse3,-ssse3,-sse4.1,-sse4.2,-avx,-avx2,-soft-float".into(), + + cpu: "x86-64".into(), + plt_by_default: false, + max_atomic_width: Some(64), + relro_level: RelroLevel::Full, + supported_sanitizers: SanitizerSet::KCFI | SanitizerSet::KERNELADDRESS, + ..base::hyperlight::opts() + }; + Target { + llvm_target: "x86_64-unknown-none-elf".into(), + metadata: TargetMetadata { + description: Some("x86_64 Hyperlight guest".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + data_layout: + "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128".into(), + arch: Arch::X86_64, + options: opts, + } +} diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index f15c712c32b91..1c2935ff264e0 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -133,6 +133,7 @@ - [\*-unikraft-linux-musl](platform-support/unikraft-linux-musl.md) - [\*-unknown-helenos](platform-support/helenos.md) - [\*-unknown-hermit](platform-support/hermit.md) + - [\*-unknown-hyperlight](platform-support/hyperlight.md) - [\*-unknown-freebsd](platform-support/freebsd.md) - [\*-unknown-managarm-mlibc](platform-support/managarm.md) - [\*-unknown-motor](platform-support/motor.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index c2a86d85dfcde..11a6ada2c4f89 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -273,6 +273,7 @@ target | std | host | notes [`aarch64-oe-linux-gnu`](platform-support/oe-linux-gnu.md) | ✓ | | ARM64 OpenEmbedded/Yocto Linux (GNU) [`aarch64-unknown-helenos`](platform-support/helenos.md) | ✓ | | ARM64 HelenOS [`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit +[`aarch64-unknown-hyperlight`](platform-support/hyperlight.md) | * | | ARM64 Hyperlight [`aarch64-unknown-illumos`](platform-support/illumos.md) | ✓ | ✓ | ARM64 illumos [`aarch64-unknown-l4re-uclibc`](platform-support/l4re.md) | ✓ | | ARM64 L4Re with uclibc `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) @@ -461,6 +462,7 @@ target | std | host | notes `x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku [`x86_64-unknown-hermit`](platform-support/hermit.md) | ✓ | | x86_64 Hermit [`x86_64-unknown-helenos`](platform-support/helenos.md) | ✓ | | x86_64 (amd64) HelenOS +[`x86_64-unknown-hyperlight`](platform-support/hyperlight.md) | * | | x86_64 (amd64) Hyperlight [`x86_64-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 64-bit GNU/Hurd [`x86_64-unknown-l4re-uclibc`](platform-support/l4re.md) | ✓ | | x86_64 L4Re with uclibc [`x86_64-unknown-linux-none`](platform-support/x86_64-unknown-linux-none.md) | * | | 64-bit Linux with no libc diff --git a/src/doc/rustc/src/platform-support/hyperlight.md b/src/doc/rustc/src/platform-support/hyperlight.md new file mode 100644 index 0000000000000..be54a87e6a0fc --- /dev/null +++ b/src/doc/rustc/src/platform-support/hyperlight.md @@ -0,0 +1,75 @@ +# `*-unknown-hyperlight` + +**Tier: 3** + +These targets are used to build guest executables for the +[Hyperlight](https://github.com/hyperlight-dev/hyperlight) sandboxing +solution. + +## Target maintainers + +- [@syntactically](https://github.com/syntactically) +- [@yoshuawuyts](https://github.com/yoshuawuyts) + +## Requirements + +These targets can only be used for cross-compilation. They should not +require anything special as host tooling, but the usual way to use +them is via the +[cargo-hyperlight](https://github.com/hyperlight-dev/cargo-hyperlight) +tool. + +Hyperlight targets do not have any `std` support, but do fully support +`alloc`. + +These targets assume ARMv8.1-A (with Neon) on aarch64 and SSE2 on +x86_64, which are required by core Hyperlight libraries. The targets +are only expected to work with recent versions of Hyperlight. + +Hyperlight uses the official hardfloat calling convention of each +architecture for `extern "C"`. + +Hyperlight guest binaries use the ELF file format. + +## Building the target + +These targets can be built by adding them to the `target` list in +`bootstrap.toml`. + +```toml +[build] +build-stage = 1 +target = [ + "", + "-unknown-hyperlight", +] + +[target.-unknown-hyperlight] +no-std = true +``` + +## Building Rust programs + +Rust does not yet ship pre-compiled artifacts for this target. To +compile for this target, you will either need to build Rust with the +target enabled (see "Building the target" above), or build your own +copy of `core` by using `build-std` or similar. When using +`cargo-hyperlight`, the tool will manage this automatically. + +## Testing + +Binaries built for this target need to use the +[`hyperlight-guest-bin`](https://crates.io/crates/hyperlight-guest-bin) +crate. A given binary can then be loaded by a host process that uses +[`hyperlight-host`](https://crates.io/crates/hyperlight-host) and +agrees with it on a host/guest interface. For more details on the +programming model and how to write a host, see those crates and +documentation on the Hyperlight [website](https://hyperlight.org) and +in the [repository](https://github.com/hyperlight-dev/hyperlight). + +## Cross-compilation toolchains and C code + +This target does support C code through +[cargo-hyperlight](https://github.com/hyperlight-dev/cargo-hyperlight), +which supports wrapping an `-unknown-none` C toolchain into +something that can build targeting Hyperlight. diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index db63dbaa24663..a3384a5ee88cd 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -672,6 +672,7 @@ fn human_readable_target_os(os: Symbol) -> Option<&'static str> { Hermit => "Hermit", Horizon => "Horizon", Hurd => "GNU/Hurd", + Hyperlight => "Hyperlight", IOs => "iOS", Illumos => "illumos", L4Re => "L4Re", diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs index c314b3f37c04d..9c24ee1a5808b 100644 --- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs +++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/attribute/cfg.rs @@ -114,7 +114,7 @@ const KNOWN_ARCH: [&str; 20] = [ const KNOWN_ENV: [&str; 7] = ["eabihf", "gnu", "gnueabihf", "msvc", "relibc", "sgx", "uclibc"]; -const KNOWN_OS: [&str; 21] = [ +const KNOWN_OS: [&str; 22] = [ "cuda", "dragonfly", "emscripten", @@ -122,6 +122,7 @@ const KNOWN_OS: [&str; 21] = [ "fuchsia", "haiku", "hermit", + "hyperlight", "illumos", "l4re", "linux", diff --git a/tests/assembly-llvm/targets/targets-elf.rs b/tests/assembly-llvm/targets/targets-elf.rs index 610a271d91144..971e9700035e5 100644 --- a/tests/assembly-llvm/targets/targets-elf.rs +++ b/tests/assembly-llvm/targets/targets-elf.rs @@ -43,6 +43,9 @@ //@ revisions: aarch64_unknown_hermit //@ [aarch64_unknown_hermit] compile-flags: --target aarch64-unknown-hermit //@ [aarch64_unknown_hermit] needs-llvm-components: aarch64 +//@ revisions: aarch64_unknown_hyperlight +//@ [aarch64_unknown_hyperlight] compile-flags: --target aarch64-unknown-hyperlight +//@ [aarch64_unknown_hyperlight] needs-llvm-components: aarch64 //@ revisions: aarch64_unknown_illumos //@ [aarch64_unknown_illumos] compile-flags: --target aarch64-unknown-illumos //@ [aarch64_unknown_illumos] needs-llvm-components: aarch64 @@ -724,6 +727,9 @@ //@ revisions: x86_64_unknown_hermit //@ [x86_64_unknown_hermit] compile-flags: --target x86_64-unknown-hermit //@ [x86_64_unknown_hermit] needs-llvm-components: x86 +//@ revisions: x86_64_unknown_hyperlight +//@ [x86_64_unknown_hyperlight] compile-flags: --target x86_64-unknown-hyperlight +//@ [x86_64_unknown_hyperlight] needs-llvm-components: x86 //@ revisions: x86_64_unknown_illumos //@ [x86_64_unknown_illumos] compile-flags: --target x86_64-unknown-illumos //@ [x86_64_unknown_illumos] needs-llvm-components: x86 diff --git a/tests/rustdoc-html/doc-cfg/all-targets.rs b/tests/rustdoc-html/doc-cfg/all-targets.rs index aec251878781e..421dfe4dcd793 100644 --- a/tests/rustdoc-html/doc-cfg/all-targets.rs +++ b/tests/rustdoc-html/doc-cfg/all-targets.rs @@ -77,9 +77,9 @@ pub fn bar() {} // 'Available on target_os=fake_os and target_os=unknown and AIX and AMD HSA \ // and Android and bare-metal and CUDA and Cygwin and DragonFly BSD and \ // Emscripten and ESP-IDF and FreeBSD and Fuchsia and GNU/Hurd and Haiku \ -// and HelenOS and Hermit and Horizon and illumos and iOS and L4Re and Linux \ -// and LynxOS-178 and macOS and Managarm and Motor OS and NetBSD and NuttX \ -// and OpenBSD and Play Station 1 and Play Station 3 and Play Station Portable \ +// and HelenOS and Hermit and Horizon and Hyperlight and illumos and iOS and L4Re \ +// and Linux and LynxOS-178 and macOS and Managarm and Motor OS and NetBSD and \ +// NuttX and OpenBSD and Play Station 1 and Play Station 3 and Play Station Portable \ // and Play Station Vita and QNX SDP 7.x and QNX SDP 8.0+ and QuRT and Redox OS \ // and RTEMS OS and Solaris and SOLID ASP3 and TEEOS and Trusty and tvOS and UEFI \ // and VEXos and visionOS and VxWorks and WASI and watchOS and Windows and Xous \ @@ -100,6 +100,7 @@ pub fn bar() {} target_os = "hermit", target_os = "horizon", target_os = "hurd", + target_os = "hyperlight", target_os = "illumos", target_os = "ios", target_os = "l4re", diff --git a/tests/ui/check-cfg/cfg-crate-features.stderr b/tests/ui/check-cfg/cfg-crate-features.stderr index d65562313cb42..6bc375e0383aa 100644 --- a/tests/ui/check-cfg/cfg-crate-features.stderr +++ b/tests/ui/check-cfg/cfg-crate-features.stderr @@ -24,7 +24,7 @@ warning: unexpected `cfg` condition value: `does_not_exist` LL | #![cfg(not(target(os = "does_not_exist")))] | ^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, and `rtems` and 16 more + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `hyperlight`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, and `redox` and 17 more = note: see for more information about checking conditional configuration = note: `#[warn(unexpected_cfgs)]` on by default diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index 5ccaf1e9aa698..a99f230c6f911 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -232,7 +232,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `hyperlight`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -305,7 +305,7 @@ LL | #[cfg(target_os = "linuz")] // testing that we suggest `linux` | | | help: there is a expected value with a similar name: `"linux"` | - = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `cygwin`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `helenos`, `hermit`, `horizon`, `hurd`, `hyperlight`, `illumos`, `ios`, `l4re`, `linux`, `lynxos178`, `macos`, `managarm`, `motor`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `ps3`, `psp`, `psx`, `qnx`, `qurt`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `vexos`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: 31 warnings emitted From a8210e14e787b3e6574414e09ea5f35cdc0e8e0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Thu, 24 Sep 2026 13:17:00 +0200 Subject: [PATCH 03/12] rustdoc: Fix where-clause placement of free const items --- src/librustdoc/html/render/print_item.rs | 15 ++++---- .../constant/const-value-display.rs | 4 +-- .../constant/generic-const-items.rs | 21 ++++++++++++ .../constant/show-const-contents.rs | 34 ++++++++----------- 4 files changed, 45 insertions(+), 29 deletions(-) diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 46dba0253766a..bf781410008fe 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -2017,13 +2017,11 @@ fn item_constant( write!( w, - "{vis}const {name}{generics}: {typ}{where_clause}", + "{vis}const {name}{generics}: {typ}", vis = visibility_print_with_space(it, cx), name = it.name.unwrap(), generics = print_generics(generics, cx), typ = print_type(ty, cx), - where_clause = - print_where_clause(generics, cx, 0, Ending::NoNewline).maybe_display(), )?; // FIXME: The code below now prints @@ -2039,9 +2037,7 @@ fn item_constant( let is_literal = c.is_literal(tcx); let expr = c.expr(tcx); if value.is_some() || is_literal { - write!(w, " = {expr};", expr = Escape(&expr))?; - } else { - w.write_str(";")?; + write!(w, " = {expr}", expr = Escape(&expr))?; } if !is_literal && let Some(value) = &value { @@ -2051,9 +2047,14 @@ fn item_constant( if value_lowercase != expr_lowercase && value_lowercase.trim_end_matches("i32") != expr_lowercase { - write!(w, " // {value}", value = Escape(value))?; + write!(w, " /* {value} */", value = Escape(value))?; } } + + print_where_clause(generics, cx, 0, Ending::NoNewline).maybe_display().fmt(w)?; + + w.write_str(";")?; + Ok::<(), fmt::Error>(()) })?; diff --git a/tests/rustdoc-html/constant/const-value-display.rs b/tests/rustdoc-html/constant/const-value-display.rs index 658978a3490b1..12259e1089edc 100644 --- a/tests/rustdoc-html/constant/const-value-display.rs +++ b/tests/rustdoc-html/constant/const-value-display.rs @@ -1,9 +1,9 @@ #![crate_name = "foo"] //@ has 'foo/constant.HOUR_IN_SECONDS.html' -//@ has - '//*[@class="rust item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = _; // 3_600u64' +//@ has - '//*[@class="rust item-decl"]//code' 'pub const HOUR_IN_SECONDS: u64 = _ /* 3_600u64 */;' pub const HOUR_IN_SECONDS: u64 = 60 * 60; //@ has 'foo/constant.NEGATIVE.html' -//@ has - '//*[@class="rust item-decl"]//code' 'pub const NEGATIVE: i64 = _; // -3_600i64' +//@ has - '//*[@class="rust item-decl"]//code' 'pub const NEGATIVE: i64 = _ /* -3_600i64 */;' pub const NEGATIVE: i64 = -60 * 60; diff --git a/tests/rustdoc-html/constant/generic-const-items.rs b/tests/rustdoc-html/constant/generic-const-items.rs index 31c300f2ff1e1..353f9c2dc6230 100644 --- a/tests/rustdoc-html/constant/generic-const-items.rs +++ b/tests/rustdoc-html/constant/generic-const-items.rs @@ -1,6 +1,8 @@ #![feature(generic_const_items)] #![allow(incomplete_features)] +// (Here we hide the RHS because it's not a literal) +// //@ has 'generic_const_items/constant.K.html' //@ has - '//*[@class="rust item-decl"]//code' \ // "pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> \ @@ -10,6 +12,25 @@ pub const K<'a, T: 'a + Copy, const N: usize>: Option<[T; N]> = None where String: From; +// Ensure that we render the where-clause *after* the RHS. +// +//@ has 'generic_const_items/constant.Q.html' +//@ has - '//*[@class="rust item-decl"]//code' \ +// "pub const Q: i32 = 0 \ +// where \ +// for<'_delay> i32: Copy;" +pub const Q: i32 = 0 where for<'_delay> i32: Copy; + +// Ensure that we properly insert the fake comment containing the value +// between the expression and the where-clause. +// +//@ has 'generic_const_items/constant.C.html' +//@ has - '//*[@class="rust item-decl"]//code' \ +// "pub const C<'a>: u8 = _ /* 2u8 */ \ +// where \ +// &'a (): Sized;" +pub const C<'a>: u8 = 1 + 1 where &'a (): Sized; + //@ has generic_const_items/trait.Trait.html pub trait Trait { //@ has - '//*[@id="associatedconstant.C"]' \ diff --git a/tests/rustdoc-html/constant/show-const-contents.rs b/tests/rustdoc-html/constant/show-const-contents.rs index 6d2701693ceff..e5d056ac0ba46 100644 --- a/tests/rustdoc-html/constant/show-const-contents.rs +++ b/tests/rustdoc-html/constant/show-const-contents.rs @@ -1,67 +1,61 @@ // Test that the contents of constants are displayed as part of the // documentation. -//@ hasraw show_const_contents/constant.CONST_S.html 'show this' -//@ !hasraw show_const_contents/constant.CONST_S.html '; //' +//@ hasraw show_const_contents/constant.CONST_S.html '"show this";' pub const CONST_S: &'static str = "show this"; //@ hasraw show_const_contents/constant.CONST_I32.html '= 42;' -//@ !hasraw show_const_contents/constant.CONST_I32.html '; //' pub const CONST_I32: i32 = 42; //@ hasraw show_const_contents/constant.CONST_I32_HEX.html '= 0x42;' -//@ !hasraw show_const_contents/constant.CONST_I32_HEX.html '; //' pub const CONST_I32_HEX: i32 = 0x42; //@ hasraw show_const_contents/constant.CONST_NEG_I32.html '= -42;' -//@ !hasraw show_const_contents/constant.CONST_NEG_I32.html '; //' pub const CONST_NEG_I32: i32 = -42; //@ hasraw show_const_contents/constant.CONST_EQ_TO_VALUE_I32.html '= 42i32;' -//@ !hasraw show_const_contents/constant.CONST_EQ_TO_VALUE_I32.html '// 42i32' pub const CONST_EQ_TO_VALUE_I32: i32 = 42i32; -//@ hasraw show_const_contents/constant.CONST_CALC_I32.html '= _; // 43i32' +//@ hasraw show_const_contents/constant.CONST_CALC_I32.html '= _ /* 43i32 */;' pub const CONST_CALC_I32: i32 = 42 + 1; //@ !hasraw show_const_contents/constant.CONST_REF_I32.html '= &42;' -//@ !hasraw show_const_contents/constant.CONST_REF_I32.html '; //' +//@ !hasraw show_const_contents/constant.CONST_REF_I32.html '= _;' pub const CONST_REF_I32: &'static i32 = &42; -//@ hasraw show_const_contents/constant.CONST_I32_MAX.html '= i32::MAX; // 2_147_483_647i32' +//@ hasraw show_const_contents/constant.CONST_I32_MAX.html '= i32::MAX /* 2_147_483_647i32 */;' pub const CONST_I32_MAX: i32 = i32::MAX; //@ !hasraw show_const_contents/constant.UNIT.html '= ();' -//@ !hasraw show_const_contents/constant.UNIT.html '; //' pub const UNIT: () = (); pub struct MyType(i32); //@ !hasraw show_const_contents/constant.MY_TYPE.html '= MyType(42);' -//@ !hasraw show_const_contents/constant.MY_TYPE.html '; //' +//@ !hasraw show_const_contents/constant.MY_TYPE.html '= _;' pub const MY_TYPE: MyType = MyType(42); pub struct MyTypeWithStr(&'static str); -//@ !hasraw show_const_contents/constant.MY_TYPE_WITH_STR.html '= MyTypeWithStr("show this");' -//@ !hasraw show_const_contents/constant.MY_TYPE_WITH_STR.html '; //' +//@ !hasraw show_const_contents/constant.MY_TYPE_WITH_STR.html \ +// '= MyTypeWithStr("show this");' +//@ !hasraw show_const_contents/constant.MY_TYPE_WITH_STR.html '= _;' pub const MY_TYPE_WITH_STR: MyTypeWithStr = MyTypeWithStr("show this"); -//@ hasraw show_const_contents/constant.PI.html '= 3.14159265358979323846264338327950288_f32;' -//@ hasraw show_const_contents/constant.PI.html '; // 3.14159274f32' +//@ hasraw show_const_contents/constant.PI.html \ +// '= 3.14159265358979323846264338327950288_f32 /* 3.14159274f32 */;' pub use std::f32::consts::PI; - -//@ hasraw show_const_contents/constant.MAX.html '= i32::MAX; // 2_147_483_647i32' +//@ hasraw show_const_contents/constant.MAX.html '= i32::MAX /* 2_147_483_647i32 */;' #[allow(deprecated, deprecated_in_future)] pub use std::i32::MAX; macro_rules! int_module { - ($T:ident) => ( + ($T:ident) => { pub const MIN: $T = $T::MIN; - ) + }; } -//@ hasraw show_const_contents/constant.MIN.html '= i16::MIN; // -32_768i16' +//@ hasraw show_const_contents/constant.MIN.html '= i16::MIN /* -32_768i16 */;' int_module!(i16); //@ has show_const_contents/constant.ESCAPE.html //pre '= r#""#;' From 9f3299ed68109f94e6a718e9571d02400cb6ba80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Thu, 24 Sep 2026 13:01:16 +0200 Subject: [PATCH 04/12] rustdoc: Fix where-clause placement of checked type aliases --- src/librustdoc/html/render/print_item.rs | 54 ++++++++----------- .../typedef/checked-type-aliases.rs | 9 ++++ .../typedef-inner-variants-lazy_type_alias.rs | 7 +-- .../where.golf_type_alias_decl.html | 5 +- tests/rustdoc-html/where.rs | 2 +- 5 files changed, 40 insertions(+), 37 deletions(-) create mode 100644 tests/rustdoc-html/typedef/checked-type-aliases.rs diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index bf781410008fe..f6d5ada07f364 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1296,79 +1296,71 @@ fn item_trait_alias( fn item_type_alias(cx: &Context<'_>, it: &clean::Item, t: &clean::TypeAlias) -> impl fmt::Display { fmt::from_fn(|w| { + let def_id = it.def_id().unwrap(); + wrap_item(w, |w| { render_attributes_in_code(w, it, "", cx)?; write!( w, - "{vis}type {name}{generics}{where_clause} = {type_};", + "{vis}type {name}{generics}", vis = visibility_print_with_space(it, cx), name = it.name.unwrap(), generics = print_generics(&t.generics, cx), - where_clause = - print_where_clause(&t.generics, cx, 0, Ending::Newline).maybe_display(), - type_ = print_type(&t.type_, cx), - ) + )?; + + let type_ = print_type(&t.type_, cx); + let where_clause = + print_where_clause(&t.generics, cx, 0, Ending::NoNewline).maybe_display(); + + if cx.tcx().type_alias_is_checked(def_id) { + write!(w, " = {type_}{where_clause}") + } else { + write!(w, "{where_clause} = {type_}") + }?; + + w.write_str(";") })?; write!(w, "{}", document(cx, it, None, HeadingOffset::H2))?; if let Some(inner_type) = &t.inner_type { - write!(w, "{}", write_section_heading("Aliased Type", "aliased-type", None, ""),)?; + write!(w, "{}", write_section_heading("Aliased Type", "aliased-type", None, ""))?; + + let ty = cx.tcx().type_of(def_id).instantiate_identity().skip_norm_wip(); + let adt_def_id = ty.ty_adt_def().unwrap().did(); match inner_type { clean::TypeAliasInnerType::Enum { variants, is_non_exhaustive } => { - let ty = cx - .tcx() - .type_of(it.def_id().unwrap()) - .instantiate_identity() - .skip_norm_wip(); - let enum_def_id = ty.ty_adt_def().unwrap().did(); - DisplayEnum { variants, generics: &t.generics, is_non_exhaustive: *is_non_exhaustive, - def_id: enum_def_id, + def_id: adt_def_id, } .render_into(cx, it, true, w)?; } clean::TypeAliasInnerType::Union { fields } => { - let ty = cx - .tcx() - .type_of(it.def_id().unwrap()) - .instantiate_identity() - .skip_norm_wip(); - let union_def_id = ty.ty_adt_def().unwrap().did(); - ItemUnion { cx, it, fields, generics: &t.generics, is_type_alias: true, - def_id: union_def_id, + def_id: adt_def_id, } .render_into(w)?; } clean::TypeAliasInnerType::Struct { ctor_kind, fields } => { - let ty = cx - .tcx() - .type_of(it.def_id().unwrap()) - .instantiate_identity() - .skip_norm_wip(); - let struct_def_id = ty.ty_adt_def().unwrap().did(); - DisplayStruct { ctor_kind: *ctor_kind, generics: &t.generics, fields, - def_id: struct_def_id, + def_id: adt_def_id, } .render_into(cx, it, true, w)?; } } } else { - let def_id = it.item_id.expect_def_id(); // Render any items associated directly to this alias, as otherwise they // won't be visible anywhere in the docs. It would be nice to also show // associated items from the aliased type (see discussion in #32077), but diff --git a/tests/rustdoc-html/typedef/checked-type-aliases.rs b/tests/rustdoc-html/typedef/checked-type-aliases.rs new file mode 100644 index 0000000000000..c61c262bb6f10 --- /dev/null +++ b/tests/rustdoc-html/typedef/checked-type-aliases.rs @@ -0,0 +1,9 @@ +#![feature(checked_type_aliases)] +#![expect(incomplete_features)] +#![crate_name = "it"] + +//@ has it/type.Alias.html '//pre[@class="rust item-decl"]' \ +// "type Alias = (T, i32) where String: From;" +pub type Alias = (T, i32) +where + String: From; diff --git a/tests/rustdoc-html/typedef/typedef-inner-variants-lazy_type_alias.rs b/tests/rustdoc-html/typedef/typedef-inner-variants-lazy_type_alias.rs index 53203504fd225..70023c7cf81f4 100644 --- a/tests/rustdoc-html/typedef/typedef-inner-variants-lazy_type_alias.rs +++ b/tests/rustdoc-html/typedef/typedef-inner-variants-lazy_type_alias.rs @@ -13,14 +13,15 @@ pub struct Pair { //@ count - '//*[@id="aliased-type"]' 1 //@ count - '//*[@id="variants"]' 0 //@ count - '//*[@id="fields"]' 1 -//@ count - '//div[@class="where"]' 0 +//@ count - '//span[@class="where"]' 0 pub type ReversedTypesPair = Pair; //@ has 'inner_types_lazy/type.ReadWrite.html' //@ count - '//*[@id="aliased-type"]' 1 //@ count - '//*[@id="variants"]' 0 //@ count - '//*[@id="fields"]' 1 -//@ count - '//div[@class="where"]' 2 +//@ count - '//span[@class="where"]' 1 +//@ count - '//div[@class="where"]' 1 pub type ReadWrite = Pair where R: std::io::Read, @@ -30,5 +31,5 @@ where //@ count - '//*[@id="aliased-type"]' 1 //@ count - '//*[@id="variants"]' 0 //@ count - '//*[@id="fields"]' 1 -//@ count - '//div[@class="where"]' 0 +//@ count - '//span[@class="where"]' 0 pub type VecPair = Pair, Vec>; diff --git a/tests/rustdoc-html/where.golf_type_alias_decl.html b/tests/rustdoc-html/where.golf_type_alias_decl.html index ab60bb262daf2..76234bd1c0239 100644 --- a/tests/rustdoc-html/where.golf_type_alias_decl.html +++ b/tests/rustdoc-html/where.golf_type_alias_decl.html @@ -1,2 +1,3 @@ -pub type Golf<T>
where - T: Clone,
= (T, T);
\ No newline at end of file +pub type Golf<T> +where + T: Clone = (T, T); \ No newline at end of file diff --git a/tests/rustdoc-html/where.rs b/tests/rustdoc-html/where.rs index aa1d61a0a1814..470af1a371462 100644 --- a/tests/rustdoc-html/where.rs +++ b/tests/rustdoc-html/where.rs @@ -68,6 +68,6 @@ pub enum Foxtrot { Foxtrot1(F) } impl MyTrait for Foxtrotwhere F: MyTrait {} //@ has foo/type.Golf.html '//pre[@class="rust item-decl"]' \ -// "type Golfwhere T: Clone, = (T, T)" +// "type Golf where T: Clone = (T, T);" //@ snapshot golf_type_alias_decl - '//*[@class="rust item-decl"]/code' pub type Golf where T: Clone = (T, T); From 2160998a06d10879cb4fb790f32ecde1eb317186 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Wed, 9 Sep 2026 13:52:30 -0700 Subject: [PATCH 05/12] Refactor CodeGen Pipeline Setup into a Single Function This patch refactors setup of the LegacyPassManager for CodeGen into a single function. This simplifies some things (lifetime for the LegacyPM object), but is primarily aimed at enabling rustc to use the new runCodeGenPipeline abstraction (introduced in LLVM 24) which handles all of these details within LLVM and additionally defaults to the NewPM when a target opts-in/the correct LLVM flag is passed. --- compiler/rustc_codegen_llvm/src/back/write.rs | 5 +- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 15 +---- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 65 +++++++++---------- 3 files changed, 31 insertions(+), 54 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index dd2dbdff6b82c..c7cfa87d86e5e 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -72,17 +72,14 @@ fn write_output_file<'ll>( std::ptr::null() }; let result = unsafe { - let pm = llvm::LLVMCreatePassManager(); - llvm::LLVMAddAnalysisPasses(target, pm); - llvm::LLVMRustAddLibraryInfo(target, pm, m, no_builtins); llvm::LLVMRustWriteOutputFile( target, - pm, m, output_c.as_ptr(), dwo_output_ptr, file_type, verify_llvm_ir, + no_builtins, ) }; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 655a79e341bd1..eca5fe429f541 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -715,8 +715,6 @@ unsafe extern "C" { } #[repr(C)] pub(crate) struct Builder<'a>(InvariantOpaque<'a>); -#[repr(C)] -pub(crate) struct PassManager<'a>(InvariantOpaque<'a>); unsafe extern "C" { pub type TargetMachine; } @@ -1637,11 +1635,6 @@ unsafe extern "C" { /// Writes a module to the specified path. Returns 0 on success. pub(crate) fn LLVMWriteBitcodeToFile(M: &Module, Path: *const c_char) -> c_int; - /// Creates a legacy pass manager -- only used for final codegen. - pub(crate) fn LLVMCreatePassManager<'a>() -> &'a mut PassManager<'a>; - - pub(crate) fn LLVMAddAnalysisPasses<'a>(T: &'a TargetMachine, PM: &PassManager<'a>); - pub(crate) fn LLVMGetHostCPUFeatures() -> *mut c_char; pub(crate) fn LLVMDisposeMessage(message: *mut c_char); @@ -2430,20 +2423,14 @@ unsafe extern "C" { pub(crate) fn LLVMRustDisposeMCSubtargetInfo(MCInfo: ptr::NonNull); - pub(crate) fn LLVMRustAddLibraryInfo<'a>( - T: &TargetMachine, - PM: &PassManager<'a>, - M: &'a Module, - DisableSimplifyLibCalls: bool, - ); pub(crate) fn LLVMRustWriteOutputFile<'a>( T: &'a TargetMachine, - PM: *mut PassManager<'a>, M: &'a Module, Output: *const c_char, DwoOutput: *const c_char, FileType: FileType, VerifyIR: bool, + DisableSimplifyLibCalls: bool, ) -> LLVMRustResult; pub(crate) fn LLVMRustOptimize<'a>( M: &'a Module, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index beb63ad61493c..5c510a74078c2 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -447,30 +447,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( return wrap(TM); } -// Unfortunately, the LLVM C API doesn't provide a way to create the -// TargetLibraryInfo pass, so we use this method to do so. -extern "C" void LLVMRustAddLibraryInfo(LLVMTargetMachineRef T, - LLVMPassManagerRef PMR, LLVMModuleRef M, - bool DisableSimplifyLibCalls) { - auto TargetTriple = Triple(unwrap(M)->getTargetTriple()); - TargetOptions *Options = &unwrap(T)->Options; - auto TLII = TargetLibraryInfoImpl(TargetTriple); - if (DisableSimplifyLibCalls) - TLII.disableAllFunctions(); - unwrap(PMR)->add(new TargetLibraryInfoWrapperPass(TLII)); -#if LLVM_VERSION_GE(24, 0) - // LLVM 24 removed TargetOptions::EABIVersion and ExceptionModel; the EABI - // version and exception model are now derived from the target triple and - // module flags respectively instead. - unwrap(PMR)->add(new RuntimeLibraryInfoWrapper(Options->MCOptions.ABIName, - Options->VecLib)); -#elif LLVM_VERSION_GE(22, 0) - unwrap(PMR)->add(new RuntimeLibraryInfoWrapper( - TargetTriple, Options->ExceptionModel, Options->FloatABIType, - Options->EABIVersion, Options->MCOptions.ABIName, Options->VecLib)); -#endif -} - extern "C" void LLVMRustSetLLVMOptions(int Argc, char **Argv) { // Initializing the command-line options more than once is not allowed. So, // check if they've already been initialized. (This could happen if we're @@ -500,10 +476,31 @@ static CodeGenFileType fromRust(LLVMRustFileType Type) { } extern "C" LLVMRustResult -LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, - LLVMModuleRef M, const char *Path, const char *DwoPath, - LLVMRustFileType RustFileType, bool VerifyIR) { - llvm::legacy::PassManager *PM = unwrap(PMR); +LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMModuleRef M, + const char *Path, const char *DwoPath, + LLVMRustFileType RustFileType, bool VerifyIR, + bool DisableSimplifyLibCalls) { + llvm::legacy::PassManager PM; + + PM.add(createTargetTransformInfoWrapperPass( + unwrap(Target)->getTargetIRAnalysis())); + + auto TargetTriple = Triple(unwrap(M)->getTargetTriple()); + TargetOptions *Options = &unwrap(Target)->Options; + auto TLII = TargetLibraryInfoImpl(TargetTriple); + if (DisableSimplifyLibCalls) + TLII.disableAllFunctions(); + PM.add(new TargetLibraryInfoWrapperPass(TLII)); +#if LLVM_VERSION_GE(24, 0) + PM.add(new RuntimeLibraryInfoWrapper( + Options->ExceptionModel, Options->EABIVersion, Options->MCOptions.ABIName, + Options->VecLib)); +#elif LLVM_VERSION_GE(22, 0) + PM.add(new RuntimeLibraryInfoWrapper( + TargetTriple, Options->ExceptionModel, Options->FloatABIType, + Options->EABIVersion, Options->MCOptions.ABIName, Options->VecLib)); +#endif + auto FileType = fromRust(RustFileType); std::string ErrorInfo; @@ -527,17 +524,13 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMPassManagerRef PMR, return LLVMRustResult::Failure; } auto DBOS = buffer_ostream(DOS); - unwrap(Target)->addPassesToEmitFile(*PM, BOS, &DBOS, FileType, !VerifyIR); - PM->run(*unwrap(M)); + unwrap(Target)->addPassesToEmitFile(PM, BOS, &DBOS, FileType, !VerifyIR); + PM.run(*unwrap(M)); } else { - unwrap(Target)->addPassesToEmitFile(*PM, BOS, nullptr, FileType, !VerifyIR); - PM->run(*unwrap(M)); + unwrap(Target)->addPassesToEmitFile(PM, BOS, nullptr, FileType, !VerifyIR); + PM.run(*unwrap(M)); } - // Apparently `addPassesToEmitFile` adds a pointer to our on-the-stack output - // stream (OS), so the only real safe place to delete this is here? Don't we - // wish this was written in Rust? - LLVMDisposePassManager(PMR); return LLVMRustResult::Success; } From dc7db04ab19b66846f7f0d082495151b13593bd7 Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Thu, 24 Sep 2026 07:53:15 -0700 Subject: [PATCH 06/12] feedback --- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 5c510a74078c2..303c0456833ad 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -480,9 +480,10 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMModuleRef M, const char *Path, const char *DwoPath, LLVMRustFileType RustFileType, bool VerifyIR, bool DisableSimplifyLibCalls) { - llvm::legacy::PassManager PM; + std::unique_ptr PM = + std::make_unique(); - PM.add(createTargetTransformInfoWrapperPass( + PM->add(createTargetTransformInfoWrapperPass( unwrap(Target)->getTargetIRAnalysis())); auto TargetTriple = Triple(unwrap(M)->getTargetTriple()); @@ -490,13 +491,15 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMModuleRef M, auto TLII = TargetLibraryInfoImpl(TargetTriple); if (DisableSimplifyLibCalls) TLII.disableAllFunctions(); - PM.add(new TargetLibraryInfoWrapperPass(TLII)); + PM->add(new TargetLibraryInfoWrapperPass(TLII)); #if LLVM_VERSION_GE(24, 0) - PM.add(new RuntimeLibraryInfoWrapper( - Options->ExceptionModel, Options->EABIVersion, Options->MCOptions.ABIName, - Options->VecLib)); + // LLVM 24 removed TargetOptions::EABIVersion and ExceptionModel; the EABI + // version and exception model are now derived from the target triple and + // module flags respectively instead. + PM->add(new RuntimeLibraryInfoWrapper(Options->MCOptions.ABIName, + Options->VecLib)); #elif LLVM_VERSION_GE(22, 0) - PM.add(new RuntimeLibraryInfoWrapper( + PM->add(new RuntimeLibraryInfoWrapper( TargetTriple, Options->ExceptionModel, Options->FloatABIType, Options->EABIVersion, Options->MCOptions.ABIName, Options->VecLib)); #endif @@ -524,13 +527,18 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMModuleRef M, return LLVMRustResult::Failure; } auto DBOS = buffer_ostream(DOS); - unwrap(Target)->addPassesToEmitFile(PM, BOS, &DBOS, FileType, !VerifyIR); - PM.run(*unwrap(M)); + unwrap(Target)->addPassesToEmitFile(*PM, BOS, &DBOS, FileType, !VerifyIR); + PM->run(*unwrap(M)); } else { - unwrap(Target)->addPassesToEmitFile(PM, BOS, nullptr, FileType, !VerifyIR); - PM.run(*unwrap(M)); + unwrap(Target)->addPassesToEmitFile(*PM, BOS, nullptr, FileType, !VerifyIR); + PM->run(*unwrap(M)); } + // TargetMachine::addPassesToEmitFile stores a pointer to the output stream + // in a couple of places inside of the object. Explicitly delete the PM here + // to ensure that the output stream always outlives the PM. + PM.reset(); + return LLVMRustResult::Success; } From 5f463ae6f6cfb8eaab1e9bae204bddc2ae87f48a Mon Sep 17 00:00:00 2001 From: Aiden Grossman Date: Thu, 24 Sep 2026 08:11:02 -0700 Subject: [PATCH 07/12] more lifetime fixes --- compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 303c0456833ad..f73ca2ea30c16 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -516,6 +516,9 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMModuleRef M, return LLVMRustResult::Failure; } + // TargetMachine::addPassesToEmitFile stores pointers to the output streams + // in a couple of places inside of the object. Explicitly delete the PM after + // we call run() to avoid dangling references. auto BOS = buffer_ostream(OS); if (DwoPath) { auto DOS = raw_fd_ostream(DwoPath, EC, sys::fs::OF_None); @@ -529,16 +532,13 @@ LLVMRustWriteOutputFile(LLVMTargetMachineRef Target, LLVMModuleRef M, auto DBOS = buffer_ostream(DOS); unwrap(Target)->addPassesToEmitFile(*PM, BOS, &DBOS, FileType, !VerifyIR); PM->run(*unwrap(M)); + PM.reset(); } else { unwrap(Target)->addPassesToEmitFile(*PM, BOS, nullptr, FileType, !VerifyIR); PM->run(*unwrap(M)); + PM.reset(); } - // TargetMachine::addPassesToEmitFile stores a pointer to the output stream - // in a couple of places inside of the object. Explicitly delete the PM here - // to ensure that the output stream always outlives the PM. - PM.reset(); - return LLVMRustResult::Success; } From 237cfc33046f007dce2985a1acdc3e56d0a74a98 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Wed, 22 Jul 2026 15:44:34 +0200 Subject: [PATCH 08/12] remove unnecessary panic --- compiler/rustc_middle/src/queries.rs | 4 +-- compiler/rustc_middle/src/query/keys.rs | 6 ++++ .../rustc_middle/src/ty/inhabitedness/mod.rs | 34 ++++++++----------- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index ddaf12f9812aa..d9d618519446d 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -2227,8 +2227,8 @@ rustc_queries! { } /// Do not call this query directly: invoke `Ty::is_opsem_inhabited` instead. - query is_opsem_inhabited_raw(env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>) -> bool { - desc { "computing whether `{}` is inhabited on the opsem level", env.value } + query is_opsem_inhabited_adt_cached(env: ty::PseudoCanonicalInput<'tcx, (ty::AdtDef<'tcx>, ty::GenericArgsRef<'tcx>)>) -> bool { + desc { "computing whether `{:?}` is inhabited on the opsem level", env.value } } query crate_dep_kind(_: CrateNum) -> CrateDepKind { diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index eae4148a30ed4..2bfe80f444090 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -308,6 +308,12 @@ impl<'tcx, T: QueryKey> QueryKey for ty::PseudoCanonicalInput<'tcx, T> { } } +impl<'tcx> QueryKey for (ty::AdtDef<'tcx>, ty::GenericArgsRef<'tcx>) { + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + tcx.def_span(self.0.did()) + } +} + impl QueryKey for Symbol { fn default_span(&self, _tcx: TyCtxt<'_>) -> Span { DUMMY_SP diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 078a171491520..820b29d078a3e 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -43,8 +43,6 @@ //! This code should only compile in modules where the uninhabitedness of `Foo` //! is visible. -use std::assert_matches; - use rustc_data_structures::fx::FxHashSet; use rustc_hir::def::DefKind; use rustc_span::bug; @@ -66,7 +64,7 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { inhabited_predicate_for_def, inhabited_predicate_type, - is_opsem_inhabited_raw, + is_opsem_inhabited_adt_cached, ..*providers }; } @@ -273,7 +271,7 @@ struct OpsemInhabitedCtx<'tcx> { tcx: TyCtxt<'tcx>, typing_env: TypingEnv<'tcx>, /// IDs of ADTs that have been encountered in the current stack. - /// It's `None` unless we are inside the `is_opsem_inhabited_raw` query, + /// It's `None` unless we are inside the `is_opsem_inhabited_adt_cached` query, /// which is only invoked for more complex types. seen: Option>, /// If an ADT is encountered recursively within itself, then `stop_at_ref` @@ -332,7 +330,7 @@ impl<'tcx> OpsemInhabitedCtx<'tcx> { let base = tcx.instantiate_bound_regions_with_erased((*base).into()); self.is_inhabited_ty(base) } - ty::Adt(..) => self.is_inhabited_adt_ty(ty), + ty::Adt(def, args) => self.is_inhabited_adt_ty(def, args), ty::Error(_error_guaranteed) => { // We have a token proving there was an error, so we can return a dummy value. @@ -350,10 +348,11 @@ impl<'tcx> OpsemInhabitedCtx<'tcx> { } } - fn is_inhabited_adt_ty(&mut self, ty: Ty<'tcx>) -> bool { - let ty::Adt(adt_def, adt_args) = *ty.kind() else { - unreachable! {} - }; + fn is_inhabited_adt_ty( + &mut self, + adt_def: ty::AdtDef<'tcx>, + adt_args: ty::GenericArgsRef<'tcx>, + ) -> bool { let Self { tcx, typing_env, .. } = *self; if adt_def.is_union() { @@ -363,7 +362,8 @@ impl<'tcx> OpsemInhabitedCtx<'tcx> { let Some(seen) = self.seen.as_mut() else { // stop recursing, invoke the query. - return tcx.is_opsem_inhabited_raw(typing_env.as_query_input(ty)); + return tcx + .is_opsem_inhabited_adt_cached(typing_env.as_query_input((adt_def, adt_args))); }; let new_adt = seen.insert(adt_def.did()); @@ -393,17 +393,11 @@ impl<'tcx> OpsemInhabitedCtx<'tcx> { } } -fn is_opsem_inhabited_raw<'tcx>( +fn is_opsem_inhabited_adt_cached<'tcx>( tcx: TyCtxt<'tcx>, - env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>, + env: ty::PseudoCanonicalInput<'tcx, (ty::AdtDef<'tcx>, ty::GenericArgsRef<'tcx>)>, ) -> bool { - let (ty, typing_env) = (env.value, env.typing_env); - assert_matches!( - ty.kind(), - ty::Adt(..), - "the query should only be invoked by `Ty::is_opsem_inhabited`" - ); - + let ((def, args), typing_env) = (env.value, env.typing_env); OpsemInhabitedCtx { tcx, typing_env, seen: Some(FxHashSet::default()), stop_at_ref: false } - .is_inhabited_adt_ty(ty) + .is_inhabited_adt_ty(def, args) } From d5a81cb799a32eacead6dd8536a2332c9e0dbae1 Mon Sep 17 00:00:00 2001 From: lcnr Date: Thu, 1 Oct 2026 16:28:26 +0200 Subject: [PATCH 09/12] ignore hanging next-solver tests, remove unnecessary ignore test --- tests/ui/closures/supertrait-hint-cycle.rs | 4 ++++ .../object-soundness-requires-generalization.rs | 6 ++++-- ...2904.stderr => error-tainting-issue-122904.old.stderr} | 4 ++-- .../type-alias-impl-trait/error-tainting-issue-122904.rs | 6 ++++++ ...n-2.stderr => recursive-drop-elaboration-2.old.stderr} | 4 ++-- .../type-alias-impl-trait/recursive-drop-elaboration-2.rs | 5 +++++ ...ation.stderr => recursive-drop-elaboration.old.stderr} | 8 ++++---- .../type-alias-impl-trait/recursive-drop-elaboration.rs | 5 +++++ 8 files changed, 32 insertions(+), 10 deletions(-) rename tests/ui/type-alias-impl-trait/{error-tainting-issue-122904.stderr => error-tainting-issue-122904.old.stderr} (90%) rename tests/ui/type-alias-impl-trait/{recursive-drop-elaboration-2.stderr => recursive-drop-elaboration-2.old.stderr} (90%) rename tests/ui/type-alias-impl-trait/{recursive-drop-elaboration.stderr => recursive-drop-elaboration.old.stderr} (89%) diff --git a/tests/ui/closures/supertrait-hint-cycle.rs b/tests/ui/closures/supertrait-hint-cycle.rs index 52c24a414aca6..08dcde28217bd 100644 --- a/tests/ui/closures/supertrait-hint-cycle.rs +++ b/tests/ui/closures/supertrait-hint-cycle.rs @@ -1,4 +1,8 @@ //@ edition:2021 +//@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] ignore-test: trait-system-refactor-initiative#242 //@ check-pass #![feature(type_alias_impl_trait)] diff --git a/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs b/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs index 3ef6bea4fd5c9..da93a10d42df4 100644 --- a/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs +++ b/tests/ui/traits/next-solver/object-soundness-requires-generalization.rs @@ -1,5 +1,7 @@ -//@ compile-flags: -Znext-solver -//@ ignore-test (see #114196) +//@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ check-pass trait Trait { type Gat<'lt>; diff --git a/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr b/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.old.stderr similarity index 90% rename from tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr rename to tests/ui/type-alias-impl-trait/error-tainting-issue-122904.old.stderr index c5e347e59de72..d90710081e4a2 100644 --- a/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.stderr +++ b/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.old.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/error-tainting-issue-122904.rs:12:1 + --> $DIR/error-tainting-issue-122904.rs:18:1 | LL | fn with_positive(fun: impl Fn(Alias<'_>)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -11,7 +11,7 @@ LL | with_positive(|&n| ()); = note: `#[warn(unconditional_recursion)]` on by default error[E0507]: cannot move out of a shared reference - --> $DIR/error-tainting-issue-122904.rs:14:20 + --> $DIR/error-tainting-issue-122904.rs:20:20 | LL | with_positive(|&n| ()); | ^- diff --git a/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.rs b/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.rs index a2de3957c0bd7..f17ce5fac3cb0 100644 --- a/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.rs +++ b/tests/ui/type-alias-impl-trait/error-tainting-issue-122904.rs @@ -1,6 +1,12 @@ // We previously didn't taint the borrowck result in this test, // causing an ICE later on. #![feature(type_alias_impl_trait)] + +//@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] ignore-test: trait-system-refactor-initiative#242 + trait T {} type Alias<'a> = impl T; diff --git a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.old.stderr similarity index 90% rename from tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr rename to tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.old.stderr index 94cd9a312ca12..ce26ccca3276b 100644 --- a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.stderr +++ b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.old.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/recursive-drop-elaboration-2.rs:13:1 + --> $DIR/recursive-drop-elaboration-2.rs:18:1 | LL | fn with_positive(fun: impl Fn(Alias<'_>)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -11,7 +11,7 @@ LL | with_positive(|&n| ()); = note: `#[warn(unconditional_recursion)]` on by default error[E0507]: cannot move out of a shared reference - --> $DIR/recursive-drop-elaboration-2.rs:15:20 + --> $DIR/recursive-drop-elaboration-2.rs:20:20 | LL | with_positive(|&n| ()); | ^- diff --git a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.rs b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.rs index 5541c5267f39a..3a9d80a9f66e5 100644 --- a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.rs +++ b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration-2.rs @@ -1,5 +1,10 @@ //! Regression test for ICE #139556 +//@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] ignore-test: trait-system-refactor-initiative#242 + #![feature(type_alias_impl_trait)] trait T {} diff --git a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.old.stderr similarity index 89% rename from tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr rename to tests/ui/type-alias-impl-trait/recursive-drop-elaboration.old.stderr index dc282f30b45b4..8bcd6d8dbdace 100644 --- a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.stderr +++ b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.old.stderr @@ -1,5 +1,5 @@ warning: function cannot return without recursing - --> $DIR/recursive-drop-elaboration.rs:13:1 + --> $DIR/recursive-drop-elaboration.rs:18:1 | LL | fn with_positive(fun: impl Fn(Alias<'_>)) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing @@ -11,7 +11,7 @@ LL | with_positive(|&n| ()); = note: `#[warn(unconditional_recursion)]` on by default error[E0507]: cannot move out of a shared reference - --> $DIR/recursive-drop-elaboration.rs:15:20 + --> $DIR/recursive-drop-elaboration.rs:20:20 | LL | with_positive(|&n| ()); | ^- @@ -25,7 +25,7 @@ LL + with_positive(|n| ()); | error[E0507]: cannot move out of a shared reference - --> $DIR/recursive-drop-elaboration.rs:22:20 + --> $DIR/recursive-drop-elaboration.rs:27:20 | LL | with_positive(|&a| ()); | ^- @@ -39,7 +39,7 @@ LL + with_positive(|a| ()); | error[E0580]: `main` function has wrong type - --> $DIR/recursive-drop-elaboration.rs:20:1 + --> $DIR/recursive-drop-elaboration.rs:25:1 | LL | type Alias<'a> = impl T; | ------ the found opaque type diff --git a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.rs b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.rs index dd28732ebb281..5cabd6ab19031 100644 --- a/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.rs +++ b/tests/ui/type-alias-impl-trait/recursive-drop-elaboration.rs @@ -1,5 +1,10 @@ //! Regression test for #122904. +//@ revisions: old next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@[next] ignore-test: trait-system-refactor-initiative#242 + #![feature(type_alias_impl_trait)] trait T {} From b923d1e13ade0197b11a670a296a38ddfebca469 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 30 Sep 2026 22:03:17 -0500 Subject: [PATCH 10/12] ctfe: Constify the `abort` intrinsic This is a well-defined operation that we want to make use of in std/core, such as with `abort_immediate`. --- .../rustc_const_eval/src/const_eval/error.rs | 2 ++ .../src/const_eval/machine.rs | 6 +++- library/core/src/intrinsics/mod.rs | 2 +- src/tools/miri/src/intrinsics/mod.rs | 1 + tests/ui/consts/const-eval/const_panic.rs | 5 +++ tests/ui/consts/const-eval/const_panic.stderr | 32 +++++++++++-------- 6 files changed, 33 insertions(+), 15 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 8532cad91b808..1cb6a8aed947d 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -30,6 +30,7 @@ pub enum ConstEvalErrKind { col: u32, file: Symbol, }, + Abort, WriteThroughImmutablePointer, /// Called `const_make_global` twice. ConstMakeGlobalPtrAlreadyMadeGlobal(AllocId), @@ -51,6 +52,7 @@ impl fmt::Display for ConstEvalErrKind { write!(f, "modifying a static's initial value from another static's initializer") } Panic { msg, .. } => write!(f, "evaluation panicked: {msg}"), + Abort => write!(f, "the program aborted execution"), RecursiveStatic => { write!(f, "encountered static that tried to access itself during initialization") } diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 843cd7cb4930d..3f7731ce95583 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -10,13 +10,13 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap, IndexEntry}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{CRATE_HIR_ID, HirId}; use rustc_lint_defs::builtin::LONG_RUNNING_CONST_EVAL; -use rustc_middle::mir; use rustc_middle::mir::AssertMessage; use rustc_middle::mir::interpret::ReportedErrorInfo; use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::consts::ConstExt; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, TyAndLayout, ValidityRequirement}; use rustc_middle::ty::{self, FieldInfo, ScalarInt, Ty, TyCtxt}; +use rustc_middle::{mir, throw_machine_stop}; use rustc_span::{Span, Symbol, bug, span_bug, sym}; use rustc_target::callconv::FnAbi; use tracing::debug; @@ -484,6 +484,10 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // CTFE-specific intrinsics. match intrinsic_name { + sym::abort => { + // Note that `abort` is also hooked separately in Miri. + throw_machine_stop!(ConstEvalErrKind::Abort); + } sym::ptr_guaranteed_cmp => { let a = ecx.read_scalar(&args[0])?; let b = ecx.read_scalar(&args[1])?; diff --git a/library/core/src/intrinsics/mod.rs b/library/core/src/intrinsics/mod.rs index 96999f154c42f..f44da9840b8e5 100644 --- a/library/core/src/intrinsics/mod.rs +++ b/library/core/src/intrinsics/mod.rs @@ -444,7 +444,7 @@ pub fn rustc_peek(_: T) -> T; /// The stabilization-track version of this intrinsic is [`core::process::abort_immediate`]. #[rustc_nounwind] #[rustc_intrinsic] -pub fn abort() -> !; +pub const fn abort() -> !; /// Informs the optimizer that this point in the code is not reachable, /// enabling further optimizations. diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 9a6bdb9b48dce..997339f66a51c 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -96,6 +96,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { match intrinsic_name { // Basic control flow "abort" => { + // Note that `abort` is also hooked separately in CTFE. throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )); diff --git a/tests/ui/consts/const-eval/const_panic.rs b/tests/ui/consts/const-eval/const_panic.rs index e4f3a4eec1b1c..26eeec7778f7c 100644 --- a/tests/ui/consts/const-eval/const_panic.rs +++ b/tests/ui/consts/const-eval/const_panic.rs @@ -1,4 +1,5 @@ //@ edition:2015..2021 +#![feature(core_intrinsics)] #![allow(non_fmt_panics)] #![crate_type = "lib"] @@ -39,3 +40,7 @@ const W_CORE: () = core::panic!(MSG); const W2_CORE: () = core::panic!("{}", MSG); //~^ ERROR evaluation panicked + +// FIXME(abort_immediate): replace with the non-intrinsic version once available +const ABORT: () = core::intrinsics::abort(); +//~^ ERROR the program aborted execution diff --git a/tests/ui/consts/const-eval/const_panic.stderr b/tests/ui/consts/const-eval/const_panic.stderr index 8e0384b2f2af6..1288112f462fe 100644 --- a/tests/ui/consts/const-eval/const_panic.stderr +++ b/tests/ui/consts/const-eval/const_panic.stderr @@ -1,75 +1,81 @@ error[E0080]: evaluation panicked: cheese - --> $DIR/const_panic.rs:7:15 + --> $DIR/const_panic.rs:8:15 | LL | const Z: () = std::panic!("cheese"); | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z` failed here error[E0080]: evaluation panicked: explicit panic - --> $DIR/const_panic.rs:10:16 + --> $DIR/const_panic.rs:11:16 | LL | const Z2: () = std::panic!(); | ^^^^^^^^^^^^^ evaluation of `Z2` failed here error[E0080]: evaluation panicked: internal error: entered unreachable code - --> $DIR/const_panic.rs:13:15 + --> $DIR/const_panic.rs:14:15 | LL | const Y: () = std::unreachable!(); | ^^^^^^^^^^^^^^^^^^^ evaluation of `Y` failed here error[E0080]: evaluation panicked: not implemented - --> $DIR/const_panic.rs:16:15 + --> $DIR/const_panic.rs:17:15 | LL | const X: () = std::unimplemented!(); | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `X` failed here error[E0080]: evaluation panicked: hello - --> $DIR/const_panic.rs:19:15 + --> $DIR/const_panic.rs:20:15 | LL | const W: () = std::panic!(MSG); | ^^^^^^^^^^^^^^^^ evaluation of `W` failed here error[E0080]: evaluation panicked: hello - --> $DIR/const_panic.rs:22:16 + --> $DIR/const_panic.rs:23:16 | LL | const W2: () = std::panic!("{}", MSG); | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `W2` failed here error[E0080]: evaluation panicked: cheese - --> $DIR/const_panic.rs:25:20 + --> $DIR/const_panic.rs:26:20 | LL | const Z_CORE: () = core::panic!("cheese"); | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `Z_CORE` failed here error[E0080]: evaluation panicked: explicit panic - --> $DIR/const_panic.rs:28:21 + --> $DIR/const_panic.rs:29:21 | LL | const Z2_CORE: () = core::panic!(); | ^^^^^^^^^^^^^^ evaluation of `Z2_CORE` failed here error[E0080]: evaluation panicked: internal error: entered unreachable code - --> $DIR/const_panic.rs:31:20 + --> $DIR/const_panic.rs:32:20 | LL | const Y_CORE: () = core::unreachable!(); | ^^^^^^^^^^^^^^^^^^^^ evaluation of `Y_CORE` failed here error[E0080]: evaluation panicked: not implemented - --> $DIR/const_panic.rs:34:20 + --> $DIR/const_panic.rs:35:20 | LL | const X_CORE: () = core::unimplemented!(); | ^^^^^^^^^^^^^^^^^^^^^^ evaluation of `X_CORE` failed here error[E0080]: evaluation panicked: hello - --> $DIR/const_panic.rs:37:20 + --> $DIR/const_panic.rs:38:20 | LL | const W_CORE: () = core::panic!(MSG); | ^^^^^^^^^^^^^^^^^ evaluation of `W_CORE` failed here error[E0080]: evaluation panicked: hello - --> $DIR/const_panic.rs:40:21 + --> $DIR/const_panic.rs:41:21 | LL | const W2_CORE: () = core::panic!("{}", MSG); | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `W2_CORE` failed here -error: aborting due to 12 previous errors +error[E0080]: the program aborted execution + --> $DIR/const_panic.rs:45:19 + | +LL | const ABORT: () = core::intrinsics::abort(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ABORT` failed here + +error: aborting due to 13 previous errors For more information about this error, try `rustc --explain E0080`. From 767210f85b306e7c3c3a920d143eeba3fba1419b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Wed, 30 Sep 2026 22:03:17 -0500 Subject: [PATCH 11/12] core: Unstably constify `abort_immediate` For const-only code there isn't much of a reason to use this over `panic!()`, but having `abort_immediate` const will make it possible to reuse more code meant for runtime at comptime. The semantics are well-defined so this is pretty straightforward. --- library/core/src/process.rs | 3 ++- tests/ui/consts/const-eval/const_panic.rs | 5 ++--- tests/ui/consts/const-eval/const_panic.stderr | 9 ++++++--- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/library/core/src/process.rs b/library/core/src/process.rs index 81481b2cba26e..2da752b42ee85 100644 --- a/library/core/src/process.rs +++ b/library/core/src/process.rs @@ -35,9 +35,10 @@ /// Other signals such as `SIGABRT`, `SIGTRAP`, `SIGSEGV`, and `SIGBUS` may be /// produced instead, depending on specifics. This is not an exhaustive list. #[unstable(feature = "abort_immediate", issue = "154601")] +#[rustc_const_unstable(feature = "abort_immediate", issue = "154601")] #[cold] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces #[doc(alias = "halt")] -pub fn abort_immediate() -> ! { +pub const fn abort_immediate() -> ! { crate::intrinsics::abort() } diff --git a/tests/ui/consts/const-eval/const_panic.rs b/tests/ui/consts/const-eval/const_panic.rs index 26eeec7778f7c..e4fd30d2e1678 100644 --- a/tests/ui/consts/const-eval/const_panic.rs +++ b/tests/ui/consts/const-eval/const_panic.rs @@ -1,5 +1,5 @@ //@ edition:2015..2021 -#![feature(core_intrinsics)] +#![feature(abort_immediate)] #![allow(non_fmt_panics)] #![crate_type = "lib"] @@ -41,6 +41,5 @@ const W_CORE: () = core::panic!(MSG); const W2_CORE: () = core::panic!("{}", MSG); //~^ ERROR evaluation panicked -// FIXME(abort_immediate): replace with the non-intrinsic version once available -const ABORT: () = core::intrinsics::abort(); +const ABORT: () = core::process::abort_immediate(); //~^ ERROR the program aborted execution diff --git a/tests/ui/consts/const-eval/const_panic.stderr b/tests/ui/consts/const-eval/const_panic.stderr index 1288112f462fe..19d8f3ae1c106 100644 --- a/tests/ui/consts/const-eval/const_panic.stderr +++ b/tests/ui/consts/const-eval/const_panic.stderr @@ -71,10 +71,13 @@ LL | const W2_CORE: () = core::panic!("{}", MSG); | ^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `W2_CORE` failed here error[E0080]: the program aborted execution - --> $DIR/const_panic.rs:45:19 + --> $DIR/const_panic.rs:44:19 | -LL | const ABORT: () = core::intrinsics::abort(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ABORT` failed here +LL | const ABORT: () = core::process::abort_immediate(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `ABORT` failed inside this call + | +note: inside `abort_immediate` + --> $SRC_DIR/core/src/process.rs:LL:COL error: aborting due to 13 previous errors From 14167187bbd399f0db2899581a604309071ef59b Mon Sep 17 00:00:00 2001 From: Zachary S Date: Wed, 30 Sep 2026 16:13:28 -0500 Subject: [PATCH 12/12] Add tests for `()`, `!`, and `bool`'s size and alignment to `coretests`. --- library/coretests/tests/mem.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/coretests/tests/mem.rs b/library/coretests/tests/mem.rs index 793c9f489e47f..845929ac54caf 100644 --- a/library/coretests/tests/mem.rs +++ b/library/coretests/tests/mem.rs @@ -10,6 +10,9 @@ use std::rc::Rc; #[test] fn size_of_basic() { + assert_eq!(size_of::<()>(), 0); + assert_eq!(size_of::(), 0); + assert_eq!(size_of::(), 1); assert_eq!(size_of::(), 1); assert_eq!(size_of::(), 2); assert_eq!(size_of::(), 4); @@ -47,6 +50,9 @@ fn size_of_val_basic() { #[test] fn align_of_basic() { + assert_eq!(align_of::<()>(), 1); + assert_eq!(align_of::(), 1); + assert_eq!(align_of::(), 1); assert_eq!(align_of::(), 1); assert_eq!(align_of::(), 2); assert_eq!(align_of::(), 4);