From 3dc4ffffc841933b9caeb5c147669cb14023250b Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 23 May 2024 11:53:27 +0300 Subject: [PATCH 01/11] create libcxx-version tool for getting currently used libcxx version Signed-off-by: onur-ozkan --- src/tools/libcxx-version/main.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 src/tools/libcxx-version/main.cpp diff --git a/src/tools/libcxx-version/main.cpp b/src/tools/libcxx-version/main.cpp new file mode 100644 index 0000000000000..d12078abbb83e --- /dev/null +++ b/src/tools/libcxx-version/main.cpp @@ -0,0 +1,28 @@ +// Detecting the standard library version manually using a bunch of shell commands is very +// complicated and fragile across different platforms. This program provides the major version +// of the standard library on any target platform without requiring any messy work. +// +// It's nothing more than specifying the name of the standard library implementation (either libstdc++ or libc++) +// and its major version. +// +// ignore-tidy-linelength + +#include + +int main() { + #ifdef _GLIBCXX_RELEASE + std::cout << "libstdc++ version: " << _GLIBCXX_RELEASE << std::endl; + #elif defined(_LIBCPP_VERSION) + // _LIBCPP_VERSION follows "XXYYZZ" format (e.g., 170001 for 17.0.1). + // ref: /~https://github.com/llvm/llvm-project/blob/f64732195c1030ee2627ff4e4142038e01df1d26/libcxx/include/__config#L51-L54 + // + // Since we use the major version from _GLIBCXX_RELEASE, we need to extract only the first 2 characters of _LIBCPP_VERSION + // to provide the major version for consistency. + std::cout << "libc++ version: " << std::to_string(_LIBCPP_VERSION).substr(0, 2) << std::endl; + #else + std::cerr << "Coudln't recognize the standard library version." << std::endl; + return 1; + #endif + + return 0; +} From c5755fa875a29aff5fa7bfa582b224e8874fd400 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 23 May 2024 11:59:25 +0300 Subject: [PATCH 02/11] check host's libstdc++ version when using ci llvm Signed-off-by: onur-ozkan --- src/bootstrap/src/core/build_steps/tool.rs | 54 ++++++++++++++++++++++ src/bootstrap/src/core/sanity.rs | 46 ++++++++++++++++-- 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 2db3f8f79364e..4f7efcb05d892 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -10,6 +10,7 @@ use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, use crate::core::config::TargetSelection; use crate::utils::channel::GitInfo; use crate::utils::exec::BootstrapCommand; +use crate::utils::helpers::output; use crate::utils::helpers::{add_dylib_path, exe, t}; use crate::Compiler; use crate::Mode; @@ -804,6 +805,59 @@ impl Step for LlvmBitcodeLinker { } } +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct LibcxxVersionTool { + pub target: TargetSelection, +} + +#[derive(Debug, Clone)] +pub enum LibcxxVersion { + Gnu(usize), + #[allow(dead_code)] + Llvm(usize), +} + +impl Step for LibcxxVersionTool { + type Output = LibcxxVersion; + const DEFAULT: bool = false; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.never() + } + + fn run(self, builder: &Builder<'_>) -> LibcxxVersion { + let out_dir = builder.out.join(self.target.to_string()).join("libcxx-version"); + let _ = fs::remove_dir_all(&out_dir); + t!(fs::create_dir_all(&out_dir)); + + let compiler = builder.cxx(self.target).unwrap(); + let mut cmd = Command::new(compiler); + + let executable = out_dir.join("libcxx-version"); + cmd.arg("-o").arg(&executable).arg(builder.src.join("src/tools/libcxx-version/main.cpp")); + + builder.run_cmd(&mut cmd); + + if !executable.exists() { + panic!("Something went wrong. {} is not present", executable.display()); + } + + let version_output = output(&mut Command::new(executable)); + + let version_str = version_output.split_once("version:").unwrap().1; + let version = version_str.trim().parse::().unwrap(); + + if version_output.starts_with("libstdc++") { + LibcxxVersion::Gnu(version) + } else if version_output.starts_with("libc++") { + LibcxxVersion::Llvm(version) + } else { + panic!("Coudln't recognize the standard library version."); + } + } +} + macro_rules! tool_extended { (($sel:ident, $builder:ident), $($name:ident, diff --git a/src/bootstrap/src/core/sanity.rs b/src/bootstrap/src/core/sanity.rs index 9c3df6fa9e39b..c90c609c0257d 100644 --- a/src/bootstrap/src/core/sanity.rs +++ b/src/bootstrap/src/core/sanity.rs @@ -16,7 +16,8 @@ use std::path::PathBuf; use std::process::Command; use walkdir::WalkDir; -use crate::builder::Kind; +use crate::builder::{Builder, Kind}; +use crate::core::build_steps::tool; use crate::core::config::Target; use crate::utils::helpers::output; use crate::Build; @@ -35,6 +36,10 @@ const STAGE0_MISSING_TARGETS: &[&str] = &[ // just a dummy comment so the list doesn't get onelined ]; +/// Minimum version threshold for libstdc++ required when using prebuilt LLVM +/// from CI (with`llvm.download-ci-llvm` option). +const LIBSTDCXX_MIN_VERSION_THRESHOLD: usize = 8; + impl Finder { pub fn new() -> Self { Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() } @@ -99,6 +104,35 @@ pub fn check(build: &mut Build) { cmd_finder.must_have("git"); } + // Ensure that a compatible version of libstdc++ is available on the system when using `llvm.download-ci-llvm`. + if !build.config.dry_run() && !build.build.is_msvc() && build.config.llvm_from_ci { + let builder = Builder::new(build); + let libcxx_version = builder.ensure(tool::LibcxxVersionTool { target: build.build }); + + match libcxx_version { + tool::LibcxxVersion::Gnu(version) => { + if LIBSTDCXX_MIN_VERSION_THRESHOLD > version { + eprintln!( + "\nYour system's libstdc++ version is too old for the `llvm.download-ci-llvm` option." + ); + eprintln!("Current version detected: '{}'", version); + eprintln!("Minimum required version: '{}'", LIBSTDCXX_MIN_VERSION_THRESHOLD); + eprintln!( + "Consider upgrading libstdc++ or disabling the `llvm.download-ci-llvm` option." + ); + crate::exit!(1); + } + } + tool::LibcxxVersion::Llvm(_) => { + eprintln!( + "\nYour system is using libc++, which is incompatible with the `llvm.download-ci-llvm` option." + ); + eprintln!("Disable `llvm.download-ci-llvm` or switch to libstdc++."); + crate::exit!(1); + } + } + } + // We need cmake, but only if we're actually building LLVM or sanitizers. let building_llvm = build .hosts @@ -199,11 +233,15 @@ than building it. if !["A-A", "B-B", "C-C"].contains(&target_str.as_str()) { let mut has_target = false; - let missing_targets_hashset: HashSet<_> = STAGE0_MISSING_TARGETS.iter().map(|t| t.to_string()).collect(); - let duplicated_targets: Vec<_> = stage0_supported_target_list.intersection(&missing_targets_hashset).collect(); + let missing_targets_hashset: HashSet<_> = + STAGE0_MISSING_TARGETS.iter().map(|t| t.to_string()).collect(); + let duplicated_targets: Vec<_> = + stage0_supported_target_list.intersection(&missing_targets_hashset).collect(); if !duplicated_targets.is_empty() { - println!("Following targets supported from the stage0 compiler, please remove them from STAGE0_MISSING_TARGETS list."); + println!( + "Following targets supported from the stage0 compiler, please remove them from STAGE0_MISSING_TARGETS list." + ); for duplicated_target in duplicated_targets { println!(" {duplicated_target}"); } From 52d9f85ea460287ce8ca7a52f7e20301dccfa8d9 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 23 May 2024 12:05:24 +0300 Subject: [PATCH 03/11] register libcxx-version in triagebot Signed-off-by: onur-ozkan --- triagebot.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 2e45b257f8126..94071a375bfb9 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -317,6 +317,7 @@ trigger_files = [ "src/tools/compiletest", "src/tools/tidy", "src/tools/rustdoc-gui-test", + "src/tools/libcxx-version", ] [autolabel."T-infra"] @@ -1068,6 +1069,7 @@ project-exploit-mitigations = [ "/src/tools/tidy" = ["bootstrap"] "/src/tools/x" = ["bootstrap"] "/src/tools/rustdoc-gui-test" = ["bootstrap", "@onur-ozkan"] +"/src/tools/libcxx-version" = ["@onur-ozkan"] # Enable tracking of PR review assignment # Documentation at: https://forge.rust-lang.org/triagebot/pr-assignment-tracking.html From 480670ead572c9b29709d7aaf7f76d86bf696277 Mon Sep 17 00:00:00 2001 From: onur-ozkan Date: Thu, 23 May 2024 12:59:58 +0300 Subject: [PATCH 04/11] skip `src/tools/libcxx-version` from tidy Signed-off-by: onur-ozkan --- src/tools/libcxx-version/main.cpp | 2 -- src/tools/tidy/src/walk.rs | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/tools/libcxx-version/main.cpp b/src/tools/libcxx-version/main.cpp index d12078abbb83e..79df7ef457c4f 100644 --- a/src/tools/libcxx-version/main.cpp +++ b/src/tools/libcxx-version/main.cpp @@ -4,8 +4,6 @@ // // It's nothing more than specifying the name of the standard library implementation (either libstdc++ or libc++) // and its major version. -// -// ignore-tidy-linelength #include diff --git a/src/tools/tidy/src/walk.rs b/src/tools/tidy/src/walk.rs index f68b7675c769f..63a0383416652 100644 --- a/src/tools/tidy/src/walk.rs +++ b/src/tools/tidy/src/walk.rs @@ -16,6 +16,7 @@ pub fn filter_dirs(path: &Path) -> bool { "library/stdarch", "src/tools/cargo", "src/tools/clippy", + "src/tools/libcxx-version", "src/tools/miri", "src/tools/rust-analyzer", "src/tools/rustc-perf", From 05fa647dc7810a756a206d2300f12b3dafec779f Mon Sep 17 00:00:00 2001 From: Dion Dokter Date: Mon, 27 May 2024 12:05:00 +0200 Subject: [PATCH 05/11] Always use the general case char count --- library/core/src/str/count.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/str/count.rs b/library/core/src/str/count.rs index 28567a7e753aa..d8667864fe554 100644 --- a/library/core/src/str/count.rs +++ b/library/core/src/str/count.rs @@ -24,7 +24,7 @@ const UNROLL_INNER: usize = 4; #[inline] pub(super) fn count_chars(s: &str) -> usize { - if s.len() < USIZE_SIZE * UNROLL_INNER { + if cfg!(feature = "optimize_for_size") || s.len() < USIZE_SIZE * UNROLL_INNER { // Avoid entering the optimized implementation for strings where the // difference is not likely to matter, or where it might even be slower. // That said, a ton of thought was not spent on the particular threshold From b3ee91128e7527b16b24bfeca81186490ace0cfa Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 May 2024 11:37:31 +0000 Subject: [PATCH 06/11] Use `rmake` for `windows-` run-make tests --- .../run-make-support/src/llvm_readobj.rs | 6 ++++++ tests/run-make/issue-85441/Makefile | 9 --------- .../windows-binary-no-external-deps/Makefile | 9 --------- .../windows-binary-no-external-deps/rmake.rs | 15 +++++++++++++++ tests/run-make/windows-safeseh/Makefile | 19 ------------------- tests/run-make/windows-safeseh/rmake.rs | 15 +++++++++++++++ tests/run-make/windows-spawn/Makefile | 8 -------- tests/run-make/windows-spawn/rmake.rs | 17 +++++++++++++++++ tests/run-make/windows-spawn/spawn.rs | 10 ++++------ tests/run-make/windows-subsystem/Makefile | 6 ------ tests/run-make/windows-subsystem/rmake.rs | 8 ++++++++ .../{issue-85441 => windows-ws2_32}/empty.rs | 0 tests/run-make/windows-ws2_32/rmake.rs | 13 +++++++++++++ 13 files changed, 78 insertions(+), 57 deletions(-) delete mode 100644 tests/run-make/issue-85441/Makefile delete mode 100644 tests/run-make/windows-binary-no-external-deps/Makefile create mode 100644 tests/run-make/windows-binary-no-external-deps/rmake.rs delete mode 100644 tests/run-make/windows-safeseh/Makefile create mode 100644 tests/run-make/windows-safeseh/rmake.rs delete mode 100644 tests/run-make/windows-spawn/Makefile create mode 100644 tests/run-make/windows-spawn/rmake.rs delete mode 100644 tests/run-make/windows-subsystem/Makefile create mode 100644 tests/run-make/windows-subsystem/rmake.rs rename tests/run-make/{issue-85441 => windows-ws2_32}/empty.rs (100%) create mode 100644 tests/run-make/windows-ws2_32/rmake.rs diff --git a/src/tools/run-make-support/src/llvm_readobj.rs b/src/tools/run-make-support/src/llvm_readobj.rs index f114aacfa3fc7..c91ed31bd41a8 100644 --- a/src/tools/run-make-support/src/llvm_readobj.rs +++ b/src/tools/run-make-support/src/llvm_readobj.rs @@ -42,6 +42,12 @@ impl LlvmReadobj { self } + /// Pass `--coff-imports` to display the Windows DLL imports + pub fn coff_imports(&mut self) -> &mut Self { + self.cmd.arg("--coff-imports"); + self + } + /// Get the [`Output`][::std::process::Output] of the finished process. #[track_caller] pub fn command_output(&mut self) -> ::std::process::Output { diff --git a/tests/run-make/issue-85441/Makefile b/tests/run-make/issue-85441/Makefile deleted file mode 100644 index 987d7f7d4a76f..0000000000000 --- a/tests/run-make/issue-85441/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# only-windows-msvc - -include ../tools.mk - -# Tests that WS2_32.dll is not unnecessarily linked, see issue #85441 - -all: - $(RUSTC) empty.rs - objdump -p $(TMPDIR)/empty.exe | $(CGREP) -v -i "WS2_32.dll" diff --git a/tests/run-make/windows-binary-no-external-deps/Makefile b/tests/run-make/windows-binary-no-external-deps/Makefile deleted file mode 100644 index 8960020fed558..0000000000000 --- a/tests/run-make/windows-binary-no-external-deps/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -include ../tools.mk - -# only-windows - -PATH=$(SYSTEMROOT)/system32 - -all: - $(RUSTC) hello.rs - $(TMPDIR)/hello.exe diff --git a/tests/run-make/windows-binary-no-external-deps/rmake.rs b/tests/run-make/windows-binary-no-external-deps/rmake.rs new file mode 100644 index 0000000000000..a9ef4996acabe --- /dev/null +++ b/tests/run-make/windows-binary-no-external-deps/rmake.rs @@ -0,0 +1,15 @@ +//@ only-windows + +// Ensure that we aren't relying on any non-system DLLs when compiling and running +// a "hello world" application by setting `PATH` to `C:\Windows\System32`. + +use run_make_support::{run, rustc}; +use std::env; +use std::path::PathBuf; + +fn main() { + let windows_dir = env::var("SystemRoot").unwrap(); + let system32: PathBuf = [&windows_dir, "System32"].iter().collect(); + rustc().input("hello.rs").env("PATH", system32).run(); + run("hello"); +} diff --git a/tests/run-make/windows-safeseh/Makefile b/tests/run-make/windows-safeseh/Makefile deleted file mode 100644 index d6a403961d791..0000000000000 --- a/tests/run-make/windows-safeseh/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# only-windows -# needs-rust-lld - -include ../tools.mk - -all: foo bar - -# Ensure that LLD can link when an .rlib contains a synthetic object -# file referencing exported or used symbols. -foo: - $(RUSTC) -C linker=rust-lld foo.rs - -# Ensure that LLD can link when /WHOLEARCHIVE: is used with an .rlib. -# Previously, lib.rmeta was not marked as (trivially) SAFESEH-aware. -bar: baz - $(RUSTC) -C linker=rust-lld -C link-arg=/WHOLEARCHIVE:libbaz.rlib bar.rs - -baz: - $(RUSTC) baz.rs diff --git a/tests/run-make/windows-safeseh/rmake.rs b/tests/run-make/windows-safeseh/rmake.rs new file mode 100644 index 0000000000000..56d3ff4ea0d81 --- /dev/null +++ b/tests/run-make/windows-safeseh/rmake.rs @@ -0,0 +1,15 @@ +//@ only-windows +//@ needs-rust-lld + +use run_make_support::rustc; + +fn main() { + // Ensure that LLD can link when an .rlib contains a synthetic object + // file referencing exported or used symbols. + rustc().input("foo.rs").arg("-Clinker=rust-lld").run(); + + // Ensure that LLD can link when /WHOLEARCHIVE: is used with an .rlib. + // Previously, lib.rmeta was not marked as (trivially) SAFESEH-aware. + rustc().input("baz.rs").run(); + rustc().input("bar.rs").arg("-Clinker=rust-lld").link_arg("/WHOLEARCHIVE:libbaz.rlib").run(); +} diff --git a/tests/run-make/windows-spawn/Makefile b/tests/run-make/windows-spawn/Makefile deleted file mode 100644 index b6cdb169bab48..0000000000000 --- a/tests/run-make/windows-spawn/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -include ../tools.mk - -# only-windows - -all: - $(RUSTC) -o "$(TMPDIR)/hopefullydoesntexist bar.exe" hello.rs - $(RUSTC) spawn.rs - $(TMPDIR)/spawn.exe diff --git a/tests/run-make/windows-spawn/rmake.rs b/tests/run-make/windows-spawn/rmake.rs new file mode 100644 index 0000000000000..fb9cf1e214909 --- /dev/null +++ b/tests/run-make/windows-spawn/rmake.rs @@ -0,0 +1,17 @@ +//@ only-windows + +use run_make_support::{run, rustc, tmp_dir}; + +// On Windows `Command` uses `CreateProcessW` to run a new process. +// However, in the past std used to not pass in the application name, leaving +// `CreateProcessW` to use heuristics to guess the intended name from the +// command line string. Sometimes this could go very wrong. +// E.g. in Rust 1.0 `Command::new("foo").arg("bar").spawn()` will try to launch +// `foo bar.exe` if foo.exe does not exist. Which is clearly not desired. + +fn main() { + let out_dir = tmp_dir(); + rustc().input("hello.rs").output(out_dir.join("hopefullydoesntexist bar.exe")).run(); + rustc().input("spawn.rs").run(); + run("spawn"); +} diff --git a/tests/run-make/windows-spawn/spawn.rs b/tests/run-make/windows-spawn/spawn.rs index c34da3d5fde4c..a9e86d1577e55 100644 --- a/tests/run-make/windows-spawn/spawn.rs +++ b/tests/run-make/windows-spawn/spawn.rs @@ -3,10 +3,8 @@ use std::process::Command; fn main() { // Make sure it doesn't try to run "hopefullydoesntexist bar.exe". - assert_eq!(Command::new("hopefullydoesntexist") - .arg("bar") - .spawn() - .unwrap_err() - .kind(), - ErrorKind::NotFound); + assert_eq!( + Command::new("hopefullydoesntexist").arg("bar").spawn().unwrap_err().kind(), + ErrorKind::NotFound + ) } diff --git a/tests/run-make/windows-subsystem/Makefile b/tests/run-make/windows-subsystem/Makefile deleted file mode 100644 index e3cf9181de418..0000000000000 --- a/tests/run-make/windows-subsystem/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) windows.rs - $(RUSTC) console.rs diff --git a/tests/run-make/windows-subsystem/rmake.rs b/tests/run-make/windows-subsystem/rmake.rs new file mode 100644 index 0000000000000..8a6460f89339c --- /dev/null +++ b/tests/run-make/windows-subsystem/rmake.rs @@ -0,0 +1,8 @@ +//@ ignore-cross-compile + +use run_make_support::rustc; + +fn main() { + rustc().input("windows.rs").run(); + rustc().input("console.rs").run(); +} diff --git a/tests/run-make/issue-85441/empty.rs b/tests/run-make/windows-ws2_32/empty.rs similarity index 100% rename from tests/run-make/issue-85441/empty.rs rename to tests/run-make/windows-ws2_32/empty.rs diff --git a/tests/run-make/windows-ws2_32/rmake.rs b/tests/run-make/windows-ws2_32/rmake.rs new file mode 100644 index 0000000000000..4157e604330e4 --- /dev/null +++ b/tests/run-make/windows-ws2_32/rmake.rs @@ -0,0 +1,13 @@ +//@ only-msvc + +// Tests that WS2_32.dll is not unnecessarily linked, see issue #85441 + +use run_make_support::{llvm_readobj, rustc, tmp_dir}; + +fn main() { + rustc().input("empty.rs").run(); + let empty = tmp_dir().join("empty.exe"); + let output = llvm_readobj().input(empty).coff_imports().run(); + let output = String::from_utf8(output.stdout).unwrap(); + assert!(!output.to_ascii_uppercase().contains("WS2_32.DLL")); +} From 57e68b689372256e564d1e64f0dc99f55d277096 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 May 2024 12:08:41 +0000 Subject: [PATCH 07/11] Remove Makefiles from allowed_run_make_makefiles --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 9a6ae18abeade..07537370bb60b 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -118,7 +118,6 @@ run-make/issue-83112-incr-test-moved-file/Makefile run-make/issue-84395-lto-embed-bitcode/Makefile run-make/issue-85019-moved-src-dir/Makefile run-make/issue-85401-static-mir/Makefile -run-make/issue-85441/Makefile run-make/issue-88756-default-output/Makefile run-make/issue-97463-abi-param-passing/Makefile run-make/jobserver-error/Makefile @@ -278,8 +277,4 @@ run-make/volatile-intrinsics/Makefile run-make/wasm-exceptions-nostd/Makefile run-make/wasm-override-linker/Makefile run-make/weird-output-filenames/Makefile -run-make/windows-binary-no-external-deps/Makefile -run-make/windows-safeseh/Makefile -run-make/windows-spawn/Makefile -run-make/windows-subsystem/Makefile run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile From e081170b947a68abd2754990577dfd687d96e534 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 May 2024 13:43:46 +0000 Subject: [PATCH 08/11] Add linker option to run-make-support --- src/tools/run-make-support/src/rustc.rs | 6 ++++++ tests/run-make/windows-safeseh/rmake.rs | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/tools/run-make-support/src/rustc.rs b/src/tools/run-make-support/src/rustc.rs index 1c83b630861cd..a617c189fb423 100644 --- a/src/tools/run-make-support/src/rustc.rs +++ b/src/tools/run-make-support/src/rustc.rs @@ -203,6 +203,12 @@ impl Rustc { self } + /// Specify the linker + pub fn linker(&mut self, linker: &str) -> &mut Self { + self.cmd.arg(format!("-Clinker={linker}")); + self + } + /// Get the [`Output`][::std::process::Output] of the finished process. #[track_caller] pub fn command_output(&mut self) -> ::std::process::Output { diff --git a/tests/run-make/windows-safeseh/rmake.rs b/tests/run-make/windows-safeseh/rmake.rs index 56d3ff4ea0d81..10e6b38aa8df1 100644 --- a/tests/run-make/windows-safeseh/rmake.rs +++ b/tests/run-make/windows-safeseh/rmake.rs @@ -6,10 +6,10 @@ use run_make_support::rustc; fn main() { // Ensure that LLD can link when an .rlib contains a synthetic object // file referencing exported or used symbols. - rustc().input("foo.rs").arg("-Clinker=rust-lld").run(); + rustc().input("foo.rs").linker("rust-lld").run(); // Ensure that LLD can link when /WHOLEARCHIVE: is used with an .rlib. // Previously, lib.rmeta was not marked as (trivially) SAFESEH-aware. rustc().input("baz.rs").run(); - rustc().input("bar.rs").arg("-Clinker=rust-lld").link_arg("/WHOLEARCHIVE:libbaz.rlib").run(); + rustc().input("bar.rs").linker("rust-lld").link_arg("/WHOLEARCHIVE:libbaz.rlib").run(); } From ad5dce55e620db3f992421debafe66194e5210c9 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Mon, 27 May 2024 13:46:41 +0000 Subject: [PATCH 09/11] Move run-make windows_subsystem tests to ui tests --- tests/run-make/windows-subsystem/rmake.rs | 8 -------- tests/{run-make => ui}/windows-subsystem/console.rs | 1 + .../{ => windows-subsystem}/windows-subsystem-invalid.rs | 0 .../windows-subsystem-invalid.stderr | 0 tests/{run-make => ui}/windows-subsystem/windows.rs | 1 + 5 files changed, 2 insertions(+), 8 deletions(-) delete mode 100644 tests/run-make/windows-subsystem/rmake.rs rename tests/{run-make => ui}/windows-subsystem/console.rs (78%) rename tests/ui/{ => windows-subsystem}/windows-subsystem-invalid.rs (100%) rename tests/ui/{ => windows-subsystem}/windows-subsystem-invalid.stderr (100%) rename tests/{run-make => ui}/windows-subsystem/windows.rs (78%) diff --git a/tests/run-make/windows-subsystem/rmake.rs b/tests/run-make/windows-subsystem/rmake.rs deleted file mode 100644 index 8a6460f89339c..0000000000000 --- a/tests/run-make/windows-subsystem/rmake.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ ignore-cross-compile - -use run_make_support::rustc; - -fn main() { - rustc().input("windows.rs").run(); - rustc().input("console.rs").run(); -} diff --git a/tests/run-make/windows-subsystem/console.rs b/tests/ui/windows-subsystem/console.rs similarity index 78% rename from tests/run-make/windows-subsystem/console.rs rename to tests/ui/windows-subsystem/console.rs index 61a92eb6a9db7..8f0ca2de370de 100644 --- a/tests/run-make/windows-subsystem/console.rs +++ b/tests/ui/windows-subsystem/console.rs @@ -1,3 +1,4 @@ +//@ run-pass #![windows_subsystem = "console"] fn main() {} diff --git a/tests/ui/windows-subsystem-invalid.rs b/tests/ui/windows-subsystem/windows-subsystem-invalid.rs similarity index 100% rename from tests/ui/windows-subsystem-invalid.rs rename to tests/ui/windows-subsystem/windows-subsystem-invalid.rs diff --git a/tests/ui/windows-subsystem-invalid.stderr b/tests/ui/windows-subsystem/windows-subsystem-invalid.stderr similarity index 100% rename from tests/ui/windows-subsystem-invalid.stderr rename to tests/ui/windows-subsystem/windows-subsystem-invalid.stderr diff --git a/tests/run-make/windows-subsystem/windows.rs b/tests/ui/windows-subsystem/windows.rs similarity index 78% rename from tests/run-make/windows-subsystem/windows.rs rename to tests/ui/windows-subsystem/windows.rs index 1138248f07da0..65db0fec7a8b6 100644 --- a/tests/run-make/windows-subsystem/windows.rs +++ b/tests/ui/windows-subsystem/windows.rs @@ -1,3 +1,4 @@ +//@ run-pass #![windows_subsystem = "windows"] fn main() {} From d5d747751d3f8f1b5709ad892fe25bd4a480e050 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 19 May 2024 11:37:56 -0400 Subject: [PATCH 10/11] 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 43e61de955af7..30ac791b8a19a 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; // Structurally normalize the lhs. 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, 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>, ) { - 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>, ) { - 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>, ) { - 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>, ) { - 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>, ) { - 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>, ) { - 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>>, 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>, ) -> Vec>> { - 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> 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> 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 ce408ddea3780..756e513f79ce9 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -344,7 +344,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, @@ -447,7 +447,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) }) @@ -498,7 +498,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, 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. @@ -584,11 +584,13 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - pub(super) fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx +impl, 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); @@ -746,7 +748,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` @@ -1041,10 +1043,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { ) -> Option> { 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)) } } } @@ -1057,7 +1059,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { principal: ty::PolyTraitRef<'tcx>, mut supertrait_visitor: impl FnMut(&mut Self, ty::PolyTraitRef<'tcx>, usize, Option), ) { - 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, 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, 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, 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, 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, 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, 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 `::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 `::AsyncDestructor` @@ -887,8 +895,9 @@ fn fetch_eligible_assoc_item_def<'tcx>( trait_assoc_def_id: DefId, impl_def_id: DefId, ) -> Result, 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, 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>, b_region: ty::Region<'tcx>, ) -> Vec> { - 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>, b_region: ty::Region<'tcx>, ) -> Result, 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 = 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, 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>, b_tys: &'tcx ty::List>, ) -> Result, 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::>(), From 56e87dfe1e4a9bd79f082090f43954091b958cb8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 19 May 2024 13:20:37 -0400 Subject: [PATCH 11/11] 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 | 6 +- .../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, 101 insertions(+), 82 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>, + ) -> &'tcx solve::inspect::CanonicalGoalEvaluationStep> { + 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>; } impl<'tcx> ResponseT<'tcx> for Response> { - fn var_values(&self) -> CanonicalVarValues<'tcx> { + fn var_values(&self) -> CanonicalVarValues> { self.var_values } } impl<'tcx, T> ResponseT<'tcx> for inspect::State, T> { - fn var_values(&self) -> CanonicalVarValues<'tcx> { + fn var_values(&self) -> CanonicalVarValues> { 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> { // 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>, ) { 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>>( - infcx: &InferCtxt<'tcx>, - var_values: &[ty::GenericArg<'tcx>], +pub(in crate::solve) fn make_canonical_state( + infcx: &Infcx, + var_values: &[I::GenericArg], max_input_universe: ty::UniverseIndex, data: T, -) -> inspect::CanonicalState, T> { - let var_values = CanonicalVarValues { var_values: infcx.tcx.mk_args(var_values) }; +) -> inspect::CanonicalState +where + Infcx: InferCtxtLike, + I: Interner, + T: TypeFoldable, +{ + 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 756e513f79ce9..7713c3dc39e3c 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -95,7 +95,7 @@ pub struct EvalCtxt< // evaluation code. tainted: Result<(), NoSolution>, - pub(super) inspect: ProofTreeBuilder, + pub(super) inspect: ProofTreeBuilder, } #[derive(derivative::Derivative)] @@ -215,7 +215,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph>, canonical_input: CanonicalInput<'tcx>, - canonical_goal_evaluation: &mut ProofTreeBuilder>, + canonical_goal_evaluation: &mut ProofTreeBuilder>, f: impl FnOnce(&mut EvalCtxt<'_, InferCtxt<'tcx>>, Goal<'tcx, ty::Predicate<'tcx>>) -> R, ) -> R { let intercrate = match search_graph.solver_mode() { @@ -277,7 +277,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { tcx: TyCtxt<'tcx>, search_graph: &'a mut search_graph::SearchGraph>, canonical_input: CanonicalInput<'tcx>, - goal_evaluation: &mut ProofTreeBuilder>, + goal_evaluation: &mut ProofTreeBuilder>, ) -> QueryResult<'tcx> { let mut canonical_goal_evaluation = goal_evaluation.new_canonical_goal_evaluation(canonical_input); 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 { +pub(in crate::solve) struct ProofTreeBuilder< + Infcx: InferCtxtLike, + I: Interner = ::Interner, +> { + _infcx: PhantomData, state: Option>>, } @@ -229,36 +231,36 @@ impl WipProbeStep { } } -// FIXME: Genericize this impl. -impl<'tcx> ProofTreeBuilder> { - fn new(state: impl Into>>) -> ProofTreeBuilder> { - ProofTreeBuilder { state: Some(Box::new(state.into())) } +impl, I: Interner> ProofTreeBuilder { + fn new(state: impl Into>) -> ProofTreeBuilder { + ProofTreeBuilder { state: Some(Box::new(state.into())), _infcx: PhantomData } } - fn opt_nested>>>( - &self, - state: impl FnOnce() -> Option, - ) -> Self { + fn opt_nested>>(&self, state: impl FnOnce() -> Option) -> Self { ProofTreeBuilder { state: self.state.as_ref().and_then(|_| Some(state()?.into())).map(Box::new), + _infcx: PhantomData, } } - fn nested>>>(&self, state: impl FnOnce() -> T) -> Self { - ProofTreeBuilder { state: self.state.as_ref().map(|_| Box::new(state().into())) } + fn nested>>(&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>> { + fn as_mut(&mut self) -> Option<&mut DebugSolver> { self.state.as_deref_mut() } - pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder> { - let mut nested = ProofTreeBuilder { state: self.state.take() }; + pub fn take_and_enter_probe(&mut self) -> ProofTreeBuilder { + let mut nested = ProofTreeBuilder { state: self.state.take(), _infcx: PhantomData }; nested.enter_probe(); nested } - pub fn finalize(self) -> Option>> { + pub fn finalize(self) -> Option> { match *self.state? { DebugSolver::GoalEvaluation(wip_goal_evaluation) => { Some(wip_goal_evaluation.finalize()) @@ -267,21 +269,19 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn new_maybe_root( - generate_proof_tree: GenerateProofTree, - ) -> ProofTreeBuilder> { + pub fn new_maybe_root(generate_proof_tree: GenerateProofTree) -> ProofTreeBuilder { match generate_proof_tree { GenerateProofTree::No => ProofTreeBuilder::new_noop(), GenerateProofTree::Yes => ProofTreeBuilder::new_root(), } } - pub fn new_root() -> ProofTreeBuilder> { + pub fn new_root() -> ProofTreeBuilder { ProofTreeBuilder::new(DebugSolver::Root) } - pub fn new_noop() -> ProofTreeBuilder> { - ProofTreeBuilder { state: None } + pub fn new_noop() -> ProofTreeBuilder { + ProofTreeBuilder { state: None, _infcx: PhantomData } } pub fn is_noop(&self) -> bool { @@ -290,10 +290,10 @@ impl<'tcx> ProofTreeBuilder> { pub(in crate::solve) fn new_goal_evaluation( &mut self, - goal: Goal, ty::Predicate<'tcx>>, - orig_values: &[ty::GenericArg<'tcx>], + goal: Goal, + orig_values: &[I::GenericArg], kind: solve::GoalEvaluationKind, - ) -> ProofTreeBuilder> { + ) -> ProofTreeBuilder { self.opt_nested(|| match kind { solve::GoalEvaluationKind::Root => Some(WipGoalEvaluation { uncanonicalized_goal: goal, @@ -306,8 +306,8 @@ impl<'tcx> ProofTreeBuilder> { pub fn new_canonical_goal_evaluation( &mut self, - goal: CanonicalInput>, - ) -> ProofTreeBuilder> { + goal: CanonicalInput, + ) -> ProofTreeBuilder { self.nested(|| WipCanonicalGoalEvaluation { goal, kind: None, @@ -318,12 +318,13 @@ impl<'tcx> ProofTreeBuilder> { pub fn finalize_canonical_goal_evaluation( &mut self, - tcx: TyCtxt<'tcx>, - ) -> Option<&'tcx inspect::CanonicalGoalEvaluationStep>> { + tcx: I, + ) -> Option { 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> { pub fn canonical_goal_evaluation( &mut self, - canonical_goal_evaluation: ProofTreeBuilder>, + canonical_goal_evaluation: ProofTreeBuilder, ) { if let Some(this) = self.as_mut() { match (this, *canonical_goal_evaluation.state.unwrap()) { @@ -350,10 +351,7 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn canonical_goal_evaluation_kind( - &mut self, - kind: WipCanonicalGoalEvaluationKind>, - ) { + pub fn canonical_goal_evaluation_kind(&mut self, kind: WipCanonicalGoalEvaluationKind) { if let Some(this) = self.as_mut() { match this { DebugSolver::CanonicalGoalEvaluation(canonical_goal_evaluation) => { @@ -364,7 +362,7 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder>) { + pub fn goal_evaluation(&mut self, goal_evaluation: ProofTreeBuilder) { if let Some(this) = self.as_mut() { match this { DebugSolver::Root => *this = *goal_evaluation.state.unwrap(), @@ -378,9 +376,9 @@ impl<'tcx> ProofTreeBuilder> { pub fn new_goal_evaluation_step( &mut self, - var_values: CanonicalVarValues<'tcx>, - instantiated_goal: QueryInput, ty::Predicate<'tcx>>, - ) -> ProofTreeBuilder> { + var_values: ty::CanonicalVarValues, + instantiated_goal: QueryInput, + ) -> ProofTreeBuilder { self.nested(|| WipCanonicalGoalEvaluationStep { var_values: var_values.var_values.to_vec(), instantiated_goal, @@ -394,7 +392,7 @@ impl<'tcx> ProofTreeBuilder> { }) } - pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder>) { + pub fn goal_evaluation_step(&mut self, goal_evaluation_step: ProofTreeBuilder) { if let Some(this) = self.as_mut() { match (this, *goal_evaluation_step.state.unwrap()) { ( @@ -408,7 +406,7 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn add_var_value>>(&mut self, arg: T) { + pub fn add_var_value>(&mut self, arg: T) { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -435,7 +433,7 @@ impl<'tcx> ProofTreeBuilder> { } } - pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind>) { + pub fn probe_kind(&mut self, probe_kind: inspect::ProbeKind) { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -446,11 +444,7 @@ impl<'tcx> ProofTreeBuilder> { } } - 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> { pub fn add_normalizes_to_goal( &mut self, - infcx: &InferCtxt<'tcx>, + infcx: &Infcx, max_input_universe: ty::UniverseIndex, - goal: Goal, ty::NormalizesTo<'tcx>>, + goal: Goal>, ) { 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, ty::Predicate<'tcx>>, + goal: Goal, ) { match self.as_mut() { None => {} @@ -505,9 +499,9 @@ impl<'tcx> ProofTreeBuilder> { 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> { } } - pub fn finish_probe(mut self) -> ProofTreeBuilder> { + pub fn finish_probe(mut self) -> ProofTreeBuilder { match self.as_mut() { None => {} Some(DebugSolver::CanonicalGoalEvaluationStep(state)) => { @@ -555,7 +549,7 @@ impl<'tcx> ProofTreeBuilder> { self } - pub fn query_result(&mut self, result: QueryResult>) { + pub fn query_result(&mut self, result: QueryResult) { 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> { &mut self, tcx: TyCtxt<'tcx>, input: CanonicalInput>, - inspect: &mut ProofTreeBuilder>, + inspect: &mut ProofTreeBuilder>, mut prove_goal: impl FnMut( &mut Self, - &mut ProofTreeBuilder>, + &mut ProofTreeBuilder>, ) -> QueryResult>, ) -> QueryResult> { self.check_invariants(); @@ -426,7 +427,7 @@ impl<'tcx> SearchGraph> { tcx: TyCtxt<'tcx>, input: CanonicalInput>, available_depth: Limit, - inspect: &mut ProofTreeBuilder>, + inspect: &mut ProofTreeBuilder>, ) -> Option>> { let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self .global_cache(tcx) @@ -473,11 +474,11 @@ impl<'tcx> SearchGraph> { &mut self, tcx: TyCtxt<'tcx>, input: CanonicalInput>, - inspect: &mut ProofTreeBuilder>, + inspect: &mut ProofTreeBuilder>, prove_goal: &mut F, ) -> StepResult> where - F: FnMut(&mut Self, &mut ProofTreeBuilder>) -> QueryResult>, + F: FnMut(&mut Self, &mut ProofTreeBuilder>) -> QueryResult>, { 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>: } pub trait Predicate>: - Copy + Debug + Hash + Eq + TypeSuperVisitable + TypeSuperFoldable + Flags + Copy + + Debug + + Hash + + Eq + + TypeSuperVisitable + + TypeSuperFoldable + + Flags + + UpcastFrom> { 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; type Predicate: Predicate; type Clause: Clause; type Clauses: Copy + Debug + Hash + Eq + TypeSuperVisitable + Flags; @@ -114,15 +115,18 @@ pub trait Interner: ) -> (ty::TraitRef, Self::OwnItemArgs); fn mk_args(self, args: &[Self::GenericArg]) -> Self::GenericArgs; - fn mk_args_from_iter(self, args: impl Iterator) -> Self::GenericArgs; - fn check_and_mk_args( self, def_id: Self::DefId, args: impl IntoIterator>, ) -> Self::GenericArgs; + fn intern_canonical_goal_evaluation_step( + self, + step: CanonicalGoalEvaluationStep, + ) -> Self::CanonicalGoalEvaluationStepRef; + fn parent(self, def_id: Self::DefId) -> Self::DefId; fn recursion_limit(self) -> usize;