From b20bc53c3d0566f681ad1686ae53216f1c1bee3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 20 Nov 2024 22:05:31 +0100 Subject: [PATCH 01/12] ci: fix explanation why LLVM download is disabled for windows-gnu --- src/ci/github-actions/jobs.yml | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 7730d29d28f68..54d6fb0a50226 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -525,8 +525,7 @@ auto: env: RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu SCRIPT: make ci-mingw - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). + # There is no dist-i686-mingw-alt, so there is no prebuilt LLVM with assertions NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows-8c @@ -535,8 +534,7 @@ auto: env: SCRIPT: make ci-mingw-x RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). + # There is no dist-x86_64-mingw-alt, so there is no prebuilt LLVM with assertions NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows @@ -544,8 +542,7 @@ auto: env: SCRIPT: make ci-mingw-bootstrap RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). + # There is no dist-x86_64-mingw-alt, so there is no prebuilt LLVM with assertions NO_DOWNLOAD_CI_LLVM: 1 <<: *job-windows @@ -593,9 +590,6 @@ auto: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-gnu --enable-full-tools - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 SCRIPT: python x.py dist bootstrap --include-default-paths DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift @@ -607,9 +601,6 @@ auto: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-gnu --enable-full-tools - # We are intentionally allowing an old toolchain on this builder (and that's - # incompatible with LLVM downloads today). - NO_DOWNLOAD_CI_LLVM: 1 DIST_REQUIRE_ALL_TOOLS: 1 CODEGEN_BACKENDS: llvm,cranelift <<: *job-windows From 56c6ffbbdabda4c23cc2bbd6473829de8125f4b9 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 28 Jan 2025 02:15:15 +0900 Subject: [PATCH 02/12] Use +secure-plt for powerpc-unknown-linux-gnu{,spe} --- .../src/spec/targets/powerpc_unknown_linux_gnu.rs | 7 ++++++- .../src/spec/targets/powerpc_unknown_linux_gnuspe.rs | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs index 1ae879d01bd46..1c537491a6cad 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnu.rs @@ -18,6 +18,11 @@ pub(crate) fn target() -> Target { pointer_width: 32, data_layout: "E-m:e-p:32:32-Fn32-i64:64-n32".into(), arch: "powerpc".into(), - options: TargetOptions { endian: Endian::Big, mcount: "_mcount".into(), ..base }, + options: TargetOptions { + endian: Endian::Big, + features: "+secure-plt".into(), + mcount: "_mcount".into(), + ..base + }, } } diff --git a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs index 4a5ab375c7307..4f5d9c661b08d 100644 --- a/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs +++ b/compiler/rustc_target/src/spec/targets/powerpc_unknown_linux_gnuspe.rs @@ -21,6 +21,7 @@ pub(crate) fn target() -> Target { options: TargetOptions { abi: "spe".into(), endian: Endian::Big, + features: "+secure-plt".into(), mcount: "_mcount".into(), ..base }, From 56795fb77a69bc61836537175564455067adada6 Mon Sep 17 00:00:00 2001 From: Flakebi Date: Thu, 2 Jan 2025 15:19:43 +0100 Subject: [PATCH 03/12] Add amdgpu target Add target and compile the amdgpu llvm backend. --- compiler/rustc_target/src/spec/mod.rs | 2 + .../src/spec/targets/amdgcn_amd_amdhsa.rs | 51 ++++++++ config.example.toml | 2 +- src/bootstrap/download-ci-llvm-stamp | 2 +- src/bootstrap/src/core/build_steps/llvm.rs | 2 +- src/doc/rustc/src/SUMMARY.md | 1 + src/doc/rustc/src/platform-support.md | 2 + .../src/platform-support/amdgcn-amd-amdhsa.md | 111 ++++++++++++++++++ src/tools/build-manifest/src/main.rs | 1 + tests/assembly/targets/targets-amdgpu.rs | 21 ++++ .../amdgpu-require-explicit-cpu.nocpu.stderr | 4 + tests/ui/amdgpu-require-explicit-cpu.rs | 17 +++ .../exhaustive-names-values.empty_cfg.stderr | 2 +- .../exhaustive-names-values.feature.stderr | 2 +- .../exhaustive-names-values.full.stderr | 2 +- tests/ui/check-cfg/well-known-values.stderr | 8 +- 16 files changed, 220 insertions(+), 10 deletions(-) create mode 100644 compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs create mode 100644 src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md create mode 100644 tests/assembly/targets/targets-amdgpu.rs create mode 100644 tests/ui/amdgpu-require-explicit-cpu.nocpu.stderr create mode 100644 tests/ui/amdgpu-require-explicit-cpu.rs diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 3fc7a07fb9139..d7241ddecec6d 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -1908,6 +1908,8 @@ supported_targets! { ("nvptx64-nvidia-cuda", nvptx64_nvidia_cuda), + ("amdgcn-amd-amdhsa", amdgcn_amd_amdhsa), + ("xtensa-esp32-none-elf", xtensa_esp32_none_elf), ("xtensa-esp32-espidf", xtensa_esp32_espidf), ("xtensa-esp32s2-none-elf", xtensa_esp32s2_none_elf), diff --git a/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs b/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs new file mode 100644 index 0000000000000..bb488c350c23e --- /dev/null +++ b/compiler/rustc_target/src/spec/targets/amdgcn_amd_amdhsa.rs @@ -0,0 +1,51 @@ +use crate::spec::{Cc, LinkerFlavor, Lld, PanicStrategy, Target, TargetOptions}; + +pub(crate) fn target() -> Target { + Target { + arch: "amdgpu".into(), + data_layout: "e-p:64:64-p1:64:64-p2:32:32-p3:32:32-p4:64:64-p5:32:32-p6:32:32-p7:160:256:256:32-p8:128:128-p9:192:256:256:32-i64:64-v16:16-v24:32-v32:32-v48:64-v96:128-v192:256-v256:256-v512:512-v1024:1024-v2048:2048-n32:64-S32-A5-G1-ni:7:8:9".into(), + llvm_target: "amdgcn-amd-amdhsa".into(), + metadata: crate::spec::TargetMetadata { + description: Some("AMD GPU".into()), + tier: Some(3), + host_tools: Some(false), + std: Some(false), + }, + pointer_width: 64, + + options: TargetOptions { + os: "amdhsa".into(), + vendor: "amd".into(), + linker_flavor: LinkerFlavor::Gnu(Cc::No, Lld::Yes), + linker: Some("rust-lld".into()), + + // There are many CPUs, one for each hardware generation. + // Require to set one explicitly as there is no good default. + need_explicit_cpu: true, + + max_atomic_width: Some(64), + + // Unwinding on GPUs is not useful. + panic_strategy: PanicStrategy::Abort, + + // amdgpu backend does not support libcalls. + no_builtins: true, + simd_types_indirect: false, + + // Allow `cdylib` crate type. + dynamic_linking: true, + only_cdylib: true, + executables: false, + dll_prefix: "".into(), + dll_suffix: ".elf".into(), + + // The LLVM backend does not support stack canaries for this target + supports_stack_protector: false, + + // Force LTO, object linking does not yet work with amdgpu. + requires_lto: true, + + ..Default::default() + }, + } +} diff --git a/config.example.toml b/config.example.toml index 04e7310e6bc34..7f6bbf2799288 100644 --- a/config.example.toml +++ b/config.example.toml @@ -108,7 +108,7 @@ # the resulting rustc being unable to compile for the disabled architectures. # # To add support for new targets, see https://rustc-dev-guide.rust-lang.org/building/new-target.html. -#targets = "AArch64;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" +#targets = "AArch64;AMDGPU;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;Sparc;SystemZ;WebAssembly;X86" # LLVM experimental targets to build support for. These targets are specified in # the same format as above, but since these targets are experimental, they are diff --git a/src/bootstrap/download-ci-llvm-stamp b/src/bootstrap/download-ci-llvm-stamp index 42cecbf5df9bb..d2c0d380fb40b 100644 --- a/src/bootstrap/download-ci-llvm-stamp +++ b/src/bootstrap/download-ci-llvm-stamp @@ -1,4 +1,4 @@ Change this file to make users of the `download-ci-llvm` configuration download a new version of LLVM from CI, even if the LLVM submodule hasn’t changed. -Last change is for: https://github.com/rust-lang/rust/pull/129788 +Last change is for: https://github.com/rust-lang/rust/pull/134740 diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 3cf25373b8963..f855be5a33d64 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -331,7 +331,7 @@ impl Step for Llvm { let llvm_targets = match &builder.config.llvm_targets { Some(s) => s, None => { - "AArch64;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;\ + "AArch64;AMDGPU;ARM;BPF;Hexagon;LoongArch;MSP430;Mips;NVPTX;PowerPC;RISCV;\ Sparc;SystemZ;WebAssembly;X86" } }; diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 670e4bd1be68b..f78d3d4aee830 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -29,6 +29,7 @@ - [\*-apple-watchos](platform-support/apple-watchos.md) - [\*-apple-visionos](platform-support/apple-visionos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) + - [amdgcn-amd-amdhsa](platform-support/amdgcn-amd-amdhsa.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) - [arm-none-eabi](platform-support/arm-none-eabi.md) - [armv4t-none-eabi](platform-support/armv4t-none-eabi.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 8227dfa043e3a..01ac9f5458644 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -272,6 +272,7 @@ target | std | host | notes `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) [`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian) +[`amdgcn-amd-amdhsa`](platform-support/amdgcn-amd-amdhsa.md) | * | | `-Ctarget-cpu=gfx...` to specify [the AMD GPU] to compile for [`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | Arm Apple WatchOS 64-bit with 32-bit pointers [`arm64e-apple-darwin`](platform-support/arm64e-apple-darwin.md) | ✓ | ✓ | ARM64e Apple Darwin [`arm64e-apple-ios`](platform-support/arm64e-apple-ios.md) | ✓ | | ARM64e Apple iOS @@ -432,3 +433,4 @@ target | std | host | notes [`xtensa-esp32s3-none-elf`](platform-support/xtensa.md) | * | | Xtensa ESP32-S3 [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets +[the AMD GPU]: https://llvm.org/docs/AMDGPUUsage.html#processors diff --git a/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md b/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md new file mode 100644 index 0000000000000..0b2f798e66de1 --- /dev/null +++ b/src/doc/rustc/src/platform-support/amdgcn-amd-amdhsa.md @@ -0,0 +1,111 @@ +# `amdgcn-amd-amdhsa` + +**Tier: 3** + +AMD GPU target for compute/HSA (Heterogeneous System Architecture). + +## Target maintainers + +- [@Flakebi](https://github.com/Flakebi) + +## Requirements + +AMD GPUs can be targeted via cross-compilation. +Supported GPUs depend on the LLVM version that is used by Rust. +In general, most GPUs starting from gfx7 (Sea Islands/CI) are supported as compilation targets, though older GPUs are not supported by the latest host runtime. +Details about supported GPUs can be found in [LLVM’s documentation] and [ROCm documentation]. + +Binaries can be loaded by [HIP] or by the HSA runtime implemented in [ROCR-Runtime]. +The format of binaries is a linked ELF. + +Binaries must be built with no-std. +They can use `core` and `alloc` (`alloc` only if an allocator is supplied). +At least one function needs to use the `"gpu-kernel"` calling convention and should be marked with `no_mangle` for simplicity. +Functions using the `"gpu-kernel"` calling convention are kernel entrypoints and can be used from the host runtime. + +## Building the target + +The target is included in rustc. + +## Building Rust programs + +The amdgpu target supports many hardware generations, which need different binaries. +The generations are exposed as different target-cpus in the backend. +As there are many, Rust does not ship pre-compiled libraries for this target. +Therefore, you have to build your own copy of `core` by using `cargo -Zbuild-std=core` or similar. + +To build a binary, create a no-std library: +```rust,ignore (platform-specific) +// src/lib.rs +#![feature(abi_gpu_kernel)] +#![no_std] + +#[panic_handler] +fn panic(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[no_mangle] +pub extern "gpu-kernel" fn kernel(/* Arguments */) { + // Code +} +``` + +Build the library as `cdylib`: +```toml +# Cargo.toml +[lib] +crate-type = ["cdylib"] + +[profile.dev] +lto = true # LTO must be explicitly enabled for now +[profile.release] +lto = true +``` + +The target-cpu must be from the list [supported by LLVM] (or printed with `rustc --target amdgcn-amd-amdhsa --print target-cpus`). +The GPU version on the current system can be found e.g. with [`rocminfo`]. + +Example `.cargo/config.toml` file to set the target and GPU generation: +```toml +# .cargo/config.toml +[build] +target = "amdgcn-amd-amdhsa" +rustflags = ["-Ctarget-cpu=gfx1100"] + +[unstable] +build-std = ["core"] # Optional: "alloc" +``` + +## Running Rust programs + +To run a binary on an AMD GPU, a host runtime is needed. +On Linux and Windows, [HIP] can be used to load and run binaries. +Example code on how to load a compiled binary and run it is available in [ROCm examples]. + +On Linux, binaries can also run through the HSA runtime as implemented in [ROCR-Runtime]. + + + + + +## Additional information + +More information can be found on the [LLVM page for amdgpu]. + +[LLVM’s documentation]: https://llvm.org/docs/AMDGPUUsage.html#processors +[ROCm documentation]: https://rocmdocs.amd.com +[HIP]: https://rocm.docs.amd.com/projects/HIP/ +[ROCR-Runtime]: https://github.com/ROCm/ROCR-Runtime +[supported by LLVM]: https://llvm.org/docs/AMDGPUUsage.html#processors +[LLVM page for amdgpu]: https://llvm.org/docs/AMDGPUUsage.html +[`rocminfo`]: https://github.com/ROCm/rocminfo +[ROCm examples]: https://github.com/ROCm/rocm-examples/tree/ca8ef5b6f1390176616cd1c18fbc98785cbc73f6/HIP-Basic/module_api diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index feec2a7444f87..835a7d8e80fad 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -67,6 +67,7 @@ static TARGETS: &[&str] = &[ "aarch64-unknown-none-softfloat", "aarch64-unknown-redox", "aarch64-unknown-uefi", + "amdgcn-amd-amdhsa", "arm64e-apple-darwin", "arm64e-apple-ios", "arm64e-apple-tvos", diff --git a/tests/assembly/targets/targets-amdgpu.rs b/tests/assembly/targets/targets-amdgpu.rs new file mode 100644 index 0000000000000..501eed2e24783 --- /dev/null +++ b/tests/assembly/targets/targets-amdgpu.rs @@ -0,0 +1,21 @@ +//@ assembly-output: emit-asm +// ignore-tidy-linelength +//@ revisions: amdgcn_amd_amdhsa +//@ [amdgcn_amd_amdhsa] compile-flags: --target amdgcn-amd-amdhsa -Ctarget-cpu=gfx900 +//@ [amdgcn_amd_amdhsa] needs-llvm-components: amdgpu + +// Sanity-check that each target can produce assembly code. + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +pub fn test() -> u8 { + 42 +} + +// CHECK: .version diff --git a/tests/ui/amdgpu-require-explicit-cpu.nocpu.stderr b/tests/ui/amdgpu-require-explicit-cpu.nocpu.stderr new file mode 100644 index 0000000000000..7480a8ed38f15 --- /dev/null +++ b/tests/ui/amdgpu-require-explicit-cpu.nocpu.stderr @@ -0,0 +1,4 @@ +error: target requires explicitly specifying a cpu with `-C target-cpu` + +error: aborting due to 1 previous error + diff --git a/tests/ui/amdgpu-require-explicit-cpu.rs b/tests/ui/amdgpu-require-explicit-cpu.rs new file mode 100644 index 0000000000000..46778a1094fab --- /dev/null +++ b/tests/ui/amdgpu-require-explicit-cpu.rs @@ -0,0 +1,17 @@ +//@ revisions: nocpu cpu +//@ no-prefer-dynamic +//@ compile-flags: --crate-type=cdylib --target=amdgcn-amd-amdhsa +//@ needs-llvm-components: amdgpu +//@ needs-rust-lld +//@[nocpu] error-pattern: target requires explicitly specifying a cpu +//@[nocpu] build-fail +//@[cpu] compile-flags: -Ctarget-cpu=gfx900 +//@[cpu] build-pass + +#![feature(no_core, lang_items)] +#![no_core] + +#[lang="sized"] +trait Sized {} + +pub fn foo() {} diff --git a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr index 7e77ba63a127f..e7b8f35505761 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.empty_cfg.stderr @@ -14,7 +14,7 @@ warning: unexpected `cfg` condition value: `value` LL | #[cfg(target_vendor = "value")] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` + = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition name: `feature` diff --git a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr index 10302f0a7e46a..93b5414cc3f2c 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.feature.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.feature.stderr @@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value: `value` LL | #[cfg(target_vendor = "value")] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` + = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `unk` diff --git a/tests/ui/check-cfg/exhaustive-names-values.full.stderr b/tests/ui/check-cfg/exhaustive-names-values.full.stderr index 10302f0a7e46a..93b5414cc3f2c 100644 --- a/tests/ui/check-cfg/exhaustive-names-values.full.stderr +++ b/tests/ui/check-cfg/exhaustive-names-values.full.stderr @@ -15,7 +15,7 @@ warning: unexpected `cfg` condition value: `value` LL | #[cfg(target_vendor = "value")] | ^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` + = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `unk` diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index ffebd7e553198..6421cb8f2c2e7 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -138,7 +138,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_arch = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_arch` are: `aarch64`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`, and `xtensa` + = note: expected values for `target_arch` are: `aarch64`, `amdgpu`, `arm`, `arm64ec`, `avr`, `bpf`, `csky`, `hexagon`, `loongarch64`, `m68k`, `mips`, `mips32r6`, `mips64`, `mips64r6`, `msp430`, `nvptx64`, `powerpc`, `powerpc64`, `riscv32`, `riscv64`, `s390x`, `sparc`, `sparc64`, `wasm32`, `wasm64`, `x86`, `x86_64`, and `xtensa` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -201,7 +201,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_os = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `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` @@ -230,7 +230,7 @@ warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` LL | target_vendor = "_UNEXPECTED_VALUE", | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: expected values for `target_vendor` are: `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` + = note: expected values for `target_vendor` are: `amd`, `apple`, `espressif`, `fortanix`, `ibm`, `kmc`, `mti`, `nintendo`, `nvidia`, `pc`, `risc0`, `sony`, `sun`, `unikraft`, `unknown`, `uwp`, `win7`, and `wrs` = note: see for more information about checking conditional configuration warning: unexpected `cfg` condition value: `_UNEXPECTED_VALUE` @@ -274,7 +274,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`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` + = note: expected values for `target_os` are: `aix`, `amdhsa`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `nuttx`, `openbsd`, `psp`, `psx`, `redox`, `rtems`, `solaris`, `solid_asp3`, `teeos`, `trusty`, `tvos`, `uefi`, `unknown`, `visionos`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous`, and `zkvm` = note: see for more information about checking conditional configuration warning: 28 warnings emitted From 2c35bd0499130af395bdbb49a49d5a019599d22e Mon Sep 17 00:00:00 2001 From: clubby789 Date: Fri, 31 Jan 2025 16:10:21 +0000 Subject: [PATCH 04/12] `#[optimize(none)]` implies `#[inline(never)]` --- compiler/rustc_mir_transform/src/inline.rs | 6 +++++- .../issues/issue-136329-optnone-noinline.rs | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 tests/codegen/issues/issue-136329-optnone-noinline.rs diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 95aeccfdda66b..f8b0688dfdcc0 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -4,7 +4,7 @@ use std::iter; use std::ops::{Range, RangeFrom}; use rustc_abi::{ExternAbi, FieldIdx}; -use rustc_attr_parsing::InlineAttr; +use rustc_attr_parsing::{InlineAttr, OptimizeAttr}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_index::Idx; @@ -770,6 +770,10 @@ fn check_codegen_attributes<'tcx, I: Inliner<'tcx>>( return Err("never inline attribute"); } + if let OptimizeAttr::DoNotOptimize = callee_attrs.optimize { + return Err("has DoNotOptimize attribute"); + } + // Reachability pass defines which functions are eligible for inlining. Generally inlining // other functions is incorrect because they could reference symbols that aren't exported. let is_generic = callsite.callee.args.non_erasable_generics().next().is_some(); diff --git a/tests/codegen/issues/issue-136329-optnone-noinline.rs b/tests/codegen/issues/issue-136329-optnone-noinline.rs new file mode 100644 index 0000000000000..57c9e47a4992a --- /dev/null +++ b/tests/codegen/issues/issue-136329-optnone-noinline.rs @@ -0,0 +1,21 @@ +//! Ensure that `#[optimize(none)]` functions are never inlined + +//@ compile-flags: -Copt-level=3 + +#![feature(optimize_attribute)] + +#[optimize(none)] +pub fn foo() { + let _x = 123; +} + +// CHECK-LABEL: define{{.*}}void @bar +// CHECK: start: +// CHECK: {{.*}}call {{.*}}void +// CHECK: ret void +#[no_mangle] +pub fn bar() { + foo(); +} + +fn main() {} From 8e9422f94e6717721ffbad50862fcef9822c2537 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 31 Jan 2025 20:36:44 +0000 Subject: [PATCH 05/12] Make comma separated lists of anything easier to make for errors Provide a new function `listify`, meant to be used in cases similar to `pluralize!`. When you have a slice of arbitrary elements that need to be presented to the user, `listify` allows you to turn that into a list of comma separated strings. This reduces a lot of redundant logic that happens often in diagnostics. --- .../rustc_borrowck/src/diagnostics/mod.rs | 20 ++++---- compiler/rustc_builtin_macros/src/format.rs | 18 ++++---- compiler/rustc_errors/src/lib.rs | 14 +----- .../src/hir_ty_lowering/errors.rs | 46 ++++--------------- compiler/rustc_hir_typeck/src/demand.rs | 20 ++++---- compiler/rustc_hir_typeck/src/expr.rs | 35 +++++--------- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 12 +++-- .../src/fn_ctxt/suggestions.rs | 14 ++---- compiler/rustc_lint_defs/src/lib.rs | 17 +++++++ compiler/rustc_middle/src/ty/diagnostics.rs | 16 +++---- compiler/rustc_privacy/src/lib.rs | 24 ++-------- 11 files changed, 88 insertions(+), 148 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index bd6f77156ca99..d13b4bde5765f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -4,7 +4,7 @@ use std::collections::BTreeMap; use rustc_abi::{FieldIdx, VariantIdx}; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan}; +use rustc_errors::{Applicability, Diag, EmissionGuarantee, MultiSpan, listify}; use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::{self as hir, CoroutineKind, LangItem}; use rustc_index::IndexSlice; @@ -29,7 +29,7 @@ use rustc_trait_selection::error_reporting::InferCtxtErrorExt; use rustc_trait_selection::error_reporting::traits::call_kind::{CallDesugaringKind, call_kind}; use rustc_trait_selection::infer::InferCtxtExt; use rustc_trait_selection::traits::{ - FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions, + FulfillmentError, FulfillmentErrorCode, type_known_to_meet_bound_modulo_regions, }; use tracing::debug; @@ -1436,17 +1436,15 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { error.obligation.predicate, ) } - [errors @ .., last] => { + _ => { format!( "you could `clone` the value and consume it, if the \ - following trait bounds could be satisfied: \ - {} and `{}`", - errors - .iter() - .map(|e| format!("`{}`", e.obligation.predicate)) - .collect::>() - .join(", "), - last.obligation.predicate, + following trait bounds could be satisfied: {}", + listify(&errors, |e: &FulfillmentError<'tcx>| format!( + "`{}`", + e.obligation.predicate + )) + .unwrap(), ) } }; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 7c746bd719f31..90447da66807b 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -8,7 +8,9 @@ use rustc_ast::{ token, }; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans}; +use rustc_errors::{ + Applicability, Diag, MultiSpan, PResult, SingleLabelManySpans, listify, pluralize, +}; use rustc_expand::base::*; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiag, LintId}; @@ -975,15 +977,11 @@ fn report_invalid_references( } else { MultiSpan::from_spans(invalid_refs.iter().filter_map(|&(_, span, _, _)| span).collect()) }; - let arg_list = if let &[index] = &indexes[..] { - format!("argument {index}") - } else { - let tail = indexes.pop().unwrap(); - format!( - "arguments {head} and {tail}", - head = indexes.into_iter().map(|i| i.to_string()).collect::>().join(", ") - ) - }; + let arg_list = format!( + "argument{} {}", + pluralize!(indexes.len()), + listify(&indexes, |i: &usize| i.to_string()).unwrap_or_default() + ); e = ecx.dcx().struct_span_err( span, format!("invalid reference to positional {arg_list} ({num_args_desc})"), diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 549729548f537..a6458c9ffdcdb 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -65,7 +65,7 @@ pub use rustc_error_messages::{ SubdiagMessage, fallback_fluent_bundle, fluent_bundle, }; use rustc_lint_defs::LintExpectationId; -pub use rustc_lint_defs::{Applicability, pluralize}; +pub use rustc_lint_defs::{Applicability, listify, pluralize}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; @@ -1999,18 +1999,6 @@ pub fn a_or_an(s: &str) -> &'static str { } } -/// Grammatical tool for displaying messages to end users in a nice form. -/// -/// Take a list ["a", "b", "c"] and output a display friendly version "a, b and c" -pub fn display_list_with_comma_and(v: &[T]) -> String { - match v { - [] => "".to_string(), - [a] => a.to_string(), - [a, b] => format!("{a} and {b}"), - [a, v @ ..] => format!("{a}, {}", display_list_with_comma_and(v)), - } -} - #[derive(Clone, Copy, PartialEq, Hash, Debug)] pub enum TerminalUrl { No, diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs index 36b214b6ae734..79aa2f4b8ccd2 100644 --- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs +++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/errors.rs @@ -3,7 +3,7 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, pluralize, struct_span_code_err, + Applicability, Diag, ErrorGuaranteed, MultiSpan, listify, pluralize, struct_span_code_err, }; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -808,14 +808,10 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { .map(|(trait_, mut assocs)| { assocs.sort(); let trait_ = trait_.print_trait_sugared(); - format!("{} in `{trait_}`", match &assocs[..] { - [] => String::new(), - [only] => format!("`{only}`"), - [assocs @ .., last] => format!( - "{} and `{last}`", - assocs.iter().map(|a| format!("`{a}`")).collect::>().join(", ") - ), - }) + format!( + "{} in `{trait_}`", + listify(&assocs[..], |a| format!("`{a}`")).unwrap_or_default() + ) }) .collect::>(); names.sort(); @@ -1075,18 +1071,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { } }) .collect(); - let this_type = match &types_and_spans[..] { - [.., _, (last, _)] => format!( - "{} and {last}", - types_and_spans[..types_and_spans.len() - 1] - .iter() - .map(|(x, _)| x.as_str()) - .intersperse(", ") - .collect::() - ), - [(only, _)] => only.to_string(), - [] => bug!("expected one segment to deny"), - }; + let this_type = listify(&types_and_spans, |(t, _)| t.to_string()) + .expect("expected one segment to deny"); let arg_spans: Vec = segments .clone() @@ -1102,21 +1088,9 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { ProhibitGenericsArg::Infer => kinds.push("generic"), }); - let (kind, s) = match kinds[..] { - [.., _, last] => ( - format!( - "{} and {last}", - kinds[..kinds.len() - 1] - .iter() - .map(|&x| x) - .intersperse(", ") - .collect::() - ), - "s", - ), - [only] => (only.to_string(), ""), - [] => bug!("expected at least one generic to prohibit"), - }; + let s = pluralize!(kinds.len()); + let kind = + listify(&kinds, |k| k.to_string()).expect("expected at least one generic to prohibit"); let last_span = *arg_spans.last().unwrap(); let span: MultiSpan = arg_spans.into(); let mut err = struct_span_code_err!( diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index bc0766705854a..85e949952f8de 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Applicability, Diag, MultiSpan}; +use rustc_errors::{Applicability, Diag, MultiSpan, listify}; use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::Visitor; @@ -1016,18 +1016,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, self.tcx.def_path_str(candidate.item.container_id(self.tcx)) ), - [.., last] if other_methods_in_scope.len() < 5 => { + _ if other_methods_in_scope.len() < 5 => { format!( - "the methods of the same name on {} and `{}`", - other_methods_in_scope[..other_methods_in_scope.len() - 1] - .iter() - .map(|c| format!( - "`{}`", - self.tcx.def_path_str(c.item.container_id(self.tcx)) - )) - .collect::>() - .join(", "), - self.tcx.def_path_str(last.item.container_id(self.tcx)) + "the methods of the same name on {}", + listify( + &other_methods_in_scope[..other_methods_in_scope.len() - 1], + |c| format!("`{}`", self.tcx.def_path_str(c.item.container_id(self.tcx))) + ) + .unwrap_or_default(), ) } _ => format!( diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index f79667e59bae1..0582a7dcee171 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -11,7 +11,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_data_structures::unord::UnordMap; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, pluralize, + Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, Subdiagnostic, listify, pluralize, struct_span_code_err, }; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -2190,13 +2190,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if !missing_mandatory_fields.is_empty() { let s = pluralize!(missing_mandatory_fields.len()); - let fields: Vec<_> = - missing_mandatory_fields.iter().map(|f| format!("`{f}`")).collect(); - let fields = match &fields[..] { - [] => unreachable!(), - [only] => only.to_string(), - [start @ .., last] => format!("{} and {last}", start.join(", ")), - }; + let fields = listify(&missing_mandatory_fields, |f| format!("`{f}`")).unwrap(); self.dcx() .struct_span_err( span.shrink_to_hi(), @@ -2553,25 +2547,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .partition(|field| field.2); err.span_labels(used_private_fields.iter().map(|(_, span, _)| *span), "private field"); if !remaining_private_fields.is_empty() { - let remaining_private_fields_len = remaining_private_fields.len(); - let names = match &remaining_private_fields - .iter() - .map(|(name, _, _)| name) - .collect::>()[..] - { - _ if remaining_private_fields_len > 6 => String::new(), - [name] => format!("`{name}` "), - [names @ .., last] => { - let names = names.iter().map(|name| format!("`{name}`")).collect::>(); - format!("{} and `{last}` ", names.join(", ")) - } - [] => bug!("expected at least one private field to report"), + let names = if remaining_private_fields.len() > 6 { + String::new() + } else { + format!( + "{} ", + listify(&remaining_private_fields, |(name, _, _)| format!("`{name}`")) + .expect("expected at least one private field to report") + ) }; err.note(format!( "{}private field{s} {names}that {were} not provided", if used_fields.is_empty() { "" } else { "...and other " }, - s = pluralize!(remaining_private_fields_len), - were = pluralize!("was", remaining_private_fields_len), + s = pluralize!(remaining_private_fields.len()), + were = pluralize!("was", remaining_private_fields.len()), )); } diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index fb5fc109ce467..bbe653714962e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -4,8 +4,7 @@ use itertools::Itertools; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::codes::*; use rustc_errors::{ - Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, - display_list_with_comma_and, pluralize, + Applicability, Diag, ErrorGuaranteed, MultiSpan, StashKey, a_or_an, listify, pluralize, }; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -2462,7 +2461,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param.span, format!( "{} need{} to match the {} type of this parameter", - display_list_with_comma_and(&other_param_matched_names), + listify(&other_param_matched_names, |n| n.to_string()) + .unwrap_or_default(), pluralize!(if other_param_matched_names.len() == 1 { 0 } else { @@ -2477,7 +2477,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { format!( "this parameter needs to match the {} type of {}", matched_ty, - display_list_with_comma_and(&other_param_matched_names), + listify(&other_param_matched_names, |n| n.to_string()) + .unwrap_or_default(), ), ); } @@ -2523,7 +2524,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { generic_param.span, format!( "{} {} reference this parameter `{}`", - display_list_with_comma_and(¶m_idents_matching), + listify(¶m_idents_matching, |n| n.to_string()) + .unwrap_or_default(), if param_idents_matching.len() == 2 { "both" } else { "all" }, generic_param.name.ident().name, ), diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 60f9265bfcc0d..beddbf971fd3e 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -4,7 +4,7 @@ use core::iter; use hir::def_id::LocalDefId; use rustc_ast::util::parser::ExprPrecedence; use rustc_data_structures::packed::Pu128; -use rustc_errors::{Applicability, Diag, MultiSpan}; +use rustc_errors::{Applicability, Diag, MultiSpan, listify}; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::lang_items::LangItem; use rustc_hir::{ @@ -1836,16 +1836,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error.obligation.predicate, )); } - [errors @ .., last] => { + _ => { diag.help(format!( "`Clone` is not implemented because the following trait bounds \ - could not be satisfied: {} and `{}`", - errors - .iter() - .map(|e| format!("`{}`", e.obligation.predicate)) - .collect::>() - .join(", "), - last.obligation.predicate, + could not be satisfied: {}", + listify(&errors, |e| format!("`{}`", e.obligation.predicate)) + .unwrap(), )); } } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 3f1e98556ef0c..7ffe4e4e4901c 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -42,6 +42,23 @@ macro_rules! pluralize { }; } +/// Grammatical tool for displaying messages to end users in a nice form. +/// +/// Take a list of items and a function to turn those items into a `String`, and output a display +/// friendly comma separated list of those items. +// FIXME(estebank): this needs to be changed to go through the translation machinery. +pub fn listify(list: &[T], fmt: impl Fn(&T) -> String) -> Option { + Some(match list { + [only] => fmt(&only), + [others @ .., last] => format!( + "{} and {}", + others.iter().map(|i| fmt(i)).collect::>().join(", "), + fmt(&last), + ), + [] => return None, + }) +} + /// Indicates the confidence in the correctness of a suggestion. /// /// All suggestions are marked with an `Applicability`. Tools use the applicability of a suggestion diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs index b4b66a8133a33..cb218a27e6237 100644 --- a/compiler/rustc_middle/src/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -5,7 +5,7 @@ use std::ops::ControlFlow; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{ - Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, pluralize, + Applicability, Diag, DiagArgValue, IntoDiagArg, into_diag_arg_using_display, listify, pluralize, }; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; @@ -362,11 +362,8 @@ pub fn suggest_constraining_type_params<'a>( let n = trait_names.len(); let stable = if all_stable { "" } else { "unstable " }; let trait_ = if all_known { format!("trait{}", pluralize!(n)) } else { String::new() }; - format!("{stable}{trait_}{}", match &trait_names[..] { - [t] => format!(" {t}"), - [ts @ .., last] => format!(" {} and {last}", ts.join(", ")), - [] => return false, - },) + let Some(trait_names) = listify(&trait_names, |n| n.to_string()) else { return false }; + format!("{stable}{trait_} {trait_names}") } else { // We're more explicit when there's a mix of stable and unstable traits. let mut trait_names = constraints @@ -378,10 +375,9 @@ pub fn suggest_constraining_type_params<'a>( .collect::>(); trait_names.sort(); trait_names.dedup(); - match &trait_names[..] { - [t] => t.to_string(), - [ts @ .., last] => format!("{} and {last}", ts.join(", ")), - [] => return false, + match listify(&trait_names, |t| t.to_string()) { + Some(names) => names, + None => return false, } }; let constraint = constraint.join(" + "); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d19df08519d26..3842b7035e537 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -24,7 +24,7 @@ use rustc_ast::MacroDef; use rustc_ast::visit::{VisitorResult, try_visit}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; -use rustc_errors::MultiSpan; +use rustc_errors::{MultiSpan, listify}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LocalDefId, LocalModDefId}; use rustc_hir::intravisit::{self, InferKind, Visitor}; @@ -958,29 +958,15 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { // | ^^ field `gamma` is private # `fields.2` is `false` // Get the list of all private fields for the main message. - let field_names: Vec<_> = fields.iter().map(|(name, _, _)| name).collect(); - let field_names = match &field_names[..] { - [] => return, - [name] => format!("`{name}`"), - [fields @ .., last] => format!( - "{} and `{last}`", - fields.iter().map(|f| format!("`{f}`")).collect::>().join(", "), - ), - }; + let Some(field_names) = listify(&fields[..], |(n, _, _)| format!("`{n}`")) else { return }; let span: MultiSpan = fields.iter().map(|(_, span, _)| *span).collect::>().into(); // Get the list of all private fields when pointing at the `..rest`. let rest_field_names: Vec<_> = fields.iter().filter(|(_, _, is_present)| !is_present).map(|(n, _, _)| n).collect(); let rest_len = rest_field_names.len(); - let rest_field_names = match &rest_field_names[..] { - [] => String::new(), - [name] => format!("`{name}`"), - [fields @ .., last] => format!( - "{} and `{last}`", - fields.iter().map(|f| format!("`{f}`")).collect::>().join(", "), - ), - }; + let rest_field_names = + listify(&rest_field_names[..], |n| format!("`{n}`")).unwrap_or_default(); // Get all the labels for each field or `..rest` in the primary MultiSpan. let labels = fields .iter() @@ -1005,7 +991,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { } else { None }, - field_names: field_names.clone(), + field_names, variant_descr: def.variant_descr(), def_path_str: self.tcx.def_path_str(def.did()), labels, From 0751e9036af0525c3e42b74cce5597ed66dd7849 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Fri, 31 Jan 2025 03:26:56 +0000 Subject: [PATCH 06/12] Rework "long type names" printing logic Make it so more type-system types can be printed in a shortened version (like `Predicate`s). Centralize printing the information about the "full type name path". Make the "long type path" for the file where long types are written part of `Diag`, so that it becomes easier to keep track of it, and ensure it will always will be printed out last in the diagnostic by making its addition to the output implicit. Tweak the shortening of types in "expected/found" labels. Remove dead file `note.rs`. --- compiler/rustc_borrowck/messages.ftl | 3 - .../src/diagnostics/conflict_errors.rs | 8 +- .../src/diagnostics/move_errors.rs | 24 +- .../rustc_borrowck/src/session_diagnostics.rs | 7 - compiler/rustc_errors/src/diagnostic.rs | 31 ++ .../rustc_hir_typeck/src/method/suggest.rs | 39 +- compiler/rustc_middle/src/ty/error.rs | 37 +- compiler/rustc_middle/src/ty/print/mod.rs | 4 + compiler/rustc_middle/src/ty/print/pretty.rs | 93 ++-- compiler/rustc_mir_build/messages.ftl | 2 - compiler/rustc_mir_build/src/errors.rs | 4 - .../src/thir/pattern/check_match.rs | 8 +- .../src/error_reporting/infer/mod.rs | 47 +- .../error_reporting/infer/need_type_info.rs | 2 +- .../src/error_reporting/infer/note.rs | 422 ------------------ .../src/error_reporting/infer/region.rs | 10 +- .../src/error_reporting/traits/ambiguity.rs | 20 +- .../traits/fulfillment_errors.rs | 82 ++-- .../src/error_reporting/traits/mod.rs | 11 - .../traits/on_unimplemented.rs | 2 +- .../src/error_reporting/traits/overflow.rs | 11 - .../src/error_reporting/traits/suggestions.rs | 54 +-- .../coerce-expect-unsized-ascribed.stderr | 6 +- tests/ui/diagnostic-width/E0271.ascii.stderr | 8 +- tests/ui/diagnostic-width/E0271.rs | 4 +- .../ui/diagnostic-width/E0271.unicode.stderr | 8 +- .../diagnostic-width/long-E0308.ascii.stderr | 28 +- .../long-E0308.unicode.stderr | 28 +- tests/ui/diagnostic-width/long-e0277.rs | 15 + tests/ui/diagnostic-width/long-e0277.stderr | 23 + .../non-copy-type-moved.stderr | 4 +- .../secondary-label-with-long-type.rs | 2 +- .../secondary-label-with-long-type.stderr | 2 +- .../hang-on-deeply-nested-dyn.stderr | 2 +- .../box-future-wrong-output.stderr | 2 +- .../expected-boxed-future-isnt-pinned.stderr | 2 +- tests/ui/suggestions/issue-107860.stderr | 2 +- .../traits/ice-with-dyn-pointee-errors.stderr | 2 +- tests/ui/traits/object/pretty.stderr | 4 +- .../traits/on_unimplemented_long_types.stderr | 2 - tests/ui/typeck/issue-107775.stderr | 2 +- .../typeck/return_type_containing_closure.rs | 2 +- .../return_type_containing_closure.stderr | 2 +- 43 files changed, 331 insertions(+), 740 deletions(-) delete mode 100644 compiler/rustc_trait_selection/src/error_reporting/infer/note.rs create mode 100644 tests/ui/diagnostic-width/long-e0277.rs create mode 100644 tests/ui/diagnostic-width/long-e0277.stderr diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl index c00e6dde91965..ada20e5c614f8 100644 --- a/compiler/rustc_borrowck/messages.ftl +++ b/compiler/rustc_borrowck/messages.ftl @@ -92,9 +92,6 @@ borrowck_lifetime_constraints_error = borrowck_limitations_implies_static = due to current limitations in the borrow checker, this implies a `'static` lifetime -borrowck_long_type_consider_verbose = consider using `--verbose` to print the full type name to the console -borrowck_long_type_full_path = the full type name has been written to '{$path}' - borrowck_move_closure_suggestion = consider adding 'move' keyword before the nested closure diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 07dcbba019ade..c6439da33d6d7 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -289,8 +289,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { None => "value".to_owned(), }; if needs_note { - let mut path = None; - let ty = self.infcx.tcx.short_ty_string(ty, &mut path); + let ty = self.infcx.tcx.short_string(ty, err.long_ty_path()); if let Some(local) = place.as_local() { let span = self.body.local_decls[local].source_info.span; err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { @@ -306,11 +305,6 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { place: ¬e_msg, }); }; - if let Some(path) = path { - err.subdiagnostic(crate::session_diagnostics::LongTypePath { - path: path.display().to_string(), - }); - } } if let UseSpans::FnSelfUse { diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 14a900f38e922..58c5c2fd7742a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -596,19 +596,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.suggest_cloning(err, place_ty, expr, None); } - let mut path = None; - let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path); + let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path()); err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, ty, place: &place_desc, span, }); - if let Some(path) = path { - err.subdiagnostic(crate::session_diagnostics::LongTypePath { - path: path.display().to_string(), - }); - } } else { binds_to.sort(); binds_to.dedup(); @@ -635,19 +629,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.suggest_cloning(err, place_ty, expr, Some(use_spans)); } - let mut path = None; - let ty = self.infcx.tcx.short_ty_string(place_ty, &mut path); + let ty = self.infcx.tcx.short_string(place_ty, err.long_ty_path()); err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, ty, place: &place_desc, span: use_span, }); - if let Some(path) = path { - err.subdiagnostic(crate::session_diagnostics::LongTypePath { - path: path.display().to_string(), - }); - } use_spans.args_subdiag(err, |args_span| { crate::session_diagnostics::CaptureArgLabel::MoveOutPlace { @@ -845,19 +833,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { self.suggest_cloning(err, bind_to.ty, expr, None); } - let mut path = None; - let ty = self.infcx.tcx.short_ty_string(bind_to.ty, &mut path); + let ty = self.infcx.tcx.short_string(bind_to.ty, err.long_ty_path()); err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label { is_partial_move: false, ty, place: place_desc, span: binding_span, }); - if let Some(path) = path { - err.subdiagnostic(crate::session_diagnostics::LongTypePath { - path: path.display().to_string(), - }); - } } } diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs index 2c37d2bc12362..11b30c145c2c2 100644 --- a/compiler/rustc_borrowck/src/session_diagnostics.rs +++ b/compiler/rustc_borrowck/src/session_diagnostics.rs @@ -458,13 +458,6 @@ pub(crate) enum OnClosureNote<'a> { }, } -#[derive(Subdiagnostic)] -#[note(borrowck_long_type_full_path)] -#[note(borrowck_long_type_consider_verbose)] -pub(crate) struct LongTypePath { - pub(crate) path: String, -} - #[derive(Subdiagnostic)] pub(crate) enum TypeNoCopy<'a> { #[label(borrowck_ty_no_impl_copy)] diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs index 797dcd7b4d1df..b96df81485294 100644 --- a/compiler/rustc_errors/src/diagnostic.rs +++ b/compiler/rustc_errors/src/diagnostic.rs @@ -4,6 +4,7 @@ use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::ops::{Deref, DerefMut}; use std::panic; +use std::path::PathBuf; use std::thread::panicking; use rustc_data_structures::fx::FxIndexMap; @@ -301,6 +302,7 @@ pub struct DiagInner { pub is_lint: Option, + pub long_ty_path: Option, /// With `-Ztrack_diagnostics` enabled, /// we print where in rustc this error was emitted. pub(crate) emitted_at: DiagLocation, @@ -324,6 +326,7 @@ impl DiagInner { args: Default::default(), sort_span: DUMMY_SP, is_lint: None, + long_ty_path: None, emitted_at: DiagLocation::caller(), } } @@ -1293,9 +1296,37 @@ impl<'a, G: EmissionGuarantee> Diag<'a, G> { /// `cancel`, etc. Afterwards, `drop` is the only code that will be run on /// `self`. fn take_diag(&mut self) -> DiagInner { + if let Some(path) = &self.long_ty_path { + self.note(format!( + "the full name for the type has been written to '{}'", + path.display() + )); + self.note("consider using `--verbose` to print the full type name to the console"); + } Box::into_inner(self.diag.take().unwrap()) } + /// This method allows us to access the path of the file where "long types" are written to. + /// + /// When calling `Diag::emit`, as part of that we will check if a `long_ty_path` has been set, + /// and if it has been then we add a note mentioning the file where the "long types" were + /// written to. + /// + /// When calling `tcx.short_string()` after a `Diag` is constructed, the preferred way of doing + /// so is `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that + /// keeps the existence of a "long type" anywhere in the diagnostic, so the note telling the + /// user where we wrote the file to is only printed once at most, *and* it makes it much harder + /// to forget to set it. + /// + /// If the diagnostic hasn't been created before a "short ty string" is created, then you should + /// ensure that this method is called to set it `*diag.long_ty_path() = path`. + /// + /// As a rule of thumb, if you see or add at least one `tcx.short_string()` call anywhere, in a + /// scope, `diag.long_ty_path()` should be called once somewhere close by. + pub fn long_ty_path(&mut self) -> &mut Option { + &mut self.long_ty_path + } + /// Most `emit_producing_guarantee` functions use this as a starting point. fn emit_producing_nothing(mut self) { let diag = self.take_diag(); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index e4a6a0fedc5a7..920418407c0f5 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -5,6 +5,7 @@ use core::ops::ControlFlow; use std::borrow::Cow; +use std::path::PathBuf; use hir::Expr; use rustc_ast::ast::Mutability; @@ -362,14 +363,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn suggest_missing_writer(&self, rcvr_ty: Ty<'tcx>, rcvr_expr: &hir::Expr<'tcx>) -> Diag<'_> { let mut file = None; - let ty_str = self.tcx.short_ty_string(rcvr_ty, &mut file); let mut err = struct_span_code_err!( self.dcx(), rcvr_expr.span, E0599, "cannot write into `{}`", - ty_str + self.tcx.short_string(rcvr_ty, &mut file), ); + *err.long_ty_path() = file; err.span_note( rcvr_expr.span, "must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method", @@ -380,11 +381,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "a writer is needed before this format string", ); }; - if let Some(file) = file { - err.note(format!("the full type name has been written to '{}'", file.display())); - err.note("consider using `--verbose` to print the full type name to the console"); - } - err } @@ -595,7 +591,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (predicates.to_string(), with_forced_trimmed_paths!(predicates.to_string())) } else { ( - tcx.short_ty_string(rcvr_ty, &mut ty_file), + tcx.short_string(rcvr_ty, &mut ty_file), with_forced_trimmed_paths!(rcvr_ty.to_string()), ) }; @@ -624,6 +620,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span, item_name, &short_ty_str, + &mut ty_file, ) { return guar; } @@ -635,6 +632,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_kind, item_name, &short_ty_str, + &mut ty_file, ) { return guar; } @@ -728,10 +726,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty_str = short_ty_str; } - if let Some(file) = ty_file { - err.note(format!("the full type name has been written to '{}'", file.display(),)); - err.note("consider using `--verbose` to print the full type name to the console"); - } if rcvr_ty.references_error() { err.downgrade_to_delayed_bug(); } @@ -1314,7 +1308,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { bound_list.into_iter().map(|(_, path)| path).collect::>().join("\n"); let actual_prefix = rcvr_ty.prefix_string(self.tcx); info!("unimplemented_traits.len() == {}", unimplemented_traits.len()); - let mut long_ty_file = None; let (primary_message, label, notes) = if unimplemented_traits.len() == 1 && unimplemented_traits_only { @@ -1329,7 +1322,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let OnUnimplementedNote { message, label, notes, .. } = self .err_ctxt() - .on_unimplemented_note(trait_ref, &obligation, &mut long_ty_file); + .on_unimplemented_note(trait_ref, &obligation, &mut ty_file); (message, label, notes) }) .unwrap() @@ -1343,15 +1336,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) }); err.primary_message(primary_message); - if let Some(file) = long_ty_file { - err.note(format!( - "the full name for the type has been written to '{}'", - file.display(), - )); - err.note( - "consider using `--verbose` to print the full type name to the console", - ); - } if let Some(label) = label { custom_span_label = true; err.span_label(span, label); @@ -2403,6 +2387,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span: Span, item_name: Ident, ty_str: &str, + long_ty_path: &mut Option, ) -> Result<(), ErrorGuaranteed> { if let SelfSource::MethodCall(expr) = source { for (_, parent) in tcx.hir().parent_iter(expr.hir_id).take(5) { @@ -2460,7 +2445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); if pick.is_ok() { let range_span = parent_expr.span.with_hi(expr.span.hi()); - return Err(self.dcx().emit_err(errors::MissingParenthesesInRange { + let mut err = self.dcx().create_err(errors::MissingParenthesesInRange { span, ty_str: ty_str.to_string(), method_name: item_name.as_str().to_string(), @@ -2469,7 +2454,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { left: range_span.shrink_to_lo(), right: range_span.shrink_to_hi(), }), - })); + }); + *err.long_ty_path() = long_ty_path.take(); + return Err(err.emit()); } } } @@ -2486,6 +2473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_kind: &str, item_name: Ident, ty_str: &str, + long_ty_path: &mut Option, ) -> Result<(), ErrorGuaranteed> { let found_candidate = all_traits(self.tcx) .into_iter() @@ -2526,6 +2514,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_name, ty_str ); + *err.long_ty_path() = long_ty_path.take(); let concrete_type = if actual.is_integral() { "i32" } else { "f32" }; match expr.kind { ExprKind::Lit(lit) => { diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs index 35fbaa99569c9..8c1991ddb36ee 100644 --- a/compiler/rustc_middle/src/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -10,8 +10,8 @@ use rustc_hir::def::{CtorOf, DefKind}; use rustc_macros::extension; pub use rustc_type_ir::error::ExpectedFound; -use crate::ty::print::{FmtPrinter, PrettyPrinter, with_forced_trimmed_paths}; -use crate::ty::{self, Ty, TyCtxt}; +use crate::ty::print::{FmtPrinter, Print, with_forced_trimmed_paths}; +use crate::ty::{self, Lift, Ty, TyCtxt}; pub type TypeError<'tcx> = rustc_type_ir::error::TypeError>; @@ -159,8 +159,8 @@ impl<'tcx> Ty<'tcx> { ty::Error(_) => "type error".into(), _ => { let width = tcx.sess.diagnostic_width(); - let length_limit = std::cmp::max(width / 4, 15); - format!("`{}`", tcx.ty_string_with_limit(self, length_limit)).into() + let length_limit = std::cmp::max(width / 4, 40); + format!("`{}`", tcx.string_with_limit(self, length_limit)).into() } } } @@ -213,10 +213,14 @@ impl<'tcx> Ty<'tcx> { } impl<'tcx> TyCtxt<'tcx> { - pub fn ty_string_with_limit(self, ty: Ty<'tcx>, length_limit: usize) -> String { + pub fn string_with_limit<'a, T>(self, p: T, length_limit: usize) -> String + where + T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift> + Copy, + >>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>, + { let mut type_limit = 50; let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| { - cx.pretty_print_type(ty) + self.lift(p).expect("could not lift for printing").print(cx) }) .expect("could not write to `String`"); if regular.len() <= length_limit { @@ -231,7 +235,10 @@ impl<'tcx> TyCtxt<'tcx> { hir::def::Namespace::TypeNS, rustc_session::Limit(type_limit), ); - cx.pretty_print_type(ty).expect("could not write to `String`"); + self.lift(p) + .expect("could not lift for printing") + .print(&mut cx) + .expect("could not print type"); cx.into_buffer() }); if short.len() <= length_limit || type_limit == 0 { @@ -242,9 +249,17 @@ impl<'tcx> TyCtxt<'tcx> { short } - pub fn short_ty_string(self, ty: Ty<'tcx>, path: &mut Option) -> String { + /// When calling this after a `Diag` is constructed, the preferred way of doing so is + /// `tcx.short_string(ty, diag.long_ty_path())`. The diagnostic itself is the one that keeps + /// the existence of a "long type" anywhere in the diagnostic, so the note telling the user + /// where we wrote the file to is only printed once. + pub fn short_string<'a, T>(self, p: T, path: &mut Option) -> String + where + T: Print<'tcx, FmtPrinter<'a, 'tcx>> + Lift> + Copy + Hash, + >>::Lifted: Print<'tcx, FmtPrinter<'a, 'tcx>>, + { let regular = FmtPrinter::print_string(self, hir::def::Namespace::TypeNS, |cx| { - cx.pretty_print_type(ty) + self.lift(p).expect("could not lift for printing").print(cx) }) .expect("could not write to `String`"); @@ -257,13 +272,13 @@ impl<'tcx> TyCtxt<'tcx> { if regular.len() <= width * 2 / 3 { return regular; } - let short = self.ty_string_with_limit(ty, length_limit); + let short = self.string_with_limit(p, length_limit); if regular == short { return regular; } // Ensure we create an unique file for the type passed in when we create a file. let mut s = DefaultHasher::new(); - ty.hash(&mut s); + p.hash(&mut s); let hash = s.finish(); *path = Some(path.take().unwrap_or_else(|| { self.output_filenames(()).temp_path_ext(&format!("long-type-{hash}.txt"), None) diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs index 72f353f06ff52..dc2040aa5cf85 100644 --- a/compiler/rustc_middle/src/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -105,6 +105,10 @@ pub trait Printer<'tcx>: Sized { args: &[GenericArg<'tcx>], ) -> Result<(), PrintError>; + fn should_truncate(&mut self) -> bool { + false + } + // Defaults (should not be overridden): #[instrument(skip(self), level = "debug")] diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 018fcc66aeed4..6c8591dae895b 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -865,7 +865,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!(write("{{")); if !self.tcx().sess.verbose_internals() { p!("coroutine witness"); - // FIXME(eddyb) should use `def_span`. if let Some(did) = did.as_local() { let span = self.tcx().def_span(did); p!(write( @@ -887,26 +886,30 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { p!(write("{{")); if !self.should_print_verbose() { p!(write("closure")); - // FIXME(eddyb) should use `def_span`. - if let Some(did) = did.as_local() { - if self.tcx().sess.opts.unstable_opts.span_free_formats { - p!("@", print_def_path(did.to_def_id(), args)); - } else { - let span = self.tcx().def_span(did); - let preference = if with_forced_trimmed_paths() { - FileNameDisplayPreference::Short + if self.should_truncate() { + write!(self, "@...}}")?; + return Ok(()); + } else { + if let Some(did) = did.as_local() { + if self.tcx().sess.opts.unstable_opts.span_free_formats { + p!("@", print_def_path(did.to_def_id(), args)); } else { - FileNameDisplayPreference::Remapped - }; - p!(write( - "@{}", - // This may end up in stderr diagnostics but it may also be emitted - // into MIR. Hence we use the remapped path if available - self.tcx().sess.source_map().span_to_string(span, preference) - )); + let span = self.tcx().def_span(did); + let preference = if with_forced_trimmed_paths() { + FileNameDisplayPreference::Short + } else { + FileNameDisplayPreference::Remapped + }; + p!(write( + "@{}", + // This may end up in stderr diagnostics but it may also be emitted + // into MIR. Hence we use the remapped path if available + self.tcx().sess.source_map().span_to_string(span, preference) + )); + } + } else { + p!(write("@"), print_def_path(did, args)); } - } else { - p!(write("@"), print_def_path(did, args)); } } else { p!(print_def_path(did, args)); @@ -942,7 +945,6 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { "coroutine from coroutine-closure should have CoroutineSource::Closure" ), } - // FIXME(eddyb) should use `def_span`. if let Some(did) = did.as_local() { if self.tcx().sess.opts.unstable_opts.span_free_formats { p!("@", print_def_path(did.to_def_id(), args)); @@ -1994,7 +1996,6 @@ pub struct FmtPrinterData<'a, 'tcx> { binder_depth: usize, printed_type_count: usize, type_length_limit: Limit, - truncated: bool, pub region_highlight_mode: RegionHighlightMode<'tcx>, @@ -2046,7 +2047,6 @@ impl<'a, 'tcx> FmtPrinter<'a, 'tcx> { binder_depth: 0, printed_type_count: 0, type_length_limit, - truncated: false, region_highlight_mode: RegionHighlightMode::default(), ty_infer_name_resolver: None, const_infer_name_resolver: None, @@ -2183,16 +2183,49 @@ impl<'tcx> Printer<'tcx> for FmtPrinter<'_, 'tcx> { } fn print_type(&mut self, ty: Ty<'tcx>) -> Result<(), PrintError> { - if self.type_length_limit.value_within_limit(self.printed_type_count) { - self.printed_type_count += 1; - self.pretty_print_type(ty) - } else { - self.truncated = true; - write!(self, "...")?; - Ok(()) + match ty.kind() { + ty::Tuple(tys) if tys.len() == 0 && self.should_truncate() => { + // Don't truncate `()`. + self.printed_type_count += 1; + self.pretty_print_type(ty) + } + ty::Adt(..) + | ty::Foreign(_) + | ty::Pat(..) + | ty::RawPtr(..) + | ty::Ref(..) + | ty::FnDef(..) + | ty::FnPtr(..) + | ty::UnsafeBinder(..) + | ty::Dynamic(..) + | ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::CoroutineWitness(..) + | ty::Tuple(_) + | ty::Alias(..) + | ty::Param(_) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Error(_) + if self.should_truncate() => + { + // We only truncate types that we know are likely to be much longer than 3 chars. + // There's no point in replacing `i32` or `!`. + write!(self, "...")?; + Ok(()) + } + _ => { + self.printed_type_count += 1; + self.pretty_print_type(ty) + } } } + fn should_truncate(&mut self) -> bool { + !self.type_length_limit.value_within_limit(self.printed_type_count) + } + fn print_dyn_existential( &mut self, predicates: &'tcx ty::List>, @@ -2942,7 +2975,7 @@ impl<'tcx> ty::TraitPredicate<'tcx> { } } -#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)] +#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift, Hash)] pub struct TraitPredPrintWithBoundConstness<'tcx>( ty::TraitPredicate<'tcx>, Option, diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl index 053775b493789..ffdb721fb18b4 100644 --- a/compiler/rustc_mir_build/messages.ftl +++ b/compiler/rustc_mir_build/messages.ftl @@ -25,8 +25,6 @@ mir_build_borrow_of_moved_value = borrow of moved value .occurs_because_label = move occurs because `{$name}` has type `{$ty}`, which does not implement the `Copy` trait .value_borrowed_label = value borrowed here after move .suggestion = borrow this binding in the pattern to avoid moving the value - .full_type_name = the full type name has been written to '{$path}' - .consider_verbose = consider using `--verbose` to print the full type name to the console mir_build_call_to_deprecated_safe_fn_requires_unsafe = call to deprecated safe function `{$function}` is unsafe and requires unsafe block diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs index 1f87bf0dbbbd6..c13db27dae856 100644 --- a/compiler/rustc_mir_build/src/errors.rs +++ b/compiler/rustc_mir_build/src/errors.rs @@ -801,10 +801,6 @@ pub(crate) struct BorrowOfMovedValue { pub(crate) ty: String, #[suggestion(code = "ref ", applicability = "machine-applicable")] pub(crate) suggest_borrowing: Option, - #[note(mir_build_full_type_name)] - #[note(mir_build_consider_verbose)] - pub(crate) has_path: bool, - pub(crate) path: String, } #[derive(Diagnostic)] diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index e0a1117f905c6..a237124a2113c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -796,16 +796,16 @@ fn check_borrow_conflicts_in_at_patterns<'tcx>(cx: &MatchVisitor<'_, 'tcx>, pat: }); if !conflicts_ref.is_empty() { let mut path = None; - let ty = cx.tcx.short_ty_string(ty, &mut path); - sess.dcx().emit_err(BorrowOfMovedValue { + let ty = cx.tcx.short_string(ty, &mut path); + let mut err = sess.dcx().create_err(BorrowOfMovedValue { binding_span: pat.span, conflicts_ref, name: Ident::new(name, pat.span), ty, suggest_borrowing: Some(pat.span.shrink_to_lo()), - has_path: path.is_some(), - path: path.map(|p| p.display().to_string()).unwrap_or_default(), }); + *err.long_ty_path() = path; + err.emit(); } return; } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs index db4a14356cc98..ac72774027cff 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs @@ -435,7 +435,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { exp_found: Option>>, terr: TypeError<'tcx>, param_env: Option>, - path: &mut Option, ) { match *cause.code() { ObligationCauseCode::Pattern { @@ -458,7 +457,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { format!("this is an iterator with items of type `{}`", args.type_at(0)), ); } else { - let expected_ty = self.tcx.short_ty_string(expected_ty, path); + let expected_ty = self.tcx.short_string(expected_ty, err.long_ty_path()); err.span_label(span, format!("this expression has type `{expected_ty}`")); } } @@ -1545,7 +1544,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (false, Mismatch::Fixed("existential projection")) } }; - let Some(vals) = self.values_str(values, cause) else { + let Some(vals) = self.values_str(values, cause, diag.long_ty_path()) else { // Derived error. Cancel the emitter. // NOTE(eddyb) this was `.cancel()`, but `diag` // is borrowed, so we can't fully defuse it. @@ -1600,9 +1599,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return; } - let mut path = None; - if let Some((expected, found, p)) = expected_found { - path = p; + if let Some((expected, found)) = expected_found { let (expected_label, found_label, exp_found) = match exp_found { Mismatch::Variable(ef) => ( ef.expected.prefix_string(self.tcx), @@ -1878,11 +1875,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // It reads better to have the error origin as the final // thing. - self.note_error_origin(diag, cause, exp_found, terr, param_env, &mut path); - if let Some(path) = path { - diag.note(format!("the full type name has been written to '{}'", path.display())); - diag.note("consider using `--verbose` to print the full type name to the console"); - } + self.note_error_origin(diag, cause, exp_found, terr, param_env); debug!(?diag); } @@ -1891,6 +1884,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, trace: &TypeTrace<'tcx>, terr: TypeError<'tcx>, + path: &mut Option, ) -> Vec { let mut suggestions = Vec::new(); let span = trace.cause.span; @@ -1969,7 +1963,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }) | ObligationCauseCode::BlockTailExpression(.., source)) = code && let hir::MatchSource::TryDesugar(_) = source - && let Some((expected_ty, found_ty, _)) = self.values_str(trace.values, &trace.cause) + && let Some((expected_ty, found_ty)) = self.values_str(trace.values, &trace.cause, path) { suggestions.push(TypeErrorAdditionalDiags::TryCannotConvert { found: found_ty.content(), @@ -2048,12 +2042,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { debug!("report_and_explain_type_error(trace={:?}, terr={:?})", trace, terr); let span = trace.cause.span; + let mut path = None; let failure_code = trace.cause.as_failure_code_diag( terr, span, - self.type_error_additional_suggestions(&trace, terr), + self.type_error_additional_suggestions(&trace, terr, &mut path), ); let mut diag = self.dcx().create_err(failure_code); + *diag.long_ty_path() = path; self.note_type_err( &mut diag, &trace.cause, @@ -2098,10 +2094,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &self, values: ValuePairs<'tcx>, cause: &ObligationCause<'tcx>, - ) -> Option<(DiagStyledString, DiagStyledString, Option)> { + file: &mut Option, + ) -> Option<(DiagStyledString, DiagStyledString)> { match values { ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found), - ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found), + ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found, file), ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), @@ -2111,7 +2108,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { found: exp_found.found.print_trait_sugared(), }; match self.expected_found_str(pretty_exp_found) { - Some((expected, found, _)) if expected == found => { + Some((expected, found)) if expected == found => { self.expected_found_str(exp_found) } ret => ret, @@ -2133,9 +2130,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { (None, None) }; - let (exp, fnd) = - self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2); - Some((exp, fnd, None)) + Some(self.cmp_fn_sig(&exp_found.expected, fn_def1, &exp_found.found, fn_def2)) } } } @@ -2143,7 +2138,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn expected_found_str_term( &self, exp_found: ty::error::ExpectedFound>, - ) -> Option<(DiagStyledString, DiagStyledString, Option)> { + path: &mut Option, + ) -> Option<(DiagStyledString, DiagStyledString)> { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { return None; @@ -2158,21 +2154,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let len = self.tcx.sess().diagnostic_width() + 40; let exp_s = exp.content(); let fnd_s = fnd.content(); - let mut path = None; if exp_s.len() > len { - let exp_s = self.tcx.short_ty_string(expected, &mut path); + let exp_s = self.tcx.short_string(expected, path); exp = DiagStyledString::highlighted(exp_s); } if fnd_s.len() > len { - let fnd_s = self.tcx.short_ty_string(found, &mut path); + let fnd_s = self.tcx.short_string(found, path); fnd = DiagStyledString::highlighted(fnd_s); } - (exp, fnd, path) + (exp, fnd) } _ => ( DiagStyledString::highlighted(exp_found.expected.to_string()), DiagStyledString::highlighted(exp_found.found.to_string()), - None, ), }) } @@ -2181,7 +2175,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { fn expected_found_str>>( &self, exp_found: ty::error::ExpectedFound, - ) -> Option<(DiagStyledString, DiagStyledString, Option)> { + ) -> Option<(DiagStyledString, DiagStyledString)> { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { return None; @@ -2190,7 +2184,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { Some(( DiagStyledString::highlighted(exp_found.expected.to_string()), DiagStyledString::highlighted(exp_found.found.to_string()), - None, )) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index 68a5338123049..99b70c87ccd1c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -713,7 +713,7 @@ impl<'tcx> InferSourceKind<'tcx> { if ty.is_closure() { ("closure", closure_as_fn_str(infcx, ty), path) } else if !ty.is_ty_or_numeric_infer() { - ("normal", infcx.tcx.short_ty_string(ty, &mut path), path) + ("normal", infcx.tcx.short_string(ty, &mut path), path) } else { ("other", String::new(), path) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs deleted file mode 100644 index beae9962f7f28..0000000000000 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/note.rs +++ /dev/null @@ -1,422 +0,0 @@ -use rustc_errors::{Diag, Subdiagnostic}; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::traits::ObligationCauseCode; -use rustc_middle::ty::error::TypeError; -use rustc_middle::ty::{self, IsSuggestable, Region, Ty}; -use rustc_span::kw; -use tracing::debug; - -use super::ObligationCauseAsDiagArg; -use crate::error_reporting::infer::{TypeErrCtxt, note_and_explain_region}; -use crate::errors::{ - FulfillReqLifetime, LfBoundNotSatisfied, OutlivesBound, OutlivesContent, RefLongerThanData, - RegionOriginNote, WhereClauseSuggestions, note_and_explain, -}; -use crate::fluent_generated as fluent; -use crate::infer::{self, SubregionOrigin}; - -impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { - pub(super) fn note_region_origin(&self, err: &mut Diag<'_>, origin: &SubregionOrigin<'tcx>) { - match *origin { - infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { - span: trace.cause.span, - requirement: ObligationCauseAsDiagArg(trace.cause.clone()), - expected_found: self.values_str(trace.values).map(|(e, f, _)| (e, f)), - } - .add_to_diag(err), - infer::Reborrow(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diag(err) - } - infer::RelateObjectBound(span) => { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound } - .add_to_diag(err); - } - infer::ReferenceOutlivesReferent(ty, span) => { - RegionOriginNote::WithName { - span, - msg: fluent::infer_reference_outlives_referent, - name: &self.ty_to_string(ty), - continues: false, - } - .add_to_diag(err); - } - infer::RelateParamBound(span, ty, opt_span) => { - RegionOriginNote::WithName { - span, - msg: fluent::infer_relate_param_bound, - name: &self.ty_to_string(ty), - continues: opt_span.is_some(), - } - .add_to_diag(err); - if let Some(span) = opt_span { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 } - .add_to_diag(err); - } - } - infer::RelateRegionParamBound(span, _) => { - RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound } - .add_to_diag(err); - } - infer::CompareImplItemObligation { span, .. } => { - RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation } - .add_to_diag(err); - } - infer::CheckAssociatedTypeBounds { ref parent, .. } => { - self.note_region_origin(err, parent); - } - infer::AscribeUserTypeProvePredicate(span) => { - RegionOriginNote::Plain { - span, - msg: fluent::infer_ascribe_user_type_prove_predicate, - } - .add_to_diag(err); - } - } - } - - pub(super) fn report_concrete_failure( - &self, - generic_param_scope: LocalDefId, - origin: SubregionOrigin<'tcx>, - sub: Region<'tcx>, - sup: Region<'tcx>, - ) -> Diag<'a> { - let mut err = match origin { - infer::Subtype(box trace) => { - let terr = TypeError::RegionsDoesNotOutlive(sup, sub); - let mut err = self.report_and_explain_type_error(trace, terr); - match (*sub, *sup) { - (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {} - (ty::RePlaceholder(_), _) => { - note_and_explain_region( - self.tcx, - &mut err, - generic_param_scope, - "", - sup, - " doesn't meet the lifetime requirements", - None, - ); - } - (_, ty::RePlaceholder(_)) => { - note_and_explain_region( - self.tcx, - &mut err, - generic_param_scope, - "the required lifetime does not necessarily outlive ", - sub, - "", - None, - ); - } - _ => { - note_and_explain_region( - self.tcx, - &mut err, - generic_param_scope, - "", - sup, - "...", - None, - ); - note_and_explain_region( - self.tcx, - &mut err, - generic_param_scope, - "...does not necessarily outlive ", - sub, - "", - None, - ); - } - } - err - } - infer::Reborrow(span) => { - let reference_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - None, - note_and_explain::PrefixKind::RefValidFor, - note_and_explain::SuffixKind::Continues, - ); - let content_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sup, - None, - note_and_explain::PrefixKind::ContentValidFor, - note_and_explain::SuffixKind::Empty, - ); - self.dcx().create_err(OutlivesContent { - span, - notes: reference_valid.into_iter().chain(content_valid).collect(), - }) - } - infer::RelateObjectBound(span) => { - let object_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - None, - note_and_explain::PrefixKind::TypeObjValidFor, - note_and_explain::SuffixKind::Empty, - ); - let pointer_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sup, - None, - note_and_explain::PrefixKind::SourcePointerValidFor, - note_and_explain::SuffixKind::Empty, - ); - self.dcx().create_err(OutlivesBound { - span, - notes: object_valid.into_iter().chain(pointer_valid).collect(), - }) - } - infer::RelateParamBound(span, ty, opt_span) => { - let prefix = match *sub { - ty::ReStatic => note_and_explain::PrefixKind::TypeSatisfy, - _ => note_and_explain::PrefixKind::TypeOutlive, - }; - let suffix = if opt_span.is_some() { - note_and_explain::SuffixKind::ReqByBinding - } else { - note_and_explain::SuffixKind::Empty - }; - let note = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - opt_span, - prefix, - suffix, - ); - self.dcx().create_err(FulfillReqLifetime { - span, - ty: self.resolve_vars_if_possible(ty), - note, - }) - } - infer::RelateRegionParamBound(span, _) => { - let param_instantiated = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sup, - None, - note_and_explain::PrefixKind::LfParamInstantiatedWith, - note_and_explain::SuffixKind::Empty, - ); - let param_must_outlive = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - None, - note_and_explain::PrefixKind::LfParamMustOutlive, - note_and_explain::SuffixKind::Empty, - ); - self.dcx().create_err(LfBoundNotSatisfied { - span, - notes: param_instantiated.into_iter().chain(param_must_outlive).collect(), - }) - } - infer::ReferenceOutlivesReferent(ty, span) => { - let pointer_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - None, - note_and_explain::PrefixKind::PointerValidFor, - note_and_explain::SuffixKind::Empty, - ); - let data_valid = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sup, - None, - note_and_explain::PrefixKind::DataValidFor, - note_and_explain::SuffixKind::Empty, - ); - self.dcx().create_err(RefLongerThanData { - span, - ty: self.resolve_vars_if_possible(ty), - notes: pointer_valid.into_iter().chain(data_valid).collect(), - }) - } - infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => { - let mut err = self.infcx.report_extra_impl_obligation( - span, - impl_item_def_id, - trait_item_def_id, - &format!("`{sup}: {sub}`"), - ); - // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause - if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) - && generics.where_clause_span.contains(span) - { - self.suggest_copy_trait_method_bounds( - trait_item_def_id, - impl_item_def_id, - &mut err, - ); - } - err - } - infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => { - let mut err = self.report_concrete_failure(generic_param_scope, *parent, sub, sup); - - // Don't mention the item name if it's an RPITIT, since that'll just confuse - // folks. - if !self.tcx.is_impl_trait_in_trait(impl_item_def_id.to_def_id()) { - let trait_item_span = self.tcx.def_span(trait_item_def_id); - let item_name = self.tcx.item_name(impl_item_def_id.to_def_id()); - err.span_label( - trait_item_span, - format!("definition of `{item_name}` from trait"), - ); - } - - self.suggest_copy_trait_method_bounds( - trait_item_def_id, - impl_item_def_id, - &mut err, - ); - err - } - infer::AscribeUserTypeProvePredicate(span) => { - let instantiated = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sup, - None, - note_and_explain::PrefixKind::LfInstantiatedWith, - note_and_explain::SuffixKind::Empty, - ); - let must_outlive = note_and_explain::RegionExplanation::new( - self.tcx, - generic_param_scope, - sub, - None, - note_and_explain::PrefixKind::LfMustOutlive, - note_and_explain::SuffixKind::Empty, - ); - self.dcx().create_err(LfBoundNotSatisfied { - span, - notes: instantiated.into_iter().chain(must_outlive).collect(), - }) - } - }; - if sub.is_error() || sup.is_error() { - err.downgrade_to_delayed_bug(); - } - err - } - - pub fn suggest_copy_trait_method_bounds( - &self, - trait_item_def_id: DefId, - impl_item_def_id: LocalDefId, - err: &mut Diag<'_>, - ) { - // FIXME(compiler-errors): Right now this is only being used for region - // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches, - // but right now it's not really very smart when it comes to implicit `Sized` - // predicates and bounds on the trait itself. - - let Some(impl_def_id) = self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) - else { - return; - }; - let Some(trait_ref) = self.tcx.impl_trait_ref(impl_def_id) else { - return; - }; - let trait_args = trait_ref - .instantiate_identity() - // Replace the explicit self type with `Self` for better suggestion rendering - .with_self_ty(self.tcx, Ty::new_param(self.tcx, 0, kw::SelfUpper)) - .args; - let trait_item_args = ty::GenericArgs::identity_for_item(self.tcx, impl_item_def_id) - .rebase_onto(self.tcx, impl_def_id, trait_args); - - let Ok(trait_predicates) = - self.tcx - .explicit_predicates_of(trait_item_def_id) - .instantiate_own(self.tcx, trait_item_args) - .map(|(pred, _)| { - if pred.is_suggestable(self.tcx, false) { - Ok(pred.to_string()) - } else { - Err(()) - } - }) - .collect::, ()>>() - else { - return; - }; - - let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { - return; - }; - - let suggestion = if trait_predicates.is_empty() { - WhereClauseSuggestions::Remove { span: generics.where_clause_span } - } else { - let space = if generics.where_clause_span.is_empty() { " " } else { "" }; - WhereClauseSuggestions::CopyPredicates { - span: generics.where_clause_span, - space, - trait_predicates: trait_predicates.join(", "), - } - }; - err.subdiagnostic(suggestion); - } - - pub(super) fn report_placeholder_failure( - &self, - generic_param_scope: LocalDefId, - placeholder_origin: SubregionOrigin<'tcx>, - sub: Region<'tcx>, - sup: Region<'tcx>, - ) -> Diag<'a> { - // I can't think how to do better than this right now. -nikomatsakis - debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure"); - match placeholder_origin { - infer::Subtype(box ref trace) - if matches!( - &trace.cause.code().peel_derives(), - ObligationCauseCode::WhereClause(..) - | ObligationCauseCode::WhereClauseInExpr(..) - ) => - { - // Hack to get around the borrow checker because trace.cause has an `Rc`. - if let ObligationCauseCode::WhereClause(_, span) - | ObligationCauseCode::WhereClauseInExpr(_, span, ..) = - &trace.cause.code().peel_derives() - && !span.is_dummy() - { - let span = *span; - self.report_concrete_failure(generic_param_scope, placeholder_origin, sub, sup) - .with_span_note(span, "the lifetime requirement is introduced here") - } else { - unreachable!( - "control flow ensures we have a `BindingObligation` or `WhereClauseInExpr` here..." - ) - } - } - infer::Subtype(box trace) => { - let terr = TypeError::RegionsPlaceholderMismatch; - return self.report_and_explain_type_error(trace, terr); - } - _ => { - return self.report_concrete_failure( - generic_param_scope, - placeholder_origin, - sub, - sup, - ); - } - } - } -} diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs index 3acca47025cbd..f35a5349ecb3c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { infer::Subtype(ref trace) => RegionOriginNote::WithRequirement { span: trace.cause.span, requirement: ObligationCauseAsDiagArg(trace.cause.clone()), - expected_found: self.values_str(trace.values, &trace.cause).map(|(e, f, _)| (e, f)), + expected_found: self.values_str(trace.values, &trace.cause, err.long_ty_path()), } .add_to_diag(err), infer::Reborrow(span) => { @@ -946,10 +946,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let infer::Subtype(ref sup_trace) = sup_origin && let infer::Subtype(ref sub_trace) = sub_origin - && let Some((sup_expected, sup_found, _)) = - self.values_str(sup_trace.values, &sup_trace.cause) - && let Some((sub_expected, sub_found, _)) = - self.values_str(sub_trace.values, &sup_trace.cause) + && let Some((sup_expected, sup_found)) = + self.values_str(sup_trace.values, &sup_trace.cause, err.long_ty_path()) + && let Some((sub_expected, sub_found)) = + self.values_str(sub_trace.values, &sup_trace.cause, err.long_ty_path()) && sub_expected == sup_expected && sub_found == sup_found { diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index b4d294a70c071..a92f8752a97da 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -163,6 +163,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { let predicate = self.resolve_vars_if_possible(obligation.predicate); let span = obligation.cause.span; + let mut file = None; debug!(?predicate, obligation.cause.code = ?obligation.cause.code()); @@ -245,7 +246,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { span, E0283, "type annotations needed: cannot satisfy `{}`", - predicate, + self.tcx.short_string(predicate, &mut file), ) }; @@ -292,7 +293,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err.cancel(); return e; } - err.note(format!("cannot satisfy `{predicate}`")); + let pred = self.tcx.short_string(predicate, &mut file); + err.note(format!("cannot satisfy `{pred}`")); let impl_candidates = self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap()); if impl_candidates.len() < 40 { @@ -524,6 +526,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .iter() .chain(Some(data.term.into_arg())) .find(|g| g.has_non_region_infer()); + let predicate = self.tcx.short_string(predicate, &mut file); if let Some(arg) = arg { self.emit_inference_failure_err( obligation.cause.body_id, @@ -539,8 +542,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.dcx(), span, E0284, - "type annotations needed: cannot satisfy `{}`", - predicate, + "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) } @@ -565,12 +567,12 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { err } else { // If we can't find a generic parameter, just print a generic error + let predicate = self.tcx.short_string(predicate, &mut file); struct_span_code_err!( self.dcx(), span, E0284, - "type annotations needed: cannot satisfy `{}`", - predicate, + "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) } @@ -590,6 +592,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Some(e) = self.tainted_by_errors() { return e; } + let alias = self.tcx.short_string(alias, &mut file); struct_span_code_err!( self.dcx(), span, @@ -603,16 +606,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Some(e) = self.tainted_by_errors() { return e; } + let predicate = self.tcx.short_string(predicate, &mut file); struct_span_code_err!( self.dcx(), span, E0284, - "type annotations needed: cannot satisfy `{}`", - predicate, + "type annotations needed: cannot satisfy `{predicate}`", ) .with_span_label(span, format!("cannot satisfy `{predicate}`")) } }; + *err.long_ty_path() = file; self.note_obligation_cause(&mut err, obligation); err.emit() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs index 6416c539f2616..d0a193e8bd524 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs @@ -1,5 +1,6 @@ use core::ops::ControlFlow; use std::borrow::Cow; +use std::path::PathBuf; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::FxHashMap; @@ -9,7 +10,6 @@ use rustc_errors::{ Applicability, Diag, ErrorGuaranteed, Level, MultiSpan, StashKey, StringPart, Suggestions, pluralize, struct_span_code_err, }; -use rustc_hir::def::Namespace; use rustc_hir::def_id::{DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, LangItem, Node}; @@ -20,8 +20,8 @@ use rustc_middle::ty::abstract_const::NotConstEvaluatable; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::print::{ - FmtPrinter, Print, PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, - PrintTraitRefExt as _, with_forced_trimmed_paths, + PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, PrintTraitRefExt as _, + with_forced_trimmed_paths, }; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast}; use rustc_middle::{bug, span_bug}; @@ -60,6 +60,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) -> ErrorGuaranteed { let tcx = self.tcx; let mut span = obligation.cause.span; + let mut long_ty_file = None; let mut err = match *error { SelectionError::Unimplemented => { @@ -169,11 +170,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let Err(guar) = self.fn_arg_obligation(&obligation) { return guar; } - let mut file = None; let (post_message, pre_message, type_def) = self .get_parent_trait_ref(obligation.cause.code()) .map(|(t, s)| { - let t = self.tcx.short_ty_string(t, &mut file); + let t = self.tcx.short_string(t, &mut long_ty_file); ( format!(" in `{t}`"), format!("within `{t}`, "), @@ -181,12 +181,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ) }) .unwrap_or_default(); - let file_note = file.as_ref().map(|file| format!( - "the full trait has been written to '{}'", - file.display(), - )); - - let mut long_ty_file = None; let OnUnimplementedNote { message, @@ -223,6 +217,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { None, append_const_msg, post_message, + &mut long_ty_file, ); let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait) @@ -251,14 +246,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let mut err = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); + *err.long_ty_path() = long_ty_file; - if let Some(long_ty_file) = long_ty_file { - err.note(format!( - "the full name for the type has been written to '{}'", - long_ty_file.display(), - )); - err.note("consider using `--verbose` to print the full type name to the console"); - } let mut suggested = false; if is_try_conversion { suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err); @@ -309,7 +298,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return err.emit(); } - file_note.map(|note| err.note(note)); if let Some(s) = label { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! @@ -762,14 +750,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { trait_ref: predicate.trait_ref, polarity: ty::PredicatePolarity::Positive, }); + let mut file = None; let err_msg = self.get_standard_error_message( trait_ref, None, Some(predicate.constness()), None, String::new(), + &mut file, ); let mut diag = struct_span_code_err!(self.dcx(), span, E0277, "{}", err_msg); + *diag.long_ty_path() = file; if !self.predicate_may_hold(&Obligation::new( self.tcx, ObligationCause::dummy(), @@ -1381,6 +1372,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { _ => (None, error.err), }; + let mut file = None; let (msg, span, closure_span) = values .and_then(|(predicate, normalized_term, expected_term)| { self.maybe_detailed_projection_msg( @@ -1388,24 +1380,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { predicate, normalized_term, expected_term, + &mut file, ) }) .unwrap_or_else(|| { - let mut cx = FmtPrinter::new_with_limit( - self.tcx, - Namespace::TypeNS, - rustc_session::Limit(10), - ); ( - with_forced_trimmed_paths!(format!("type mismatch resolving `{}`", { - self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap(); - cx.into_buffer() - })), + with_forced_trimmed_paths!(format!( + "type mismatch resolving `{}`", + self.tcx + .short_string(self.resolve_vars_if_possible(predicate), &mut file), + )), obligation.cause.span, None, ) }); let mut diag = struct_span_code_err!(self.dcx(), span, E0271, "{msg}"); + *diag.long_ty_path() = file; if let Some(span) = closure_span { // Mark the closure decl so that it is seen even if we are pointing at the return // type or expression. @@ -1471,15 +1461,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { ty.span, with_forced_trimmed_paths!(Cow::from(format!( "type mismatch resolving `{}`", - { - let mut cx = FmtPrinter::new_with_limit( - self.tcx, - Namespace::TypeNS, - rustc_session::Limit(5), - ); - self.resolve_vars_if_possible(predicate).print(&mut cx).unwrap(); - cx.into_buffer() - } + self.tcx.short_string( + self.resolve_vars_if_possible(predicate), + diag.long_ty_path() + ), ))), true, )), @@ -1512,6 +1497,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { projection_term: ty::AliasTerm<'tcx>, normalized_ty: ty::Term<'tcx>, expected_ty: ty::Term<'tcx>, + file: &mut Option, ) -> Option<(String, Span, Option)> { let trait_def_id = projection_term.trait_def_id(self.tcx); let self_ty = projection_term.self_ty(); @@ -1552,7 +1538,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; let item = match self_ty.kind() { ty::FnDef(def, _) => self.tcx.item_name(*def).to_string(), - _ => self_ty.to_string(), + _ => self.tcx.short_string(self_ty, file), }; Some((format!( "expected `{item}` to be a {fn_kind} that returns `{expected_ty}`, but it \ @@ -1984,8 +1970,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { StringPart::normal(" implemented for `"), ]); if types_content.0 == types_content.1 { - let ty = - self.tcx.short_ty_string(obligation_trait_ref.self_ty(), &mut None); + let ty = self + .tcx + .short_string(obligation_trait_ref.self_ty(), err.long_ty_path()); msg.push(StringPart::normal(ty)); } else { msg.extend(types.0.0); @@ -2342,7 +2329,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // First, attempt to add note to this error with an async-await-specific // message, and fall back to regular note otherwise. if !self.maybe_note_obligation_cause_for_async_await(err, obligation) { - let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -2351,15 +2337,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.code(), &mut vec![], &mut Default::default(), - &mut long_ty_file, ); - if let Some(file) = long_ty_file { - err.note(format!( - "the full name for the type has been written to '{}'", - file.display(), - )); - err.note("consider using `--verbose` to print the full type name to the console"); - } self.suggest_unsized_bound_if_applicable(err, obligation); if let Some(span) = err.span.primary_span() && let Some(mut diag) = @@ -2403,6 +2381,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { predicate_constness: Option, append_const_msg: Option, post_message: String, + long_ty_file: &mut Option, ) -> String { message .and_then(|cannot_do_this| { @@ -2426,7 +2405,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { .unwrap_or_else(|| { format!( "the trait bound `{}` is not satisfied{post_message}", - trait_predicate.print_with_bound_constness(predicate_constness) + self.tcx.short_string( + trait_predicate.print_with_bound_constness(predicate_constness), + long_ty_file, + ), ) }) } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs index 8111983c53982..d1bd23bf8266c 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs @@ -306,7 +306,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { if let ObligationCauseCode::WhereClause(..) | ObligationCauseCode::WhereClauseInExpr(..) = code { - let mut long_ty_file = None; self.note_obligation_cause_code( error.obligation.cause.body_id, &mut diag, @@ -315,17 +314,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { code, &mut vec![], &mut Default::default(), - &mut long_ty_file, ); - if let Some(file) = long_ty_file { - diag.note(format!( - "the full name for the type has been written to '{}'", - file.display(), - )); - diag.note( - "consider using `--verbose` to print the full type name to the console", - ); - } } diag.emit() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs index 3d79b0acf83a9..518323f6526a6 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs @@ -932,7 +932,7 @@ impl<'tcx> OnUnimplementedFormatString { let value = match param.kind { GenericParamDefKind::Type { .. } | GenericParamDefKind::Const { .. } => { if let Some(ty) = trait_ref.args[param.index as usize].as_type() { - tcx.short_ty_string(ty, long_ty_file) + tcx.short_string(ty, long_ty_file) } else { trait_ref.args[param.index as usize].to_string() } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs index d82acc4e0543f..fad03b5e9bf5a 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/overflow.rs @@ -141,7 +141,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.span, suggest_increasing_limit, |err| { - let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -150,17 +149,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { obligation.cause.code(), &mut vec![], &mut Default::default(), - &mut long_ty_file, ); - if let Some(file) = long_ty_file { - err.note(format!( - "the full name for the type has been written to '{}'", - file.display(), - )); - err.note( - "consider using `--verbose` to print the full type name to the console", - ); - } }, ); } diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs index ab25bef4120ee..24ca7bb7fc207 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs @@ -3,7 +3,6 @@ use std::assert_matches::debug_assert_matches; use std::borrow::Cow; use std::iter; -use std::path::PathBuf; use itertools::{EitherOrBoth, Itertools}; use rustc_abi::ExternAbi; @@ -1297,30 +1296,24 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Because of this, we modify the error to refer to the original obligation and // return early in the caller. - let msg = format!("the trait bound `{old_pred}` is not satisfied"); + let msg = format!( + "the trait bound `{}` is not satisfied", + self.tcx.short_string(old_pred, err.long_ty_path()), + ); + let self_ty_str = + self.tcx.short_string(old_pred.self_ty().skip_binder(), err.long_ty_path()); if has_custom_message { err.note(msg); } else { err.messages = vec![(rustc_errors::DiagMessage::from(msg), Style::NoStyle)]; } - let mut file = None; err.span_label( span, format!( - "the trait `{}` is not implemented for `{}`", - old_pred.print_modifiers_and_trait_path(), - self.tcx.short_ty_string(old_pred.self_ty().skip_binder(), &mut file), + "the trait `{}` is not implemented for `{self_ty_str}`", + old_pred.print_modifiers_and_trait_path() ), ); - if let Some(file) = file { - err.note(format!( - "the full type name has been written to '{}'", - file.display() - )); - err.note( - "consider using `--verbose` to print full type name to the console", - ); - } if imm_ref_self_ty_satisfies_pred && mut_ref_self_ty_satisfies_pred { err.span_suggestions( @@ -2689,7 +2682,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { // Add a note for the item obligation that remains - normally a note pointing to the // bound that introduced the obligation (e.g. `T: Send`). debug!(?next_code); - let mut long_ty_file = None; self.note_obligation_cause_code( obligation.cause.body_id, err, @@ -2698,7 +2690,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { next_code.unwrap(), &mut Vec::new(), &mut Default::default(), - &mut long_ty_file, ); } @@ -2711,7 +2702,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cause_code: &ObligationCauseCode<'tcx>, obligated_types: &mut Vec>, seen_requirements: &mut FxHashSet, - long_ty_file: &mut Option, ) where T: Upcast, ty::Predicate<'tcx>>, { @@ -2965,9 +2955,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::Coercion { source, target } => { let source = - tcx.short_ty_string(self.resolve_vars_if_possible(source), long_ty_file); + tcx.short_string(self.resolve_vars_if_possible(source), err.long_ty_path()); let target = - tcx.short_ty_string(self.resolve_vars_if_possible(target), long_ty_file); + tcx.short_string(self.resolve_vars_if_possible(target), err.long_ty_path()); err.note(with_forced_trimmed_paths!(format!( "required for the cast from `{source}` to `{target}`", ))); @@ -3252,7 +3242,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }; if !is_upvar_tys_infer_tuple { - let ty_str = tcx.short_ty_string(ty, long_ty_file); + let ty_str = tcx.short_string(ty, err.long_ty_path()); let msg = format!("required because it appears within the type `{ty_str}`"); match ty.kind() { ty::Adt(def, _) => match tcx.opt_item_ident(def.did()) { @@ -3330,7 +3320,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } else { @@ -3343,7 +3332,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { cause_code.peel_derives(), obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3353,7 +3341,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { self.resolve_vars_if_possible(data.derived.parent_trait_pred); let parent_def_id = parent_trait_pred.def_id(); let self_ty_str = - tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file); + tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path()); let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string(); let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`"); let mut is_auto_trait = false; @@ -3449,8 +3437,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { count, pluralize!(count) )); - let self_ty = tcx - .short_ty_string(parent_trait_pred.skip_binder().self_ty(), long_ty_file); + let self_ty = tcx.short_string( + parent_trait_pred.skip_binder().self_ty(), + err.long_ty_path(), + ); err.note(format!( "required for `{self_ty}` to implement `{}`", parent_trait_pred.print_modifiers_and_trait_path() @@ -3466,7 +3456,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3505,7 +3494,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.derived.parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3519,7 +3507,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3536,7 +3523,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { &data.parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3551,7 +3537,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { nested, obligated_types, seen_requirements, - long_ty_file, ) }); let mut multispan = MultiSpan::from(span); @@ -3582,7 +3567,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { parent_code, obligated_types, seen_requirements, - long_ty_file, ) }); } @@ -3622,7 +3606,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { } ObligationCauseCode::OpaqueReturnType(expr_info) => { let (expr_ty, expr) = if let Some((expr_ty, hir_id)) = expr_info { - let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file); + let expr_ty = tcx.short_string(expr_ty, err.long_ty_path()); let expr = tcx.hir().expect_expr(hir_id); (expr_ty, expr) } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id() @@ -3637,7 +3621,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { && let ty::ClauseKind::Trait(pred) = pred.kind().skip_binder() && self.can_eq(param_env, pred.self_ty(), expr_ty) { - let expr_ty = tcx.short_ty_string(expr_ty, long_ty_file); + let expr_ty = tcx.short_string(expr_ty, err.long_ty_path()); (expr_ty, expr) } else { return; @@ -5231,7 +5215,7 @@ pub(super) fn get_explanation_based_on_obligation<'tcx>( format!( "{pre_message}the trait `{}` is not implemented for{desc} `{}`", trait_predicate.print_modifiers_and_trait_path(), - tcx.short_ty_string(trait_predicate.self_ty().skip_binder(), &mut None), + tcx.short_string(trait_predicate.self_ty().skip_binder(), &mut None), ) } else { // "the trait bound `T: !Send` is not satisfied" reads better than "`!Send` is diff --git a/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr b/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr index 0c220a13876b8..b682bdac0341d 100644 --- a/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr +++ b/tests/ui/coercion/coerce-expect-unsized-ascribed.stderr @@ -29,7 +29,7 @@ error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:14:27 | LL | let _ = type_ascribe!(Box::new( { |x| (x as u8) }), Box _>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box u8>`, found `Box<{closure@coerce-expect-unsized-ascribed.rs:14:39}>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `Box u8>`, found `Box<{closure@...}>` | = note: expected struct `Box u8>` found struct `Box<{closure@$DIR/coerce-expect-unsized-ascribed.rs:14:39: 14:42}>` @@ -85,7 +85,7 @@ error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:22:27 | LL | let _ = type_ascribe!(&{ |x| (x as u8) }, &dyn Fn(i32) -> _); - | ^^^^^^^^^^^^^^^^^^ expected `&dyn Fn(i32) -> u8`, found `&{closure@coerce-expect-unsized-ascribed.rs:22:30}` + | ^^^^^^^^^^^^^^^^^^ expected `&dyn Fn(i32) -> u8`, found `&{closure@...}` | = note: expected reference `&dyn Fn(i32) -> u8` found reference `&{closure@$DIR/coerce-expect-unsized-ascribed.rs:22:30: 22:33}` @@ -123,7 +123,7 @@ error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:27:27 | LL | let _ = type_ascribe!(Box::new(|x| (x as u8)), Box _>); - | ^^^^^^^^^^^^^^^^^^^^^^^ expected `Box u8>`, found `Box<{closure@coerce-expect-unsized-ascribed.rs:27:36}>` + | ^^^^^^^^^^^^^^^^^^^^^^^ expected `Box u8>`, found `Box<{closure@...}>` | = note: expected struct `Box u8>` found struct `Box<{closure@$DIR/coerce-expect-unsized-ascribed.rs:27:36: 27:39}>` diff --git a/tests/ui/diagnostic-width/E0271.ascii.stderr b/tests/ui/diagnostic-width/E0271.ascii.stderr index 7446b1a543e70..93555b336a66f 100644 --- a/tests/ui/diagnostic-width/E0271.ascii.stderr +++ b/tests/ui/diagnostic-width/E0271.ascii.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo` +error[E0271]: type mismatch resolving ` as Future>::Error == Foo` --> $DIR/E0271.rs:20:5 | LL | / Box::new( @@ -7,14 +7,16 @@ LL | | Err::<(), _>( LL | | Ok::<_, ()>( ... | LL | | ) - | |_____^ type mismatch resolving `, ...>>, ...> as Future>::Error == Foo` + | |_____^ type mismatch resolving ` as Future>::Error == Foo` | note: expected this to be `Foo` --> $DIR/E0271.rs:10:18 | LL | type Error = E; | ^ - = note: required for the cast from `Box>, ()>>, ()>>, ()>>` to `Box<(dyn Future + 'static)>` + = note: required for the cast from `Box>` to `Box<...>` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271.ascii/E0271.long-type-hash.txt' + = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/E0271.rs b/tests/ui/diagnostic-width/E0271.rs index 061ba45c21980..2faf09d46c6ea 100644 --- a/tests/ui/diagnostic-width/E0271.rs +++ b/tests/ui/diagnostic-width/E0271.rs @@ -1,6 +1,6 @@ //@ revisions: ascii unicode -//@[ascii] compile-flags: --diagnostic-width=40 -//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=40 +//@[ascii] compile-flags: --diagnostic-width=40 -Zwrite-long-types-to-disk=yes +//@[unicode] compile-flags: -Zunstable-options --error-format=human-unicode --diagnostic-width=40 -Zwrite-long-types-to-disk=yes //@ normalize-stderr: "long-type-\d+" -> "long-type-hash" trait Future { type Error; diff --git a/tests/ui/diagnostic-width/E0271.unicode.stderr b/tests/ui/diagnostic-width/E0271.unicode.stderr index 72df2a381a422..1e9acf603b2bd 100644 --- a/tests/ui/diagnostic-width/E0271.unicode.stderr +++ b/tests/ui/diagnostic-width/E0271.unicode.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `>, ...>>, ...>>, ...> as Future>::Error == Foo` +error[E0271]: type mismatch resolving ` as Future>::Error == Foo` ╭▸ $DIR/E0271.rs:20:5 │ LL │ ┏ Box::new( @@ -7,14 +7,16 @@ LL │ ┃ Err::<(), _>( LL │ ┃ Ok::<_, ()>( ‡ ┃ LL │ ┃ ) - │ ┗━━━━━┛ type mismatch resolving `, ...>>, ...> as Future>::Error == Foo` + │ ┗━━━━━┛ type mismatch resolving ` as Future>::Error == Foo` ╰╴ note: expected this to be `Foo` ╭▸ $DIR/E0271.rs:10:18 │ LL │ type Error = E; │ ━ - ╰ note: required for the cast from `Box>, ()>>, ()>>, ()>>` to `Box<(dyn Future + 'static)>` + ├ note: required for the cast from `Box>` to `Box<...>` + ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271.unicode/E0271.long-type-hash.txt' + ╰ note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/diagnostic-width/long-E0308.ascii.stderr b/tests/ui/diagnostic-width/long-E0308.ascii.stderr index 3053e37a87a79..83da558618870 100644 --- a/tests/ui/diagnostic-width/long-E0308.ascii.stderr +++ b/tests/ui/diagnostic-width/long-E0308.ascii.stderr @@ -16,11 +16,11 @@ LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok... LL | | Ok("") LL | | )))))))))))))))))))))))))))))) LL | | )))))))))))))))))))))))))))))); - | |__________________________________^ expected `Atype, ...>`, found `Result, ...>` + | |__________________________________^ expected `Atype, i32>, i32>`, found `Result, _>, _>` | - = note: expected struct `Atype, ...>` - found enum `Result, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + = note: expected struct `Atype, i32>` + found enum `Result, _>` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types @@ -32,11 +32,11 @@ LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(... LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) LL | | )))))))))))))))))))))))))))))) LL | | )))))))))))))))))))))))); - | |____________________________^ expected `Option>`, found `Result, ...>` + | |____________________________^ expected `Option>, _>>`, found `Result, _>, _>` | - = note: expected enum `Option>` - found enum `Result, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + = note: expected enum `Option, _>>` + found enum `Result, _>` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types @@ -50,13 +50,13 @@ LL | | Atype< ... | LL | | i32 LL | | > = (); - | | - ^^ expected `Atype, ...>`, found `()` + | | - ^^ expected `Atype, i32>, i32>`, found `()` | |_____| | expected due to this | - = note: expected struct `Atype, ...>` + = note: expected struct `Atype, i32>` found unit type `()` - = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types @@ -70,11 +70,11 @@ LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(... LL | | Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) LL | | )))))))))))))))))))))))))))))) LL | | )))))))))))))))))))))))); - | |____________________________^ expected `()`, found `Result, ...>` + | |____________________________^ expected `()`, found `Result, _>, _>` | = note: expected unit type `()` - found enum `Result, ...>` - = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + found enum `Result, _>` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error: aborting due to 4 previous errors diff --git a/tests/ui/diagnostic-width/long-E0308.unicode.stderr b/tests/ui/diagnostic-width/long-E0308.unicode.stderr index 50b386325b938..54abf576dbd07 100644 --- a/tests/ui/diagnostic-width/long-E0308.unicode.stderr +++ b/tests/ui/diagnostic-width/long-E0308.unicode.stderr @@ -16,11 +16,11 @@ LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(O… LL │ ┃ Ok("") LL │ ┃ )))))))))))))))))))))))))))))) LL │ ┃ )))))))))))))))))))))))))))))); - │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype, ...>`, found `Result, ...>` + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Atype, i32>, i32>`, found `Result, _>, _>` │ - ├ note: expected struct `Atype, ...>` - │ found enum `Result, ...>` - ├ note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + ├ note: expected struct `Atype, i32>` + │ found enum `Result, _>` + ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' ╰ note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types @@ -32,11 +32,11 @@ LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok… LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) LL │ ┃ )))))))))))))))))))))))))))))) LL │ ┃ )))))))))))))))))))))))); - │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Option>`, found `Result, ...>` + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `Option>, _>>`, found `Result, _>, _>` │ - ├ note: expected enum `Option>` - │ found enum `Result, ...>` - ├ note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + ├ note: expected enum `Option, _>>` + │ found enum `Result, _>` + ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' ╰ note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types @@ -50,13 +50,13 @@ LL │ │ Atype< ‡ │ LL │ │ i32 LL │ │ > = (); - │ │ │ ━━ expected `Atype, ...>`, found `()` + │ │ │ ━━ expected `Atype, i32>, i32>`, found `()` │ └─────┤ │ expected due to this │ - ├ note: expected struct `Atype, ...>` + ├ note: expected struct `Atype, i32>` │ found unit type `()` - ├ note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' ╰ note: consider using `--verbose` to print the full type name to the console error[E0308]: mismatched types @@ -70,11 +70,11 @@ LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok(Ok… LL │ ┃ Ok(Ok(Ok(Ok(Ok(Ok(Ok(""))))))) LL │ ┃ )))))))))))))))))))))))))))))) LL │ ┃ )))))))))))))))))))))))); - │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `()`, found `Result, ...>` + │ ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛ expected `()`, found `Result, _>, _>` │ ├ note: expected unit type `()` - │ found enum `Result, ...>` - ├ note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + │ found enum `Result, _>` + ├ note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' ╰ note: consider using `--verbose` to print the full type name to the console error: aborting due to 4 previous errors diff --git a/tests/ui/diagnostic-width/long-e0277.rs b/tests/ui/diagnostic-width/long-e0277.rs new file mode 100644 index 0000000000000..9b3bd8bb72896 --- /dev/null +++ b/tests/ui/diagnostic-width/long-e0277.rs @@ -0,0 +1,15 @@ +//@ compile-flags: --diagnostic-width=60 -Zwrite-long-types-to-disk=yes +// The regex below normalizes the long type file name to make it suitable for compare-modes. +//@ normalize-stderr: "'\$TEST_BUILD_DIR/.*\.long-type-\d+.txt'" -> "'$$TEST_BUILD_DIR/$$FILE.long-type-hash.txt'" +type A = (i32, i32, i32, i32); +type B = (A, A, A, A); +type C = (B, B, B, B); +type D = (C, C, C, C); + +trait Trait {} + +fn require_trait() {} + +fn main() { + require_trait::(); //~ ERROR the trait bound `(... +} diff --git a/tests/ui/diagnostic-width/long-e0277.stderr b/tests/ui/diagnostic-width/long-e0277.stderr new file mode 100644 index 0000000000000..a57270df7e252 --- /dev/null +++ b/tests/ui/diagnostic-width/long-e0277.stderr @@ -0,0 +1,23 @@ +error[E0277]: the trait bound `(..., ..., ..., ...): Trait` is not satisfied + --> $DIR/long-e0277.rs:14:21 + | +LL | require_trait::(); + | ^ unsatisfied trait bound + | + = help: the trait `Trait` is not implemented for `(..., ..., ..., ...)` +help: this trait has no implementations, consider adding one + --> $DIR/long-e0277.rs:9:1 + | +LL | trait Trait {} + | ^^^^^^^^^^^ +note: required by a bound in `require_trait` + --> $DIR/long-e0277.rs:11:21 + | +LL | fn require_trait() {} + | ^^^^^ required by this bound in `require_trait` + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + = note: consider using `--verbose` to print the full type name to the console + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/diagnostic-width/non-copy-type-moved.stderr b/tests/ui/diagnostic-width/non-copy-type-moved.stderr index 889a2b3666dd0..254542c7b3908 100644 --- a/tests/ui/diagnostic-width/non-copy-type-moved.stderr +++ b/tests/ui/diagnostic-width/non-copy-type-moved.stderr @@ -2,13 +2,13 @@ error[E0382]: use of moved value: `x` --> $DIR/non-copy-type-moved.rs:16:14 | LL | fn foo(x: D) { - | - move occurs because `x` has type `((..., ..., ..., ...), ..., ..., ...)`, which does not implement the `Copy` trait + | - move occurs because `x` has type `(..., ..., ..., ...)`, which does not implement the `Copy` trait LL | let _a = x; | - value moved here LL | let _b = x; | ^ value used here after move | - = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console help: consider cloning the value if the performance cost is acceptable | diff --git a/tests/ui/diagnostic-width/secondary-label-with-long-type.rs b/tests/ui/diagnostic-width/secondary-label-with-long-type.rs index 4caa94244250c..c8845af318357 100644 --- a/tests/ui/diagnostic-width/secondary-label-with-long-type.rs +++ b/tests/ui/diagnostic-width/secondary-label-with-long-type.rs @@ -12,7 +12,7 @@ fn foo(x: D) { //~^ NOTE this expression has type `((..., //~| NOTE expected `((..., //~| NOTE expected tuple - //~| NOTE the full type name has been written to + //~| NOTE the full name for the type has been written to //~| NOTE consider using `--verbose` to print the full type name to the console } diff --git a/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr b/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr index 346b112019fa8..a95e17091489e 100644 --- a/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr +++ b/tests/ui/diagnostic-width/secondary-label-with-long-type.stderr @@ -8,7 +8,7 @@ LL | let () = x; | = note: expected tuple `((..., ..., ..., ...), ..., ..., ...)` found unit type `()` - = note: the full type name has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' + = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' = note: consider using `--verbose` to print the full type name to the console error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr index 67417a5e525cf..be2eca3e61ad9 100644 --- a/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr +++ b/tests/ui/higher-ranked/trait-bounds/hang-on-deeply-nested-dyn.stderr @@ -11,7 +11,7 @@ LL | | ), LL | | ) { | |_- expected `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn Fn(u32) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a))` because of return type LL | f - | ^ expected `&dyn Fn(&dyn Fn(&dyn Fn(&...)))`, found `&dyn Fn(u32)` + | ^ expected `&dyn Fn(&dyn Fn(&dyn Fn(&dyn Fn(&...))))`, found `&dyn Fn(u32)` | = note: expected reference `&dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn for<'a> Fn(&'a (dyn Fn(u32) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a)) + 'a))` found reference `&dyn Fn(u32)` diff --git a/tests/ui/suggestions/box-future-wrong-output.stderr b/tests/ui/suggestions/box-future-wrong-output.stderr index 6a232c3444d93..bac26ae8fb5dd 100644 --- a/tests/ui/suggestions/box-future-wrong-output.stderr +++ b/tests/ui/suggestions/box-future-wrong-output.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/box-future-wrong-output.rs:20:39 | LL | let _: BoxFuture<'static, bool> = async {}.boxed(); - | ------------------------ ^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | ------------------------ ^^^^^^^^^^^^^^^^ expected `Pin>`, found `Pin + Send>>` | | | expected due to this | diff --git a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index 42bc094859a97..61a1d30d31d4a 100644 --- a/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/tests/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -32,7 +32,7 @@ error[E0308]: mismatched types LL | fn baz + Send + 'static>(x: F) -> BoxFuture<'static, i32> { | - found this type parameter LL | Pin::new(x) - | -------- ^ expected `Box + Send>`, found type parameter `F` + | -------- ^ expected `Box + Send>`, found type parameter `F` | | | arguments to this function are incorrect | help: use `Box::pin` to pin and box this expression: `Box::pin` diff --git a/tests/ui/suggestions/issue-107860.stderr b/tests/ui/suggestions/issue-107860.stderr index 4be495da46b1f..2bfd219398141 100644 --- a/tests/ui/suggestions/issue-107860.stderr +++ b/tests/ui/suggestions/issue-107860.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-107860.rs:3:36 | LL | async fn str(T: &str) -> &str { &str } - | ^^^^ expected `&str`, found `&fn(&str) -> ... {str::<...>}` + | ^^^^ expected `&str`, found `&fn(&str) -> ... {str::<_>}` | = note: expected reference `&str` found reference `&for<'a> fn(&'a str) -> impl Future {str::<_>}` diff --git a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr index 8bfda71bac1fb..5299236026d7e 100644 --- a/tests/ui/traits/ice-with-dyn-pointee-errors.stderr +++ b/tests/ui/traits/ice-with-dyn-pointee-errors.stderr @@ -2,7 +2,7 @@ error[E0271]: type mismatch resolving ` as Pointee>:: --> $DIR/ice-with-dyn-pointee-errors.rs:9:33 | LL | unknown_sized_object_ptr_in(x) - | --------------------------- ^ expected `()`, found `DynMetadata>` + | --------------------------- ^ expected `()`, found `DynMetadata>` | | | required by a bound introduced by this call | diff --git a/tests/ui/traits/object/pretty.stderr b/tests/ui/traits/object/pretty.stderr index af941e69c5f84..2f9fdf151f08c 100644 --- a/tests/ui/traits/object/pretty.stderr +++ b/tests/ui/traits/object/pretty.stderr @@ -110,7 +110,7 @@ error[E0308]: mismatched types --> $DIR/pretty.rs:36:79 | LL | fn dyn_fixed_generic_multi(x: &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>) { x } - | - ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = ...>` + | - ^ expected `()`, found `&dyn FixedGeneric1<'a, Assoc2 = &u8>` | | | help: try adding a return type: `-> &dyn for<'a> FixedGeneric1<'a, Assoc2 = &u8>` | @@ -132,7 +132,7 @@ error[E0308]: mismatched types --> $DIR/pretty.rs:38:73 | LL | fn dyn_any_different_binders(x: &dyn AnyDifferentBinders) { x } - | - ^ expected `()`, found `&dyn AnyDifferentBinders` + | - ^ expected `()`, found `&dyn AnyDifferentBinders` | | | help: try adding a return type: `-> &dyn AnyDifferentBinders` | diff --git a/tests/ui/traits/on_unimplemented_long_types.stderr b/tests/ui/traits/on_unimplemented_long_types.stderr index 5722f4006ffd9..2705d7c501ec6 100644 --- a/tests/ui/traits/on_unimplemented_long_types.stderr +++ b/tests/ui/traits/on_unimplemented_long_types.stderr @@ -13,8 +13,6 @@ LL | | ))))))))))), LL | | ))))))))))) | |_______________- return type was inferred to be `Option>>` here | - = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' - = note: consider using `--verbose` to print the full type name to the console = help: the trait `std::fmt::Display` is not implemented for `Option>>` = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead = note: the full name for the type has been written to '$TEST_BUILD_DIR/$FILE.long-type-hash.txt' diff --git a/tests/ui/typeck/issue-107775.stderr b/tests/ui/typeck/issue-107775.stderr index dad7e1581e79a..1be2689746941 100644 --- a/tests/ui/typeck/issue-107775.stderr +++ b/tests/ui/typeck/issue-107775.stderr @@ -6,7 +6,7 @@ LL | map.insert(1, Struct::do_something); | | | ... which causes `map` to have type `HashMap<{integer}, fn(u8) -> Pin + Send>> {::do_something::<'_>}>` LL | Self { map } - | ^^^ expected `HashMap Pin<...>>`, found `HashMap<{integer}, ...>` + | ^^^ expected `HashMap Pin>>`, found `HashMap<{integer}, ...>` | = note: expected struct `HashMap Pin + Send + 'static)>>>` found struct `HashMap<{integer}, fn(_) -> Pin + Send>> {::do_something::<'_>}>` diff --git a/tests/ui/typeck/return_type_containing_closure.rs b/tests/ui/typeck/return_type_containing_closure.rs index b81cac0a58ab9..a9bb89bae2d6a 100644 --- a/tests/ui/typeck/return_type_containing_closure.rs +++ b/tests/ui/typeck/return_type_containing_closure.rs @@ -2,7 +2,7 @@ fn foo() { //~ HELP try adding a return type vec!['a'].iter().map(|c| c) //~^ ERROR mismatched types [E0308] - //~| NOTE expected `()`, found `Map, ...>` + //~| NOTE expected `()`, found `Map, {closure@...}>` //~| NOTE expected unit type `()` //~| HELP consider using a semicolon here } diff --git a/tests/ui/typeck/return_type_containing_closure.stderr b/tests/ui/typeck/return_type_containing_closure.stderr index 3f14650a82cce..a60bf79a57b8a 100644 --- a/tests/ui/typeck/return_type_containing_closure.stderr +++ b/tests/ui/typeck/return_type_containing_closure.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/return_type_containing_closure.rs:3:5 | LL | vec!['a'].iter().map(|c| c) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Map, ...>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found `Map, {closure@...}>` | = note: expected unit type `()` found struct `Map, {closure@$DIR/return_type_containing_closure.rs:3:26: 3:29}>` From 24cdaa146a166e679cbc3fc5187315b043090af2 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 30 Jan 2025 16:20:09 +1100 Subject: [PATCH 07/12] Rename `tcx.ensure()` to `tcx.ensure_ok()` --- .../rustc_codegen_cranelift/src/driver/aot.rs | 2 +- compiler/rustc_codegen_ssa/src/base.rs | 2 +- compiler/rustc_driver_impl/src/lib.rs | 4 +- compiler/rustc_driver_impl/src/pretty.rs | 2 +- .../rustc_hir_analysis/src/check/check.rs | 10 +- .../src/check/compare_impl_item.rs | 2 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 16 +- .../src/coherence/builtin.rs | 2 +- .../rustc_hir_analysis/src/coherence/mod.rs | 4 +- compiler/rustc_hir_analysis/src/collect.rs | 150 +++++++++--------- .../rustc_hir_analysis/src/impl_wf_check.rs | 2 +- compiler/rustc_hir_analysis/src/lib.rs | 16 +- compiler/rustc_hir_typeck/src/callee.rs | 2 +- compiler/rustc_interface/src/passes.rs | 45 +++--- compiler/rustc_lint/src/late.rs | 2 +- .../src/rmeta/decoder/cstore_impl.rs | 2 +- .../rustc_middle/src/mir/interpret/queries.rs | 4 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/query/plumbing.rs | 45 ++++-- compiler/rustc_middle/src/ty/context.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 4 +- compiler/rustc_mir_build/src/builder/mod.rs | 2 +- compiler/rustc_monomorphize/src/collector.rs | 2 +- .../src/error_reporting/traits/ambiguity.rs | 8 +- .../src/traits/specialize/mod.rs | 2 +- .../traits/specialize/specialization_graph.rs | 4 +- compiler/rustc_ty_utils/src/instance.rs | 2 +- src/librustdoc/core.rs | 4 +- src/tools/clippy/clippy_lints/src/ctfe.rs | 2 +- 29 files changed, 186 insertions(+), 160 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 27adf6318e227..a52b18573b152 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -692,7 +692,7 @@ pub(crate) fn run_aot( if tcx.dep_graph.is_fully_enabled() { for cgu in cgus { - tcx.ensure().codegen_unit(cgu.name()); + tcx.ensure_ok().codegen_unit(cgu.name()); } } diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 6e0333cf3cef6..df945920ee8df 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -634,7 +634,7 @@ pub fn codegen_crate( // unnecessarily. if tcx.dep_graph.is_fully_enabled() { for cgu in codegen_units { - tcx.ensure().codegen_unit(cgu.name()); + tcx.ensure_ok().codegen_unit(cgu.name()); } } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index c9d38a0f93253..d489926148795 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -317,7 +317,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) if let Some(pp_mode) = sess.opts.pretty { if pp_mode.needs_ast_map() { create_and_enter_global_ctxt(compiler, krate, |tcx| { - tcx.ensure().early_lint_checks(()); + tcx.ensure_ok().early_lint_checks(()); pretty::print(sess, pp_mode, pretty::PrintExtra::NeedsAstMap { tcx }); passes::write_dep_info(tcx); }); @@ -365,7 +365,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send)) return early_exit(); } - tcx.ensure().analysis(()); + tcx.ensure_ok().analysis(()); if callbacks.after_analysis(compiler, tcx) == Compilation::Stop { return early_exit(); diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 699742aa0ea1a..9ace486fa56f7 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -222,7 +222,7 @@ impl<'tcx> PrintExtra<'tcx> { pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { if ppm.needs_analysis() { - ex.tcx().ensure().analysis(()); + ex.tcx().ensure_ok().analysis(()); } let (src, src_name) = get_source(sess); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 40049f96de4a1..6c534d58a7da8 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -778,13 +778,13 @@ fn check_static_linkage(tcx: TyCtxt<'_>, def_id: LocalDefId) { pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { match tcx.def_kind(def_id) { DefKind::Static { .. } => { - tcx.ensure().typeck(def_id); + tcx.ensure_ok().typeck(def_id); maybe_check_static_with_link_section(tcx, def_id); check_static_inhabited(tcx, def_id); check_static_linkage(tcx, def_id); } DefKind::Const => { - tcx.ensure().typeck(def_id); + tcx.ensure_ok().typeck(def_id); } DefKind::Enum => { check_enum(tcx, def_id); @@ -804,7 +804,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) { DefKind::Impl { of_trait } => { if of_trait && let Some(impl_trait_header) = tcx.impl_trait_header(def_id) { if tcx - .ensure() + .ensure_ok() .coherent_trait(impl_trait_header.trait_ref.instantiate_identity().def_id) .is_ok() { @@ -1042,7 +1042,7 @@ fn check_impl_items_against_trait<'tcx>( continue; }; - let res = tcx.ensure().compare_impl_item(impl_item.expect_local()); + let res = tcx.ensure_ok().compare_impl_item(impl_item.expect_local()); if res.is_ok() { match ty_impl_item.kind { @@ -1488,7 +1488,7 @@ fn check_enum(tcx: TyCtxt<'_>, def_id: LocalDefId) { for v in def.variants() { if let ty::VariantDiscr::Explicit(discr_def_id) = v.discr { - tcx.ensure().typeck(discr_def_id.expect_local()); + tcx.ensure_ok().typeck(discr_def_id.expect_local()); } } diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index 3bff5fe02c033..a91d72e922518 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -2034,7 +2034,7 @@ pub(super) fn check_type_bounds<'tcx>( ) -> Result<(), ErrorGuaranteed> { // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. - tcx.ensure().coherent_trait(impl_trait_ref.def_id)?; + tcx.ensure_ok().coherent_trait(impl_trait_ref.def_id)?; let param_env = tcx.param_env(impl_ty.def_id); debug!(?param_env); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index c9837ca3716c6..79e2d764ac598 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -1046,7 +1046,7 @@ fn check_associated_item( // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. - tcx.ensure() + tcx.ensure_ok() .coherent_trait(tcx.parent(item.trait_item_def_id.unwrap_or(item_id.into())))?; let self_ty = match item.container { @@ -1354,7 +1354,7 @@ fn check_impl<'tcx>( let trait_ref = tcx.impl_trait_ref(item.owner_id).unwrap().instantiate_identity(); // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. - tcx.ensure().coherent_trait(trait_ref.def_id)?; + tcx.ensure_ok().coherent_trait(trait_ref.def_id)?; let trait_span = hir_trait_ref.path.span; let trait_ref = wfcx.normalize( trait_span, @@ -2268,11 +2268,13 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> { fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> { let items = tcx.hir_module_items(module); let res = items - .par_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id)) - .and(items.par_impl_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))) - .and(items.par_trait_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))) - .and(items.par_foreign_items(|item| tcx.ensure().check_well_formed(item.owner_id.def_id))) - .and(items.par_opaques(|item| tcx.ensure().check_well_formed(item))); + .par_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)) + .and(items.par_impl_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))) + .and(items.par_trait_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))) + .and( + items.par_foreign_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)), + ) + .and(items.par_opaques(|item| tcx.ensure_ok().check_well_formed(item))); if module == LocalModDefId::CRATE_DEF_ID { super::entry::check_for_entry_fn(tcx); } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 30f51fe17246f..3511dbc625295 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -192,7 +192,7 @@ fn visit_implementation_of_coerce_unsized(checker: &Checker<'_>) -> Result<(), E // errors; other parts of the code may demand it for the info of // course. let span = tcx.def_span(impl_did); - tcx.at(span).ensure().coerce_unsized_info(impl_did) + tcx.at(span).ensure_ok().coerce_unsized_info(impl_did) } fn visit_implementation_of_dispatch_from_dyn(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index b9ef166fc3f10..1bc60087ab5ee 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -151,7 +151,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> let Some(impls) = tcx.all_local_trait_impls(()).get(&def_id) else { return Ok(()) }; // Trigger building the specialization graph for the trait. This will detect and report any // overlap errors. - let mut res = tcx.ensure().specialization_graph_of(def_id); + let mut res = tcx.ensure_ok().specialization_graph_of(def_id); for &impl_def_id in impls { let trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); @@ -162,7 +162,7 @@ fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> .and(check_impl(tcx, impl_def_id, trait_ref, trait_def)) .and(check_object_overlap(tcx, impl_def_id, trait_ref)) .and(unsafety::check_item(tcx, impl_def_id, trait_header, trait_def)) - .and(tcx.ensure().orphan_check_impl(impl_def_id)) + .and(tcx.ensure_ok().orphan_check_impl(impl_def_id)) .and(builtin::check_trait(tcx, def_id, impl_def_id, trait_header)); } diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 226370fccadde..ce7319f656190 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -292,16 +292,16 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { match param.kind { hir::GenericParamKind::Lifetime { .. } => {} hir::GenericParamKind::Type { default: Some(_), .. } => { - self.tcx.ensure().type_of(param.def_id); + self.tcx.ensure_ok().type_of(param.def_id); } hir::GenericParamKind::Type { .. } => {} hir::GenericParamKind::Const { default, .. } => { - self.tcx.ensure().type_of(param.def_id); + self.tcx.ensure_ok().type_of(param.def_id); if let Some(default) = default { // need to store default and type of default - self.tcx.ensure().const_param_default(param.def_id); + self.tcx.ensure_ok().const_param_default(param.def_id); if let hir::ConstArgKind::Anon(ac) = default.kind { - self.tcx.ensure().type_of(ac.def_id); + self.tcx.ensure_ok().type_of(ac.def_id); } } } @@ -312,8 +312,8 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { fn visit_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) { if let hir::ExprKind::Closure(closure) = expr.kind { - self.tcx.ensure().generics_of(closure.def_id); - self.tcx.ensure().codegen_fn_attrs(closure.def_id); + self.tcx.ensure_ok().generics_of(closure.def_id); + self.tcx.ensure_ok().codegen_fn_attrs(closure.def_id); // We do not call `type_of` for closures here as that // depends on typecheck and would therefore hide // any further errors in case one typeck fails. @@ -325,15 +325,15 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> { /// `check_item_type` ensures that it's called instead. fn visit_opaque_ty(&mut self, opaque: &'tcx hir::OpaqueTy<'tcx>) { let def_id = opaque.def_id; - self.tcx.ensure().generics_of(def_id); - self.tcx.ensure().predicates_of(def_id); - self.tcx.ensure().explicit_item_bounds(def_id); - self.tcx.ensure().explicit_item_self_bounds(def_id); - self.tcx.ensure().item_bounds(def_id); - self.tcx.ensure().item_self_bounds(def_id); + self.tcx.ensure_ok().generics_of(def_id); + self.tcx.ensure_ok().predicates_of(def_id); + self.tcx.ensure_ok().explicit_item_bounds(def_id); + self.tcx.ensure_ok().explicit_item_self_bounds(def_id); + self.tcx.ensure_ok().item_bounds(def_id); + self.tcx.ensure_ok().item_self_bounds(def_id); if self.tcx.is_conditionally_const(def_id) { - self.tcx.ensure().explicit_implied_const_bounds(def_id); - self.tcx.ensure().const_conditions(def_id); + self.tcx.ensure_ok().explicit_implied_const_bounds(def_id); + self.tcx.ensure_ok().const_conditions(def_id); } intravisit::walk_opaque_ty(self, opaque); } @@ -683,20 +683,20 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { hir::ItemKind::ForeignMod { items, .. } => { for item in *items { let item = tcx.hir().foreign_item(item.id); - tcx.ensure().generics_of(item.owner_id); - tcx.ensure().type_of(item.owner_id); - tcx.ensure().predicates_of(item.owner_id); + tcx.ensure_ok().generics_of(item.owner_id); + tcx.ensure_ok().type_of(item.owner_id); + tcx.ensure_ok().predicates_of(item.owner_id); if tcx.is_conditionally_const(def_id) { - tcx.ensure().explicit_implied_const_bounds(def_id); - tcx.ensure().const_conditions(def_id); + tcx.ensure_ok().explicit_implied_const_bounds(def_id); + tcx.ensure_ok().const_conditions(def_id); } match item.kind { hir::ForeignItemKind::Fn(..) => { - tcx.ensure().codegen_fn_attrs(item.owner_id); - tcx.ensure().fn_sig(item.owner_id) + tcx.ensure_ok().codegen_fn_attrs(item.owner_id); + tcx.ensure_ok().fn_sig(item.owner_id) } hir::ForeignItemKind::Static(..) => { - tcx.ensure().codegen_fn_attrs(item.owner_id); + tcx.ensure_ok().codegen_fn_attrs(item.owner_id); let mut visitor = HirPlaceholderCollector::default(); visitor.visit_foreign_item(item); placeholder_type_error( @@ -713,40 +713,40 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } } hir::ItemKind::Enum(..) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); lower_enum_variant_types(tcx, def_id.to_def_id()); } hir::ItemKind::Impl { .. } => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().impl_trait_header(def_id); - tcx.ensure().predicates_of(def_id); - tcx.ensure().associated_items(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().impl_trait_header(def_id); + tcx.ensure_ok().predicates_of(def_id); + tcx.ensure_ok().associated_items(def_id); } hir::ItemKind::Trait(..) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().trait_def(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().trait_def(def_id); tcx.at(it.span).explicit_super_predicates_of(def_id); - tcx.ensure().predicates_of(def_id); - tcx.ensure().associated_items(def_id); + tcx.ensure_ok().predicates_of(def_id); + tcx.ensure_ok().associated_items(def_id); } hir::ItemKind::TraitAlias(..) => { - tcx.ensure().generics_of(def_id); + tcx.ensure_ok().generics_of(def_id); tcx.at(it.span).explicit_implied_predicates_of(def_id); tcx.at(it.span).explicit_super_predicates_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().predicates_of(def_id); } hir::ItemKind::Struct(struct_def, _) | hir::ItemKind::Union(struct_def, _) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); for f in struct_def.fields() { - tcx.ensure().generics_of(f.def_id); - tcx.ensure().type_of(f.def_id); - tcx.ensure().predicates_of(f.def_id); + tcx.ensure_ok().generics_of(f.def_id); + tcx.ensure_ok().type_of(f.def_id); + tcx.ensure_ok().predicates_of(f.def_id); } if let Some(ctor_def_id) = struct_def.ctor_def_id() { @@ -755,15 +755,15 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } hir::ItemKind::TyAlias(..) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); } hir::ItemKind::Static(ty, ..) | hir::ItemKind::Const(ty, ..) => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); if !ty.is_suggestable_infer_ty() { let mut visitor = HirPlaceholderCollector::default(); visitor.visit_item(it); @@ -779,11 +779,11 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { } hir::ItemKind::Fn { .. } => { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); - tcx.ensure().fn_sig(def_id); - tcx.ensure().codegen_fn_attrs(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); + tcx.ensure_ok().fn_sig(def_id); + tcx.ensure_ok().codegen_fn_attrs(def_id); } } } @@ -791,18 +791,18 @@ fn lower_item(tcx: TyCtxt<'_>, item_id: hir::ItemId) { fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { let trait_item = tcx.hir().trait_item(trait_item_id); let def_id = trait_item_id.owner_id; - tcx.ensure().generics_of(def_id); + tcx.ensure_ok().generics_of(def_id); let icx = ItemCtxt::new(tcx, def_id.def_id); match trait_item.kind { hir::TraitItemKind::Fn(..) => { - tcx.ensure().codegen_fn_attrs(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().fn_sig(def_id); + tcx.ensure_ok().codegen_fn_attrs(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().fn_sig(def_id); } hir::TraitItemKind::Const(ty, body_id) => { - tcx.ensure().type_of(def_id); + tcx.ensure_ok().type_of(def_id); if !tcx.dcx().has_stashed_diagnostic(ty.span, StashKey::ItemNoType) && !(ty.is_suggestable_infer_ty() && body_id.is_some()) { @@ -821,9 +821,9 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { } hir::TraitItemKind::Type(_, Some(_)) => { - tcx.ensure().item_bounds(def_id); - tcx.ensure().item_self_bounds(def_id); - tcx.ensure().type_of(def_id); + tcx.ensure_ok().item_bounds(def_id); + tcx.ensure_ok().item_self_bounds(def_id); + tcx.ensure_ok().type_of(def_id); // Account for `type T = _;`. let mut visitor = HirPlaceholderCollector::default(); visitor.visit_trait_item(trait_item); @@ -838,8 +838,8 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { } hir::TraitItemKind::Type(_, None) => { - tcx.ensure().item_bounds(def_id); - tcx.ensure().item_self_bounds(def_id); + tcx.ensure_ok().item_bounds(def_id); + tcx.ensure_ok().item_self_bounds(def_id); // #74612: Visit and try to find bad placeholders // even if there is no concrete type. let mut visitor = HirPlaceholderCollector::default(); @@ -856,20 +856,20 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) { } }; - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().predicates_of(def_id); } fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { let def_id = impl_item_id.owner_id; - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); let impl_item = tcx.hir().impl_item(impl_item_id); let icx = ItemCtxt::new(tcx, def_id.def_id); match impl_item.kind { hir::ImplItemKind::Fn(..) => { - tcx.ensure().codegen_fn_attrs(def_id); - tcx.ensure().fn_sig(def_id); + tcx.ensure_ok().codegen_fn_attrs(def_id); + tcx.ensure_ok().fn_sig(def_id); } hir::ImplItemKind::Type(_) => { // Account for `type T = _;` @@ -904,9 +904,9 @@ fn lower_impl_item(tcx: TyCtxt<'_>, impl_item_id: hir::ImplItemId) { } fn lower_variant_ctor(tcx: TyCtxt<'_>, def_id: LocalDefId) { - tcx.ensure().generics_of(def_id); - tcx.ensure().type_of(def_id); - tcx.ensure().predicates_of(def_id); + tcx.ensure_ok().generics_of(def_id); + tcx.ensure_ok().type_of(def_id); + tcx.ensure_ok().predicates_of(def_id); } fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { @@ -937,9 +937,9 @@ fn lower_enum_variant_types(tcx: TyCtxt<'_>, def_id: DefId) { ); for f in &variant.fields { - tcx.ensure().generics_of(f.did); - tcx.ensure().type_of(f.did); - tcx.ensure().predicates_of(f.did); + tcx.ensure_ok().generics_of(f.did); + tcx.ensure_ok().type_of(f.did); + tcx.ensure_ok().predicates_of(f.did); } // Lower the ctor, if any. This also registers the variant as an item. diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index fd5a7089b4cf8..c30b39dfe7656 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -62,7 +62,7 @@ pub(crate) fn check_impl_wf( // Check that the args are constrained. We queryfied the check for ty/const params // since unconstrained type/const params cause ICEs in projection, so we want to // detect those specifically and project those to `TyKind::Error`. - let mut res = tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id); + let mut res = tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id); res = res.and(enforce_impl_lifetime_params_are_constrained(tcx, impl_def_id)); if tcx.features().min_specialization() { diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index ae054a9eaeb7a..274dbb1ec1c87 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -140,15 +140,15 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.sess.time("coherence_checking", || { tcx.hir().par_for_each_module(|module| { - let _ = tcx.ensure().check_mod_type_wf(module); + let _ = tcx.ensure_ok().check_mod_type_wf(module); }); for &trait_def_id in tcx.all_local_trait_impls(()).keys() { - let _ = tcx.ensure().coherent_trait(trait_def_id); + let _ = tcx.ensure_ok().coherent_trait(trait_def_id); } // these queries are executed for side-effects (error reporting): - let _ = tcx.ensure().crate_inherent_impls_validity_check(()); - let _ = tcx.ensure().crate_inherent_impls_overlap_check(()); + let _ = tcx.ensure_ok().crate_inherent_impls_validity_check(()); + let _ = tcx.ensure_ok().crate_inherent_impls_overlap_check(()); }); if tcx.features().rustc_attrs() { @@ -167,12 +167,12 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.hir().par_body_owners(|item_def_id| { let def_kind = tcx.def_kind(item_def_id); match def_kind { - DefKind::Static { .. } => tcx.ensure().eval_static_initializer(item_def_id), + DefKind::Static { .. } => tcx.ensure_ok().eval_static_initializer(item_def_id), DefKind::Const if tcx.generics_of(item_def_id).is_empty() => { let instance = ty::Instance::new(item_def_id.into(), ty::GenericArgs::empty()); let cid = GlobalId { instance, promoted: None }; let typing_env = ty::TypingEnv::fully_monomorphized(); - tcx.ensure().eval_to_const_value_raw(typing_env.as_query_input(cid)); + tcx.ensure_ok().eval_to_const_value_raw(typing_env.as_query_input(cid)); } _ => (), } @@ -185,11 +185,11 @@ pub fn check_crate(tcx: TyCtxt<'_>) { tcx.hir().par_body_owners(|item_def_id| { let def_kind = tcx.def_kind(item_def_id); if !matches!(def_kind, DefKind::AnonConst) { - tcx.ensure().typeck(item_def_id); + tcx.ensure_ok().typeck(item_def_id); } }); - tcx.ensure().check_unused_traits(()); + tcx.ensure_ok().check_unused_traits(()); } /// Lower a [`hir::Ty`] to a [`Ty`]. diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs index 28b1a823daea0..edc3702d90b58 100644 --- a/compiler/rustc_hir_typeck/src/callee.rs +++ b/compiler/rustc_hir_typeck/src/callee.rs @@ -49,7 +49,7 @@ pub(crate) fn check_legal_trait_for_method_call( }; return Err(tcx.dcx().emit_err(errors::ExplicitDestructorCall { span, sugg })); } - tcx.ensure().coherent_trait(trait_id) + tcx.ensure_ok().coherent_trait(trait_id) } #[derive(Debug)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 0b91c023cfc87..57a8c272c5cbb 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -832,20 +832,20 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { sess.time("misc_checking_1", || { parallel!( { - sess.time("looking_for_entry_point", || tcx.ensure().entry_fn(())); + sess.time("looking_for_entry_point", || tcx.ensure_ok().entry_fn(())); sess.time("looking_for_derive_registrar", || { - tcx.ensure().proc_macro_decls_static(()) + tcx.ensure_ok().proc_macro_decls_static(()) }); CStore::from_tcx(tcx).report_unused_deps(tcx); }, { tcx.hir().par_for_each_module(|module| { - tcx.ensure().check_mod_loops(module); - tcx.ensure().check_mod_attrs(module); - tcx.ensure().check_mod_naked_functions(module); - tcx.ensure().check_mod_unstable_api_usage(module); + tcx.ensure_ok().check_mod_loops(module); + tcx.ensure_ok().check_mod_attrs(module); + tcx.ensure_ok().check_mod_naked_functions(module); + tcx.ensure_ok().check_mod_unstable_api_usage(module); }); }, { @@ -858,8 +858,8 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // since they might not otherwise get called. // This marks the corresponding crate-level attributes // as used, and ensures that their values are valid. - tcx.ensure().limits(()); - tcx.ensure().stability_index(()); + tcx.ensure_ok().limits(()); + tcx.ensure_ok().stability_index(()); } ); }); @@ -883,13 +883,13 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { tcx.hir().par_body_owners(|def_id| { // Run unsafety check because it's responsible for stealing and // deallocating THIR. - tcx.ensure().check_unsafety(def_id); - tcx.ensure().mir_borrowck(def_id) + tcx.ensure_ok().check_unsafety(def_id); + tcx.ensure_ok().mir_borrowck(def_id) }); }); sess.time("MIR_effect_checking", || { tcx.hir().par_body_owners(|def_id| { - tcx.ensure().has_ffi_unwind_calls(def_id); + tcx.ensure_ok().has_ffi_unwind_calls(def_id); // If we need to codegen, ensure that we emit all errors from // `mir_drops_elaborated_and_const_checked` now, to avoid discovering @@ -897,15 +897,15 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { if tcx.sess.opts.output_types.should_codegen() || tcx.hir().body_const_context(def_id).is_some() { - tcx.ensure().mir_drops_elaborated_and_const_checked(def_id); + tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id); } }); }); sess.time("coroutine_obligations", || { tcx.hir().par_body_owners(|def_id| { if tcx.is_coroutine(def_id.to_def_id()) { - tcx.ensure().mir_coroutine_witnesses(def_id); - tcx.ensure().check_coroutine_obligations( + tcx.ensure_ok().mir_coroutine_witnesses(def_id); + tcx.ensure_ok().check_coroutine_obligations( tcx.typeck_root_def_id(def_id.to_def_id()).expect_local(), ); } @@ -950,15 +950,16 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { sess.time("misc_checking_3", || { parallel!( { - tcx.ensure().effective_visibilities(()); + tcx.ensure_ok().effective_visibilities(()); parallel!( { - tcx.ensure().check_private_in_public(()); + tcx.ensure_ok().check_private_in_public(()); }, { - tcx.hir() - .par_for_each_module(|module| tcx.ensure().check_mod_deathness(module)); + tcx.hir().par_for_each_module(|module| { + tcx.ensure_ok().check_mod_deathness(module) + }); }, { sess.time("lint_checking", || { @@ -966,14 +967,14 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { }); }, { - tcx.ensure().clashing_extern_declarations(()); + tcx.ensure_ok().clashing_extern_declarations(()); } ); }, { sess.time("privacy_checking_modules", || { tcx.hir().par_for_each_module(|module| { - tcx.ensure().check_mod_privacy(module); + tcx.ensure_ok().check_mod_privacy(module); }); }); } @@ -981,7 +982,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) { // This check has to be run after all lints are done processing. We don't // define a lint filter, as all lint checks should have finished at this point. - sess.time("check_lint_expectations", || tcx.ensure().check_expectations(None)); + sess.time("check_lint_expectations", || tcx.ensure_ok().check_expectations(None)); // This query is only invoked normally if a diagnostic is emitted that needs any // diagnostic item. If the crate compiles without checking any diagnostic items, @@ -1006,7 +1007,7 @@ fn check_for_rustc_errors_attr(tcx: TyCtxt<'_>) { ) }) => { - tcx.ensure().trigger_delayed_bug(def_id); + tcx.ensure_ok().trigger_delayed_bug(def_id); } // Bare `#[rustc_error]`. diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index c6d7b839e1970..826ecc22c24ba 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -458,7 +458,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>) { || { tcx.sess.time("module_lints", || { // Run per-module lints - tcx.hir().par_for_each_module(|module| tcx.ensure().lint_mod(module)); + tcx.hir().par_for_each_module(|module| tcx.ensure_ok().lint_mod(module)); }); }, ); diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index da07ad8f6c074..5fcb9c8503566 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -165,7 +165,7 @@ macro_rules! provide_one { // doesn't need to do this (and can't, as it would cause a query cycle). use rustc_middle::dep_graph::dep_kinds; if dep_kinds::$name != dep_kinds::crate_hash && $tcx.dep_graph.is_fully_enabled() { - $tcx.ensure().crate_hash($def_id.krate); + $tcx.ensure_ok().crate_hash($def_id.krate); } let cdata = rustc_data_structures::sync::FreezeReadGuard::map(CStore::from_tcx($tcx), |c| { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 4c47d9636d3f2..78749428c6df3 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -9,7 +9,7 @@ use super::{ ReportedErrorInfo, }; use crate::mir; -use crate::query::TyCtxtEnsure; +use crate::query::TyCtxtEnsureOk; use crate::ty::visit::TypeVisitableExt; use crate::ty::{self, GenericArgs, TyCtxt}; @@ -198,7 +198,7 @@ impl<'tcx> TyCtxt<'tcx> { } } -impl<'tcx> TyCtxtEnsure<'tcx> { +impl<'tcx> TyCtxtEnsureOk<'tcx> { /// Evaluates a constant without providing any generic parameters. This is useful to evaluate consts /// that can't take any generic arguments like const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::TooGeneric` will be returned. diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 41e9858030c8f..bdd24d3977fef 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -91,7 +91,7 @@ pub use keys::{AsLocalKey, Key, LocalCrate}; pub mod on_disk_cache; #[macro_use] pub mod plumbing; -pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue}; +pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsureOk, TyCtxtEnsureWithValue}; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 1c157f33a813b..16660d7a1f99f 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -88,7 +88,7 @@ impl<'tcx> Deref for TyCtxtAt<'tcx> { } #[derive(Copy, Clone)] -pub struct TyCtxtEnsure<'tcx> { +pub struct TyCtxtEnsureOk<'tcx> { pub tcx: TyCtxt<'tcx>, } @@ -98,11 +98,29 @@ pub struct TyCtxtEnsureWithValue<'tcx> { } impl<'tcx> TyCtxt<'tcx> { - /// Returns a transparent wrapper for `TyCtxt`, which ensures queries - /// are executed instead of just returning their results. + /// Wrapper that calls queries in a special "ensure OK" mode, for callers + /// that don't need the return value and just want to invoke a query for + /// its potential side-effect of emitting fatal errors. + /// + /// This can be more efficient than a normal query call, because if the + /// query's inputs are all green, the call can return immediately without + /// needing to obtain a value (by decoding one from disk or by executing + /// the query). + /// + /// (As with all query calls, execution is also skipped if the query result + /// is already cached in memory.) + /// + /// ## WARNING + /// A subsequent normal call to the same query might still cause it to be + /// executed! This can occur when the inputs are all green, but the query's + /// result is not cached on disk, so the query must be executed to obtain a + /// return value. + /// + /// Therefore, this call mode is not appropriate for callers that want to + /// ensure that the query is _never_ executed in the future. #[inline(always)] - pub fn ensure(self) -> TyCtxtEnsure<'tcx> { - TyCtxtEnsure { tcx: self } + pub fn ensure_ok(self) -> TyCtxtEnsureOk<'tcx> { + TyCtxtEnsureOk { tcx: self } } /// Returns a transparent wrapper for `TyCtxt`, which ensures queries @@ -248,15 +266,15 @@ macro_rules! separate_provide_extern_decl { }; } -macro_rules! ensure_result { - ([][$ty:ty]) => { +macro_rules! ensure_ok_result { + ( [] ) => { () }; - ([(ensure_forwards_result_if_red) $($rest:tt)*][$ty:ty]) => { + ( [(ensure_forwards_result_if_red) $($rest:tt)*] ) => { Result<(), ErrorGuaranteed> }; - ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { - ensure_result!([$($modifiers)*][$($args)*]) + ( [$other:tt $($modifiers:tt)*] ) => { + ensure_ok_result!( [$($modifiers)*] ) }; } @@ -383,10 +401,13 @@ macro_rules! define_callbacks { $($(#[$attr])* pub $name: queries::$name::Storage<'tcx>,)* } - impl<'tcx> TyCtxtEnsure<'tcx> { + impl<'tcx> TyCtxtEnsureOk<'tcx> { $($(#[$attr])* #[inline(always)] - pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> ensure_result!([$($modifiers)*][$V]) { + pub fn $name( + self, + key: query_helper_param_ty!($($K)*), + ) -> ensure_ok_result!([$($modifiers)*]) { query_ensure!( [$($modifiers)*] self.tcx, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 69f6fc0ad8a66..522a553d2432e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1957,7 +1957,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> &'tcx rustc_hir::def_path_hash_map::DefPathHashMap { // Create a dependency to the crate to be sure we re-execute this when the amount of // definitions change. - self.ensure().hir_crate(()); + self.ensure_ok().hir_crate(()); // Freeze definitions once we start iterating on them, to prevent adding new ones // while iterating. If some query needs to add definitions, it should be `ensure`d above. self.untracked.definitions.freeze().def_path_hash_to_def_index_map() diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 7d5e5c2e82370..318bd0c7ec020 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -367,7 +367,7 @@ impl<'tcx> TyCtxt<'tcx> { validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, ) -> Option { let drop_trait = self.lang_items().drop_trait()?; - self.ensure().coherent_trait(drop_trait).ok()?; + self.ensure_ok().coherent_trait(drop_trait).ok()?; let ty = self.type_of(adt_did).instantiate_identity(); let mut dtor_candidate = None; @@ -404,7 +404,7 @@ impl<'tcx> TyCtxt<'tcx> { validate: impl Fn(Self, DefId) -> Result<(), ErrorGuaranteed>, ) -> Option { let async_drop_trait = self.lang_items().async_drop_trait()?; - self.ensure().coherent_trait(async_drop_trait).ok()?; + self.ensure_ok().coherent_trait(async_drop_trait).ok()?; let ty = self.type_of(adt_did).instantiate_identity(); let mut dtor_candidate = None; diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 93fb9873e80ab..8eb9f786c59eb 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -68,7 +68,7 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> { // "not all control paths return a value" is reported here. // // maybe move the check to a MIR pass? - tcx.ensure().check_liveness(def); + tcx.ensure_ok().check_liveness(def); // Don't steal here, instead steal in unsafeck. This is so that // pattern inline constants can be evaluated as part of building the diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 246faed50e369..de8a20c5deeef 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -1222,7 +1222,7 @@ fn collect_items_of_instance<'tcx>( mode: CollectionMode, ) -> (MonoItems<'tcx>, MonoItems<'tcx>) { // This item is getting monomorphized, do mono-time checks. - tcx.ensure().check_mono_item(instance); + tcx.ensure_ok().check_mono_item(instance); let body = tcx.instance_mir(instance.def); // Naively, in "used" collection mode, all functions get added to *both* `used_items` and diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs index b4d294a70c071..b798853a1dbe8 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs @@ -179,7 +179,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return e; } - if let Err(guar) = self.tcx.ensure().coherent_trait(trait_pred.def_id()) { + if let Err(guar) = self.tcx.ensure_ok().coherent_trait(trait_pred.def_id()) { // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. return guar; @@ -511,8 +511,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { return e; } - if let Err(guar) = - self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_term.def_id)) + if let Err(guar) = self + .tcx + .ensure_ok() + .coherent_trait(self.tcx.parent(data.projection_term.def_id)) { // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case // other `Foo` impls are incoherent. diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 401b41c796dad..cb3e81f5477fc 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -575,7 +575,7 @@ fn report_conflicting_impls<'tcx>( match used_to_be_allowed { None => { let reported = if overlap.with_impl.is_local() - || tcx.ensure().orphan_check_impl(impl_def_id).is_ok() + || tcx.ensure_ok().orphan_check_impl(impl_def_id).is_ok() { let mut err = tcx.dcx().struct_span_err(impl_span, msg()); err.code(E0119); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index c351cf5aaac61..f39c611d19fe0 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -379,7 +379,7 @@ pub(crate) fn assoc_def( // Ensure that the impl is constrained, otherwise projection may give us // bad unconstrained infer vars. if let Some(impl_def_id) = impl_def_id.as_local() { - tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; + tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; } let item = tcx.associated_item(impl_item_id); @@ -402,7 +402,7 @@ pub(crate) fn assoc_def( if assoc_item.item.container == ty::AssocItemContainer::Impl && let Some(impl_def_id) = assoc_item.item.container_id(tcx).as_local() { - tcx.ensure().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; + tcx.ensure_ok().enforce_impl_non_lifetime_params_are_constrained(impl_def_id)?; } Ok(assoc_item) diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index d5e1937efaa45..8c6e3c86bf5c8 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -225,7 +225,7 @@ fn resolve_associated_item<'tcx>( if trait_item_id != leaf_def.item.def_id && let Some(leaf_def_item) = leaf_def.item.def_id.as_local() { - tcx.ensure().compare_impl_item(leaf_def_item)?; + tcx.ensure_ok().compare_impl_item(leaf_def_item)?; } Some(ty::Instance::new(leaf_def.item.def_id, args)) diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 0437ebb585768..a072b1256f479 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -336,14 +336,14 @@ pub(crate) fn run_global_ctxt( // NOTE: These are copy/pasted from typeck/lib.rs and should be kept in sync with those changes. let _ = tcx.sess.time("wf_checking", || { - tcx.hir().try_par_for_each_module(|module| tcx.ensure().check_mod_type_wf(module)) + tcx.hir().try_par_for_each_module(|module| tcx.ensure_ok().check_mod_type_wf(module)) }); tcx.dcx().abort_if_errors(); tcx.sess.time("missing_docs", || rustc_lint::check_crate(tcx)); tcx.sess.time("check_mod_attrs", || { - tcx.hir().for_each_module(|module| tcx.ensure().check_mod_attrs(module)) + tcx.hir().for_each_module(|module| tcx.ensure_ok().check_mod_attrs(module)) }); rustc_passes::stability::check_unused_or_stable_features(tcx); diff --git a/src/tools/clippy/clippy_lints/src/ctfe.rs b/src/tools/clippy/clippy_lints/src/ctfe.rs index 589b99518a09b..7bae04a10f10b 100644 --- a/src/tools/clippy/clippy_lints/src/ctfe.rs +++ b/src/tools/clippy/clippy_lints/src/ctfe.rs @@ -21,6 +21,6 @@ impl<'tcx> LateLintPass<'tcx> for ClippyCtfe { _: Span, defid: LocalDefId, ) { - cx.tcx.ensure().mir_drops_elaborated_and_const_checked(defid); // Lint + cx.tcx.ensure_ok().mir_drops_elaborated_and_const_checked(defid); // Lint } } From 9e4f10db658700a191bcb6dba9e4e285297a5683 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 30 Jan 2025 16:28:44 +1100 Subject: [PATCH 08/12] Rename `tcx.ensure_with_value()` to `tcx.ensure_done()` --- compiler/rustc_ast_lowering/src/lib.rs | 8 +++--- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 6 ++--- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/query/plumbing.rs | 26 ++++++++++++++----- compiler/rustc_mir_build/src/builder/mod.rs | 2 +- .../rustc_mir_build/src/check_unsafety.rs | 4 +-- compiler/rustc_mir_transform/src/lib.rs | 12 ++++----- 8 files changed, 37 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index b9f1a4220b80f..893da93085533 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -418,10 +418,10 @@ fn compute_hir_hash( pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { let sess = tcx.sess; // Queries that borrow `resolver_for_lowering`. - tcx.ensure_with_value().output_filenames(()); - tcx.ensure_with_value().early_lint_checks(()); - tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE); - tcx.ensure_with_value().get_lang_items(()); + tcx.ensure_done().output_filenames(()); + tcx.ensure_done().early_lint_checks(()); + tcx.ensure_done().debugger_visualizers(LOCAL_CRATE); + tcx.ensure_done().get_lang_items(()); let (mut resolver, krate) = tcx.resolver_for_lowering().steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 57a8c272c5cbb..0324ebf9fd21e 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -868,7 +868,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { sess.time("MIR_coroutine_by_move_body", || { tcx.hir().par_body_owners(|def_id| { if tcx.needs_coroutine_by_move_body_def_id(def_id.to_def_id()) { - tcx.ensure_with_value().coroutine_by_move_body_def_id(def_id); + tcx.ensure_done().coroutine_by_move_body_def_id(def_id); } }); }); diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 43372154b2ce4..6e562e457d212 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -2191,13 +2191,13 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id); if encode_const { - tcx.ensure_with_value().mir_for_ctfe(def_id); + tcx.ensure_done().mir_for_ctfe(def_id); } if encode_opt { - tcx.ensure_with_value().optimized_mir(def_id); + tcx.ensure_done().optimized_mir(def_id); } if encode_opt || encode_const { - tcx.ensure_with_value().promoted_mir(def_id); + tcx.ensure_done().promoted_mir(def_id); } }) } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index bdd24d3977fef..934593dfb7979 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -91,7 +91,7 @@ pub use keys::{AsLocalKey, Key, LocalCrate}; pub mod on_disk_cache; #[macro_use] pub mod plumbing; -pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsureOk, TyCtxtEnsureWithValue}; +pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsureDone, TyCtxtEnsureOk}; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 16660d7a1f99f..6648e3d9d53b5 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -93,7 +93,7 @@ pub struct TyCtxtEnsureOk<'tcx> { } #[derive(Copy, Clone)] -pub struct TyCtxtEnsureWithValue<'tcx> { +pub struct TyCtxtEnsureDone<'tcx> { pub tcx: TyCtxt<'tcx>, } @@ -123,13 +123,25 @@ impl<'tcx> TyCtxt<'tcx> { TyCtxtEnsureOk { tcx: self } } - /// Returns a transparent wrapper for `TyCtxt`, which ensures queries - /// are executed instead of just returning their results. + /// Wrapper that calls queries in a special "ensure done" mode, for callers + /// that don't need the return value and just want to guarantee that the + /// query won't be executed in the future, by executing it now if necessary. /// - /// This version verifies that the computed result exists in the cache before returning. + /// This is useful for queries that read from a [`Steal`] value, to ensure + /// that they are executed before the query that will steal the value. + /// + /// Unlike [`Self::ensure_ok`], a query with all-green inputs will only be + /// skipped if its return value is stored in the disk-cache. This is still + /// more efficient than a regular query, because in that situation the + /// return value doesn't necessarily need to be decoded. + /// + /// (As with all query calls, execution is also skipped if the query result + /// is already cached in memory.) + /// + /// [`Steal`]: rustc_data_structures::steal::Steal #[inline(always)] - pub fn ensure_with_value(self) -> TyCtxtEnsureWithValue<'tcx> { - TyCtxtEnsureWithValue { tcx: self } + pub fn ensure_done(self) -> TyCtxtEnsureDone<'tcx> { + TyCtxtEnsureDone { tcx: self } } /// Returns a transparent wrapper for `TyCtxt` which uses @@ -419,7 +431,7 @@ macro_rules! define_callbacks { })* } - impl<'tcx> TyCtxtEnsureWithValue<'tcx> { + impl<'tcx> TyCtxtEnsureDone<'tcx> { $($(#[$attr])* #[inline(always)] pub fn $name(self, key: query_helper_param_ty!($($K)*)) { diff --git a/compiler/rustc_mir_build/src/builder/mod.rs b/compiler/rustc_mir_build/src/builder/mod.rs index 8eb9f786c59eb..e04c70b588377 100644 --- a/compiler/rustc_mir_build/src/builder/mod.rs +++ b/compiler/rustc_mir_build/src/builder/mod.rs @@ -47,7 +47,7 @@ pub(crate) fn closure_saved_names_of_captured_variables<'tcx>( /// Create the MIR for a given `DefId`, including unreachable code. Do not call /// this directly; instead use the cached version via `mir_built`. pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> { - tcx.ensure_with_value().thir_abstract_const(def); + tcx.ensure_done().thir_abstract_const(def); if let Err(e) = tcx.check_match(def) { return construct_error(tcx, def, e); } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 995bc311b7c48..0cca0a43143fd 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -200,7 +200,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { fn visit_inner_body(&mut self, def: LocalDefId) { if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) { // Runs all other queries that depend on THIR. - self.tcx.ensure_with_value().mir_built(def); + self.tcx.ensure_done().mir_built(def); let inner_thir = &inner_thir.steal(); let hir_context = self.tcx.local_def_id_to_hir_id(def); let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe); @@ -1112,7 +1112,7 @@ pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { let Ok((thir, expr)) = tcx.thir_body(def) else { return }; // Runs all other queries that depend on THIR. - tcx.ensure_with_value().mir_built(def); + tcx.ensure_done().mir_built(def); let thir = &thir.steal(); let hir_id = tcx.local_def_id_to_hir_id(def); diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 4af9a111bdf98..b572f6ca0b36a 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -421,11 +421,11 @@ fn mir_promoted( }; // the `has_ffi_unwind_calls` query uses the raw mir, so make sure it is run. - tcx.ensure_with_value().has_ffi_unwind_calls(def); + tcx.ensure_done().has_ffi_unwind_calls(def); // the `by_move_body` query uses the raw mir, so make sure it is run. if tcx.needs_coroutine_by_move_body_def_id(def.to_def_id()) { - tcx.ensure_with_value().coroutine_by_move_body_def_id(def); + tcx.ensure_done().coroutine_by_move_body_def_id(def); } let mut body = tcx.mir_built(def).steal(); @@ -488,7 +488,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { /// end up missing the source MIR due to stealing happening. fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { if tcx.is_coroutine(def.to_def_id()) { - tcx.ensure_with_value().mir_coroutine_witnesses(def); + tcx.ensure_done().mir_coroutine_witnesses(def); } // We only need to borrowck non-synthetic MIR. @@ -501,7 +501,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & if pm::should_run_pass(tcx, &inline::Inline, pm::Optimizations::Allowed) || inline::ForceInline::should_run_pass_for_callee(tcx, def.to_def_id()) { - tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id())); + tcx.ensure_done().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id())); } } @@ -733,7 +733,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> { // Run the `mir_for_ctfe` query, which depends on `mir_drops_elaborated_and_const_checked` // which we are going to steal below. Thus we need to run `mir_for_ctfe` first, so it // computes and caches its result. - Some(hir::ConstContext::ConstFn) => tcx.ensure_with_value().mir_for_ctfe(did), + Some(hir::ConstContext::ConstFn) => tcx.ensure_done().mir_for_ctfe(did), None => {} Some(other) => panic!("do not use `optimized_mir` for constants: {other:?}"), } @@ -772,7 +772,7 @@ fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec Date: Thu, 30 Jan 2025 16:41:12 +1100 Subject: [PATCH 09/12] Rename `ensure_forwards_result_if_red` to `return_result_from_ensure_ok` --- compiler/rustc_macros/src/query.rs | 26 +++++++++++++-------- compiler/rustc_middle/src/query/mod.rs | 20 ++++++++-------- compiler/rustc_middle/src/query/plumbing.rs | 10 ++++++-- 3 files changed, 34 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index 88ea6e07d6eb6..62bf34ad5adce 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -118,11 +118,17 @@ struct QueryModifiers { /// Generate a `feed` method to set the query's value from another query. feedable: Option, - /// Forward the result on ensure if the query gets recomputed, and - /// return `Ok(())` otherwise. Only applicable to queries returning - /// `Result`. The `T` is not returned from `ensure` - /// invocations. - ensure_forwards_result_if_red: Option, + /// When this query is called via `tcx.ensure_ok()`, it returns + /// `Result<(), ErrorGuaranteed>` instead of `()`. If the query needs to + /// be executed, and that execution returns an error, the error result is + /// returned to the caller. + /// + /// If execution is skipped, a synthetic `Ok(())` is returned, on the + /// assumption that a query with all-green inputs must have succeeded. + /// + /// Can only be applied to queries with a return value of + /// `Result<_, ErrorGuaranteed>`. + return_result_from_ensure_ok: Option, } fn parse_query_modifiers(input: ParseStream<'_>) -> Result { @@ -138,7 +144,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { let mut depth_limit = None; let mut separate_provide_extern = None; let mut feedable = None; - let mut ensure_forwards_result_if_red = None; + let mut return_result_from_ensure_ok = None; while !input.is_empty() { let modifier: Ident = input.parse()?; @@ -200,8 +206,8 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { try_insert!(separate_provide_extern = modifier); } else if modifier == "feedable" { try_insert!(feedable = modifier); - } else if modifier == "ensure_forwards_result_if_red" { - try_insert!(ensure_forwards_result_if_red = modifier); + } else if modifier == "return_result_from_ensure_ok" { + try_insert!(return_result_from_ensure_ok = modifier); } else { return Err(Error::new(modifier.span(), "unknown query modifier")); } @@ -222,7 +228,7 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result { depth_limit, separate_provide_extern, feedable, - ensure_forwards_result_if_red, + return_result_from_ensure_ok, }) } @@ -354,7 +360,7 @@ pub(super) fn rustc_queries(input: TokenStream) -> TokenStream { eval_always, depth_limit, separate_provide_extern, - ensure_forwards_result_if_red, + return_result_from_ensure_ok, ); if modifiers.cache.is_some() { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 934593dfb7979..6c442fc1047fa 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1087,7 +1087,7 @@ rustc_queries! { query check_mod_type_wf(key: LocalModDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that types are well-formed in {}", describe_as_module(key, tcx) } - ensure_forwards_result_if_red + return_result_from_ensure_ok } /// Caches `CoerceUnsized` kinds for impls on custom types. @@ -1095,7 +1095,7 @@ rustc_queries! { desc { |tcx| "computing CoerceUnsized info for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } separate_provide_extern - ensure_forwards_result_if_red + return_result_from_ensure_ok } query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> { @@ -1110,7 +1110,7 @@ rustc_queries! { query coherent_trait(def_id: DefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "coherence checking all impls of trait `{}`", tcx.def_path_str(def_id) } - ensure_forwards_result_if_red + return_result_from_ensure_ok } /// Borrow-checks the function body. If this is a closure, returns @@ -1140,7 +1140,7 @@ rustc_queries! { /// query crate_inherent_impls_validity_check(_: ()) -> Result<(), ErrorGuaranteed> { desc { "check for inherent impls that should not be defined in crate" } - ensure_forwards_result_if_red + return_result_from_ensure_ok } /// Checks all types in the crate for overlap in their inherent impls. Reports errors. @@ -1152,7 +1152,7 @@ rustc_queries! { /// query crate_inherent_impls_overlap_check(_: ()) -> Result<(), ErrorGuaranteed> { desc { "check for overlap between inherent impls defined in this crate" } - ensure_forwards_result_if_red + return_result_from_ensure_ok } /// Checks whether all impls in the crate pass the overlap check, returning @@ -1162,7 +1162,7 @@ rustc_queries! { "checking whether impl `{}` follows the orphan rules", tcx.def_path_str(key), } - ensure_forwards_result_if_red + return_result_from_ensure_ok } /// Check whether the function has any recursion that could cause the inliner to trigger @@ -1479,7 +1479,7 @@ rustc_queries! { query specialization_graph_of(trait_id: DefId) -> Result<&'tcx specialization_graph::Graph, ErrorGuaranteed> { desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) } cache_on_disk_if { true } - ensure_forwards_result_if_red + return_result_from_ensure_ok } query dyn_compatibility_violations(trait_id: DefId) -> &'tcx [DynCompatibilityViolation] { desc { |tcx| "determining dyn-compatibility of trait `{}`", tcx.def_path_str(trait_id) } @@ -1715,12 +1715,12 @@ rustc_queries! { query check_well_formed(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) } - ensure_forwards_result_if_red + return_result_from_ensure_ok } query enforce_impl_non_lifetime_params_are_constrained(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking that `{}`'s generics are constrained by the impl header", tcx.def_path_str(key) } - ensure_forwards_result_if_red + return_result_from_ensure_ok } // The `DefId`s of all non-generic functions and statics in the given crate @@ -2442,7 +2442,7 @@ rustc_queries! { /// Any other def id will ICE. query compare_impl_item(key: LocalDefId) -> Result<(), ErrorGuaranteed> { desc { |tcx| "checking assoc item `{}` is compatible with trait definition", tcx.def_path_str(key) } - ensure_forwards_result_if_red + return_result_from_ensure_ok } query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] { diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 6648e3d9d53b5..6c1ef046a60a5 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -118,6 +118,12 @@ impl<'tcx> TyCtxt<'tcx> { /// /// Therefore, this call mode is not appropriate for callers that want to /// ensure that the query is _never_ executed in the future. + /// + /// ## `return_result_from_ensure_ok` + /// If a query has the `return_result_from_ensure_ok` modifier, calls via + /// `ensure_ok` will instead return `Result<(), ErrorGuaranteed>`. If the + /// query needs to be executed, and execution returns an error, that error + /// is returned to the caller. #[inline(always)] pub fn ensure_ok(self) -> TyCtxtEnsureOk<'tcx> { TyCtxtEnsureOk { tcx: self } @@ -223,7 +229,7 @@ macro_rules! query_ensure { ([]$($args:tt)*) => { query_ensure($($args)*) }; - ([(ensure_forwards_result_if_red) $($rest:tt)*]$($args:tt)*) => { + ([(return_result_from_ensure_ok) $($rest:tt)*]$($args:tt)*) => { query_ensure_error_guaranteed($($args)*).map(|_| ()) }; ([$other:tt $($modifiers:tt)*]$($args:tt)*) => { @@ -282,7 +288,7 @@ macro_rules! ensure_ok_result { ( [] ) => { () }; - ( [(ensure_forwards_result_if_red) $($rest:tt)*] ) => { + ( [(return_result_from_ensure_ok) $($rest:tt)*] ) => { Result<(), ErrorGuaranteed> }; ( [$other:tt $($modifiers:tt)*] ) => { From 3581512fb897053099f5ee010bdf4527b0157b9e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 30 Jan 2025 16:59:07 +1100 Subject: [PATCH 10/12] Use an explicit type when discarding the result of `tcx.ensure_ok()` --- compiler/rustc_hir_analysis/src/lib.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 274dbb1ec1c87..3af4318544e96 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -100,7 +100,7 @@ use rustc_middle::middle; use rustc_middle::mir::interpret::GlobalId; use rustc_middle::query::Providers; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_trait_selection::traits; pub use crate::collect::suggest_impl_trait; @@ -139,16 +139,20 @@ pub fn check_crate(tcx: TyCtxt<'_>) { let _prof_timer = tcx.sess.timer("type_check_crate"); tcx.sess.time("coherence_checking", || { + // When discarding query call results, use an explicit type to indicate + // what we are intending to discard, to help future type-based refactoring. + type R = Result<(), ErrorGuaranteed>; + tcx.hir().par_for_each_module(|module| { - let _ = tcx.ensure_ok().check_mod_type_wf(module); + let _: R = tcx.ensure_ok().check_mod_type_wf(module); }); for &trait_def_id in tcx.all_local_trait_impls(()).keys() { - let _ = tcx.ensure_ok().coherent_trait(trait_def_id); + let _: R = tcx.ensure_ok().coherent_trait(trait_def_id); } // these queries are executed for side-effects (error reporting): - let _ = tcx.ensure_ok().crate_inherent_impls_validity_check(()); - let _ = tcx.ensure_ok().crate_inherent_impls_overlap_check(()); + let _: R = tcx.ensure_ok().crate_inherent_impls_validity_check(()); + let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(()); }); if tcx.features().rustc_attrs() { From 3ae0239f85e13c07810d7d6f941ed319fccefb6e Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 30 Jan 2025 17:24:19 +1100 Subject: [PATCH 11/12] Mark the tcx-ensure wrapper types with `#[must_use]` --- compiler/rustc_middle/src/query/plumbing.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index 6c1ef046a60a5..6c019b427dbd1 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -88,11 +88,13 @@ impl<'tcx> Deref for TyCtxtAt<'tcx> { } #[derive(Copy, Clone)] +#[must_use] pub struct TyCtxtEnsureOk<'tcx> { pub tcx: TyCtxt<'tcx>, } #[derive(Copy, Clone)] +#[must_use] pub struct TyCtxtEnsureDone<'tcx> { pub tcx: TyCtxt<'tcx>, } From 06171066d2ff8d71138c42f5f7c9c7e906be1102 Mon Sep 17 00:00:00 2001 From: Marijn Schouten Date: Mon, 27 Jan 2025 15:00:21 +0100 Subject: [PATCH 12/12] Fix sentence in process::abort --- library/std/src/process.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index e0dd2e14817a8..fd0fd1cb755e0 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -2318,14 +2318,10 @@ pub fn exit(code: i32) -> ! { /// Terminates the process in an abnormal fashion. /// /// The function will never return and will immediately terminate the current -/// process in a platform specific "abnormal" manner. -/// -/// Note that because this function never returns, and that it terminates the -/// process, no destructors on the current stack or any other thread's stack -/// will be run. -/// -/// Rust IO buffers (eg, from `BufWriter`) will not be flushed. -/// Likewise, C stdio buffers will (on most platforms) not be flushed. +/// process in a platform specific "abnormal" manner. As a consequence, +/// no destructors on the current stack or any other thread's stack +/// will be run, Rust IO buffers (eg, from `BufWriter`) will not be flushed, +/// and C stdio buffers will (on most platforms) not be flushed. /// /// This is in contrast to the default behavior of [`panic!`] which unwinds /// the current thread's stack and calls all destructors.