From ead02ba0f14f8d54c3c05d8382d317d9b320072a Mon Sep 17 00:00:00 2001 From: Kjetil Kjeka <kjetil@muybridge.com> Date: Fri, 10 May 2024 18:39:05 +0200 Subject: [PATCH 01/15] NVPTX: Avoid PassMode::Direct for args in C abi --- compiler/rustc_target/src/abi/call/nvptx64.rs | 9 +- tests/assembly/nvptx-c-abi-arg-v7.rs | 206 ++++++++++++++++ tests/assembly/nvptx-c-abi-ret-v7.rs | 230 ++++++++++++++++++ 3 files changed, 440 insertions(+), 5 deletions(-) create mode 100644 tests/assembly/nvptx-c-abi-arg-v7.rs create mode 100644 tests/assembly/nvptx-c-abi-ret-v7.rs diff --git a/compiler/rustc_target/src/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs index f85fa2419f0f6..c6b6f66e6be87 100644 --- a/compiler/rustc_target/src/abi/call/nvptx64.rs +++ b/compiler/rustc_target/src/abi/call/nvptx64.rs @@ -11,11 +11,10 @@ fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) { } fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) { - if arg.layout.is_aggregate() && arg.layout.size.bits() > 64 { - arg.make_indirect(); - } else { - // FIXME: this is wrong! Need to decide which ABI we really want here. - arg.make_direct_deprecated(); + if arg.layout.is_aggregate() { + arg.make_indirect_byval(None); + } else if arg.layout.size.bits() < 32 { + arg.extend_integer_width_to(32); } } diff --git a/tests/assembly/nvptx-c-abi-arg-v7.rs b/tests/assembly/nvptx-c-abi-arg-v7.rs new file mode 100644 index 0000000000000..99f90ea526e1b --- /dev/null +++ b/tests/assembly/nvptx-c-abi-arg-v7.rs @@ -0,0 +1,206 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 + +// The PTX ABI stability is tied to major versions of the PTX ISA +// These tests assume major version 7 + +// CHECK: .version 7 + +#![feature(abi_ptx, lang_items, no_core)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[repr(C)] +pub struct SingleU8 { + f: u8, +} + +#[repr(C)] +pub struct DoubleU8 { + f: u8, + g: u8, +} + +#[repr(C)] +pub struct TripleU8 { + f: u8, + g: u8, + h: u8, +} + +#[repr(C)] +pub struct TripleU16 { + f: u16, + g: u16, + h: u16, +} +#[repr(C)] +pub struct TripleU32 { + f: u32, + g: u32, + h: u32, +} +#[repr(C)] +pub struct TripleU64 { + f: u64, + g: u64, + h: u64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f32, + g: f32, +} + +#[repr(C)] +pub struct TripleFloat { + f: f32, + g: f32, + h: f32, +} + +#[repr(C)] +pub struct TripleDouble { + f: f64, + g: f64, + h: f64, +} + +#[repr(C)] +pub struct ManyIntegers { + f: u8, + g: u16, + h: u32, + i: u64, +} + +#[repr(C)] +pub struct ManyNumerics { + f: u8, + g: u16, + h: u32, + i: u64, + j: f32, + k: f64, +} + +// CHECK: .visible .func f_u8_arg( +// CHECK: .param .b32 f_u8_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u8_arg(_a: u8) {} + +// CHECK: .visible .func f_u16_arg( +// CHECK: .param .b32 f_u16_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u16_arg(_a: u16) {} + +// CHECK: .visible .func f_u32_arg( +// CHECK: .param .b32 f_u32_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u32_arg(_a: u32) {} + +// CHECK: .visible .func f_u64_arg( +// CHECK: .param .b64 f_u64_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_u64_arg(_a: u64) {} + +// CHECK: .visible .func f_u128_arg( +// CHECK: .param .align 16 .b8 f_u128_arg_param_0[16] +#[no_mangle] +pub unsafe extern "C" fn f_u128_arg(_a: u128) {} + +// CHECK: .visible .func f_i8_arg( +// CHECK: .param .b32 f_i8_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i8_arg(_a: i8) {} + +// CHECK: .visible .func f_i16_arg( +// CHECK: .param .b32 f_i16_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i16_arg(_a: i16) {} + +// CHECK: .visible .func f_i32_arg( +// CHECK: .param .b32 f_i32_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i32_arg(_a: i32) {} + +// CHECK: .visible .func f_i64_arg( +// CHECK: .param .b64 f_i64_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_i64_arg(_a: i64) {} + +// CHECK: .visible .func f_i128_arg( +// CHECK: .param .align 16 .b8 f_i128_arg_param_0[16] +#[no_mangle] +pub unsafe extern "C" fn f_i128_arg(_a: i128) {} + +// CHECK: .visible .func f_f32_arg( +// CHECK: .param .b32 f_f32_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_f32_arg(_a: f32) {} + +// CHECK: .visible .func f_f64_arg( +// CHECK: .param .b64 f_f64_arg_param_0 +#[no_mangle] +pub unsafe extern "C" fn f_f64_arg(_a: f64) {} + +// CHECK: .visible .func f_single_u8_arg( +// CHECK: .param .align 1 .b8 f_single_u8_arg_param_0[1] +#[no_mangle] +pub unsafe extern "C" fn f_single_u8_arg(_a: SingleU8) {} + +// CHECK: .visible .func f_double_u8_arg( +// CHECK: .param .align 1 .b8 f_double_u8_arg_param_0[2] +#[no_mangle] +pub unsafe extern "C" fn f_double_u8_arg(_a: DoubleU8) {} + +// CHECK: .visible .func f_triple_u8_arg( +// CHECK: .param .align 1 .b8 f_triple_u8_arg_param_0[3] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u8_arg(_a: TripleU8) {} + +// CHECK: .visible .func f_triple_u16_arg( +// CHECK: .param .align 2 .b8 f_triple_u16_arg_param_0[6] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u16_arg(_a: TripleU16) {} + +// CHECK: .visible .func f_triple_u32_arg( +// CHECK: .param .align 4 .b8 f_triple_u32_arg_param_0[12] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u32_arg(_a: TripleU32) {} + +// CHECK: .visible .func f_triple_u64_arg( +// CHECK: .param .align 8 .b8 f_triple_u64_arg_param_0[24] +#[no_mangle] +pub unsafe extern "C" fn f_triple_u64_arg(_a: TripleU64) {} + +// CHECK: .visible .func f_many_integers_arg( +// CHECK: .param .align 8 .b8 f_many_integers_arg_param_0[16] +#[no_mangle] +pub unsafe extern "C" fn f_many_integers_arg(_a: ManyIntegers) {} + +// CHECK: .visible .func f_double_float_arg( +// CHECK: .param .align 4 .b8 f_double_float_arg_param_0[8] +#[no_mangle] +pub unsafe extern "C" fn f_double_float_arg(_a: DoubleFloat) {} + +// CHECK: .visible .func f_triple_float_arg( +// CHECK: .param .align 4 .b8 f_triple_float_arg_param_0[12] +#[no_mangle] +pub unsafe extern "C" fn f_triple_float_arg(_a: TripleFloat) {} + +// CHECK: .visible .func f_triple_double_arg( +// CHECK: .param .align 8 .b8 f_triple_double_arg_param_0[24] +#[no_mangle] +pub unsafe extern "C" fn f_triple_double_arg(_a: TripleDouble) {} + +// CHECK: .visible .func f_many_numerics_arg( +// CHECK: .param .align 8 .b8 f_many_numerics_arg_param_0[32] +#[no_mangle] +pub unsafe extern "C" fn f_many_numerics_arg(_a: ManyNumerics) {} diff --git a/tests/assembly/nvptx-c-abi-ret-v7.rs b/tests/assembly/nvptx-c-abi-ret-v7.rs new file mode 100644 index 0000000000000..0c1594a5f2007 --- /dev/null +++ b/tests/assembly/nvptx-c-abi-ret-v7.rs @@ -0,0 +1,230 @@ +//@ assembly-output: ptx-linker +//@ compile-flags: --crate-type cdylib -C target-cpu=sm_86 -Z unstable-options -Clinker-flavor=llbc +//@ only-nvptx64 +//@ ignore-nvptx64 + +// The PTX ABI stability is tied to major versions of the PTX ISA +// These tests assume major version 7 + +// CHECK: .version 7 + +#![feature(abi_ptx, lang_items, no_core)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[repr(C)] +pub struct SingleU8 { + f: u8, +} + +#[repr(C)] +pub struct DoubleU8 { + f: u8, + g: u8, +} + +#[repr(C)] +pub struct TripleU8 { + f: u8, + g: u8, + h: u8, +} + +#[repr(C)] +pub struct TripleU16 { + f: u16, + g: u16, + h: u16, +} +#[repr(C)] +pub struct TripleU32 { + f: u32, + g: u32, + h: u32, +} +#[repr(C)] +pub struct TripleU64 { + f: u64, + g: u64, + h: u64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f32, + g: f32, +} + +#[repr(C)] +pub struct TripleFloat { + f: f32, + g: f32, + h: f32, +} + +#[repr(C)] +pub struct TripleDouble { + f: f64, + g: f64, + h: f64, +} + +#[repr(C)] +pub struct ManyIntegers { + f: u8, + g: u16, + h: u32, + i: u64, +} + +#[repr(C)] +pub struct ManyNumerics { + f: u8, + g: u16, + h: u32, + i: u64, + j: f32, + k: f64, +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u8_ret() -> u8 { + 0 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_u16_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u16_ret() -> u16 { + 1 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_u32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u32_ret() -> u32 { + 2 +} + +// CHECK: .visible .func (.param .b64 func_retval0) f_u64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u64_ret() -> u64 { + 3 +} + +// CHECK: .visible .func (.param .align 16 .b8 func_retval0[16]) f_u128_ret( +#[no_mangle] +pub unsafe extern "C" fn f_u128_ret() -> u128 { + 4 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_i8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i8_ret() -> i8 { + 5 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_i16_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i16_ret() -> i16 { + 6 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_i32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i32_ret() -> i32 { + 7 +} + +// CHECK: .visible .func (.param .b64 func_retval0) f_i64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i64_ret() -> i64 { + 8 +} + +// CHECK: .visible .func (.param .align 16 .b8 func_retval0[16]) f_i128_ret( +#[no_mangle] +pub unsafe extern "C" fn f_i128_ret() -> i128 { + 9 +} + +// CHECK: .visible .func (.param .b32 func_retval0) f_f32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_f32_ret() -> f32 { + 10.0 +} + +// CHECK: .visible .func (.param .b64 func_retval0) f_f64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_f64_ret() -> f64 { + 11.0 +} + +// CHECK: .visible .func (.param .align 1 .b8 func_retval0[1]) f_single_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_single_u8_ret() -> SingleU8 { + SingleU8 { f: 12 } +} + +// CHECK: .visible .func (.param .align 1 .b8 func_retval0[2]) f_double_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_double_u8_ret() -> DoubleU8 { + DoubleU8 { f: 13, g: 14 } +} + +// CHECK: .visible .func (.param .align 1 .b8 func_retval0[3]) f_triple_u8_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u8_ret() -> TripleU8 { + TripleU8 { f: 15, g: 16, h: 17 } +} + +// CHECK: .visible .func (.param .align 2 .b8 func_retval0[6]) f_triple_u16_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u16_ret() -> TripleU16 { + TripleU16 { f: 18, g: 19, h: 20 } +} + +// CHECK: .visible .func (.param .align 4 .b8 func_retval0[12]) f_triple_u32_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u32_ret() -> TripleU32 { + TripleU32 { f: 20, g: 21, h: 22 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[24]) f_triple_u64_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_u64_ret() -> TripleU64 { + TripleU64 { f: 23, g: 24, h: 25 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[16]) f_many_integers_ret( +#[no_mangle] +pub unsafe extern "C" fn f_many_integers_ret() -> ManyIntegers { + ManyIntegers { f: 26, g: 27, h: 28, i: 29 } +} + +// CHECK: .visible .func (.param .align 4 .b8 func_retval0[8]) f_double_float_ret( +#[no_mangle] +pub unsafe extern "C" fn f_double_float_ret() -> DoubleFloat { + DoubleFloat { f: 29.0, g: 30.0 } +} + +// CHECK: .visible .func (.param .align 4 .b8 func_retval0[12]) f_triple_float_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_float_ret() -> TripleFloat { + TripleFloat { f: 31.0, g: 32.0, h: 33.0 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[24]) f_triple_double_ret( +#[no_mangle] +pub unsafe extern "C" fn f_triple_double_ret() -> TripleDouble { + TripleDouble { f: 34.0, g: 35.0, h: 36.0 } +} + +// CHECK: .visible .func (.param .align 8 .b8 func_retval0[32]) f_many_numerics_ret( +#[no_mangle] +pub unsafe extern "C" fn f_many_numerics_ret() -> ManyNumerics { + ManyNumerics { f: 37, g: 38, h: 39, i: 40, j: 41.0, k: 43.0 } +} From f63931bc1a8cc44e7fd5cea772da87dfac44bedc Mon Sep 17 00:00:00 2001 From: Chris Denton <chris@chrisdenton.dev> Date: Sun, 26 May 2024 22:00:43 +0000 Subject: [PATCH 02/15] Cleanup custom mingw in CI --- .github/workflows/ci.yml | 3 --- src/ci/github-actions/jobs.yml | 4 ---- src/ci/scripts/install-mingw.sh | 17 ++++------------- src/ci/scripts/install-msys2.sh | 27 --------------------------- 4 files changed, 4 insertions(+), 47 deletions(-) delete mode 100755 src/ci/scripts/install-msys2.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0551d44649cdd..3f9936dc5b23e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -155,9 +155,6 @@ jobs: - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh - - name: install MSYS2 - run: src/ci/scripts/install-msys2.sh - - name: install MinGW run: src/ci/scripts/install-mingw.sh diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 05470eebf014b..ca86f3f0110ec 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -378,7 +378,6 @@ auto: # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 <<: *job-windows-8c - image: x86_64-mingw @@ -390,7 +389,6 @@ auto: # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 <<: *job-windows-8c - image: dist-x86_64-msvc @@ -439,7 +437,6 @@ auto: # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 SCRIPT: python x.py dist bootstrap --include-default-paths - CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-8c @@ -453,7 +450,6 @@ auto: # We are intentionally allowing an old toolchain on this builder (and that's # incompatible with LLVM downloads today). NO_DOWNLOAD_CI_LLVM: 1 - CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-8c diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 45541b8b6934d..38af8b6acebb6 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -1,8 +1,6 @@ #!/bin/bash # If we need to download a custom MinGW, do so here and set the path # appropriately. -# -# Otherwise install MinGW through `pacman` set -euo pipefail IFS=$'\n\t' @@ -16,19 +14,16 @@ if isWindows && isKnownToBeMingwBuild; then case "${CI_JOB_NAME}" in *i686*) bits=32 - arch=i686 mingw_archive="${MINGW_ARCHIVE_32}" ;; *x86_64*) bits=64 - arch=x86_64 mingw_archive="${MINGW_ARCHIVE_64}" ;; *aarch64*) # aarch64 is a cross-compiled target. Use the x86_64 # mingw, since that's the host architecture. bits=64 - arch=x86_64 mingw_archive="${MINGW_ARCHIVE_64}" ;; *) @@ -38,13 +33,9 @@ if isWindows && isKnownToBeMingwBuild; then ;; esac - if [[ "${CUSTOM_MINGW:-0}" == 0 ]]; then - pacman -S --noconfirm --needed mingw-w64-$arch-toolchain - else - mingw_dir="mingw${bits}" + mingw_dir="mingw${bits}" - curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" - 7z x -y mingw.7z > /dev/null - ciCommandAddPath "$(pwd)/${mingw_dir}/bin" - fi + curl -o mingw.7z "${MIRRORS_BASE}/${mingw_archive}" + 7z x -y mingw.7z > /dev/null + ciCommandAddPath "$(pwd)/${mingw_dir}/bin" fi diff --git a/src/ci/scripts/install-msys2.sh b/src/ci/scripts/install-msys2.sh deleted file mode 100755 index 968b1e572e43b..0000000000000 --- a/src/ci/scripts/install-msys2.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -# Clean up and prepare the MSYS2 installation. -# MSYS2 is used by the MinGW toolchain for assembling things. - -set -euo pipefail -IFS=$'\n\t' - -source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" -if isWindows; then - # Detect the native Python version installed on the agent. On GitHub - # Actions, the C:\hostedtoolcache\windows\Python directory contains a - # subdirectory for each installed Python version. - # - # The -V flag of the sort command sorts the input by version number. - native_python_version="$(ls /c/hostedtoolcache/windows/Python | sort -Vr | head -n 1)" - - # Make sure we use the native python interpreter instead of some msys equivalent - # one way or another. The msys interpreters seem to have weird path conversions - # baked in which break LLVM's build system one way or another, so let's use the - # native version which keeps everything as native as possible. - python_home="/c/hostedtoolcache/windows/Python/${native_python_version}/x64" - if ! [[ -f "${python_home}/python3.exe" ]]; then - cp "${python_home}/python.exe" "${python_home}/python3.exe" - fi - ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64" - ciCommandAddPath "C:\\hostedtoolcache\\windows\\Python\\${native_python_version}\\x64\\Scripts" -fi From 19cfe8d9e6989c4ea49be203757cd086e0ab015c Mon Sep 17 00:00:00 2001 From: Chris Denton <chris@chrisdenton.dev> Date: Sun, 26 May 2024 22:01:26 +0000 Subject: [PATCH 03/15] Add "Setup Python" action to github-hosted runners --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3f9936dc5b23e..c9d6c56076a97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -154,6 +154,12 @@ jobs: - name: checkout submodules run: src/ci/scripts/checkout-submodules.sh + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + if: runner.environment == 'github-hosted' - name: install MinGW run: src/ci/scripts/install-mingw.sh From ede62b867c90eb8f00618eab95b0ecc35defd53b Mon Sep 17 00:00:00 2001 From: Scott McMurray <scottmcm@users.noreply.github.com> Date: Sun, 21 Apr 2024 16:11:01 -0700 Subject: [PATCH 04/15] Add an intrinsic for `ptr::metadata` --- compiler/rustc_codegen_cranelift/src/base.rs | 20 ++++-- .../rustc_codegen_cranelift/src/constant.rs | 2 +- .../src/value_and_place.rs | 8 +++ compiler/rustc_codegen_ssa/src/mir/operand.rs | 5 ++ compiler/rustc_codegen_ssa/src/mir/place.rs | 5 ++ compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 34 +++++++--- .../rustc_const_eval/src/interpret/cast.rs | 2 +- .../src/interpret/operator.rs | 28 +++++++-- .../rustc_hir_analysis/src/check/intrinsic.rs | 2 + compiler/rustc_middle/src/mir/syntax.rs | 7 +++ compiler/rustc_middle/src/mir/tcx.rs | 26 +++++++- compiler/rustc_middle/src/ty/print/pretty.rs | 2 + .../src/lower_intrinsics.rs | 17 +++++ .../rustc_mir_transform/src/promote_consts.rs | 2 +- compiler/rustc_mir_transform/src/validate.rs | 10 +++ .../rustc_smir/src/rustc_internal/internal.rs | 14 ++++- compiler/rustc_smir/src/rustc_smir/context.rs | 10 ++- .../rustc_smir/src/rustc_smir/convert/mir.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_ty_utils/src/consts.rs | 2 +- compiler/stable_mir/src/compiler_interface.rs | 5 +- compiler/stable_mir/src/mir/body.rs | 14 ++++- library/core/src/intrinsics.rs | 15 +++++ library/core/src/ptr/metadata.rs | 21 +++++-- library/core/tests/ptr.rs | 12 ++++ tests/codegen/intrinsics/ptr_metadata.rs | 36 +++++++++++ ..._metadata.LowerIntrinsics.panic-abort.diff | 63 +++++++++++++++++++ ...metadata.LowerIntrinsics.panic-unwind.diff | 63 +++++++++++++++++++ tests/mir-opt/lower_intrinsics.rs | 9 +++ ...e_add_fat.PreCodegen.after.panic-abort.mir | 10 +-- ..._add_fat.PreCodegen.after.panic-unwind.mir | 10 +-- 31 files changed, 413 insertions(+), 43 deletions(-) create mode 100644 tests/codegen/intrinsics/ptr_metadata.rs create mode 100644 tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff create mode 100644 tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 8d778f736d671..476a3912b968b 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -619,9 +619,10 @@ fn codegen_stmt<'tcx>( Rvalue::UnaryOp(un_op, ref operand) => { let operand = codegen_operand(fx, operand); let layout = operand.layout(); - let val = operand.load_scalar(fx); let res = match un_op { - UnOp::Not => match layout.ty.kind() { + UnOp::Not => { + let val = operand.load_scalar(fx); + match layout.ty.kind() { ty::Bool => { let res = fx.bcx.ins().icmp_imm(IntCC::Equal, val, 0); CValue::by_val(res, layout) @@ -630,11 +631,22 @@ fn codegen_stmt<'tcx>( CValue::by_val(fx.bcx.ins().bnot(val), layout) } _ => unreachable!("un op Not for {:?}", layout.ty), - }, - UnOp::Neg => match layout.ty.kind() { + } + } + UnOp::Neg => { + let val = operand.load_scalar(fx); + match layout.ty.kind() { ty::Int(_) => CValue::by_val(fx.bcx.ins().ineg(val), layout), ty::Float(_) => CValue::by_val(fx.bcx.ins().fneg(val), layout), _ => unreachable!("un op Neg for {:?}", layout.ty), + } + } + UnOp::PtrMetadata => match layout.abi { + Abi::Scalar(_) => CValue::zst(dest_layout), + Abi::ScalarPair(_, _) => { + CValue::by_val(operand.load_scalar_pair(fx).1, dest_layout) + } + _ => bug!("Unexpected `PtrToMetadata` operand: {operand:?}"), }, }; lval.write_cvalue(fx, res); diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 64e83e43d3272..ba98f2e772cbf 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -100,7 +100,7 @@ pub(crate) fn codegen_const_value<'tcx>( assert!(layout.is_sized(), "unsized const value"); if layout.is_zst() { - return CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout); + return CValue::zst(layout); } match const_val { diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 4146137c2263a..512a96450a4b6 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -95,6 +95,14 @@ impl<'tcx> CValue<'tcx> { CValue(CValueInner::ByValPair(value, extra), layout) } + /// Create an instance of a ZST + /// + /// The is represented by a dangling pointer of suitable alignment. + pub(crate) fn zst(layout: TyAndLayout<'tcx>) -> CValue<'tcx> { + assert!(layout.is_zst()); + CValue::by_ref(crate::Pointer::dangling(layout.align.pref), layout) + } + pub(crate) fn layout(&self) -> TyAndLayout<'tcx> { self.1 } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 5b2f9a3be2792..cc0e913965067 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -565,6 +565,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { for elem in place_ref.projection.iter() { match elem { mir::ProjectionElem::Field(ref f, _) => { + debug_assert!( + !o.layout.ty.is_any_ptr(), + "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \ + but tried to access field {f:?} of pointer {o:?}", + ); o = o.extract_field(bx, f.index()); } mir::ProjectionElem::Index(_) diff --git a/compiler/rustc_codegen_ssa/src/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs index 7c3569a9dd2e2..449fd9ae0db9c 100644 --- a/compiler/rustc_codegen_ssa/src/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -480,6 +480,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cg_base = match *elem { mir::ProjectionElem::Deref => bx.load_operand(cg_base).deref(bx.cx()), mir::ProjectionElem::Field(ref field, _) => { + debug_assert!( + !cg_base.layout.ty.is_any_ptr(), + "Bad PlaceRef: destructing pointers should use cast/PtrMetadata, \ + but tried to access field {field:?} of pointer {cg_base:?}", + ); cg_base.project_field(bx, field.index()) } mir::ProjectionElem::OpaqueCast(ty) => { diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 4dd80d34ea703..c23867be3a10d 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -623,19 +623,36 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { mir::Rvalue::UnaryOp(op, ref operand) => { let operand = self.codegen_operand(bx, operand); - let lloperand = operand.immediate(); let is_float = operand.layout.ty.is_floating_point(); - let llval = match op { - mir::UnOp::Not => bx.not(lloperand), + let (val, layout) = match op { + mir::UnOp::Not => { + let llval = bx.not(operand.immediate()); + (OperandValue::Immediate(llval), operand.layout) + } mir::UnOp::Neg => { - if is_float { - bx.fneg(lloperand) + let llval = if is_float { + bx.fneg(operand.immediate()) + } else { + bx.neg(operand.immediate()) + }; + (OperandValue::Immediate(llval), operand.layout) + } + mir::UnOp::PtrMetadata => { + debug_assert!(operand.layout.ty.is_unsafe_ptr()); + let (_, meta) = operand.val.pointer_parts(); + assert_eq!(operand.layout.fields.count() > 1, meta.is_some()); + if let Some(meta) = meta { + (OperandValue::Immediate(meta), operand.layout.field(self.cx, 1)) } else { - bx.neg(lloperand) + (OperandValue::ZeroSized, bx.cx().layout_of(bx.tcx().types.unit)) } } }; - OperandRef { val: OperandValue::Immediate(llval), layout: operand.layout } + debug_assert!( + val.is_expected_variant_for_type(self.cx, layout), + "Made wrong variant {val:?} for type {layout:?}", + ); + OperandRef { val, layout } } mir::Rvalue::Discriminant(ref place) => { @@ -718,8 +735,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let values = op.val.immediates_or_place().left_or_else(|p| { bug!("Field {field_idx:?} is {p:?} making {layout:?}"); }); - inputs.extend(values); let scalars = self.value_kind(op.layout).scalars().unwrap(); + debug_assert_eq!(values.len(), scalars.len()); + inputs.extend(values); input_scalars.extend(scalars); } diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index ecfb25e32cda7..d599d4353754a 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -207,7 +207,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { assert!(cast_to.ty.is_unsafe_ptr()); // Handle casting any ptr to raw ptr (might be a fat ptr). if cast_to.size == src.layout.size { - // Thin or fat pointer that just hast the ptr kind of target type changed. + // Thin or fat pointer that just has the ptr kind of target type changed. return Ok(ImmTy::from_immediate(**src, cast_to)); } else { // Casting the metadata away from a fat ptr. diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs index 62641b868e623..4d91ca651616e 100644 --- a/compiler/rustc_const_eval/src/interpret/operator.rs +++ b/compiler/rustc_const_eval/src/interpret/operator.rs @@ -9,7 +9,7 @@ use rustc_middle::{bug, span_bug}; use rustc_span::symbol::sym; use tracing::trace; -use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine}; +use super::{err_ub, throw_ub, ImmTy, InterpCx, Machine, MemPlaceMeta}; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> { @@ -415,11 +415,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { use rustc_middle::mir::UnOp::*; let layout = val.layout; - let val = val.to_scalar(); trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty); match layout.ty.kind() { ty::Bool => { + let val = val.to_scalar(); let val = val.to_bool()?; let res = match un_op { Not => !val, @@ -428,6 +428,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(ImmTy::from_bool(res, *self.tcx)) } ty::Float(fty) => { + let val = val.to_scalar(); // No NaN adjustment here, `-` is a bitwise operation! let res = match (un_op, fty) { (Neg, FloatTy::F32) => Scalar::from_f32(-val.to_f32()?), @@ -436,8 +437,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; Ok(ImmTy::from_scalar(res, layout)) } - _ => { - assert!(layout.ty.is_integral()); + _ if layout.ty.is_integral() => { + let val = val.to_scalar(); let val = val.to_bits(layout.size)?; let res = match un_op { Not => self.truncate(!val, layout), // bitwise negation, then truncate @@ -450,9 +451,28 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Truncate to target type. self.truncate(res, layout) } + _ => span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op), }; Ok(ImmTy::from_uint(res, layout)) } + ty::RawPtr(..) => { + assert_eq!(un_op, PtrMetadata); + let (_, meta) = val.to_scalar_and_meta(); + Ok(match meta { + MemPlaceMeta::Meta(scalar) => { + let ty = un_op.ty(*self.tcx, val.layout.ty); + let layout = self.layout_of(ty)?; + ImmTy::from_scalar(scalar, layout) + } + MemPlaceMeta::None => { + let unit_layout = self.layout_of(self.tcx.types.unit)?; + ImmTy::uninit(unit_layout) + } + }) + } + _ => { + bug!("Unexpected unary op argument {val:?}") + } } } } diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs index 8506b8d75f957..f7989aeab41bb 100644 --- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs +++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs @@ -130,6 +130,7 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: LocalDefId) - | sym::is_val_statically_known | sym::ptr_mask | sym::aggregate_raw_ptr + | sym::ptr_metadata | sym::ub_checks | sym::fadd_algebraic | sym::fsub_algebraic @@ -576,6 +577,7 @@ pub fn check_intrinsic_type( // This type check is not particularly useful, but the `where` bounds // on the definition in `core` do the heavy lifting for checking it. sym::aggregate_raw_ptr => (3, 1, vec![param(1), param(2)], param(0)), + sym::ptr_metadata => (2, 1, vec![Ty::new_imm_ptr(tcx, param(0))], param(1)), sym::ub_checks => (0, 1, Vec::new(), tcx.types.bool), diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 2b28496faec73..47da924ba49af 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -1434,6 +1434,13 @@ pub enum UnOp { Not, /// The `-` operator for negation Neg, + /// Get the metadata `M` from a `*const/mut impl Pointee<Metadata = M>`. + /// + /// For example, this will give a `()` from `*const i32`, a `usize` from + /// `*mut [u8]`, or a pointer to a vtable from a `*const dyn Foo`. + /// + /// Allowed only in [`MirPhase::Runtime`]; earlier it's an intrinsic. + PtrMetadata, } #[derive(Copy, Clone, Debug, PartialEq, PartialOrd, Ord, Eq, Hash)] diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index a122cffdb876a..126387db1d9c5 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -180,7 +180,10 @@ impl<'tcx> Rvalue<'tcx> { let rhs_ty = rhs.ty(local_decls, tcx); op.ty(tcx, lhs_ty, rhs_ty) } - Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx), + Rvalue::UnaryOp(op, ref operand) => { + let arg_ty = operand.ty(local_decls, tcx); + op.ty(tcx, arg_ty) + } Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx), Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => { tcx.types.usize @@ -282,6 +285,27 @@ impl<'tcx> BinOp { } } +impl<'tcx> UnOp { + pub fn ty(&self, tcx: TyCtxt<'tcx>, arg_ty: Ty<'tcx>) -> Ty<'tcx> { + match self { + UnOp::Not | UnOp::Neg => arg_ty, + UnOp::PtrMetadata => { + let pointee_ty = arg_ty + .builtin_deref(true) + .unwrap_or_else(|| bug!("PtrMetadata of non-dereferenceable ty {arg_ty:?}")); + if pointee_ty.is_trivially_sized(tcx) { + tcx.types.unit + } else { + let Some(metadata_def_id) = tcx.lang_items().metadata_type() else { + bug!("No metadata_type lang item while looking at {arg_ty:?}") + }; + Ty::new_projection(tcx, metadata_def_id, [pointee_ty]) + } + } + } + } +} + impl BorrowKind { pub fn to_mutbl_lossy(self) -> hir::Mutability { match self { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 0bcd02aaa3acf..183ea76393c86 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1579,8 +1579,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { let formatted_op = match op { UnOp::Not => "!", UnOp::Neg => "-", + UnOp::PtrMetadata => "PtrMetadata", }; let parenthesized = match ct.kind() { + _ if op == UnOp::PtrMetadata => true, ty::ConstKind::Expr(Expr::UnOp(c_op, ..)) => c_op != op, ty::ConstKind::Expr(_) => true, _ => false, diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs index 221301b2ceb04..3ffc447217d7d 100644 --- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs +++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs @@ -316,6 +316,23 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics { terminator.kind = TerminatorKind::Goto { target }; } + sym::ptr_metadata => { + let Ok([ptr]) = <[_; 1]>::try_from(std::mem::take(args)) else { + span_bug!( + terminator.source_info.span, + "Wrong number of arguments for ptr_metadata intrinsic", + ); + }; + let target = target.unwrap(); + block.statements.push(Statement { + source_info: terminator.source_info, + kind: StatementKind::Assign(Box::new(( + *destination, + Rvalue::UnaryOp(UnOp::PtrMetadata, ptr.node), + ))), + }); + terminator.kind = TerminatorKind::Goto { target }; + } _ => {} } } diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index e37f90ae7f400..7ec59cc983f53 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -464,7 +464,7 @@ impl<'tcx> Validator<'_, 'tcx> { Rvalue::UnaryOp(op, operand) => { match op { // These operations can never fail. - UnOp::Neg | UnOp::Not => {} + UnOp::Neg | UnOp::Not | UnOp::PtrMetadata => {} } self.validate_operand(operand)?; diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 66cc65de64709..f3807e731cf3b 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1089,6 +1089,16 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ty::Int(..) | ty::Uint(..) | ty::Bool ); } + UnOp::PtrMetadata => { + if !matches!(self.mir_phase, MirPhase::Runtime(_)) { + // It would probably be fine to support this in earlier phases, + // but at the time of writing it's only ever introduced from intrinsic lowering, + // so earlier things can just `bug!` on it. + self.fail(location, "PtrMetadata should be in runtime MIR only"); + } + + check_kinds!(a, "Cannot PtrMetadata non-pointer type {:?}", ty::RawPtr(..)); + } } } Rvalue::ShallowInitBox(operand, _) => { diff --git a/compiler/rustc_smir/src/rustc_internal/internal.rs b/compiler/rustc_smir/src/rustc_internal/internal.rs index 6b73c1ebd1cac..6ec710f97d16a 100644 --- a/compiler/rustc_smir/src/rustc_internal/internal.rs +++ b/compiler/rustc_smir/src/rustc_internal/internal.rs @@ -10,7 +10,7 @@ use rustc_span::Symbol; use stable_mir::abi::Layout; use stable_mir::mir::alloc::AllocId; use stable_mir::mir::mono::{Instance, MonoItem, StaticDef}; -use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety}; +use stable_mir::mir::{BinOp, Mutability, Place, ProjectionElem, Safety, UnOp}; use stable_mir::ty::{ Abi, AdtDef, Binder, BoundRegionKind, BoundTyKind, BoundVariableKind, ClosureKind, Const, DynKind, ExistentialPredicate, ExistentialProjection, ExistentialTraitRef, FloatTy, FnSig, @@ -582,6 +582,18 @@ impl RustcInternal for BinOp { } } +impl RustcInternal for UnOp { + type T<'tcx> = rustc_middle::mir::UnOp; + + fn internal<'tcx>(&self, _tables: &mut Tables<'_>, _tcx: TyCtxt<'tcx>) -> Self::T<'tcx> { + match self { + UnOp::Not => rustc_middle::mir::UnOp::Not, + UnOp::Neg => rustc_middle::mir::UnOp::Neg, + UnOp::PtrMetadata => rustc_middle::mir::UnOp::PtrMetadata, + } + } +} + impl<T> RustcInternal for &T where T: RustcInternal, diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 7afe46f2cbe1c..fa7b2a30ba6cf 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -19,7 +19,7 @@ use stable_mir::abi::{FnAbi, Layout, LayoutShape}; use stable_mir::compiler_interface::Context; use stable_mir::mir::alloc::GlobalAlloc; use stable_mir::mir::mono::{InstanceDef, StaticDef}; -use stable_mir::mir::{BinOp, Body, Place}; +use stable_mir::mir::{BinOp, Body, Place, UnOp}; use stable_mir::target::{MachineInfo, MachineSize}; use stable_mir::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, @@ -700,6 +700,14 @@ impl<'tcx> Context for TablesWrapper<'tcx> { let ty = bin_op.internal(&mut *tables, tcx).ty(tcx, rhs_internal, lhs_internal); ty.stable(&mut *tables) } + + fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty { + let mut tables = self.0.borrow_mut(); + let tcx = tables.tcx; + let arg_internal = arg.internal(&mut *tables, tcx); + let ty = un_op.internal(&mut *tables, tcx).ty(tcx, arg_internal); + ty.stable(&mut *tables) + } } pub struct TablesWrapper<'tcx>(pub RefCell<Tables<'tcx>>); diff --git a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs index d89caabab3e1a..a1a5c09ef0af4 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/mir.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/mir.rs @@ -526,6 +526,7 @@ impl<'tcx> Stable<'tcx> for mir::UnOp { match self { UnOp::Not => stable_mir::mir::UnOp::Not, UnOp::Neg => stable_mir::mir::UnOp::Neg, + UnOp::PtrMetadata => stable_mir::mir::UnOp::PtrMetadata, } } } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index ace4dff46aa0a..b025fe5454c2f 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1433,6 +1433,7 @@ symbols! { ptr_guaranteed_cmp, ptr_is_null, ptr_mask, + ptr_metadata, ptr_null, ptr_null_mut, ptr_offset_from, diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 67ffb8a58b5ad..6e51368f0315f 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -94,7 +94,7 @@ fn check_binop(op: mir::BinOp) -> bool { fn check_unop(op: mir::UnOp) -> bool { use mir::UnOp::*; match op { - Not | Neg => true, + Not | Neg | PtrMetadata => true, } } diff --git a/compiler/stable_mir/src/compiler_interface.rs b/compiler/stable_mir/src/compiler_interface.rs index 4dd64228bbadb..858ce5301d84c 100644 --- a/compiler/stable_mir/src/compiler_interface.rs +++ b/compiler/stable_mir/src/compiler_interface.rs @@ -8,7 +8,7 @@ use std::cell::Cell; use crate::abi::{FnAbi, Layout, LayoutShape}; use crate::mir::alloc::{AllocId, GlobalAlloc}; use crate::mir::mono::{Instance, InstanceDef, StaticDef}; -use crate::mir::{BinOp, Body, Place}; +use crate::mir::{BinOp, Body, Place, UnOp}; use crate::target::MachineInfo; use crate::ty::{ AdtDef, AdtKind, Allocation, ClosureDef, ClosureKind, Const, FieldDef, FnDef, ForeignDef, @@ -226,6 +226,9 @@ pub trait Context { /// Get the resulting type of binary operation. fn binop_ty(&self, bin_op: BinOp, rhs: Ty, lhs: Ty) -> Ty; + + /// Get the resulting type of unary operation. + fn unop_ty(&self, un_op: UnOp, arg: Ty) -> Ty; } // A thread local variable that stores a pointer to the tables mapping between TyCtxt diff --git a/compiler/stable_mir/src/mir/body.rs b/compiler/stable_mir/src/mir/body.rs index a1432acf93cb9..4c779ae96a81b 100644 --- a/compiler/stable_mir/src/mir/body.rs +++ b/compiler/stable_mir/src/mir/body.rs @@ -346,6 +346,15 @@ impl BinOp { pub enum UnOp { Not, Neg, + PtrMetadata, +} + +impl UnOp { + /// Return the type of this operation for the given input Ty. + /// This function does not perform type checking, and it currently doesn't handle SIMD. + pub fn ty(&self, arg_ty: Ty) -> Ty { + with(|ctx| ctx.unop_ty(*self, arg_ty)) + } } #[derive(Clone, Debug, Eq, PartialEq)] @@ -580,7 +589,10 @@ impl Rvalue { let ty = op.ty(lhs_ty, rhs_ty); Ok(Ty::new_tuple(&[ty, Ty::bool_ty()])) } - Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, operand) => operand.ty(locals), + Rvalue::UnaryOp(op, operand) => { + let arg_ty = operand.ty(locals)?; + Ok(op.ty(arg_ty)) + } Rvalue::Discriminant(place) => { let place_ty = place.ty(locals)?; place_ty diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 5a2a4c5ae6ebe..89e0b67099519 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2821,6 +2821,21 @@ impl<P: ?Sized, T: ptr::Thin> AggregateRawPtr<*mut T> for *mut P { type Metadata = <P as ptr::Pointee>::Metadata; } +/// Lowers in MIR to `Rvalue::UnaryOp` with `UnOp::PtrMetadata`. +/// +/// This is used to implement functions like `ptr::metadata`. +#[rustc_nounwind] +#[unstable(feature = "core_intrinsics", issue = "none")] +#[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] +#[rustc_intrinsic] +#[rustc_intrinsic_must_be_overridden] +#[cfg(not(bootstrap))] +pub const fn ptr_metadata<P: ptr::Pointee<Metadata = M> + ?Sized, M>(_ptr: *const P) -> M { + // To implement a fallback we'd have to assume the layout of the pointer, + // but the whole point of this intrinsic is that we shouldn't do that. + unreachable!() +} + // Some functions are defined here because they accidentally got made // available in this module on stable. See <https://github.com/rust-lang/rust/issues/15702>. // (`transmute` also falls into this category, but it cannot be wrapped due to the diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index e501970b580de..84287ec3f5142 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -3,6 +3,8 @@ use crate::fmt; use crate::hash::{Hash, Hasher}; use crate::intrinsics::aggregate_raw_ptr; +#[cfg(not(bootstrap))] +use crate::intrinsics::ptr_metadata; use crate::marker::Freeze; /// Provides the pointer metadata type of any pointed-to type. @@ -94,10 +96,17 @@ pub trait Thin = Pointee<Metadata = ()>; #[rustc_const_unstable(feature = "ptr_metadata", issue = "81513")] #[inline] pub const fn metadata<T: ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata { - // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T - // and PtrComponents<T> have the same memory layouts. Only std can make this - // guarantee. - unsafe { PtrRepr { const_ptr: ptr }.components.metadata } + #[cfg(bootstrap)] + { + // SAFETY: Accessing the value from the `PtrRepr` union is safe since *const T + // and PtrComponents<T> have the same memory layouts. Only std can make this + // guarantee. + unsafe { PtrRepr { const_ptr: ptr }.components.metadata } + } + #[cfg(not(bootstrap))] + { + ptr_metadata(ptr) + } } /// Forms a (possibly-wide) raw pointer from a data pointer and metadata. @@ -132,6 +141,7 @@ pub const fn from_raw_parts_mut<T: ?Sized>( } #[repr(C)] +#[cfg(bootstrap)] union PtrRepr<T: ?Sized> { const_ptr: *const T, mut_ptr: *mut T, @@ -139,15 +149,18 @@ union PtrRepr<T: ?Sized> { } #[repr(C)] +#[cfg(bootstrap)] struct PtrComponents<T: ?Sized> { data_pointer: *const (), metadata: <T as Pointee>::Metadata, } // Manual impl needed to avoid `T: Copy` bound. +#[cfg(bootstrap)] impl<T: ?Sized> Copy for PtrComponents<T> {} // Manual impl needed to avoid `T: Clone` bound. +#[cfg(bootstrap)] impl<T: ?Sized> Clone for PtrComponents<T> { fn clone(&self) -> Self { *self diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 7b55c2bf8a813..e8d05c2483de2 100644 --- a/library/core/tests/ptr.rs +++ b/library/core/tests/ptr.rs @@ -1171,3 +1171,15 @@ fn test_ptr_from_raw_parts_in_const() { assert_eq!(EMPTY_SLICE_PTR.addr(), 123); assert_eq!(EMPTY_SLICE_PTR.len(), 456); } + +#[test] +fn test_ptr_metadata_in_const() { + use std::fmt::Debug; + + const ARRAY_META: () = std::ptr::metadata::<[u16; 3]>(&[1, 2, 3]); + const SLICE_META: usize = std::ptr::metadata::<[u16]>(&[1, 2, 3]); + const DYN_META: DynMetadata<dyn Debug> = std::ptr::metadata::<dyn Debug>(&[0_u8; 42]); + assert_eq!(ARRAY_META, ()); + assert_eq!(SLICE_META, 3); + assert_eq!(DYN_META.size_of(), 42); +} diff --git a/tests/codegen/intrinsics/ptr_metadata.rs b/tests/codegen/intrinsics/ptr_metadata.rs new file mode 100644 index 0000000000000..f4bf5a1f5f173 --- /dev/null +++ b/tests/codegen/intrinsics/ptr_metadata.rs @@ -0,0 +1,36 @@ +//@ compile-flags: -O -C no-prepopulate-passes -Z inline-mir +//@ only-64bit (so I don't need to worry about usize) + +#![crate_type = "lib"] +#![feature(core_intrinsics)] + +use std::intrinsics::ptr_metadata; + +// CHECK-LABEL: @thin_metadata( +#[no_mangle] +pub fn thin_metadata(p: *const ()) { + // CHECK: start + // CHECK-NEXT: ret void + ptr_metadata(p) +} + +// CHECK-LABEL: @slice_metadata( +#[no_mangle] +pub fn slice_metadata(p: *const [u8]) -> usize { + // CHECK: start + // CHECK-NEXT: ret i64 %p.1 + ptr_metadata(p) +} + +// CHECK-LABEL: @dyn_byte_offset( +#[no_mangle] +pub unsafe fn dyn_byte_offset( + p: *const dyn std::fmt::Debug, + n: usize, +) -> *const dyn std::fmt::Debug { + // CHECK: %[[Q:.+]] = getelementptr inbounds i8, ptr %p.0, i64 %n + // CHECK: %[[TEMP1:.+]] = insertvalue { ptr, ptr } poison, ptr %[[Q]], 0 + // CHECK: %[[TEMP2:.+]] = insertvalue { ptr, ptr } %[[TEMP1]], ptr %p.1, 1 + // CHECK: ret { ptr, ptr } %[[TEMP2]] + p.byte_add(n) +} diff --git a/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff new file mode 100644 index 0000000000000..d256058c05ee6 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-abort.diff @@ -0,0 +1,63 @@ +- // MIR for `get_metadata` before LowerIntrinsics ++ // MIR for `get_metadata` after LowerIntrinsics + + fn get_metadata(_1: *const i32, _2: *const [u8], _3: *const dyn Debug) -> () { + debug a => _1; + debug b => _2; + debug c => _3; + let mut _0: (); + let _4: (); + let mut _5: *const i32; + let mut _7: *const [u8]; + let mut _9: *const dyn std::fmt::Debug; + scope 1 { + debug _unit => _4; + let _6: usize; + scope 2 { + debug _usize => _6; + let _8: std::ptr::DynMetadata<dyn std::fmt::Debug>; + scope 3 { + debug _vtable => _8; + } + } + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = ptr_metadata::<i32, ()>(move _5) -> [return: bb1, unwind unreachable]; ++ _4 = PtrMetadata(move _5); ++ goto -> bb1; + } + + bb1: { + StorageDead(_5); + StorageLive(_6); + StorageLive(_7); + _7 = _2; +- _6 = ptr_metadata::<[u8], usize>(move _7) -> [return: bb2, unwind unreachable]; ++ _6 = PtrMetadata(move _7); ++ goto -> bb2; + } + + bb2: { + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + _9 = _3; +- _8 = ptr_metadata::<dyn Debug, DynMetadata<dyn Debug>>(move _9) -> [return: bb3, unwind unreachable]; ++ _8 = PtrMetadata(move _9); ++ goto -> bb3; + } + + bb3: { + StorageDead(_9); + _0 = const (); + StorageDead(_8); + StorageDead(_6); + StorageDead(_4); + return; + } + } + diff --git a/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff new file mode 100644 index 0000000000000..d256058c05ee6 --- /dev/null +++ b/tests/mir-opt/lower_intrinsics.get_metadata.LowerIntrinsics.panic-unwind.diff @@ -0,0 +1,63 @@ +- // MIR for `get_metadata` before LowerIntrinsics ++ // MIR for `get_metadata` after LowerIntrinsics + + fn get_metadata(_1: *const i32, _2: *const [u8], _3: *const dyn Debug) -> () { + debug a => _1; + debug b => _2; + debug c => _3; + let mut _0: (); + let _4: (); + let mut _5: *const i32; + let mut _7: *const [u8]; + let mut _9: *const dyn std::fmt::Debug; + scope 1 { + debug _unit => _4; + let _6: usize; + scope 2 { + debug _usize => _6; + let _8: std::ptr::DynMetadata<dyn std::fmt::Debug>; + scope 3 { + debug _vtable => _8; + } + } + } + + bb0: { + StorageLive(_4); + StorageLive(_5); + _5 = _1; +- _4 = ptr_metadata::<i32, ()>(move _5) -> [return: bb1, unwind unreachable]; ++ _4 = PtrMetadata(move _5); ++ goto -> bb1; + } + + bb1: { + StorageDead(_5); + StorageLive(_6); + StorageLive(_7); + _7 = _2; +- _6 = ptr_metadata::<[u8], usize>(move _7) -> [return: bb2, unwind unreachable]; ++ _6 = PtrMetadata(move _7); ++ goto -> bb2; + } + + bb2: { + StorageDead(_7); + StorageLive(_8); + StorageLive(_9); + _9 = _3; +- _8 = ptr_metadata::<dyn Debug, DynMetadata<dyn Debug>>(move _9) -> [return: bb3, unwind unreachable]; ++ _8 = PtrMetadata(move _9); ++ goto -> bb3; + } + + bb3: { + StorageDead(_9); + _0 = const (); + StorageDead(_8); + StorageDead(_6); + StorageDead(_4); + return; + } + } + diff --git a/tests/mir-opt/lower_intrinsics.rs b/tests/mir-opt/lower_intrinsics.rs index 180bfd0a92462..2569f4f4de5df 100644 --- a/tests/mir-opt/lower_intrinsics.rs +++ b/tests/mir-opt/lower_intrinsics.rs @@ -258,3 +258,12 @@ pub fn make_pointers(a: *const u8, b: *mut (), n: usize) { let _slice_const: *const [u16] = aggregate_raw_ptr(a, n); let _slice_mut: *mut [u64] = aggregate_raw_ptr(b, n); } + +// EMIT_MIR lower_intrinsics.get_metadata.LowerIntrinsics.diff +pub fn get_metadata(a: *const i32, b: *const [u8], c: *const dyn std::fmt::Debug) { + use std::intrinsics::ptr_metadata; + + let _unit = ptr_metadata(a); + let _usize = ptr_metadata(b); + let _vtable = ptr_metadata(c); +} diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir index db0c84bd560fd..ea4ed2713056f 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-abort.mir @@ -13,9 +13,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { } scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) { let mut _5: *const (); - let mut _7: usize; + let mut _6: usize; scope 5 (inlined std::ptr::metadata::<[u32]>) { - let mut _6: std::ptr::metadata::PtrRepr<[u32]>; } scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) { } @@ -30,13 +29,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { StorageDead(_3); StorageLive(_5); _5 = _4 as *const () (PtrToPtr); - StorageLive(_7); StorageLive(_6); - _6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 }; - _7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize); + _6 = PtrMetadata(_1); + _0 = *const [u32] from (_5, _6); StorageDead(_6); - _0 = *const [u32] from (_5, _7); - StorageDead(_7); StorageDead(_5); StorageDead(_4); return; diff --git a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir index db0c84bd560fd..ea4ed2713056f 100644 --- a/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/ptr_offset.demo_byte_add_fat.PreCodegen.after.panic-unwind.mir @@ -13,9 +13,8 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { } scope 4 (inlined std::ptr::const_ptr::<impl *const u8>::with_metadata_of::<[u32]>) { let mut _5: *const (); - let mut _7: usize; + let mut _6: usize; scope 5 (inlined std::ptr::metadata::<[u32]>) { - let mut _6: std::ptr::metadata::PtrRepr<[u32]>; } scope 6 (inlined std::ptr::from_raw_parts::<[u32]>) { } @@ -30,13 +29,10 @@ fn demo_byte_add_fat(_1: *const [u32], _2: usize) -> *const [u32] { StorageDead(_3); StorageLive(_5); _5 = _4 as *const () (PtrToPtr); - StorageLive(_7); StorageLive(_6); - _6 = std::ptr::metadata::PtrRepr::<[u32]> { const_ptr: _1 }; - _7 = ((_6.2: std::ptr::metadata::PtrComponents<[u32]>).1: usize); + _6 = PtrMetadata(_1); + _0 = *const [u32] from (_5, _6); StorageDead(_6); - _0 = *const [u32] from (_5, _7); - StorageDead(_7); StorageDead(_5); StorageDead(_4); return; From ce8f37be22ac26249c917ac6cdcffa0102c11c94 Mon Sep 17 00:00:00 2001 From: Scott McMurray <scottmcm@users.noreply.github.com> Date: Sat, 25 May 2024 02:11:45 -0700 Subject: [PATCH 05/15] Add custom mir support for `PtrMetadata` --- .../src/build/custom/parse/instruction.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/intrinsics/mir.rs | 4 ++++ .../building/custom/operators.g.runtime.after.mir | 13 +++++++++++++ tests/mir-opt/building/custom/operators.rs | 10 ++++++++++ 5 files changed, 29 insertions(+) create mode 100644 tests/mir-opt/building/custom/operators.g.runtime.after.mir diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 6f8cfc3af4473..de748b9c85d17 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -212,6 +212,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset)))) }, @call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)), + @call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)), @call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)), ExprKind::Borrow { borrow_kind, arg } => Ok( Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index b025fe5454c2f..90da220b3f549 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1179,6 +1179,7 @@ symbols! { mir_make_place, mir_move, mir_offset, + mir_ptr_metadata, mir_retag, mir_return, mir_return_to, diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 02665b2676cc1..fa5bb28adff94 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -360,6 +360,10 @@ define!("mir_assume", fn Assume(operand: bool)); define!("mir_deinit", fn Deinit<T>(place: T)); define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool)); define!("mir_len", fn Len<T>(place: T) -> usize); +define!( + "mir_ptr_metadata", + fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata +); define!("mir_copy_for_deref", fn CopyForDeref<T>(place: T) -> T); define!("mir_retag", fn Retag<T>(place: T)); define!("mir_move", fn Move<T>(place: T) -> T); diff --git a/tests/mir-opt/building/custom/operators.g.runtime.after.mir b/tests/mir-opt/building/custom/operators.g.runtime.after.mir new file mode 100644 index 0000000000000..a0ad7d0f93f4e --- /dev/null +++ b/tests/mir-opt/building/custom/operators.g.runtime.after.mir @@ -0,0 +1,13 @@ +// MIR for `g` after runtime + +fn g(_1: *const i32, _2: *const [i32]) -> () { + let mut _0: (); + let mut _3: (); + let mut _4: usize; + + bb0: { + _3 = PtrMetadata(_1); + _4 = PtrMetadata(_2); + return; + } +} diff --git a/tests/mir-opt/building/custom/operators.rs b/tests/mir-opt/building/custom/operators.rs index eb97bcc73b7e1..ff0e8dcbb4156 100644 --- a/tests/mir-opt/building/custom/operators.rs +++ b/tests/mir-opt/building/custom/operators.rs @@ -30,3 +30,13 @@ pub fn f(a: i32, b: bool) -> i32 { Return() }) } + +// EMIT_MIR operators.g.runtime.after.mir +#[custom_mir(dialect = "runtime")] +pub fn g(p: *const i32, q: *const [i32]) { + mir!({ + let a = PtrMetadata(p); + let b = PtrMetadata(q); + Return() + }) +} From 0f9e4d6561b42fb4c31f3b961906aac8b899b269 Mon Sep 17 00:00:00 2001 From: Scott McMurray <scottmcm@users.noreply.github.com> Date: Sun, 26 May 2024 14:20:32 -0700 Subject: [PATCH 06/15] Add Miri tests for `PtrMetadata` UB --- .../ptr_metadata_uninit_slice_data.rs | 22 ++++++++++++ .../ptr_metadata_uninit_slice_data.stderr | 20 +++++++++++ .../ptr_metadata_uninit_slice_len.rs | 22 ++++++++++++ .../ptr_metadata_uninit_slice_len.stderr | 35 +++++++++++++++++++ .../intrinsics/ptr_metadata_uninit_thin.rs | 23 ++++++++++++ .../ptr_metadata_uninit_thin.stderr | 20 +++++++++++ 6 files changed, 142 insertions(+) create mode 100644 src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs create mode 100644 src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr create mode 100644 src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs create mode 100644 src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr create mode 100644 src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs create mode 100644 src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs new file mode 100644 index 0000000000000..ff23f1e729e87 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.rs @@ -0,0 +1,22 @@ +//@compile-flags: -Zmiri-disable-validation +#![feature(core_intrinsics, custom_mir)] +use std::intrinsics::mir::*; + +// This disables validation and uses custom MIR hit exactly the UB in the intrinsic, +// rather than getting UB from the typed load or parameter passing. + +#[custom_mir(dialect = "runtime")] +pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { + mir!({ + RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + Return() + }) +} + +fn main() { + let mut p = std::mem::MaybeUninit::<*const [i32]>::uninit(); + unsafe { + (*p.as_mut_ptr().cast::<[usize; 2]>())[1] = 4; + let _meta = deref_meta(p.as_ptr().cast()); + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr new file mode 100644 index 0000000000000..61e1541d1ee4a --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_data.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC + | +LL | RET = PtrMetadata(*p); + | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC +note: inside `main` + --> $DIR/ptr_metadata_uninit_slice_data.rs:LL:CC + | +LL | let _meta = deref_meta(p.as_ptr().cast()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs new file mode 100644 index 0000000000000..65f74c0acdd6d --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.rs @@ -0,0 +1,22 @@ +//@compile-flags: -Zmiri-disable-validation +#![feature(core_intrinsics, custom_mir)] +use std::intrinsics::mir::*; + +// This disables validation and uses custom MIR hit exactly the UB in the intrinsic, +// rather than getting UB from the typed load or parameter passing. + +#[custom_mir(dialect = "runtime")] +pub unsafe fn deref_meta(p: *const *const [i32]) -> usize { + mir!({ + RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + Return() + }) +} + +fn main() { + let mut p = std::mem::MaybeUninit::<*const [i32]>::uninit(); + unsafe { + (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; + let _meta = deref_meta(p.as_ptr().cast()); + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr new file mode 100644 index 0000000000000..de559263a326d --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_slice_len.stderr @@ -0,0 +1,35 @@ +warning: integer-to-pointer cast + --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + | +LL | (*p.as_mut_ptr().cast::<[*const i32; 2]>())[0] = 4 as *const i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::with_exposed_provenance`, + = help: which means that Miri might miss pointer bugs in this program. + = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.with_exposed_provenance.html for more details on that operation. + = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. + = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `with_exposed_provenance` semantics. + = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. + = note: BACKTRACE: + = note: inside `main` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + | +LL | RET = PtrMetadata(*p); + | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC +note: inside `main` + --> $DIR/ptr_metadata_uninit_slice_len.rs:LL:CC + | +LL | let _meta = deref_meta(p.as_ptr().cast()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error; 1 warning emitted + diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs new file mode 100644 index 0000000000000..ad2e9fc800eb9 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.rs @@ -0,0 +1,23 @@ +//@compile-flags: -Zmiri-disable-validation +#![feature(core_intrinsics, custom_mir)] +use std::intrinsics::mir::*; + +// This disables validation and uses custom MIR hit exactly the UB in the intrinsic, +// rather than getting UB from the typed load or parameter passing. + +#[custom_mir(dialect = "runtime")] +pub unsafe fn deref_meta(p: *const *const i32) -> () { + mir!({ + RET = PtrMetadata(*p); //~ ERROR: Undefined Behavior: using uninitialized data + Return() + }) +} + +fn main() { + // Even though the meta is the trivially-valid `()`, this is still UB + + let p = std::mem::MaybeUninit::<*const i32>::uninit(); + unsafe { + let _meta = deref_meta(p.as_ptr()); + } +} diff --git a/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr new file mode 100644 index 0000000000000..3ab2643afa728 --- /dev/null +++ b/src/tools/miri/tests/fail/intrinsics/ptr_metadata_uninit_thin.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/ptr_metadata_uninit_thin.rs:LL:CC + | +LL | RET = PtrMetadata(*p); + | ^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: BACKTRACE: + = note: inside `deref_meta` at $DIR/ptr_metadata_uninit_thin.rs:LL:CC +note: inside `main` + --> $DIR/ptr_metadata_uninit_thin.rs:LL:CC + | +LL | let _meta = deref_meta(p.as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + From f931290949b215dbf1789dddb66bf6f33c914ba0 Mon Sep 17 00:00:00 2001 From: Chris Denton <chris@chrisdenton.dev> Date: Mon, 27 May 2024 09:32:25 +0000 Subject: [PATCH 07/15] Update description of install-mingw --- src/ci/scripts/install-mingw.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ci/scripts/install-mingw.sh b/src/ci/scripts/install-mingw.sh index 38af8b6acebb6..31aa3785bc369 100755 --- a/src/ci/scripts/install-mingw.sh +++ b/src/ci/scripts/install-mingw.sh @@ -1,6 +1,5 @@ #!/bin/bash -# If we need to download a custom MinGW, do so here and set the path -# appropriately. +# For mingw builds use a vendored mingw. set -euo pipefail IFS=$'\n\t' From 713ddc20f4f6e908ab190e5eec59de251e62f0fd Mon Sep 17 00:00:00 2001 From: Scott McMurray <scottmcm@users.noreply.github.com> Date: Mon, 27 May 2024 14:45:45 -0700 Subject: [PATCH 08/15] Add Miri smoke pass test for ptr_metadata intrinsic --- src/tools/miri/tests/pass/intrinsics/intrinsics.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs index 0dda5aadce20a..89289a25d50a3 100644 --- a/src/tools/miri/tests/pass/intrinsics/intrinsics.rs +++ b/src/tools/miri/tests/pass/intrinsics/intrinsics.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-permissive-provenance -#![feature(core_intrinsics, layout_for_ptr)] +#![feature(core_intrinsics, layout_for_ptr, ptr_metadata)] //! Tests for various intrinsics that do not fit anywhere else. use std::intrinsics; @@ -57,4 +57,10 @@ fn main() { // Make sure that even if the discriminant is stored together with data, the intrinsic returns // only the discriminant, nothing about the data. assert_eq!(discriminant(&Some(false)), discriminant(&Some(true))); + + let () = intrinsics::ptr_metadata(&[1, 2, 3]); + let len = intrinsics::ptr_metadata(&[1, 2, 3][..]); + assert_eq!(len, 3); + let dyn_meta = intrinsics::ptr_metadata(&[1, 2, 3] as &dyn std::fmt::Debug); + assert_eq!(dyn_meta.size_of(), 12); } From bcfa67d50d29bbe99ef0ee4d41838e6bdd651b68 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote <n.nethercote@gmail.com> Date: Thu, 23 May 2024 09:12:19 +1000 Subject: [PATCH 09/15] Remove out-of-date comment. This comment -- "by default we ignore everything in the repository" -- was added in #65939 when rustfmt was first being introduced for this repository and (briefly) every directory was ignored. Since then lots of directories have opted in to formatting, so it is no longer true. --- rustfmt.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/rustfmt.toml b/rustfmt.toml index ef56059feb1c7..1f914964e2410 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -3,7 +3,6 @@ version = "Two" use_small_heuristics = "Max" merge_derives = false -# by default we ignore everything in the repository # tidy only checks files which are not ignored, each entry follows gitignore style ignore = [ "/build/", From 56733372b8b78bf4d47877d7e50d6ab514d3e67c Mon Sep 17 00:00:00 2001 From: Guillaume Gomez <guillaume.gomez@huawei.com> Date: Mon, 27 May 2024 11:06:43 +0200 Subject: [PATCH 10/15] Add `assert_not_contains` to `run-make-support` library --- src/tools/run-make-support/src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index d96c8b891278b..35d7b65bec085 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -268,6 +268,17 @@ pub fn recursive_diff(dir1: impl AsRef<Path>, dir2: impl AsRef<Path>) { } } +/// Check that `haystack` does not contain `needle`. Panic otherwise. +pub fn assert_not_contains(haystack: &str, needle: &str) { + if haystack.contains(needle) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was unexpectedly found in haystack"); + } +} + /// Implement common helpers for command wrappers. This assumes that the command wrapper is a struct /// containing a `cmd: Command` field and a `output` function. The provided helpers are: /// From 404d47ec20cf7606d28156945a6a4fc831c6e7d8 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez <guillaume.gomez@huawei.com> Date: Sun, 26 May 2024 13:37:53 +0200 Subject: [PATCH 11/15] Migrate `run-make/allow-warnings-cmdline-stability` to `rmake.rs` --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../allow-warnings-cmdline-stability/Makefile | 16 ---------------- .../allow-warnings-cmdline-stability/rmake.rs | 11 +++++++++++ 3 files changed, 11 insertions(+), 17 deletions(-) delete mode 100644 tests/run-make/allow-warnings-cmdline-stability/Makefile create mode 100644 tests/run-make/allow-warnings-cmdline-stability/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 2329b8b44dea0..9ca27834cf720 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,6 +1,5 @@ run-make/allocator-shim-circular-deps/Makefile run-make/allow-non-lint-warnings-cmdline/Makefile -run-make/allow-warnings-cmdline-stability/Makefile run-make/archive-duplicate-names/Makefile run-make/atomic-lock-free/Makefile run-make/bare-outfile/Makefile diff --git a/tests/run-make/allow-warnings-cmdline-stability/Makefile b/tests/run-make/allow-warnings-cmdline-stability/Makefile deleted file mode 100644 index 368a39af6bfe2..0000000000000 --- a/tests/run-make/allow-warnings-cmdline-stability/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Test that -A warnings makes the 'empty trait list for derive' warning go away -DEP=$(shell $(RUSTC) bar.rs) -OUT=$(shell $(RUSTC) foo.rs -A warnings 2>&1 | grep "warning" ) - -all: foo bar - test -z '$(OUT)' - -# These are just to ensure that the above commands actually work -bar: - $(RUSTC) bar.rs - -foo: bar - $(RUSTC) foo.rs -A warnings diff --git a/tests/run-make/allow-warnings-cmdline-stability/rmake.rs b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs new file mode 100644 index 0000000000000..8f6fe6bd0b66a --- /dev/null +++ b/tests/run-make/allow-warnings-cmdline-stability/rmake.rs @@ -0,0 +1,11 @@ +// Test that `-Awarnings` suppresses warnings for unstable APIs. + +use run_make_support::{assert_not_contains, rustc}; + +fn main() { + rustc().input("bar.rs").run(); + let output = rustc().input("foo.rs").arg("-Awarnings").run(); + + assert_not_contains(&String::from_utf8(output.stdout).unwrap(), "warning"); + assert_not_contains(&String::from_utf8(output.stderr).unwrap(), "warning"); +} From 4702a1c345f1c13e13bdbe9bb3fdb81d6f866d85 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote <n.nethercote@gmail.com> Date: Tue, 28 May 2024 10:36:37 +1000 Subject: [PATCH 12/15] Fix comments. Some are too long, some aren't complete sentences, some are complete sentences but don't bother with an upper case letter at the start. All annoying and hurt readability. --- rustfmt.toml | 14 ++++----- src/bootstrap/src/core/build_steps/format.rs | 31 +++++++++++--------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/rustfmt.toml b/rustfmt.toml index 1f914964e2410..4812c9302dfdf 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -3,24 +3,24 @@ version = "Two" use_small_heuristics = "Max" merge_derives = false -# tidy only checks files which are not ignored, each entry follows gitignore style +# Files to ignore. Each entry uses gitignore syntax. ignore = [ "/build/", "/*-build/", "/build-*/", "/vendor/", - # tests for now are not formatted, as they are sometimes pretty-printing constrained - # (and generally rustfmt can move around comments in UI-testing incompatible ways) + # Tests for now are not formatted, as they are sometimes pretty-printing constrained + # (and generally rustfmt can move around comments in UI-testing incompatible ways). "/tests/*", - # but we still want to format rmake.rs files in tests/run-make/ so we need to do this - # dance to avoid the parent directory from being excluded + # But we still want to format rmake.rs files in tests/run-make/ so we need to do this + # dance to avoid the parent directory from being excluded. "!/tests/run-make/", "/tests/run-make/*/*.rs", "!/tests/run-make/*/rmake.rs", - # do not format submodules + # Do not format submodules. # FIXME: sync submodule list with tidy/bootstrap/etc # tidy/src/walk.rs:filter_dirs "library/backtrace", @@ -42,7 +42,7 @@ ignore = [ "src/tools/rustc-perf", "src/tools/rustfmt", - # these are ignored by a standard cargo fmt run + # These are ignored by a standard cargo fmt run. "compiler/rustc_codegen_cranelift/scripts", "compiler/rustc_codegen_cranelift/example/gen_block_iterate.rs", # uses edition 2024 ] diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index d9dc34c013700..7f9d88ca7216c 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -12,8 +12,8 @@ use std::sync::mpsc::SyncSender; fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl FnMut(bool) -> bool { let mut cmd = Command::new(rustfmt); - // avoid the submodule config paths from coming into play, - // we only allow a single global config for the workspace for now + // Avoid the submodule config paths from coming into play. We only allow a single global config + // for the workspace for now. cmd.arg("--config-path").arg(&src.canonicalize().unwrap()); cmd.arg("--edition").arg("2021"); cmd.arg("--unstable-features"); @@ -24,7 +24,7 @@ fn rustfmt(src: &Path, rustfmt: &Path, paths: &[PathBuf], check: bool) -> impl F cmd.args(paths); let cmd_debug = format!("{cmd:?}"); let mut cmd = cmd.spawn().expect("running rustfmt"); - // poor man's async: return a closure that'll wait for rustfmt's completion + // Poor man's async: return a closure that'll wait for rustfmt's completion. move |block: bool| -> bool { if !block { match cmd.try_wait() { @@ -72,7 +72,7 @@ fn verify_rustfmt_version(build: &Builder<'_>) -> bool { !program_out_of_date(&stamp_file, &version) } -/// Updates the last rustfmt version used +/// Updates the last rustfmt version used. fn update_rustfmt_version(build: &Builder<'_>) { let Some((version, stamp_file)) = get_rustfmt_version(build) else { return; @@ -168,9 +168,10 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { untracked_count += 1; fmt_override.add(&format!("!/{untracked_path}")).expect(untracked_path); } - // Only check modified files locally to speed up runtime. - // We still check all files in CI to avoid bugs in `get_modified_rs_files` letting regressions slip through; - // we also care about CI time less since this is still very fast compared to building the compiler. + // Only check modified files locally to speed up runtime. We still check all files in + // CI to avoid bugs in `get_modified_rs_files` letting regressions slip through; we + // also care about CI time less since this is still very fast compared to building the + // compiler. if !CiEnv::is_ci() && paths.is_empty() { match get_modified_rs_files(build) { Ok(Some(files)) => { @@ -275,21 +276,23 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { .overrides(fmt_override) .build_parallel(); - // there is a lot of blocking involved in spawning a child process and reading files to format. - // spawn more processes than available concurrency to keep the CPU busy + // There is a lot of blocking involved in spawning a child process and reading files to format. + // Spawn more processes than available concurrency to keep the CPU busy. let max_processes = build.jobs() as usize * 2; - // spawn child processes on a separate thread so we can batch entries we have received from ignore + // Spawn child processes on a separate thread so we can batch entries we have received from + // ignore. let thread = std::thread::spawn(move || { let mut children = VecDeque::new(); while let Ok(path) = rx.recv() { - // try getting more paths from the channel to amortize the overhead of spawning processes + // Try getting more paths from the channel to amortize the overhead of spawning + // processes. let paths: Vec<_> = rx.try_iter().take(63).chain(std::iter::once(path)).collect(); let child = rustfmt(&src, &rustfmt_path, paths.as_slice(), check); children.push_back(child); - // poll completion before waiting + // Poll completion before waiting. for i in (0..children.len()).rev() { if children[i](false) { children.swap_remove_back(i); @@ -298,12 +301,12 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { } if children.len() >= max_processes { - // await oldest child + // Await oldest child. children.pop_front().unwrap()(true); } } - // await remaining children + // Await remaining children. for mut child in children { child(true); } From f1b0ca08a42e9cbfcd91e25174be2e36cdaf2651 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote <n.nethercote@gmail.com> Date: Tue, 28 May 2024 10:03:00 +1000 Subject: [PATCH 13/15] Don't format `tests/run-make/*/rmake.rs`. It's reasonable to want to, but in the current implementation this causes multiple problems. - All the `rmake.rs` files are formatted every time even when they haven't changed. This is because they get whitelisted unconditionally in the `OverrideBuilder`, before the changed files get added. - The way `OverrideBuilder` works, if any files gets whitelisted then no unmentioned files will get traversed. This is surprising, and means that the `rmake.rs` entries broke the use of explicit paths to `x fmt`, and also broke `GITHUB_ACTIONS=true git check --fmt`. The commit removes the `rmake.rs` entries, fixes the formatting of a couple of files that were misformatted (not previously caught due to the `GITHUB_ACTIONS` breakage), and bans `!`-prefixed entries in `rustfmt.toml` because they cause all these problems. --- compiler/rustc_mir_transform/src/instsimplify.rs | 6 ++---- compiler/rustc_mir_transform/src/validate.rs | 2 +- library/core/src/ptr/metadata.rs | 8 ++------ rustfmt.toml | 10 ++-------- src/bootstrap/src/core/build_steps/format.rs | 11 +++++++++-- 5 files changed, 16 insertions(+), 21 deletions(-) diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 5e70b300f3384..a54332b6f2571 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -219,10 +219,8 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { for (i, field) in variant.fields.iter_enumerated() { let field_ty = field.ty(self.tcx, args); if field_ty == *cast_ty { - let place = place.project_deeper( - &[ProjectionElem::Field(i, *cast_ty)], - self.tcx, - ); + let place = place + .project_deeper(&[ProjectionElem::Field(i, *cast_ty)], self.tcx); let operand = if operand.is_move() { Operand::Move(place) } else { diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 6df32169eecb0..8d7547d03e8e1 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -691,7 +691,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { location, format!( "You can't project to field {f:?} of `DynMetadata` because \ - layout is weird and thinks it doesn't have fields." + layout is weird and thinks it doesn't have fields." ), ); } diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs index e501970b580de..6dfeb66694d34 100644 --- a/library/core/src/ptr/metadata.rs +++ b/library/core/src/ptr/metadata.rs @@ -209,18 +209,14 @@ impl<Dyn: ?Sized> DynMetadata<Dyn> { // Consider a reference like `&(i32, dyn Send)`: the vtable will only store the size of the // `Send` part! // SAFETY: DynMetadata always contains a valid vtable pointer - return unsafe { - crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) - }; + return unsafe { crate::intrinsics::vtable_size(self.vtable_ptr() as *const ()) }; } /// Returns the alignment of the type associated with this vtable. #[inline] pub fn align_of(self) -> usize { // SAFETY: DynMetadata always contains a valid vtable pointer - return unsafe { - crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) - }; + return unsafe { crate::intrinsics::vtable_align(self.vtable_ptr() as *const ()) }; } /// Returns the size and alignment together as a `Layout` diff --git a/rustfmt.toml b/rustfmt.toml index 4812c9302dfdf..b78e96d5872f8 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -3,7 +3,7 @@ version = "Two" use_small_heuristics = "Max" merge_derives = false -# Files to ignore. Each entry uses gitignore syntax. +# Files to ignore. Each entry uses gitignore syntax, but `!` prefixes aren't allowed. ignore = [ "/build/", "/*-build/", @@ -12,13 +12,7 @@ ignore = [ # Tests for now are not formatted, as they are sometimes pretty-printing constrained # (and generally rustfmt can move around comments in UI-testing incompatible ways). - "/tests/*", - - # But we still want to format rmake.rs files in tests/run-make/ so we need to do this - # dance to avoid the parent directory from being excluded. - "!/tests/run-make/", - "/tests/run-make/*/*.rs", - "!/tests/run-make/*/rmake.rs", + "/tests/", # Do not format submodules. # FIXME: sync submodule list with tidy/bootstrap/etc diff --git a/src/bootstrap/src/core/build_steps/format.rs b/src/bootstrap/src/core/build_steps/format.rs index 7f9d88ca7216c..44f575b51da24 100644 --- a/src/bootstrap/src/core/build_steps/format.rs +++ b/src/bootstrap/src/core/build_steps/format.rs @@ -115,8 +115,15 @@ pub fn format(build: &Builder<'_>, check: bool, paths: &[PathBuf]) { let rustfmt_config: RustfmtConfig = t!(toml::from_str(&rustfmt_config)); let mut fmt_override = ignore::overrides::OverrideBuilder::new(&build.src); for ignore in rustfmt_config.ignore { - if let Some(ignore) = ignore.strip_prefix('!') { - fmt_override.add(ignore).expect(ignore); + if ignore.starts_with('!') { + // A `!`-prefixed entry could be added as a whitelisted entry in `fmt_override`, i.e. + // strip the `!` prefix. But as soon as whitelisted entries are added, an + // `OverrideBuilder` will only traverse those whitelisted entries, and won't traverse + // any files that aren't explicitly mentioned. No bueno! Maybe there's a way to combine + // explicit whitelisted entries and traversal of unmentioned files, but for now just + // forbid such entries. + eprintln!("`!`-prefixed entries are not supported in rustfmt.toml, sorry"); + crate::exit!(1); } else { fmt_override.add(&format!("!{ignore}")).expect(&ignore); } From 50a5da16b815d7ff6f145cb86ea5c146b1c95329 Mon Sep 17 00:00:00 2001 From: Michael Goulet <michael@errs.io> Date: Sun, 19 May 2024 11:37:56 -0400 Subject: [PATCH 14/15] EvalCtxt::tcx() -> EvalCtxt::interner() --- .../src/solve/alias_relate.rs | 2 +- .../src/solve/assembly/mod.rs | 28 +++++----- .../src/solve/assembly/structural_traits.rs | 22 ++++---- .../src/solve/eval_ctxt/canonical.rs | 10 ++-- .../src/solve/eval_ctxt/mod.rs | 22 ++++---- .../rustc_trait_selection/src/solve/mod.rs | 4 +- .../src/solve/normalizes_to/anon_const.rs | 2 +- .../src/solve/normalizes_to/inherent.rs | 2 +- .../src/solve/normalizes_to/mod.rs | 49 ++++++++++-------- .../src/solve/normalizes_to/opaque_types.rs | 4 +- .../src/solve/normalizes_to/weak_types.rs | 2 +- .../src/solve/project_goals.rs | 2 +- .../src/solve/trait_goals.rs | 51 ++++++++++--------- 13 files changed, 108 insertions(+), 92 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/alias_relate.rs b/compiler/rustc_trait_selection/src/solve/alias_relate.rs index 33b30bef68328..4d7e2fc2cefab 100644 --- a/compiler/rustc_trait_selection/src/solve/alias_relate.rs +++ b/compiler/rustc_trait_selection/src/solve/alias_relate.rs @@ -26,7 +26,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, (ty::Term<'tcx>, ty::Term<'tcx>, ty::AliasRelationDirection)>, ) -> QueryResult<'tcx> { - let tcx = self.tcx(); + let tcx = self.interner(); let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some()); diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 1152441069280..aae6fa9f635b6 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -83,7 +83,7 @@ pub(super) trait GoalKind<'tcx>: assumption: ty::Clause<'tcx>, ) -> Result<Candidate<'tcx>, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else { bug!("expected object type in `probe_and_consider_object_bound_candidate`"); }; @@ -288,8 +288,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { return self.forced_ambiguity(MaybeCause::Ambiguity).into_iter().collect(); } - let goal: Goal<'tcx, G> = - goal.with(self.tcx(), goal.predicate.with_self_ty(self.tcx(), normalized_self_ty)); + let goal: Goal<'tcx, G> = goal.with( + self.interner(), + goal.predicate.with_self_ty(self.interner(), normalized_self_ty), + ); // Vars that show up in the rest of the goal substs may have been constrained by // normalizing the self type as well, since type variables are not uniquified. let goal = self.resolve_vars_if_possible(goal); @@ -339,7 +341,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec<Candidate<'tcx>>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); let self_ty = goal.predicate.self_ty(); let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); let mut consider_impls_for_simplified_type = |simp| { @@ -455,7 +457,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec<Candidate<'tcx>>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); let trait_impls = tcx.trait_impls_of(goal.predicate.trait_def_id(tcx)); for &impl_def_id in trait_impls.blanket_impls() { // For every `default impl`, there's always a non-default `impl` @@ -478,7 +480,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec<Candidate<'tcx>>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); let lang_items = tcx.lang_items(); let trait_def_id = goal.predicate.trait_def_id(tcx); @@ -505,9 +507,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { G::consider_builtin_pointer_like_candidate(self, goal) } else if lang_items.fn_ptr_trait() == Some(trait_def_id) { G::consider_builtin_fn_ptr_trait_candidate(self, goal) - } else if let Some(kind) = self.tcx().fn_trait_kind_from_def_id(trait_def_id) { + } else if let Some(kind) = self.interner().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) - } else if let Some(kind) = self.tcx().async_fn_trait_kind_from_def_id(trait_def_id) { + } else if let Some(kind) = self.interner().async_fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_async_fn_trait_candidates(self, goal, kind) } else if lang_items.async_fn_kind_helper() == Some(trait_def_id) { G::consider_builtin_async_fn_kind_helper_candidate(self, goal) @@ -634,7 +636,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty), ty::Alias(ty::Inherent | ty::Weak, _) => { - self.tcx().sess.dcx().span_delayed_bug( + self.interner().sess.dcx().span_delayed_bug( DUMMY_SP, format!("could not normalize {self_ty}, it is not WF"), ); @@ -643,7 +645,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { }; for assumption in - self.tcx().item_bounds(alias_ty.def_id).instantiate(self.tcx(), alias_ty.args) + self.interner().item_bounds(alias_ty.def_id).instantiate(self.interner(), alias_ty.args) { candidates.extend(G::probe_and_consider_implied_clause( self, @@ -673,7 +675,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec<Candidate<'tcx>>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); if !tcx.trait_def(goal.predicate.trait_def_id(tcx)).implement_via_object { return; } @@ -764,7 +766,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec<Candidate<'tcx>>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter( |ecx| { @@ -793,7 +795,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, G>, candidates: &mut Vec<Candidate<'tcx>>, ) { - let tcx = self.tcx(); + let tcx = self.interner(); let trait_goal: Goal<'tcx, ty::TraitPredicate<'tcx>> = goal.with(tcx, goal.predicate.trait_ref(tcx)); diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 6f68875e6f63f..64d5f725a1f4d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -22,7 +22,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, ty: Ty<'tcx>, ) -> Result<Vec<ty::Binder<'tcx, Ty<'tcx>>>, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); match *ty.kind() { ty::Uint(_) | ty::Int(_) @@ -75,7 +75,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( } ty::CoroutineWitness(def_id, args) => Ok(ecx - .tcx() + .interner() .bound_coroutine_hidden_types(def_id) .map(|bty| bty.instantiate(tcx, args)) .collect()), @@ -151,8 +151,8 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( // "best effort" optimization and `sized_constraint` may return `Some`, even // if the ADT is sized for all possible args. ty::Adt(def, args) => { - if let Some(sized_crit) = def.sized_constraint(ecx.tcx()) { - Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.tcx(), args))]) + if let Some(sized_crit) = def.sized_constraint(ecx.interner()) { + Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), args))]) } else { Ok(vec![]) } @@ -210,10 +210,10 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( // only when `coroutine_clone` is enabled and the coroutine is movable // impl Copy/Clone for Coroutine where T: Copy/Clone forall T in (upvars, witnesses) - ty::Coroutine(def_id, args) => match ecx.tcx().coroutine_movability(def_id) { + ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) { Movability::Static => Err(NoSolution), Movability::Movable => { - if ecx.tcx().features().coroutine_clone { + if ecx.interner().features().coroutine_clone { let coroutine = args.as_coroutine(); Ok(vec![ ty::Binder::dummy(coroutine.tupled_upvars_ty()), @@ -227,9 +227,9 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( // impl Copy/Clone for CoroutineWitness where T: Copy/Clone forall T in coroutine_hidden_types ty::CoroutineWitness(def_id, args) => Ok(ecx - .tcx() + .interner() .bound_coroutine_hidden_types(def_id) - .map(|bty| bty.instantiate(ecx.tcx(), args)) + .map(|bty| bty.instantiate(ecx.interner(), args)) .collect()), } } @@ -666,7 +666,7 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( trait_ref: ty::TraitRef<'tcx>, object_bound: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, ) -> Vec<Goal<'tcx, ty::Predicate<'tcx>>> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let mut requirements = vec![]; requirements.extend( tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.args).predicates, @@ -722,7 +722,7 @@ struct ReplaceProjectionWith<'a, 'tcx> { impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> { fn interner(&self) -> TyCtxt<'tcx> { - self.ecx.tcx() + self.ecx.interner() } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { @@ -739,7 +739,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceProjectionWith<'_, 'tcx> { .eq_and_get_goals( self.param_env, alias_ty, - proj.projection_term.expect_ty(self.ecx.tcx()), + proj.projection_term.expect_ty(self.ecx.interner()), ) .expect("expected to be able to unify goal projection with dyn's projection"), ); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index f6ec654908450..fc10a8a43cc97 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -71,7 +71,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { QueryInput { goal, predefined_opaques_in_body: self - .tcx() + .interner() .mk_predefined_opaques_in_body(PredefinedOpaquesData { opaque_types }), }, ); @@ -144,7 +144,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { Response { var_values, certainty, - external_constraints: self.tcx().mk_external_constraints(external_constraints), + external_constraints: self.interner().mk_external_constraints(external_constraints), }, ); @@ -160,7 +160,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { maybe_cause: MaybeCause, ) -> CanonicalResponse<'tcx> { response_no_constraints_raw( - self.tcx(), + self.interner(), self.max_input_universe, self.variables, Certainty::Maybe(maybe_cause), @@ -194,7 +194,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| { make_query_region_constraints( - self.tcx(), + self.interner(), region_obligations.iter().map(|r_o| { (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()) }), @@ -239,7 +239,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ); let Response { var_values, external_constraints, certainty } = - response.instantiate(self.tcx(), &instantiation); + response.instantiate(self.interner(), &instantiation); Self::unify_query_var_values(self.infcx, param_env, &original_values, var_values); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 4cf0af948119d..72a4096f2aaa4 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -347,7 +347,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); let canonical_response = EvalCtxt::evaluate_canonical_goal( - self.tcx(), + self.interner(), self.search_graph, canonical_goal, &mut goal_evaluation, @@ -450,7 +450,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } else { self.infcx.enter_forall(kind, |kind| { - let goal = goal.with(self.tcx(), ty::Binder::dummy(kind)); + let goal = goal.with(self.interner(), ty::Binder::dummy(kind)); self.add_goal(GoalSource::InstantiateHigherRanked, goal); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) @@ -511,7 +511,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { /// /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result<Option<Certainty>, NoSolution> { - let tcx = self.tcx(); + let tcx = self.interner(); let mut goals = core::mem::take(&mut self.nested_goals); // If this loop did not result in any progress, what's our final certainty. @@ -597,11 +597,13 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - pub(super) fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx +impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> EvalCtxt<'_, Infcx> { + pub(super) fn interner(&self) -> I { + self.infcx.interner() } +} +impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> { let ty = self.infcx.next_ty_var(DUMMY_SP); self.inspect.add_var_value(ty); @@ -759,7 +761,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // NOTE: this check is purely an optimization, the structural eq would // always fail if the term is not an inference variable. if term.is_infer() { - let tcx = self.tcx(); + let tcx = self.interner(); // We need to relate `alias` to `term` treating only the outermost // constructor as rigid, relating any contained generic arguments as // normal. We do this by first structurally equating the `term` @@ -1054,10 +1056,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ) -> Option<ty::Const<'tcx>> { use rustc_middle::mir::interpret::ErrorHandled; match self.infcx.const_eval_resolve(param_env, unevaluated, DUMMY_SP) { - Ok(Some(val)) => Some(ty::Const::new_value(self.tcx(), val, ty)), + Ok(Some(val)) => Some(ty::Const::new_value(self.interner(), val, ty)), Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None, Err(ErrorHandled::Reported(e, _)) => { - Some(ty::Const::new_error(self.tcx(), e.into(), ty)) + Some(ty::Const::new_error(self.interner(), e.into(), ty)) } } } @@ -1070,7 +1072,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { principal: ty::PolyTraitRef<'tcx>, mut supertrait_visitor: impl FnMut(&mut Self, ty::PolyTraitRef<'tcx>, usize, Option<usize>), ) { - let tcx = self.tcx(); + let tcx = self.interner(); let mut offset = 0; prepare_vtable_segments::<()>(tcx, principal, |segment| { match segment { diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 60722d3618f9a..a432090f78cd3 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -133,7 +133,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } fn compute_object_safe_goal(&mut self, trait_def_id: DefId) -> QueryResult<'tcx> { - if self.tcx().check_is_object_safe(trait_def_id) { + if self.interner().check_is_object_safe(trait_def_id) { self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } else { Err(NoSolution) @@ -274,7 +274,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { if let ty::Alias(..) = ty.kind() { let normalized_ty = self.next_ty_infer(); let alias_relate_goal = Goal::new( - self.tcx(), + self.interner(), param_env, ty::PredicateKind::AliasRelate( ty.into(), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs index c9621e705e575..362c4072278d6 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/anon_const.rs @@ -12,7 +12,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { if let Some(normalized_const) = self.try_const_eval_resolve( goal.param_env, ty::UnevaluatedConst::new(goal.predicate.alias.def_id, goal.predicate.alias.args), - self.tcx() + self.interner() .type_of(goal.predicate.alias.def_id) .no_bound_vars() .expect("const ty should not rely on other generics"), diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs index 2146a2c2f0819..41b2b9cd4d260 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/inherent.rs @@ -15,7 +15,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - let tcx = self.tcx(); + let tcx = self.interner(); let inherent = goal.predicate.alias.expect_ty(tcx); let impl_def_id = tcx.parent(inherent.def_id); diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 7ef8373663ba5..7fd2a3801cc4c 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -54,7 +54,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - match goal.predicate.alias.kind(self.tcx()) { + match goal.predicate.alias.kind(self.interner()) { ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst => { let candidates = self.assemble_and_evaluate_candidates(goal); self.merge_candidates(candidates) @@ -107,7 +107,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ) -> Result<Candidate<'tcx>, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); @@ -142,7 +142,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal: Goal<'tcx, NormalizesTo<'tcx>>, impl_def_id: DefId, ) -> Result<Candidate<'tcx>, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let goal_trait_ref = goal.predicate.alias.trait_ref(tcx); let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); @@ -290,8 +290,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, ) -> Result<Candidate<'tcx>, NoSolution> { - ecx.tcx().dcx().span_delayed_bug( - ecx.tcx().def_span(goal.predicate.def_id()), + ecx.interner().dcx().span_delayed_bug( + ecx.interner().def_span(goal.predicate.def_id()), "associated types not allowed on auto traits", ); Err(NoSolution) @@ -337,7 +337,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, ) -> Result<Candidate<'tcx>, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, @@ -380,7 +380,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal: Goal<'tcx, Self>, goal_kind: ty::ClosureKind, ) -> Result<Candidate<'tcx>, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let env_region = match goal_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), @@ -493,7 +493,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } let upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind( - ecx.tcx(), + ecx.interner(), goal_kind, tupled_inputs_ty.expect_ty(), tupled_upvars_ty.expect_ty(), @@ -518,7 +518,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, goal: Goal<'tcx, Self>, ) -> Result<Candidate<'tcx>, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let metadata_def_id = tcx.require_lang_item(LangItem::Metadata, None); assert_eq!(metadata_def_id, goal.predicate.def_id()); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { @@ -606,7 +606,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { }; // Coroutines are not futures unless they come from `async` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_async(def_id) { return Err(NoSolution); } @@ -618,7 +618,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]), + projection_term: ty::AliasTerm::new( + ecx.interner(), + goal.predicate.def_id(), + [self_ty], + ), term, } .upcast(tcx), @@ -638,7 +642,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { }; // Coroutines are not Iterators unless they come from `gen` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -650,7 +654,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, ty::ProjectionPredicate { - projection_term: ty::AliasTerm::new(ecx.tcx(), goal.predicate.def_id(), [self_ty]), + projection_term: ty::AliasTerm::new( + ecx.interner(), + goal.predicate.def_id(), + [self_ty], + ), term, } .upcast(tcx), @@ -677,7 +685,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { }; // Coroutines are not AsyncIterators unless they come from `gen` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_async_gen(def_id) { return Err(NoSolution); } @@ -713,7 +721,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { }; // `async`-desugared coroutines do not implement the coroutine trait - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.is_general_coroutine(def_id) { return Err(NoSolution); } @@ -735,7 +743,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { goal, ty::ProjectionPredicate { projection_term: ty::AliasTerm::new( - ecx.tcx(), + ecx.interner(), goal.predicate.def_id(), [self_ty, coroutine.resume_ty()], ), @@ -784,7 +792,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::Slice(_) | ty::Dynamic(_, _, _) | ty::Tuple(_) - | ty::Error(_) => self_ty.discriminant_ty(ecx.tcx()), + | ty::Error(_) => self_ty.discriminant_ty(ecx.interner()), // We do not call `Ty::discriminant_ty` on alias, param, or placeholder // types, which return `<self_ty as DiscriminantKind>::Discriminant` @@ -831,7 +839,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { | ty::Str | ty::Slice(_) | ty::Tuple(_) - | ty::Error(_) => self_ty.async_destructor_ty(ecx.tcx(), goal.param_env), + | ty::Error(_) => self_ty.async_destructor_ty(ecx.interner(), goal.param_env), // We do not call `Ty::async_destructor_ty` on alias, param, or placeholder // types, which return `<self_ty as AsyncDestruct>::AsyncDestructor` @@ -887,8 +895,9 @@ fn fetch_eligible_assoc_item_def<'tcx>( trait_assoc_def_id: DefId, impl_def_id: DefId, ) -> Result<Option<LeafDef>, NoSolution> { - let node_item = specialization_graph::assoc_def(ecx.tcx(), impl_def_id, trait_assoc_def_id) - .map_err(|ErrorGuaranteed { .. }| NoSolution)?; + let node_item = + specialization_graph::assoc_def(ecx.interner(), impl_def_id, trait_assoc_def_id) + .map_err(|ErrorGuaranteed { .. }| NoSolution)?; let eligible = if node_item.is_final() { // Non-specializable items are always projectable. diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs index 3b83d347276f7..67ec2f3be4814 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/opaque_types.rs @@ -15,7 +15,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - let tcx = self.tcx(); + let tcx = self.interner(); let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.ty().expect("no such thing as an opaque const"); @@ -31,7 +31,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { return Err(NoSolution); } // FIXME: This may have issues when the args contain aliases... - match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.args) { + match self.interner().uses_unique_placeholders_ignoring_regions(opaque_ty.args) { Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => { return self.evaluate_added_goals_and_make_canonical_response( Certainty::AMBIGUOUS, diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs index 109a9e9671f08..5442b9ccffc87 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/weak_types.rs @@ -14,7 +14,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { - let tcx = self.tcx(); + let tcx = self.interner(); let weak_ty = goal.predicate.alias; // Check where clauses diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 8fa78e49dc6e6..cae73cc2d073c 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -11,7 +11,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { &mut self, goal: Goal<'tcx, ProjectionPredicate<'tcx>>, ) -> QueryResult<'tcx> { - let tcx = self.tcx(); + let tcx = self.interner(); let projection_term = goal.predicate.projection_term.to_term(tcx); let goal = goal.with( tcx, diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index e59eef22f4111..67dd3fa85fa1a 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -42,7 +42,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { goal: Goal<'tcx, TraitPredicate<'tcx>>, impl_def_id: DefId, ) -> Result<Candidate<'tcx>, NoSolution> { - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let impl_trait_header = tcx.impl_trait_header(impl_def_id).unwrap(); let drcx = DeepRejectCtxt { treat_obligation_params: TreatParams::ForLookup }; @@ -181,7 +181,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - let tcx = ecx.tcx(); + let tcx = ecx.interner(); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let nested_obligations = tcx @@ -235,7 +235,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { } // The regions of a type don't affect the size of the type - let tcx = ecx.tcx(); + let tcx = ecx.interner(); // We should erase regions from both the param-env and type, since both // may have infer regions. Specifically, after canonicalizing and instantiating, // early bound regions turn into region vars in both the new and old solver. @@ -296,7 +296,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( tcx, @@ -337,7 +337,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return Err(NoSolution); } - let tcx = ecx.tcx(); + let tcx = ecx.interner(); let (tupled_inputs_and_output_and_coroutine, nested_preds) = structural_traits::extract_tupled_inputs_and_output_from_async_callable( tcx, @@ -447,7 +447,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; // Coroutines are not futures unless they come from `async` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_async(def_id) { return Err(NoSolution); } @@ -473,7 +473,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -499,7 +499,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -523,7 +523,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.coroutine_is_async_gen(def_id) { return Err(NoSolution); } @@ -550,7 +550,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { }; // `async`-desugared coroutines do not implement the coroutine trait - let tcx = ecx.tcx(); + let tcx = ecx.interner(); if !tcx.is_general_coroutine(def_id) { return Err(NoSolution); } @@ -625,10 +625,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // Erase regions because we compute layouts in `rustc_transmute`, // which will ICE for region vars. - let args = ecx.tcx().erase_regions(goal.predicate.trait_ref.args); + let args = ecx.interner().erase_regions(goal.predicate.trait_ref.args); let Some(assume) = - rustc_transmute::Assume::from_const(ecx.tcx(), goal.param_env, args.const_at(2)) + rustc_transmute::Assume::from_const(ecx.interner(), goal.param_env, args.const_at(2)) else { return Err(NoSolution); }; @@ -675,7 +675,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { return vec![]; }; - let goal = goal.with(ecx.tcx(), (a_ty, b_ty)); + let goal = goal.with(ecx.interner(), (a_ty, b_ty)); match (a_ty.kind(), b_ty.kind()) { (ty::Infer(ty::TyVar(..)), ..) => bug!("unexpected infer {a_ty:?} {b_ty:?}"), @@ -741,7 +741,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, b_region: ty::Region<'tcx>, ) -> Vec<Candidate<'tcx>> { - let tcx = self.tcx(); + let tcx = self.interner(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; let mut responses = vec![]; @@ -787,7 +787,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { b_data: &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>>, b_region: ty::Region<'tcx>, ) -> Result<Candidate<'tcx>, NoSolution> { - let tcx = self.tcx(); + let tcx = self.interner(); let Goal { predicate: (a_ty, _), .. } = goal; // Can only unsize to an object-safe trait. @@ -837,8 +837,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { let a_auto_traits: FxIndexSet<DefId> = a_data .auto_traits() .chain(a_data.principal_def_id().into_iter().flat_map(|principal_def_id| { - supertrait_def_ids(self.tcx(), principal_def_id) - .filter(|def_id| self.tcx().trait_is_auto(*def_id)) + supertrait_def_ids(self.interner(), principal_def_id) + .filter(|def_id| self.interner().trait_is_auto(*def_id)) })) .collect(); @@ -907,7 +907,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ecx.add_goal( GoalSource::ImplWhereBound, Goal::new( - ecx.tcx(), + ecx.interner(), param_env, ty::Binder::dummy(ty::OutlivesPredicate(a_region, b_region)), ), @@ -956,7 +956,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_args: ty::GenericArgsRef<'tcx>, b_args: ty::GenericArgsRef<'tcx>, ) -> Result<Candidate<'tcx>, NoSolution> { - let tcx = self.tcx(); + let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; let unsizing_params = tcx.unsizing_params_for_adt(def.did()); @@ -1017,7 +1017,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { a_tys: &'tcx ty::List<Ty<'tcx>>, b_tys: &'tcx ty::List<Ty<'tcx>>, ) -> Result<Candidate<'tcx>, NoSolution> { - let tcx = self.tcx(); + let tcx = self.interner(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); @@ -1077,9 +1077,9 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // takes precedence over the structural auto trait candidate being // assembled. ty::Coroutine(def_id, _) - if Some(goal.predicate.def_id()) == self.tcx().lang_items().unpin_trait() => + if Some(goal.predicate.def_id()) == self.interner().lang_items().unpin_trait() => { - match self.tcx().coroutine_movability(def_id) { + match self.interner().coroutine_movability(def_id) { Movability::Static => Some(Err(NoSolution)), Movability::Movable => Some( self.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { @@ -1124,7 +1124,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { | ty::Tuple(_) | ty::Adt(_, _) => { let mut disqualifying_impl = None; - self.tcx().for_each_relevant_impl( + self.interner().for_each_relevant_impl( goal.predicate.def_id(), goal.predicate.self_ty(), |impl_def_id| { @@ -1164,7 +1164,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { .into_iter() .map(|ty| { ecx.enter_forall(ty, |ty| { - goal.with(ecx.tcx(), goal.predicate.with_self_ty(ecx.tcx(), ty)) + goal.with( + ecx.interner(), + goal.predicate.with_self_ty(ecx.interner(), ty), + ) }) }) .collect::<Vec<_>>(), From f49403653017bfe5a62b7121b36249c19dcf1a0d Mon Sep 17 00:00:00 2001 From: Michael Goulet <michael@errs.io> Date: Sun, 19 May 2024 13:20:37 -0400 Subject: [PATCH 15/15] Make ProofTreeBuilder actually generic over interner --- compiler/rustc_middle/src/ty/context.rs | 7 ++ .../src/solve/eval_ctxt/canonical.rs | 28 +++-- .../src/solve/eval_ctxt/mod.rs | 8 +- .../src/solve/inspect/build.rs | 112 +++++++++--------- .../src/solve/search_graph.rs | 11 +- compiler/rustc_type_ir/src/inherent.rs | 9 +- compiler/rustc_type_ir/src/interner.rs | 10 +- 7 files changed, 102 insertions(+), 83 deletions(-) diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index c09cb95de8837..5a04324dc7dcb 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -218,6 +218,13 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.check_and_mk_args(def_id, args) } + fn intern_canonical_goal_evaluation_step( + self, + step: solve::inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>, + ) -> &'tcx solve::inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>> { + self.arena.alloc(step) + } + fn parent(self, def_id: Self::DefId) -> Self::DefId { self.parent(def_id) } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index fc10a8a43cc97..4977807aa6cf2 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -16,7 +16,6 @@ use crate::solve::{ use rustc_data_structures::fx::FxHashSet; use rustc_index::IndexVec; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; -use rustc_infer::infer::canonical::CanonicalVarValues; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; use rustc_infer::infer::RegionVariableOrigin; use rustc_infer::infer::{InferCtxt, InferOk}; @@ -32,22 +31,24 @@ use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty, TyCtxt, TypeFoldable} use rustc_next_trait_solver::canonicalizer::{CanonicalizeMode, Canonicalizer}; use rustc_next_trait_solver::resolve::EagerResolver; use rustc_span::{Span, DUMMY_SP}; +use rustc_type_ir::CanonicalVarValues; +use rustc_type_ir::{InferCtxtLike, Interner}; use std::assert_matches::assert_matches; use std::iter; use std::ops::Deref; trait ResponseT<'tcx> { - fn var_values(&self) -> CanonicalVarValues<'tcx>; + fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>>; } impl<'tcx> ResponseT<'tcx> for Response<TyCtxt<'tcx>> { - fn var_values(&self) -> CanonicalVarValues<'tcx> { + fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> { self.var_values } } impl<'tcx, T> ResponseT<'tcx> for inspect::State<TyCtxt<'tcx>, T> { - fn var_values(&self) -> CanonicalVarValues<'tcx> { + fn var_values(&self) -> CanonicalVarValues<TyCtxt<'tcx>> { self.var_values } } @@ -260,7 +261,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { infcx: &InferCtxt<'tcx>, original_values: &[ty::GenericArg<'tcx>], response: &Canonical<'tcx, T>, - ) -> CanonicalVarValues<'tcx> { + ) -> CanonicalVarValues<TyCtxt<'tcx>> { // FIXME: Longterm canonical queries should deal with all placeholders // created inside of the query directly instead of returning them to the // caller. @@ -354,7 +355,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, original_values: &[ty::GenericArg<'tcx>], - var_values: CanonicalVarValues<'tcx>, + var_values: CanonicalVarValues<TyCtxt<'tcx>>, ) { assert_eq!(original_values.len(), var_values.len()); @@ -393,13 +394,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// evaluating a goal. The `var_values` not only include the bound variables /// of the query input, but also contain all unconstrained inference vars /// created while evaluating this goal. -pub(in crate::solve) fn make_canonical_state<'tcx, T: TypeFoldable<TyCtxt<'tcx>>>( - infcx: &InferCtxt<'tcx>, - var_values: &[ty::GenericArg<'tcx>], +pub(in crate::solve) fn make_canonical_state<Infcx, T, I>( + infcx: &Infcx, + var_values: &[I::GenericArg], max_input_universe: ty::UniverseIndex, data: T, -) -> inspect::CanonicalState<TyCtxt<'tcx>, T> { - let var_values = CanonicalVarValues { var_values: infcx.tcx.mk_args(var_values) }; +) -> inspect::CanonicalState<I, T> +where + Infcx: InferCtxtLike<Interner = I>, + I: Interner, + T: TypeFoldable<I>, +{ + let var_values = CanonicalVarValues { var_values: infcx.interner().mk_args(var_values) }; let state = inspect::State { var_values, data }; let state = state.fold_with(&mut EagerResolver::new(infcx)); Canonicalizer::canonicalize( diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 72a4096f2aaa4..98ba3feeca132 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -98,7 +98,7 @@ pub struct EvalCtxt< // evaluation code. tainted: Result<(), NoSolution>, - pub(super) inspect: ProofTreeBuilder<I>, + pub(super) inspect: ProofTreeBuilder<Infcx>, } #[derive(derivative::Derivative)] @@ -218,7 +218,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>, canonical_input: CanonicalInput<'tcx>, - canonical_goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>, + canonical_goal_evaluation: &mut ProofTreeBuilder<InferCtxt<'tcx>>, f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R, ) -> R { let intercrate = match search_graph.solver_mode() { @@ -280,7 +280,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph<TyCtxt<'tcx>>, canonical_input: CanonicalInput<'tcx>, - goal_evaluation: &mut ProofTreeBuilder<TyCtxt<'tcx>>, + goal_evaluation: &mut ProofTreeBuilder<InferCtxt<'tcx>>, ) -> QueryResult<'tcx> { let mut canonical_goal_evaluation = goal_evaluation.new_canonical_goal_evaluation(canonical_input); @@ -1114,7 +1114,7 @@ struct ReplaceAliasWithInfer<'me, 'a, 'tcx> { impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReplaceAliasWithInfer<'_, '_, 'tcx> { fn interner(&self) -> TyCtxt<'tcx> { - self.ecx.tcx() + self.ecx.interner() } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 3c63336264831..84c04900ae484 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -3,18 +3,16 @@ //! This code is *a bit* of a mess and can hopefully be //! mostly ignored. For a general overview of how it works, //! see the comment on [ProofTreeBuilder]. +use std::marker::PhantomData; use std::mem; use crate::solve::eval_ctxt::canonical; use crate::solve::{self, inspect, GenerateProofTree}; -use rustc_infer::infer::InferCtxt; use rustc_middle::bug; -use rustc_middle::infer::canonical::CanonicalVarValues; -use rustc_middle::ty::{self, TyCtxt}; use rustc_next_trait_solver::solve::{ CanonicalInput, Certainty, Goal, GoalSource, QueryInput, QueryResult, }; -use rustc_type_ir::Interner; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; /// The core data structure when building proof trees. /// @@ -36,7 +34,11 @@ use rustc_type_ir::Interner; /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder<I: Interner> { +pub(in crate::solve) struct ProofTreeBuilder< + Infcx: InferCtxtLike<Interner = I>, + I: Interner = <Infcx as InferCtxtLike>::Interner, +> { + _infcx: PhantomData<Infcx>, state: Option<Box<DebugSolver<I>>>, } @@ -229,36 +231,36 @@ impl<I: Interner> WipProbeStep<I> { } } -// FIXME: Genericize this impl. -impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { - fn new(state: impl Into<DebugSolver<TyCtxt<'tcx>>>) -> ProofTreeBuilder<TyCtxt<'tcx>> { - ProofTreeBuilder { state: Some(Box::new(state.into())) } +impl<Infcx: InferCtxtLike<Interner = I>, I: Interner> ProofTreeBuilder<Infcx> { + fn new(state: impl Into<DebugSolver<I>>) -> ProofTreeBuilder<Infcx> { + ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData } } - fn opt_nested<T: Into<DebugSolver<TyCtxt<'tcx>>>>( - &self, - state: impl FnOnce() -> Option<T>, - ) -> Self { + fn opt_nested<T: Into<DebugSolver<I>>>(&self, state: impl FnOnce() -> Option<T>) -> Self { ProofTreeBuilder { state: self.state.as_ref().and_then(|_| Some(state()?.into())).map(Box::new), + _infcx: PhantomData, } } - fn nested<T: Into<DebugSolver<TyCtxt<'tcx>>>>(&self, state: impl FnOnce() -> T) -> Self { - ProofTreeBuilder { state: self.state.as_ref().map(|_| Box::new(state().into())) } + fn nested<T: Into<DebugSolver<I>>>(&self, state: impl FnOnce() -> T) -> Self { + ProofTreeBuilder { + state: self.state.as_ref().map(|_| Box::new(state().into())), + _infcx: PhantomData, + } } - fn as_mut(&mut self) -> Option<&mut DebugSolver<TyCtxt<'tcx>>> { + fn as_mut(&mut self) -> Option<&mut DebugSolver<I>> { self.state.as_deref_mut() } - pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<TyCtxt<'tcx>> { - let mut nested = ProofTreeBuilder { state: self.state.take() }; + pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder<Infcx> { + let mut nested = ProofTreeBuilder { state: self.state.take(), _infcx: PhantomData }; nested.enter_probe(); nested } - pub fn finalize(self) -> Option<inspect::GoalEvaluation<TyCtxt<'tcx>>> { + pub fn finalize(self) -> Option<inspect::GoalEvaluation<I>> { match *self.state? { DebugSolver::GoalEvaluation(wip_goal_evaluation) => { Some(wip_goal_evaluation.finalize()) @@ -267,21 +269,19 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { } } - pub fn new_maybe_root( - generate_proof_tree: GenerateProofTree, - ) -> ProofTreeBuilder<TyCtxt<'tcx>> { + pub fn new_maybe_root(generate_proof_tree: GenerateProofTree) -> ProofTreeBuilder<Infcx> { match generate_proof_tree { GenerateProofTree::No => ProofTreeBuilder::new_noop(), GenerateProofTree::Yes => ProofTreeBuilder::new_root(), } } - pub fn new_root() -> ProofTreeBuilder<TyCtxt<'tcx>> { + pub fn new_root() -> ProofTreeBuilder<Infcx> { ProofTreeBuilder::new(DebugSolver::Root) } - pub fn new_noop() -> ProofTreeBuilder<TyCtxt<'tcx>> { - ProofTreeBuilder { state: None } + pub fn new_noop() -> ProofTreeBuilder<Infcx> { + ProofTreeBuilder { state: None, _infcx: PhantomData } } pub fn is_noop(&self) -> bool { @@ -290,10 +290,10 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { pub(in crate::solve) fn new_goal_evaluation( &mut self, - goal: Goal<TyCtxt<'tcx>, ty::Predicate<'tcx>>, - orig_values: &[ty::GenericArg<'tcx>], + goal: Goal<I, I::Predicate>, + orig_values: &[I::GenericArg], kind: solve::GoalEvaluationKind, - ) -> ProofTreeBuilder<TyCtxt<'tcx>> { + ) -> ProofTreeBuilder<Infcx> { self.opt_nested(|| match kind { solve::GoalEvaluationKind::Root => Some(WipGoalEvaluation { uncanonicalized_goal: goal, @@ -306,8 +306,8 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { pub fn new_canonical_goal_evaluation( &mut self, - goal: CanonicalInput<TyCtxt<'tcx>>, - ) -> ProofTreeBuilder<TyCtxt<'tcx>> { + goal: CanonicalInput<I>, + ) -> ProofTreeBuilder<Infcx> { self.nested(|| WipCanonicalGoalEvaluation { goal, kind: None, @@ -318,12 +318,13 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { pub fn finalize_canonical_goal_evaluation( &mut self, - tcx: TyCtxt<'tcx>, - ) -> Option<&'tcx inspect::CanonicalGoalEvaluationStep<TyCtxt<'tcx>>> { + tcx: I, + ) -> Option<I::CanonicalGoalEvaluationStepRef> { self.as_mut().map(|this| match this { DebugSolver::CanonicalGoalEvaluation(evaluation) => { let final_revision = mem::take(&mut evaluation.final_revision).unwrap(); - let final_revision = &*tcx.arena.alloc(final_revision.finalize()); + let final_revision = + tcx.intern_canonical_goal_evaluation_step(final_revision.finalize()); let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision }; assert_eq!(evaluation.kind.replace(kind), None); final_revision @@ -334,7 +335,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { pub fn canonical_goal_evaluation( &mut self, - canonical_goal_evaluation: ProofTreeBuilder<TyCtxt<'tcx>>, + canonical_goal_evaluation: ProofTreeBuilder<Infcx>, ) { if let Some(this) = self.as_mut() { match (this, *canonical_goal_evaluation.state.unwrap()) { @@ -350,10 +351,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { } } - pub fn canonical_goal_evaluation_kind( - &mut self, - kind: WipCanonicalGoalEvaluationKind<TyCtxt<'tcx>>, - ) { + pub fn canonical_goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind<I>) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { @@ -364,7 +362,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { } } - pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<TyCtxt<'tcx>>) { + pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder<Infcx>) { if let Some(this) = self.as_mut() { match this { DebugSolver::Root => *this = *goal_evaluation.state.unwrap(), @@ -378,9 +376,9 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { pub fn new_goal_evaluation_step( &mut self, - var_values: CanonicalVarValues<'tcx>, - instantiated_goal: QueryInput<TyCtxt<'tcx>, ty::Predicate<'tcx>>, - ) -> ProofTreeBuilder<TyCtxt<'tcx>> { + var_values: ty::CanonicalVarValues<I>, + instantiated_goal: QueryInput<I, I::Predicate>, + ) -> ProofTreeBuilder<Infcx> { self.nested(|| WipCanonicalGoalEvaluationStep { var_values: var_values.var_values.to_vec(), instantiated_goal, @@ -394,7 +392,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { }) } - pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<TyCtxt<'tcx>>) { + pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder<Infcx>) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation_step.state.unwrap()) { ( @@ -408,7 +406,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { } } - pub fn add_var_value<T: Into<ty::GenericArg<'tcx>>>(&mut self, arg: T) { + pub fn add_var_value<T: Into<I::GenericArg>>(&mut self, arg: T) { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -435,7 +433,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { } } - pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<TyCtxt<'tcx>>) { + pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind<I>) { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -446,11 +444,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { } } - pub fn probe_final_state( - &mut self, - infcx: &InferCtxt<'tcx>, - max_input_universe: ty::UniverseIndex, - ) { + pub fn probe_final_state(&mut self, infcx: &Infcx, max_input_universe: ty::UniverseIndex) { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -469,24 +463,24 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { pub fn add_normalizes_to_goal( &mut self, - infcx: &InferCtxt<'tcx>, + infcx: &Infcx, max_input_universe: ty::UniverseIndex, - goal: Goal<TyCtxt<'tcx>, ty::NormalizesTo<'tcx>>, + goal: Goal<I, ty::NormalizesTo<I>>, ) { self.add_goal( infcx, max_input_universe, GoalSource::Misc, - goal.with(infcx.tcx, goal.predicate), + goal.with(infcx.interner(), goal.predicate), ); } pub fn add_goal( &mut self, - infcx: &InferCtxt<'tcx>, + infcx: &Infcx, max_input_universe: ty::UniverseIndex, source: GoalSource, - goal: Goal<TyCtxt<'tcx>, ty::Predicate<'tcx>>, + goal: Goal<I, I::Predicate>, ) { match self.as_mut() { None => {} @@ -505,9 +499,9 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { pub(crate) fn record_impl_args( &mut self, - infcx: &InferCtxt<'tcx>, + infcx: &Infcx, max_input_universe: ty::UniverseIndex, - impl_args: ty::GenericArgsRef<'tcx>, + impl_args: I::GenericArgs, ) { match self.as_mut() { Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -540,7 +534,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { } } - pub fn finish_probe(mut self) -> ProofTreeBuilder<TyCtxt<'tcx>> { + pub fn finish_probe(mut self) -> ProofTreeBuilder<Infcx> { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -555,7 +549,7 @@ impl<'tcx> ProofTreeBuilder<TyCtxt<'tcx>> { self } - pub fn query_result(&mut self, result: QueryResult<TyCtxt<'tcx>>) { + pub fn query_result(&mut self, result: QueryResult<I>) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { diff --git a/compiler/rustc_trait_selection/src/solve/search_graph.rs b/compiler/rustc_trait_selection/src/solve/search_graph.rs index 6be623b6044f0..f1b8bf4676ee7 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph.rs @@ -3,6 +3,7 @@ use std::mem; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::Idx; use rustc_index::IndexVec; +use rustc_infer::infer::InferCtxt; use rustc_middle::dep_graph::dep_kinds; use rustc_middle::traits::solve::CacheData; use rustc_middle::traits::solve::EvaluationCache; @@ -261,10 +262,10 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> { &mut self, tcx: TyCtxt<'tcx>, input: CanonicalInput<TyCtxt<'tcx>>, - inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>, + inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>, mut prove_goal: impl FnMut( &mut Self, - &mut ProofTreeBuilder<TyCtxt<'tcx>>, + &mut ProofTreeBuilder<InferCtxt<'tcx>>, ) -> QueryResult<TyCtxt<'tcx>>, ) -> QueryResult<TyCtxt<'tcx>> { self.check_invariants(); @@ -426,7 +427,7 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> { tcx: TyCtxt<'tcx>, input: CanonicalInput<TyCtxt<'tcx>>, available_depth: Limit, - inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>, + inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>, ) -> Option<QueryResult<TyCtxt<'tcx>>> { let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self .global_cache(tcx) @@ -473,11 +474,11 @@ impl<'tcx> SearchGraph<TyCtxt<'tcx>> { &mut self, tcx: TyCtxt<'tcx>, input: CanonicalInput<TyCtxt<'tcx>>, - inspect: &mut ProofTreeBuilder<TyCtxt<'tcx>>, + inspect: &mut ProofTreeBuilder<InferCtxt<'tcx>>, prove_goal: &mut F, ) -> StepResult<TyCtxt<'tcx>> where - F: FnMut(&mut Self, &mut ProofTreeBuilder<TyCtxt<'tcx>>) -> QueryResult<TyCtxt<'tcx>>, + F: FnMut(&mut Self, &mut ProofTreeBuilder<InferCtxt<'tcx>>) -> QueryResult<TyCtxt<'tcx>>, { let result = prove_goal(self, inspect); let stack_entry = self.pop_stack(); diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index e7e893f27daa9..7b1dfecfee2e0 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -132,7 +132,14 @@ pub trait GenericArgs<I: Interner<GenericArgs = Self>>: } pub trait Predicate<I: Interner<Predicate = Self>>: - Copy + Debug + Hash + Eq + TypeSuperVisitable<I> + TypeSuperFoldable<I> + Flags + Copy + + Debug + + Hash + + Eq + + TypeSuperVisitable<I> + + TypeSuperFoldable<I> + + Flags + + UpcastFrom<I, ty::NormalizesTo<I>> { fn is_coinductive(self, interner: I) -> bool; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index e49db171a534a..2a228c973d34a 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -3,6 +3,7 @@ use std::fmt::Debug; use std::hash::Hash; use std::ops::Deref; +use crate::fold::TypeFoldable; use crate::inherent::*; use crate::ir_print::IrPrint; use crate::solve::inspect::CanonicalGoalEvaluationStep; @@ -90,7 +91,7 @@ pub trait Interner: type PlaceholderRegion: PlaceholderLike; // Predicates - type ParamEnv: Copy + Debug + Hash + Eq; + type ParamEnv: Copy + Debug + Hash + Eq + TypeFoldable<Self>; type Predicate: Predicate<Self>; type Clause: Clause<Self>; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable<Self> + Flags; @@ -114,15 +115,18 @@ pub trait Interner: ) -> (ty::TraitRef<Self>, Self::OwnItemArgs); fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; - fn mk_args_from_iter(self, args: impl Iterator<Item = Self::GenericArg>) -> Self::GenericArgs; - fn check_and_mk_args( self, def_id: Self::DefId, args: impl IntoIterator<Item: Into<Self::GenericArg>>, ) -> Self::GenericArgs; + fn intern_canonical_goal_evaluation_step( + self, + step: CanonicalGoalEvaluationStep<Self>, + ) -> Self::CanonicalGoalEvaluationStepRef; + fn parent(self, def_id: Self::DefId) -> Self::DefId; fn recursion_limit(self) -> usize;