From 30721b0e909d7451a37bbb4ae371e1c909a0cbaf Mon Sep 17 00:00:00 2001 From: jyn Date: Mon, 26 May 2025 20:10:17 -0400 Subject: [PATCH 01/28] Add stubs for environment variables; document some of the important ones This uses a very hacky regex that will probably miss some variables. But having some docs seems better than none at all. This uses a very hacky regex that will probably miss some variables. But having some docs seems better than none at all. In particular, this generates stubs for the following env vars: - COLORTERM - QNX_TARGET - RUST_BACKTRACE - RUSTC_BLESS - RUSTC_BOOTSTRAP - RUSTC_BREAK_ON_ICE - RUSTC_CTFE_BACKTRACE - RUSTC_FORCE_RUSTC_VERSION - RUSTC_GRAPHVIZ_FONT - RUSTC_ICE - RUSTC_LOG - RUSTC_OVERRIDE_VERSION_STRING - RUSTC_RETRY_LINKER_ON_SEGFAULT - RUSTC_TRANSLATION_NO_DEBUG_ASSERT - RUST_DEP_GRAPH_FILTER - RUST_DEP_GRAPH - RUST_FORBID_DEP_GRAPH_EDGE - RUST_MIN_STACK - RUST_TARGET_PATH - SDKROOT - TERM - UNSTABLE_RUSTDOC_TEST_LINE - UNSTABLE_RUSTDOC_TEST_PATH [rendered](![screenshot of unstable-book running locally, with 14 environment variables shown in the sidebar](https://github.com/user-attachments/assets/8238d094-fb7a-456f-ad43-7c07aa2c44dd)) --- .../COLORTERM.md | 5 +++ .../QNX_TARGET.md | 11 ++++++ .../compiler-environment-variables/SDKROOT.md | 6 ++++ .../compiler-environment-variables/TERM.md | 5 +++ .../src/compiler-flags/terminal-urls.md | 13 +++++++ src/tools/tidy/src/features.rs | 35 +++++++++++++++++++ src/tools/tidy/src/unstable_book.rs | 2 ++ src/tools/unstable-book-gen/src/main.rs | 29 +++++++++++---- .../unstable-book-gen/src/stub-env-var.md | 9 +++++ 9 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 src/doc/unstable-book/src/compiler-environment-variables/COLORTERM.md create mode 100644 src/doc/unstable-book/src/compiler-environment-variables/QNX_TARGET.md create mode 100644 src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md create mode 100644 src/doc/unstable-book/src/compiler-environment-variables/TERM.md create mode 100644 src/doc/unstable-book/src/compiler-flags/terminal-urls.md create mode 100644 src/tools/unstable-book-gen/src/stub-env-var.md diff --git a/src/doc/unstable-book/src/compiler-environment-variables/COLORTERM.md b/src/doc/unstable-book/src/compiler-environment-variables/COLORTERM.md new file mode 100644 index 0000000000000..f5be63b796c94 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-environment-variables/COLORTERM.md @@ -0,0 +1,5 @@ +# `COLORTERM` + +This environment variable is used by [`-Zterminal-urls`] to detect if URLs are supported by the terminal emulator. + +[`-Zterminal-urls`]: ../compiler-flags/terminal-urls.html diff --git a/src/doc/unstable-book/src/compiler-environment-variables/QNX_TARGET.md b/src/doc/unstable-book/src/compiler-environment-variables/QNX_TARGET.md new file mode 100644 index 0000000000000..cc98fc3b3b284 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-environment-variables/QNX_TARGET.md @@ -0,0 +1,11 @@ +# `QNX_TARGET` + +---- + +This environment variable is mandatory when linking on `nto-qnx*_iosock` platforms. It is used to determine an `-L` path to pass to the QNX linker. + +You should [set this variable] by running `source qnxsdp-env.sh`. +See [the QNX docs] for more background information. + +[set this variable]: https://www.qnx.com/developers/docs/qsc/com.qnx.doc.qsc.inst_larg_org/topic/build_server_developer_steps.html +[the QNX docs]: https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html. diff --git a/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md b/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md new file mode 100644 index 0000000000000..b00c2f773ad6d --- /dev/null +++ b/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md @@ -0,0 +1,6 @@ +# `SDKROOT` + +This environment variable is used on MacOS targets. +It is passed through to the linker (either as `-isysroot` or `-syslibroot`) without changes. + +Note that this variable is not always respected. When the SDKROOT is clearly wrong (e.g. when the platform of the SDK does not match the `--target` used by rustc), this is ignored and rustc does its own detection. diff --git a/src/doc/unstable-book/src/compiler-environment-variables/TERM.md b/src/doc/unstable-book/src/compiler-environment-variables/TERM.md new file mode 100644 index 0000000000000..9208fd378a3a5 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-environment-variables/TERM.md @@ -0,0 +1,5 @@ +# `TERM` + +This environment variable is used by [`-Zterminal-urls`] to detect if URLs are supported by the terminal emulator. + +[`-Zterminal-urls`]: ../compiler-flags/terminal-urls.html diff --git a/src/doc/unstable-book/src/compiler-flags/terminal-urls.md b/src/doc/unstable-book/src/compiler-flags/terminal-urls.md new file mode 100644 index 0000000000000..a5427978f258b --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/terminal-urls.md @@ -0,0 +1,13 @@ +# `-Z terminal-urls` + +The tracking feature for this issue is [#125586] + +[#125586]: https://github.com/rust-lang/rust/issues/125586 + +--- + +This flag takes either a boolean or the string "auto". + +When enabled, use the OSC 8 hyperlink terminal specification to print hyperlinks in the compiler output. +Use "auto" to try and autodetect whether the terminal emulator supports hyperlinks. +Currently, "auto" only enables hyperlinks if `COLORTERM=truecolor` and `TERM=xterm-256color`. diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index fcd7943e6e0a8..cbb7e18a8db72 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -9,6 +9,7 @@ //! * All unstable lang features have tests to ensure they are actually unstable. //! * Language features in a group are sorted by feature name. +use std::collections::BTreeSet; use std::collections::hash_map::{Entry, HashMap}; use std::ffi::OsStr; use std::num::NonZeroU32; @@ -21,6 +22,7 @@ use crate::walk::{filter_dirs, filter_not_rust, walk, walk_many}; mod tests; mod version; +use regex::Regex; use version::Version; const FEATURE_GROUP_START_PREFIX: &str = "// feature-group-start"; @@ -610,3 +612,36 @@ fn map_lib_features( }, ); } + +fn should_document(var: &str) -> bool { + if var.starts_with("RUSTC_") || var.starts_with("RUST_") || var.starts_with("UNSTABLE_RUSTDOC_") + { + return true; + } + ["SDKROOT", "QNX_TARGET", "COLORTERM", "TERM"].contains(&var) +} + +pub fn collect_env_vars(compiler: &Path) -> BTreeSet { + let env_var_regex: Regex = Regex::new(r#"env::var(_os)?\("([^"]+)"#).unwrap(); + + let mut vars = BTreeSet::new(); + walk( + compiler, + // skip build scripts, tests, and non-rust files + |path, _is_dir| { + filter_dirs(path) + || filter_not_rust(path) + || path.ends_with("build.rs") + || path.ends_with("tests.rs") + }, + &mut |_entry, contents| { + for env_var in env_var_regex.captures_iter(contents).map(|c| c.get(2).unwrap().as_str()) + { + if should_document(env_var) { + vars.insert(env_var.to_owned()); + } + } + }, + ); + vars +} diff --git a/src/tools/tidy/src/unstable_book.rs b/src/tools/tidy/src/unstable_book.rs index a2453a6c96057..5b0bf2201c173 100644 --- a/src/tools/tidy/src/unstable_book.rs +++ b/src/tools/tidy/src/unstable_book.rs @@ -6,6 +6,8 @@ use crate::features::{CollectedFeatures, Features, Status}; pub const PATH_STR: &str = "doc/unstable-book"; +pub const ENV_VARS_DIR: &str = "src/compiler-environment-variables"; + pub const COMPILER_FLAGS_DIR: &str = "src/compiler-flags"; pub const LANG_FEATURES_DIR: &str = "src/language-features"; diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs index b9a2d313182fd..2a3388590cdf8 100644 --- a/src/tools/unstable-book-gen/src/main.rs +++ b/src/tools/unstable-book-gen/src/main.rs @@ -5,11 +5,11 @@ use std::env; use std::fs::{self, write}; use std::path::Path; -use tidy::features::{Features, collect_lang_features, collect_lib_features}; +use tidy::features::{Features, collect_env_vars, collect_lang_features, collect_lib_features}; use tidy::t; use tidy::unstable_book::{ - LANG_FEATURES_DIR, LIB_FEATURES_DIR, PATH_STR, collect_unstable_book_section_file_names, - collect_unstable_feature_names, + ENV_VARS_DIR, LANG_FEATURES_DIR, LIB_FEATURES_DIR, PATH_STR, + collect_unstable_book_section_file_names, collect_unstable_feature_names, }; fn generate_stub_issue(path: &Path, name: &str, issue: u32) { @@ -22,6 +22,11 @@ fn generate_stub_no_issue(path: &Path, name: &str) { t!(write(path, content), path); } +fn generate_stub_env_var(path: &Path, name: &str) { + let content = format!(include_str!("stub-env-var.md"), name = name); + t!(write(path, content), path); +} + fn set_to_summary_str(set: &BTreeSet, dir: &str) -> String { set.iter() .map(|ref n| format!(" - [{}]({}/{}.md)", n.replace('-', "_"), dir, n)) @@ -54,7 +59,7 @@ fn generate_summary(path: &Path, lang_features: &Features, lib_features: &Featur t!(write(&summary_path, content), summary_path); } -fn generate_unstable_book_files(src: &Path, out: &Path, features: &Features) { +fn generate_feature_files(src: &Path, out: &Path, features: &Features) { let unstable_features = collect_unstable_feature_names(features); let unstable_section_file_names = collect_unstable_book_section_file_names(src); t!(fs::create_dir_all(&out)); @@ -72,6 +77,16 @@ fn generate_unstable_book_files(src: &Path, out: &Path, features: &Features) { } } +fn generate_env_files(src: &Path, out: &Path, env_vars: &BTreeSet) { + let env_var_file_names = collect_unstable_book_section_file_names(src); + t!(fs::create_dir_all(&out)); + for env_var in env_vars - &env_var_file_names { + let file_name = format!("{env_var}.md"); + let out_file_path = out.join(&file_name); + generate_stub_env_var(&out_file_path, &env_var); + } +} + fn copy_recursive(from: &Path, to: &Path) { for entry in t!(fs::read_dir(from)) { let e = t!(entry); @@ -101,21 +116,23 @@ fn main() { .into_iter() .filter(|&(ref name, _)| !lang_features.contains_key(name)) .collect(); + let env_vars = collect_env_vars(compiler_path); let doc_src_path = src_path.join(PATH_STR); t!(fs::create_dir_all(&dest_path)); - generate_unstable_book_files( + generate_feature_files( &doc_src_path.join(LANG_FEATURES_DIR), &dest_path.join(LANG_FEATURES_DIR), &lang_features, ); - generate_unstable_book_files( + generate_feature_files( &doc_src_path.join(LIB_FEATURES_DIR), &dest_path.join(LIB_FEATURES_DIR), &lib_features, ); + generate_env_files(&doc_src_path.join(ENV_VARS_DIR), &dest_path.join(ENV_VARS_DIR), &env_vars); copy_recursive(&doc_src_path, &dest_path); diff --git a/src/tools/unstable-book-gen/src/stub-env-var.md b/src/tools/unstable-book-gen/src/stub-env-var.md new file mode 100644 index 0000000000000..e8a7ddb855a67 --- /dev/null +++ b/src/tools/unstable-book-gen/src/stub-env-var.md @@ -0,0 +1,9 @@ +# `{name}` + +Environment variables have no tracking issue. This environment variable has no documentation, and therefore is likely internal to the compiler and not meant for general use. + +See [the code][github search] for more information. + +[github search]: https://github.com/search?q=repo%3Arust-lang%2Frust+%22{name}%22+path%3Acompiler&type=code + +------------------------ From a383fb0c738967ea8c6af200d8f4a37c751427c1 Mon Sep 17 00:00:00 2001 From: WANG Rui Date: Thu, 9 Jan 2025 20:35:49 +0800 Subject: [PATCH 02/28] asm: Stabilize loongarch32 --- compiler/rustc_ast_lowering/src/asm.rs | 1 + .../asm-experimental-arch.md | 5 -- tests/assembly-llvm/asm/loongarch-type.rs | 51 +++++++++------ .../bad-reg.loongarch32_ilp32d.stderr | 38 ++++++++++++ .../bad-reg.loongarch32_ilp32s.stderr | 62 +++++++++++++++++++ .../bad-reg.loongarch64_lp64d.stderr | 12 ++-- .../bad-reg.loongarch64_lp64s.stderr | 20 +++--- tests/ui/asm/loongarch/bad-reg.rs | 15 +++-- 8 files changed, 158 insertions(+), 46 deletions(-) create mode 100644 tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr create mode 100644 tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index af279e07acc6e..d44faad017ee5 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -48,6 +48,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { | asm::InlineAsmArch::Arm64EC | asm::InlineAsmArch::RiscV32 | asm::InlineAsmArch::RiscV64 + | asm::InlineAsmArch::LoongArch32 | asm::InlineAsmArch::LoongArch64 | asm::InlineAsmArch::S390x ); diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 121f949343594..d9566c9f55c5c 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -19,7 +19,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - M68k - CSKY - SPARC -- LoongArch32 ## Register classes @@ -54,8 +53,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | `f[0-31]` | `f` | | SPARC | `reg` | `r[2-29]` | `r` | | SPARC | `yreg` | `y` | Only clobbers | -| LoongArch32 | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` | -| LoongArch32 | `freg` | `$f[0-31]` | `f` | > **Notes**: > - NVPTX doesn't have a fixed register set, so named registers are not supported. @@ -94,8 +91,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | CSKY | `freg` | None | `f32`, | | SPARC | `reg` | None | `i8`, `i16`, `i32`, `i64` (SPARC64 only) | | SPARC | `yreg` | N/A | Only clobbers | -| LoongArch32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | -| LoongArch32 | `freg` | None | `f32`, `f64` | ## Register aliases diff --git a/tests/assembly-llvm/asm/loongarch-type.rs b/tests/assembly-llvm/asm/loongarch-type.rs index c782be19f1d2a..95d811a6bd0ab 100644 --- a/tests/assembly-llvm/asm/loongarch-type.rs +++ b/tests/assembly-llvm/asm/loongarch-type.rs @@ -1,8 +1,15 @@ //@ add-core-stubs +//@ revisions: loongarch32 loongarch64 + //@ assembly-output: emit-asm -//@ compile-flags: --target loongarch64-unknown-linux-gnu + +//@[loongarch32] compile-flags: --target loongarch32-unknown-none +//@[loongarch32] needs-llvm-components: loongarch + +//@[loongarch64] compile-flags: --target loongarch64-unknown-none +//@[loongarch64] needs-llvm-components: loongarch + //@ compile-flags: -Zmerge-functions=disabled -//@ needs-llvm-components: loongarch #![feature(no_core, f16)] #![crate_type = "rlib"] @@ -22,7 +29,7 @@ extern "C" { // CHECK-LABEL: sym_fn: // CHECK: #APP // CHECK: pcalau12i $t0, %got_pc_hi20(extern_func) -// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_func) +// CHECK: ld.{{[wd]}} $t0, $t0, %got_pc_lo12(extern_func) // CHECK: #NO_APP #[no_mangle] pub unsafe fn sym_fn() { @@ -32,7 +39,7 @@ pub unsafe fn sym_fn() { // CHECK-LABEL: sym_static: // CHECK: #APP // CHECK: pcalau12i $t0, %got_pc_hi20(extern_static) -// CHECK: ld.d $t0, $t0, %got_pc_lo12(extern_static) +// CHECK: ld.{{[wd]}} $t0, $t0, %got_pc_lo12(extern_static) // CHECK: #NO_APP #[no_mangle] pub unsafe fn sym_static() { @@ -87,16 +94,18 @@ check!(reg_i32, i32, reg, "move"); // CHECK: #NO_APP check!(reg_f32, f32, reg, "move"); -// CHECK-LABEL: reg_i64: -// CHECK: #APP -// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} -// CHECK: #NO_APP +// loongarch64-LABEL: reg_i64: +// loongarch64: #APP +// loongarch64: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// loongarch64: #NO_APP +#[cfg(loongarch64)] check!(reg_i64, i64, reg, "move"); -// CHECK-LABEL: reg_f64: -// CHECK: #APP -// CHECK: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} -// CHECK: #NO_APP +// loongarch64-LABEL: reg_f64: +// loongarch64: #APP +// loongarch64: move ${{[a-z0-9]+}}, ${{[a-z0-9]+}} +// loongarch64: #NO_APP +#[cfg(loongarch64)] check!(reg_f64, f64, reg, "move"); // CHECK-LABEL: reg_ptr: @@ -153,16 +162,18 @@ check_reg!(r4_i32, i32, "$r4", "move"); // CHECK: #NO_APP check_reg!(r4_f32, f32, "$r4", "move"); -// CHECK-LABEL: r4_i64: -// CHECK: #APP -// CHECK: move $a0, $a0 -// CHECK: #NO_APP +// loongarch64-LABEL: r4_i64: +// loongarch64: #APP +// loongarch64: move $a0, $a0 +// loongarch64: #NO_APP +#[cfg(loongarch64)] check_reg!(r4_i64, i64, "$r4", "move"); -// CHECK-LABEL: r4_f64: -// CHECK: #APP -// CHECK: move $a0, $a0 -// CHECK: #NO_APP +// loongarch64-LABEL: r4_f64: +// loongarch64: #APP +// loongarch64: move $a0, $a0 +// loongarch64: #NO_APP +#[cfg(loongarch64)] check_reg!(r4_f64, f64, "$r4", "move"); // CHECK-LABEL: r4_ptr: diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr new file mode 100644 index 0000000000000..8742d4bd82cd5 --- /dev/null +++ b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr @@ -0,0 +1,38 @@ +error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:27:18 + | +LL | asm!("", out("$r0") _); + | ^^^^^^^^^^^^ + +error: invalid register `$tp`: reserved for TLS + --> $DIR/bad-reg.rs:29:18 + | +LL | asm!("", out("$tp") _); + | ^^^^^^^^^^^^ + +error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:31:18 + | +LL | asm!("", out("$sp") _); + | ^^^^^^^^^^^^ + +error: invalid register `$r21`: reserved by the ABI + --> $DIR/bad-reg.rs:33:18 + | +LL | asm!("", out("$r21") _); + | ^^^^^^^^^^^^^ + +error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:35:18 + | +LL | asm!("", out("$fp") _); + | ^^^^^^^^^^^^ + +error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:37:18 + | +LL | asm!("", out("$r31") _); + | ^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors + diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr new file mode 100644 index 0000000000000..e6cb6e40c701d --- /dev/null +++ b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr @@ -0,0 +1,62 @@ +error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:27:18 + | +LL | asm!("", out("$r0") _); + | ^^^^^^^^^^^^ + +error: invalid register `$tp`: reserved for TLS + --> $DIR/bad-reg.rs:29:18 + | +LL | asm!("", out("$tp") _); + | ^^^^^^^^^^^^ + +error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:31:18 + | +LL | asm!("", out("$sp") _); + | ^^^^^^^^^^^^ + +error: invalid register `$r21`: reserved by the ABI + --> $DIR/bad-reg.rs:33:18 + | +LL | asm!("", out("$r21") _); + | ^^^^^^^^^^^^^ + +error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:35:18 + | +LL | asm!("", out("$fp") _); + | ^^^^^^^^^^^^ + +error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:37:18 + | +LL | asm!("", out("$r31") _); + | ^^^^^^^^^^^^^ + +error: register class `freg` requires at least one of the following target features: d, f + --> $DIR/bad-reg.rs:41:26 + | +LL | asm!("/* {} */", in(freg) f); + | ^^^^^^^^^^ + +error: register class `freg` requires at least one of the following target features: d, f + --> $DIR/bad-reg.rs:43:26 + | +LL | asm!("/* {} */", out(freg) _); + | ^^^^^^^^^^^ + +error: register class `freg` requires at least one of the following target features: d, f + --> $DIR/bad-reg.rs:45:26 + | +LL | asm!("/* {} */", in(freg) d); + | ^^^^^^^^^^ + +error: register class `freg` requires at least one of the following target features: d, f + --> $DIR/bad-reg.rs:47:26 + | +LL | asm!("/* {} */", out(freg) d); + | ^^^^^^^^^^^ + +error: aborting due to 10 previous errors + diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr index 0e54411965012..8742d4bd82cd5 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr @@ -1,35 +1,35 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:22:18 + --> $DIR/bad-reg.rs:27:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:24:18 + --> $DIR/bad-reg.rs:29:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:26:18 + --> $DIR/bad-reg.rs:31:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:28:18 + --> $DIR/bad-reg.rs:33:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:30:18 + --> $DIR/bad-reg.rs:35:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:37:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr index 6d0410dc6a13f..e6cb6e40c701d 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr @@ -1,59 +1,59 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:22:18 + --> $DIR/bad-reg.rs:27:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:24:18 + --> $DIR/bad-reg.rs:29:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:26:18 + --> $DIR/bad-reg.rs:31:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:28:18 + --> $DIR/bad-reg.rs:33:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:30:18 + --> $DIR/bad-reg.rs:35:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:37:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:36:26 + --> $DIR/bad-reg.rs:41:26 | LL | asm!("/* {} */", in(freg) f); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:38:26 + --> $DIR/bad-reg.rs:43:26 | LL | asm!("/* {} */", out(freg) _); | ^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:40:26 + --> $DIR/bad-reg.rs:45:26 | LL | asm!("/* {} */", in(freg) d); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:42:26 + --> $DIR/bad-reg.rs:47:26 | LL | asm!("/* {} */", out(freg) d); | ^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.rs b/tests/ui/asm/loongarch/bad-reg.rs index 685b460bc922c..0d3eba07f14da 100644 --- a/tests/ui/asm/loongarch/bad-reg.rs +++ b/tests/ui/asm/loongarch/bad-reg.rs @@ -1,6 +1,11 @@ //@ add-core-stubs //@ needs-asm-support -//@ revisions: loongarch64_lp64d loongarch64_lp64s +//@ revisions: loongarch32_ilp32d loongarch32_ilp32s loongarch64_lp64d loongarch64_lp64s +//@ min-llvm-version: 20 +//@[loongarch32_ilp32d] compile-flags: --target loongarch32-unknown-none +//@[loongarch32_ilp32d] needs-llvm-components: loongarch +//@[loongarch32_ilp32s] compile-flags: --target loongarch32-unknown-none-softfloat +//@[loongarch32_ilp32s] needs-llvm-components: loongarch //@[loongarch64_lp64d] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64_lp64d] needs-llvm-components: loongarch //@[loongarch64_lp64s] compile-flags: --target loongarch64-unknown-none-softfloat @@ -34,12 +39,12 @@ fn f() { asm!("", out("$f0") _); // ok asm!("/* {} */", in(freg) f); - //[loongarch64_lp64s]~^ ERROR register class `freg` requires at least one of the following target features: d, f + //[loongarch32_ilp32s,loongarch64_lp64s]~^ ERROR register class `freg` requires at least one of the following target features: d, f asm!("/* {} */", out(freg) _); - //[loongarch64_lp64s]~^ ERROR register class `freg` requires at least one of the following target features: d, f + //[loongarch32_ilp32s,loongarch64_lp64s]~^ ERROR register class `freg` requires at least one of the following target features: d, f asm!("/* {} */", in(freg) d); - //[loongarch64_lp64s]~^ ERROR register class `freg` requires at least one of the following target features: d, f + //[loongarch32_ilp32s,loongarch64_lp64s]~^ ERROR register class `freg` requires at least one of the following target features: d, f asm!("/* {} */", out(freg) d); - //[loongarch64_lp64s]~^ ERROR register class `freg` requires at least one of the following target features: d, f + //[loongarch32_ilp32s,loongarch64_lp64s]~^ ERROR register class `freg` requires at least one of the following target features: d, f } } From 90bb5cacb5c1a5fe20ba821d28e7eb7a21e35d09 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 24 Jul 2025 18:29:09 +0500 Subject: [PATCH 03/28] moved 34 tests to organized locations --- .../issue-16256.rs => closures/unused-closure-warning-16256.rs} | 0 .../array-slice-coercion-mismatch-15783.rs} | 0 .../derive-partial-ord-discriminant-64bit.rs} | 0 .../issue-15523.rs => derives/derive-partial-ord-discriminant.rs} | 0 .../ui/{issues/issue-15763.rs => drop/early-return-drop-order.rs} | 0 tests/ui/{issues/issue-15063.rs => drop/enum-drop-impl-15063.rs} | 0 .../issue-15858.rs => drop/generic-drop-trait-bound-15858.rs} | 0 .../ui/{issues/issue-16492.rs => drop/struct-field-drop-order.rs} | 0 .../issue-16151.rs => drop/vec-replace-skip-while-drop.rs} | 0 .../issue-16441.rs => extern/empty-struct-extern-fn-16441.rs} | 0 .../issue-15094.rs => fn/fn-traits-call-once-signature.rs} | 0 .../issue-15774.rs => imports/enum-variant-import-path-15774.rs} | 0 .../return-block-type-inference-15965.rs} | 0 .../issue-15756.rs => iterators/chunk-iterator-mut-pattern.rs} | 0 .../issue-15673.rs => iterators/iterator-sum-array-15673.rs} | 0 .../explicit-lifetime-required-15034.rs} | 0 .../struct-lifetime-inference-15735.rs} | 0 .../issue-15167.rs => macros/macro-hygiene-scope-15167.rs} | 0 .../issue-15189.rs => macros/macro-variable-capture-15189.rs} | 0 .../issue-15793.rs => match/nested-enum-match-optimization.rs} | 0 .../issue-15571.rs => moves/match-move-same-binding-15571.rs} | 0 .../issue-15207.rs => never/never-type-method-call-15207.rs} | 0 .../issue-15896.rs => pattern/enum-struct-pattern-mismatch.rs} | 0 .../refutable-pattern-for-loop-15381.rs} | 0 .../issue-15104.rs => pattern/slice-pattern-recursion-15104.rs} | 0 .../issue-16149.rs => pattern/static-binding-shadow-16149.rs} | 0 .../issue-15260.rs => pattern/struct-field-duplicate-binding.rs} | 0 .../issue-15129-rpass.rs => pattern/tuple-enum-match-15129.rs} | 0 .../unit-type-struct-pattern-mismatch.rs} | 0 .../issue-16452.rs => statics/conditional-static-declaration.rs} | 0 .../issue-15043.rs => structs/static-struct-init-15043.rs} | 0 .../{issues/issue-15444.rs => traits/fn-type-trait-impl-15444.rs} | 0 .../issue-15734.rs => traits/index-trait-multiple-impls.rs} | 0 .../issue-16048.rs => traits/lifetime-mismatch-trait-impl.rs} | 0 34 files changed, 0 insertions(+), 0 deletions(-) rename tests/ui/{issues/issue-16256.rs => closures/unused-closure-warning-16256.rs} (100%) rename tests/ui/{issues/issue-15783.rs => coercion/array-slice-coercion-mismatch-15783.rs} (100%) rename tests/ui/{issues/issue-15523-big.rs => derives/derive-partial-ord-discriminant-64bit.rs} (100%) rename tests/ui/{issues/issue-15523.rs => derives/derive-partial-ord-discriminant.rs} (100%) rename tests/ui/{issues/issue-15763.rs => drop/early-return-drop-order.rs} (100%) rename tests/ui/{issues/issue-15063.rs => drop/enum-drop-impl-15063.rs} (100%) rename tests/ui/{issues/issue-15858.rs => drop/generic-drop-trait-bound-15858.rs} (100%) rename tests/ui/{issues/issue-16492.rs => drop/struct-field-drop-order.rs} (100%) rename tests/ui/{issues/issue-16151.rs => drop/vec-replace-skip-while-drop.rs} (100%) rename tests/ui/{issues/issue-16441.rs => extern/empty-struct-extern-fn-16441.rs} (100%) rename tests/ui/{issues/issue-15094.rs => fn/fn-traits-call-once-signature.rs} (100%) rename tests/ui/{issues/issue-15774.rs => imports/enum-variant-import-path-15774.rs} (100%) rename tests/ui/{issues/issue-15965.rs => inference/return-block-type-inference-15965.rs} (100%) rename tests/ui/{issues/issue-15756.rs => iterators/chunk-iterator-mut-pattern.rs} (100%) rename tests/ui/{issues/issue-15673.rs => iterators/iterator-sum-array-15673.rs} (100%) rename tests/ui/{issues/issue-15034.rs => lifetimes/explicit-lifetime-required-15034.rs} (100%) rename tests/ui/{issues/issue-15735.rs => lifetimes/struct-lifetime-inference-15735.rs} (100%) rename tests/ui/{issues/issue-15167.rs => macros/macro-hygiene-scope-15167.rs} (100%) rename tests/ui/{issues/issue-15189.rs => macros/macro-variable-capture-15189.rs} (100%) rename tests/ui/{issues/issue-15793.rs => match/nested-enum-match-optimization.rs} (100%) rename tests/ui/{issues/issue-15571.rs => moves/match-move-same-binding-15571.rs} (100%) rename tests/ui/{issues/issue-15207.rs => never/never-type-method-call-15207.rs} (100%) rename tests/ui/{issues/issue-15896.rs => pattern/enum-struct-pattern-mismatch.rs} (100%) rename tests/ui/{issues/issue-15381.rs => pattern/refutable-pattern-for-loop-15381.rs} (100%) rename tests/ui/{issues/issue-15104.rs => pattern/slice-pattern-recursion-15104.rs} (100%) rename tests/ui/{issues/issue-16149.rs => pattern/static-binding-shadow-16149.rs} (100%) rename tests/ui/{issues/issue-15260.rs => pattern/struct-field-duplicate-binding.rs} (100%) rename tests/ui/{issues/issue-15129-rpass.rs => pattern/tuple-enum-match-15129.rs} (100%) rename tests/ui/{issues/issue-16401.rs => pattern/unit-type-struct-pattern-mismatch.rs} (100%) rename tests/ui/{issues/issue-16452.rs => statics/conditional-static-declaration.rs} (100%) rename tests/ui/{issues/issue-15043.rs => structs/static-struct-init-15043.rs} (100%) rename tests/ui/{issues/issue-15444.rs => traits/fn-type-trait-impl-15444.rs} (100%) rename tests/ui/{issues/issue-15734.rs => traits/index-trait-multiple-impls.rs} (100%) rename tests/ui/{issues/issue-16048.rs => traits/lifetime-mismatch-trait-impl.rs} (100%) diff --git a/tests/ui/issues/issue-16256.rs b/tests/ui/closures/unused-closure-warning-16256.rs similarity index 100% rename from tests/ui/issues/issue-16256.rs rename to tests/ui/closures/unused-closure-warning-16256.rs diff --git a/tests/ui/issues/issue-15783.rs b/tests/ui/coercion/array-slice-coercion-mismatch-15783.rs similarity index 100% rename from tests/ui/issues/issue-15783.rs rename to tests/ui/coercion/array-slice-coercion-mismatch-15783.rs diff --git a/tests/ui/issues/issue-15523-big.rs b/tests/ui/derives/derive-partial-ord-discriminant-64bit.rs similarity index 100% rename from tests/ui/issues/issue-15523-big.rs rename to tests/ui/derives/derive-partial-ord-discriminant-64bit.rs diff --git a/tests/ui/issues/issue-15523.rs b/tests/ui/derives/derive-partial-ord-discriminant.rs similarity index 100% rename from tests/ui/issues/issue-15523.rs rename to tests/ui/derives/derive-partial-ord-discriminant.rs diff --git a/tests/ui/issues/issue-15763.rs b/tests/ui/drop/early-return-drop-order.rs similarity index 100% rename from tests/ui/issues/issue-15763.rs rename to tests/ui/drop/early-return-drop-order.rs diff --git a/tests/ui/issues/issue-15063.rs b/tests/ui/drop/enum-drop-impl-15063.rs similarity index 100% rename from tests/ui/issues/issue-15063.rs rename to tests/ui/drop/enum-drop-impl-15063.rs diff --git a/tests/ui/issues/issue-15858.rs b/tests/ui/drop/generic-drop-trait-bound-15858.rs similarity index 100% rename from tests/ui/issues/issue-15858.rs rename to tests/ui/drop/generic-drop-trait-bound-15858.rs diff --git a/tests/ui/issues/issue-16492.rs b/tests/ui/drop/struct-field-drop-order.rs similarity index 100% rename from tests/ui/issues/issue-16492.rs rename to tests/ui/drop/struct-field-drop-order.rs diff --git a/tests/ui/issues/issue-16151.rs b/tests/ui/drop/vec-replace-skip-while-drop.rs similarity index 100% rename from tests/ui/issues/issue-16151.rs rename to tests/ui/drop/vec-replace-skip-while-drop.rs diff --git a/tests/ui/issues/issue-16441.rs b/tests/ui/extern/empty-struct-extern-fn-16441.rs similarity index 100% rename from tests/ui/issues/issue-16441.rs rename to tests/ui/extern/empty-struct-extern-fn-16441.rs diff --git a/tests/ui/issues/issue-15094.rs b/tests/ui/fn/fn-traits-call-once-signature.rs similarity index 100% rename from tests/ui/issues/issue-15094.rs rename to tests/ui/fn/fn-traits-call-once-signature.rs diff --git a/tests/ui/issues/issue-15774.rs b/tests/ui/imports/enum-variant-import-path-15774.rs similarity index 100% rename from tests/ui/issues/issue-15774.rs rename to tests/ui/imports/enum-variant-import-path-15774.rs diff --git a/tests/ui/issues/issue-15965.rs b/tests/ui/inference/return-block-type-inference-15965.rs similarity index 100% rename from tests/ui/issues/issue-15965.rs rename to tests/ui/inference/return-block-type-inference-15965.rs diff --git a/tests/ui/issues/issue-15756.rs b/tests/ui/iterators/chunk-iterator-mut-pattern.rs similarity index 100% rename from tests/ui/issues/issue-15756.rs rename to tests/ui/iterators/chunk-iterator-mut-pattern.rs diff --git a/tests/ui/issues/issue-15673.rs b/tests/ui/iterators/iterator-sum-array-15673.rs similarity index 100% rename from tests/ui/issues/issue-15673.rs rename to tests/ui/iterators/iterator-sum-array-15673.rs diff --git a/tests/ui/issues/issue-15034.rs b/tests/ui/lifetimes/explicit-lifetime-required-15034.rs similarity index 100% rename from tests/ui/issues/issue-15034.rs rename to tests/ui/lifetimes/explicit-lifetime-required-15034.rs diff --git a/tests/ui/issues/issue-15735.rs b/tests/ui/lifetimes/struct-lifetime-inference-15735.rs similarity index 100% rename from tests/ui/issues/issue-15735.rs rename to tests/ui/lifetimes/struct-lifetime-inference-15735.rs diff --git a/tests/ui/issues/issue-15167.rs b/tests/ui/macros/macro-hygiene-scope-15167.rs similarity index 100% rename from tests/ui/issues/issue-15167.rs rename to tests/ui/macros/macro-hygiene-scope-15167.rs diff --git a/tests/ui/issues/issue-15189.rs b/tests/ui/macros/macro-variable-capture-15189.rs similarity index 100% rename from tests/ui/issues/issue-15189.rs rename to tests/ui/macros/macro-variable-capture-15189.rs diff --git a/tests/ui/issues/issue-15793.rs b/tests/ui/match/nested-enum-match-optimization.rs similarity index 100% rename from tests/ui/issues/issue-15793.rs rename to tests/ui/match/nested-enum-match-optimization.rs diff --git a/tests/ui/issues/issue-15571.rs b/tests/ui/moves/match-move-same-binding-15571.rs similarity index 100% rename from tests/ui/issues/issue-15571.rs rename to tests/ui/moves/match-move-same-binding-15571.rs diff --git a/tests/ui/issues/issue-15207.rs b/tests/ui/never/never-type-method-call-15207.rs similarity index 100% rename from tests/ui/issues/issue-15207.rs rename to tests/ui/never/never-type-method-call-15207.rs diff --git a/tests/ui/issues/issue-15896.rs b/tests/ui/pattern/enum-struct-pattern-mismatch.rs similarity index 100% rename from tests/ui/issues/issue-15896.rs rename to tests/ui/pattern/enum-struct-pattern-mismatch.rs diff --git a/tests/ui/issues/issue-15381.rs b/tests/ui/pattern/refutable-pattern-for-loop-15381.rs similarity index 100% rename from tests/ui/issues/issue-15381.rs rename to tests/ui/pattern/refutable-pattern-for-loop-15381.rs diff --git a/tests/ui/issues/issue-15104.rs b/tests/ui/pattern/slice-pattern-recursion-15104.rs similarity index 100% rename from tests/ui/issues/issue-15104.rs rename to tests/ui/pattern/slice-pattern-recursion-15104.rs diff --git a/tests/ui/issues/issue-16149.rs b/tests/ui/pattern/static-binding-shadow-16149.rs similarity index 100% rename from tests/ui/issues/issue-16149.rs rename to tests/ui/pattern/static-binding-shadow-16149.rs diff --git a/tests/ui/issues/issue-15260.rs b/tests/ui/pattern/struct-field-duplicate-binding.rs similarity index 100% rename from tests/ui/issues/issue-15260.rs rename to tests/ui/pattern/struct-field-duplicate-binding.rs diff --git a/tests/ui/issues/issue-15129-rpass.rs b/tests/ui/pattern/tuple-enum-match-15129.rs similarity index 100% rename from tests/ui/issues/issue-15129-rpass.rs rename to tests/ui/pattern/tuple-enum-match-15129.rs diff --git a/tests/ui/issues/issue-16401.rs b/tests/ui/pattern/unit-type-struct-pattern-mismatch.rs similarity index 100% rename from tests/ui/issues/issue-16401.rs rename to tests/ui/pattern/unit-type-struct-pattern-mismatch.rs diff --git a/tests/ui/issues/issue-16452.rs b/tests/ui/statics/conditional-static-declaration.rs similarity index 100% rename from tests/ui/issues/issue-16452.rs rename to tests/ui/statics/conditional-static-declaration.rs diff --git a/tests/ui/issues/issue-15043.rs b/tests/ui/structs/static-struct-init-15043.rs similarity index 100% rename from tests/ui/issues/issue-15043.rs rename to tests/ui/structs/static-struct-init-15043.rs diff --git a/tests/ui/issues/issue-15444.rs b/tests/ui/traits/fn-type-trait-impl-15444.rs similarity index 100% rename from tests/ui/issues/issue-15444.rs rename to tests/ui/traits/fn-type-trait-impl-15444.rs diff --git a/tests/ui/issues/issue-15734.rs b/tests/ui/traits/index-trait-multiple-impls.rs similarity index 100% rename from tests/ui/issues/issue-15734.rs rename to tests/ui/traits/index-trait-multiple-impls.rs diff --git a/tests/ui/issues/issue-16048.rs b/tests/ui/traits/lifetime-mismatch-trait-impl.rs similarity index 100% rename from tests/ui/issues/issue-16048.rs rename to tests/ui/traits/lifetime-mismatch-trait-impl.rs From d9b725abb02c5c648b847b0b4d13b213567df0e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Fri, 8 Aug 2025 13:16:07 +0200 Subject: [PATCH 04/28] Improve error output when a command fails in bootstrap --- src/bootstrap/src/utils/exec.rs | 165 ++++++++++++++++---------------- 1 file changed, 83 insertions(+), 82 deletions(-) diff --git a/src/bootstrap/src/utils/exec.rs b/src/bootstrap/src/utils/exec.rs index 7527dff9cd843..03760faec690b 100644 --- a/src/bootstrap/src/utils/exec.rs +++ b/src/bootstrap/src/utils/exec.rs @@ -80,11 +80,21 @@ impl CommandFingerprint { /// Helper method to format both Command and BootstrapCommand as a short execution line, /// without all the other details (e.g. environment variables). pub fn format_short_cmd(&self) -> String { - let program = Path::new(&self.program); - let mut line = vec![program.file_name().unwrap().to_str().unwrap().to_owned()]; - line.extend(self.args.iter().map(|arg| arg.to_string_lossy().into_owned())); - line.extend(self.cwd.iter().map(|p| p.to_string_lossy().into_owned())); - line.join(" ") + use std::fmt::Write; + + let mut cmd = self.program.to_string_lossy().to_string(); + for arg in &self.args { + let arg = arg.to_string_lossy(); + if arg.contains(' ') { + write!(cmd, " '{arg}'").unwrap(); + } else { + write!(cmd, " {arg}").unwrap(); + } + } + if let Some(cwd) = &self.cwd { + write!(cmd, " [workdir={}]", cwd.to_string_lossy()).unwrap(); + } + cmd } } @@ -434,8 +444,8 @@ impl From for BootstrapCommand { enum CommandStatus { /// The command has started and finished with some status. Finished(ExitStatus), - /// It was not even possible to start the command. - DidNotStart, + /// It was not even possible to start the command or wait for it to finish. + DidNotStartOrFinish, } /// Create a new BootstrapCommand. This is a helper function to make command creation @@ -456,9 +466,9 @@ pub struct CommandOutput { impl CommandOutput { #[must_use] - pub fn did_not_start(stdout: OutputMode, stderr: OutputMode) -> Self { + pub fn not_finished(stdout: OutputMode, stderr: OutputMode) -> Self { Self { - status: CommandStatus::DidNotStart, + status: CommandStatus::DidNotStartOrFinish, stdout: match stdout { OutputMode::Print => None, OutputMode::Capture => Some(vec![]), @@ -489,7 +499,7 @@ impl CommandOutput { pub fn is_success(&self) -> bool { match self.status { CommandStatus::Finished(status) => status.success(), - CommandStatus::DidNotStart => false, + CommandStatus::DidNotStartOrFinish => false, } } @@ -501,7 +511,7 @@ impl CommandOutput { pub fn status(&self) -> Option { match self.status { CommandStatus::Finished(status) => Some(status), - CommandStatus::DidNotStart => None, + CommandStatus::DidNotStartOrFinish => None, } } @@ -745,25 +755,11 @@ impl ExecutionContext { self.start(command, stdout, stderr).wait_for_output(self) } - fn fail(&self, message: &str, output: CommandOutput) -> ! { - if self.is_verbose() { - println!("{message}"); - } else { - let (stdout, stderr) = (output.stdout_if_present(), output.stderr_if_present()); - // If the command captures output, the user would not see any indication that - // it has failed. In this case, print a more verbose error, since to provide more - // context. - if stdout.is_some() || stderr.is_some() { - if let Some(stdout) = output.stdout_if_present().take_if(|s| !s.trim().is_empty()) { - println!("STDOUT:\n{stdout}\n"); - } - if let Some(stderr) = output.stderr_if_present().take_if(|s| !s.trim().is_empty()) { - println!("STDERR:\n{stderr}\n"); - } - println!("Command has failed. Rerun with -v to see more details."); - } else { - println!("Command has failed. Rerun with -v to see more details."); - } + fn fail(&self, message: &str) -> ! { + println!("{message}"); + + if !self.is_verbose() { + println!("Command has failed. Rerun with -v to see more details."); } exit!(1); } @@ -856,7 +852,7 @@ impl<'a> DeferredCommand<'a> { && command.should_cache { exec_ctx.command_cache.insert(fingerprint.clone(), output.clone()); - exec_ctx.profiler.record_execution(fingerprint.clone(), start_time); + exec_ctx.profiler.record_execution(fingerprint, start_time); } output @@ -872,6 +868,8 @@ impl<'a> DeferredCommand<'a> { executed_at: &'a std::panic::Location<'a>, exec_ctx: &ExecutionContext, ) -> CommandOutput { + use std::fmt::Write; + command.mark_as_executed(); let process = match process.take() { @@ -881,79 +879,82 @@ impl<'a> DeferredCommand<'a> { let created_at = command.get_created_location(); - let mut message = String::new(); + #[allow(clippy::enum_variant_names)] + enum FailureReason { + FailedAtRuntime(ExitStatus), + FailedToFinish(std::io::Error), + FailedToStart(std::io::Error), + } - let output = match process { + let (output, fail_reason) = match process { Ok(child) => match child.wait_with_output() { - Ok(result) if result.status.success() => { + Ok(output) if output.status.success() => { // Successful execution - CommandOutput::from_output(result, stdout, stderr) + (CommandOutput::from_output(output, stdout, stderr), None) } - Ok(result) => { - // Command ran but failed - use std::fmt::Write; - - writeln!( - message, - r#" -Command {command:?} did not execute successfully. -Expected success, got {} -Created at: {created_at} -Executed at: {executed_at}"#, - result.status, + Ok(output) => { + // Command started, but then it failed + let status = output.status; + ( + CommandOutput::from_output(output, stdout, stderr), + Some(FailureReason::FailedAtRuntime(status)), ) - .unwrap(); - - let output = CommandOutput::from_output(result, stdout, stderr); - - if stdout.captures() { - writeln!(message, "\nSTDOUT ----\n{}", output.stdout().trim()).unwrap(); - } - if stderr.captures() { - writeln!(message, "\nSTDERR ----\n{}", output.stderr().trim()).unwrap(); - } - - output } Err(e) => { // Failed to wait for output - use std::fmt::Write; - - writeln!( - message, - "\n\nCommand {command:?} did not execute successfully.\ - \nIt was not possible to execute the command: {e:?}" + ( + CommandOutput::not_finished(stdout, stderr), + Some(FailureReason::FailedToFinish(e)), ) - .unwrap(); - - CommandOutput::did_not_start(stdout, stderr) } }, Err(e) => { // Failed to spawn the command - use std::fmt::Write; - - writeln!( - message, - "\n\nCommand {command:?} did not execute successfully.\ - \nIt was not possible to execute the command: {e:?}" - ) - .unwrap(); - - CommandOutput::did_not_start(stdout, stderr) + (CommandOutput::not_finished(stdout, stderr), Some(FailureReason::FailedToStart(e))) } }; - if !output.is_success() { + if let Some(fail_reason) = fail_reason { + let mut error_message = String::new(); + let command_str = if exec_ctx.is_verbose() { + format!("{command:?}") + } else { + command.fingerprint().format_short_cmd() + }; + let action = match fail_reason { + FailureReason::FailedAtRuntime(e) => { + format!("failed with exit code {}", e.code().unwrap_or(1)) + } + FailureReason::FailedToFinish(e) => { + format!("failed to finish: {e:?}") + } + FailureReason::FailedToStart(e) => { + format!("failed to start: {e:?}") + } + }; + writeln!( + error_message, + r#"Command `{command_str}` {action} +Created at: {created_at} +Executed at: {executed_at}"#, + ) + .unwrap(); + if stdout.captures() { + writeln!(error_message, "\n--- STDOUT vvv\n{}", output.stdout().trim()).unwrap(); + } + if stderr.captures() { + writeln!(error_message, "\n--- STDERR vvv\n{}", output.stderr().trim()).unwrap(); + } + match command.failure_behavior { BehaviorOnFailure::DelayFail => { if exec_ctx.fail_fast { - exec_ctx.fail(&message, output); + exec_ctx.fail(&error_message); } - exec_ctx.add_to_delay_failure(message); + exec_ctx.add_to_delay_failure(error_message); } BehaviorOnFailure::Exit => { - exec_ctx.fail(&message, output); + exec_ctx.fail(&error_message); } BehaviorOnFailure::Ignore => { // If failures are allowed, either the error has been printed already From 43327b5da6bc4ccbddebb935b1bcf362ccb8f993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 14 Feb 2025 11:06:06 +0000 Subject: [PATCH 05/28] switch polonius compare-mode to polonius=next --- src/tools/compiletest/src/runtest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f283a625f977c..debf67e2741dd 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -1766,7 +1766,7 @@ impl<'test> TestCx<'test> { match self.config.compare_mode { Some(CompareMode::Polonius) => { - rustc.args(&["-Zpolonius"]); + rustc.args(&["-Zpolonius=next"]); } Some(CompareMode::NextSolver) => { rustc.args(&["-Znext-solver"]); From f4094ea25236bc4ba3d9b7b03d2674ba7ab92907 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 24 Mar 2025 07:09:18 +0000 Subject: [PATCH 06/28] update test expectations for boring locals + dropckoutlives interactions The suboptimal error only appears with NLLs due to liveness differences where polonius cannot have as many boring locals. Sometimes this causes NLLs to emit a duplicate error as well. --- ...err => dropck-normalize-errors.nll.stderr} | 24 +++---- .../dropck-normalize-errors.polonius.stderr | 64 +++++++++++++++++++ tests/ui/drop/dropck-normalize-errors.rs | 6 +- ... => hir-wf-check-erase-regions.nll.stderr} | 8 +-- ...hir-wf-check-erase-regions.polonius.stderr | 39 +++++++++++ tests/ui/wf/hir-wf-check-erase-regions.rs | 6 +- 6 files changed, 129 insertions(+), 18 deletions(-) rename tests/ui/drop/{dropck-normalize-errors.stderr => dropck-normalize-errors.nll.stderr} (82%) create mode 100644 tests/ui/drop/dropck-normalize-errors.polonius.stderr rename tests/ui/wf/{hir-wf-check-erase-regions.stderr => hir-wf-check-erase-regions.nll.stderr} (91%) create mode 100644 tests/ui/wf/hir-wf-check-erase-regions.polonius.stderr diff --git a/tests/ui/drop/dropck-normalize-errors.stderr b/tests/ui/drop/dropck-normalize-errors.nll.stderr similarity index 82% rename from tests/ui/drop/dropck-normalize-errors.stderr rename to tests/ui/drop/dropck-normalize-errors.nll.stderr index 2bb5909c6b226..b008daa51a33e 100644 --- a/tests/ui/drop/dropck-normalize-errors.stderr +++ b/tests/ui/drop/dropck-normalize-errors.nll.stderr @@ -1,44 +1,44 @@ error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied in `ADecoder<'a>` - --> $DIR/dropck-normalize-errors.rs:15:28 + --> $DIR/dropck-normalize-errors.rs:19:28 | LL | fn make_a_decoder<'a>() -> ADecoder<'a> { | ^^^^^^^^^^^^ within `ADecoder<'a>`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` | help: this trait has no implementations, consider adding one - --> $DIR/dropck-normalize-errors.rs:7:1 + --> $DIR/dropck-normalize-errors.rs:11:1 | LL | trait NonImplementedTrait { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it appears within the type `BDecoder` - --> $DIR/dropck-normalize-errors.rs:26:12 + --> $DIR/dropck-normalize-errors.rs:30:12 | LL | pub struct BDecoder { | ^^^^^^^^ note: required because it appears within the type `ADecoder<'a>` - --> $DIR/dropck-normalize-errors.rs:12:12 + --> $DIR/dropck-normalize-errors.rs:16:12 | LL | pub struct ADecoder<'a> { | ^^^^^^^^ = note: the return type of a function must have a statically known size error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied in `BDecoder` - --> $DIR/dropck-normalize-errors.rs:23:20 + --> $DIR/dropck-normalize-errors.rs:27:20 | LL | type Decoder = BDecoder; | ^^^^^^^^ within `BDecoder`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` | help: this trait has no implementations, consider adding one - --> $DIR/dropck-normalize-errors.rs:7:1 + --> $DIR/dropck-normalize-errors.rs:11:1 | LL | trait NonImplementedTrait { | ^^^^^^^^^^^^^^^^^^^^^^^^^ note: required because it appears within the type `BDecoder` - --> $DIR/dropck-normalize-errors.rs:26:12 + --> $DIR/dropck-normalize-errors.rs:30:12 | LL | pub struct BDecoder { | ^^^^^^^^ note: required by a bound in `Decode::Decoder` - --> $DIR/dropck-normalize-errors.rs:4:5 + --> $DIR/dropck-normalize-errors.rs:8:5 | LL | type Decoder; | ^^^^^^^^^^^^^ required by this bound in `Decode::Decoder` @@ -48,25 +48,25 @@ LL | type Decoder: ?Sized; | ++++++++ error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied - --> $DIR/dropck-normalize-errors.rs:27:22 + --> $DIR/dropck-normalize-errors.rs:31:22 | LL | non_implemented: ::Assoc, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` | help: this trait has no implementations, consider adding one - --> $DIR/dropck-normalize-errors.rs:7:1 + --> $DIR/dropck-normalize-errors.rs:11:1 | LL | trait NonImplementedTrait { | ^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied - --> $DIR/dropck-normalize-errors.rs:15:28 + --> $DIR/dropck-normalize-errors.rs:19:28 | LL | fn make_a_decoder<'a>() -> ADecoder<'a> { | ^^^^^^^^^^^^ the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` | help: this trait has no implementations, consider adding one - --> $DIR/dropck-normalize-errors.rs:7:1 + --> $DIR/dropck-normalize-errors.rs:11:1 | LL | trait NonImplementedTrait { | ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/drop/dropck-normalize-errors.polonius.stderr b/tests/ui/drop/dropck-normalize-errors.polonius.stderr new file mode 100644 index 0000000000000..f8674b8e34a42 --- /dev/null +++ b/tests/ui/drop/dropck-normalize-errors.polonius.stderr @@ -0,0 +1,64 @@ +error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied in `ADecoder<'a>` + --> $DIR/dropck-normalize-errors.rs:19:28 + | +LL | fn make_a_decoder<'a>() -> ADecoder<'a> { + | ^^^^^^^^^^^^ within `ADecoder<'a>`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | +help: this trait has no implementations, consider adding one + --> $DIR/dropck-normalize-errors.rs:11:1 + | +LL | trait NonImplementedTrait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `BDecoder` + --> $DIR/dropck-normalize-errors.rs:30:12 + | +LL | pub struct BDecoder { + | ^^^^^^^^ +note: required because it appears within the type `ADecoder<'a>` + --> $DIR/dropck-normalize-errors.rs:16:12 + | +LL | pub struct ADecoder<'a> { + | ^^^^^^^^ + = note: the return type of a function must have a statically known size + +error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied in `BDecoder` + --> $DIR/dropck-normalize-errors.rs:27:20 + | +LL | type Decoder = BDecoder; + | ^^^^^^^^ within `BDecoder`, the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | +help: this trait has no implementations, consider adding one + --> $DIR/dropck-normalize-errors.rs:11:1 + | +LL | trait NonImplementedTrait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +note: required because it appears within the type `BDecoder` + --> $DIR/dropck-normalize-errors.rs:30:12 + | +LL | pub struct BDecoder { + | ^^^^^^^^ +note: required by a bound in `Decode::Decoder` + --> $DIR/dropck-normalize-errors.rs:8:5 + | +LL | type Decoder; + | ^^^^^^^^^^^^^ required by this bound in `Decode::Decoder` +help: consider relaxing the implicit `Sized` restriction + | +LL | type Decoder: ?Sized; + | ++++++++ + +error[E0277]: the trait bound `NonImplementedStruct: NonImplementedTrait` is not satisfied + --> $DIR/dropck-normalize-errors.rs:31:22 + | +LL | non_implemented: ::Assoc, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `NonImplementedTrait` is not implemented for `NonImplementedStruct` + | +help: this trait has no implementations, consider adding one + --> $DIR/dropck-normalize-errors.rs:11:1 + | +LL | trait NonImplementedTrait { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/drop/dropck-normalize-errors.rs b/tests/ui/drop/dropck-normalize-errors.rs index 793122bd33d4b..2ade63f27c5f6 100644 --- a/tests/ui/drop/dropck-normalize-errors.rs +++ b/tests/ui/drop/dropck-normalize-errors.rs @@ -1,5 +1,9 @@ // Test that we don't ICE when computing the drop types for +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: nll polonius +//@ [polonius] compile-flags: -Zpolonius=next + trait Decode<'a> { type Decoder; } @@ -14,7 +18,7 @@ pub struct ADecoder<'a> { } fn make_a_decoder<'a>() -> ADecoder<'a> { //~^ ERROR the trait bound - //~| ERROR the trait bound + //[nll]~| ERROR the trait bound panic!() } diff --git a/tests/ui/wf/hir-wf-check-erase-regions.stderr b/tests/ui/wf/hir-wf-check-erase-regions.nll.stderr similarity index 91% rename from tests/ui/wf/hir-wf-check-erase-regions.stderr rename to tests/ui/wf/hir-wf-check-erase-regions.nll.stderr index 07304cd448ebb..dcade3aa36796 100644 --- a/tests/ui/wf/hir-wf-check-erase-regions.stderr +++ b/tests/ui/wf/hir-wf-check-erase-regions.nll.stderr @@ -1,5 +1,5 @@ error[E0277]: `&'a T` is not an iterator - --> $DIR/hir-wf-check-erase-regions.rs:7:21 + --> $DIR/hir-wf-check-erase-regions.rs:11:21 | LL | type IntoIter = std::iter::Flatten>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator @@ -11,7 +11,7 @@ note: required by a bound in `std::iter::IntoIterator::IntoIter` --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL error[E0277]: `&'a T` is not an iterator - --> $DIR/hir-wf-check-erase-regions.rs:7:5 + --> $DIR/hir-wf-check-erase-regions.rs:11:5 | LL | type IntoIter = std::iter::Flatten>; | ^^^^^^^^^^^^^ `&'a T` is not an iterator @@ -23,7 +23,7 @@ note: required by a bound in `Flatten` --> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL error[E0277]: `&'a T` is not an iterator - --> $DIR/hir-wf-check-erase-regions.rs:11:27 + --> $DIR/hir-wf-check-erase-regions.rs:15:27 | LL | fn into_iter(self) -> Self::IntoIter { | ^^^^^^^^^^^^^^ `&'a T` is not an iterator @@ -35,7 +35,7 @@ note: required by a bound in `Flatten` --> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL error[E0277]: `&T` is not an iterator - --> $DIR/hir-wf-check-erase-regions.rs:11:27 + --> $DIR/hir-wf-check-erase-regions.rs:15:27 | LL | fn into_iter(self) -> Self::IntoIter { | ^^^^^^^^^^^^^^ `&T` is not an iterator diff --git a/tests/ui/wf/hir-wf-check-erase-regions.polonius.stderr b/tests/ui/wf/hir-wf-check-erase-regions.polonius.stderr new file mode 100644 index 0000000000000..55728aa642b80 --- /dev/null +++ b/tests/ui/wf/hir-wf-check-erase-regions.polonius.stderr @@ -0,0 +1,39 @@ +error[E0277]: `&'a T` is not an iterator + --> $DIR/hir-wf-check-erase-regions.rs:11:21 + | +LL | type IntoIter = std::iter::Flatten>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&'a T` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&'a T` + = help: the trait `Iterator` is implemented for `&mut I` + = note: required for `Flatten>` to implement `Iterator` +note: required by a bound in `std::iter::IntoIterator::IntoIter` + --> $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + +error[E0277]: `&'a T` is not an iterator + --> $DIR/hir-wf-check-erase-regions.rs:11:5 + | +LL | type IntoIter = std::iter::Flatten>; + | ^^^^^^^^^^^^^ `&'a T` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&'a T` + = help: the trait `Iterator` is implemented for `&mut I` + = note: required for `&'a T` to implement `IntoIterator` +note: required by a bound in `Flatten` + --> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL + +error[E0277]: `&'a T` is not an iterator + --> $DIR/hir-wf-check-erase-regions.rs:15:27 + | +LL | fn into_iter(self) -> Self::IntoIter { + | ^^^^^^^^^^^^^^ `&'a T` is not an iterator + | + = help: the trait `Iterator` is not implemented for `&'a T` + = help: the trait `Iterator` is implemented for `&mut I` + = note: required for `&'a T` to implement `IntoIterator` +note: required by a bound in `Flatten` + --> $SRC_DIR/core/src/iter/adapters/flatten.rs:LL:COL + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/wf/hir-wf-check-erase-regions.rs b/tests/ui/wf/hir-wf-check-erase-regions.rs index 20cc1cfe73018..ef9132697efc8 100644 --- a/tests/ui/wf/hir-wf-check-erase-regions.rs +++ b/tests/ui/wf/hir-wf-check-erase-regions.rs @@ -1,6 +1,10 @@ // Regression test for #87549. //@ incremental +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: nll polonius +//@ [polonius] compile-flags: -Zpolonius=next + pub struct Table([Option; N]); impl<'a, T, const N: usize> IntoIterator for &'a Table { @@ -10,7 +14,7 @@ impl<'a, T, const N: usize> IntoIterator for &'a Table { fn into_iter(self) -> Self::IntoIter { //~^ ERROR `&'a T` is not an iterator - //~| ERROR `&T` is not an iterator + //[nll]~| ERROR `&T` is not an iterator unimplemented!() } } From a5adde8eaae4ad5d9510897b02117bf0a9f45d0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 8 Aug 2025 15:14:17 +0000 Subject: [PATCH 07/28] simplify polonius=next Remove incomplete handling of kills during traversal for loan liveness to get to a simpler and actionable prototype. This handles the cases, on sufficiently simple examples, that were deferred from NLLs (NLL problem case 3, lending iterators), and is still a good step to put in people's hands without needing to wait for another full implementation. This is a practical cut in scope, but it also shows where are the areas of improvement, that we will explore in the future. --- .../src/polonius/constraints.rs | 4 +- .../src/polonius/liveness_constraints.rs | 12 +- .../src/polonius/loan_liveness.rs | 191 ++---------------- compiler/rustc_borrowck/src/polonius/mod.rs | 6 +- .../src/polonius/typeck_constraints.rs | 14 +- 5 files changed, 28 insertions(+), 199 deletions(-) diff --git a/compiler/rustc_borrowck/src/polonius/constraints.rs b/compiler/rustc_borrowck/src/polonius/constraints.rs index 50f59dd0dee67..5259575785955 100644 --- a/compiler/rustc_borrowck/src/polonius/constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/constraints.rs @@ -7,9 +7,7 @@ use rustc_mir_dataflow::points::PointIndex; /// /// This models two sources of constraints: /// - constraints that traverse the subsets between regions at a given point, `a@p: b@p`. These -/// depend on typeck constraints generated via assignments, calls, etc. (In practice there are -/// subtleties where a statement's effect only starts being visible at the successor point, via -/// the "result" of that statement). +/// depend on typeck constraints generated via assignments, calls, etc. /// - constraints that traverse the CFG via the same region, `a@p: a@q`, where `p` is a predecessor /// of `q`. These depend on the liveness of the regions at these points, as well as their /// variance. diff --git a/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs b/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs index 6ab09f731c078..2ba72180d66a6 100644 --- a/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs @@ -105,22 +105,14 @@ fn propagate_loans_between_points( }); } - let Some(current_live_regions) = live_regions.row(current_point) else { - // There are no constraints to add: there are no live regions at the current point. - return; - }; let Some(next_live_regions) = live_regions.row(next_point) else { // There are no constraints to add: there are no live regions at the next point. return; }; for region in next_live_regions.iter() { - if !current_live_regions.contains(region) { - continue; - } - - // `region` is indeed live at both points, add a constraint between them, according to - // variance. + // `region` could be live at the current point, and is live at the next point: add a + // constraint between them, according to variance. if let Some(&direction) = live_region_variances.get(®ion) { add_liveness_constraint( region, diff --git a/compiler/rustc_borrowck/src/polonius/loan_liveness.rs b/compiler/rustc_borrowck/src/polonius/loan_liveness.rs index 5cd265e0db92d..bdc3047e5ba01 100644 --- a/compiler/rustc_borrowck/src/polonius/loan_liveness.rs +++ b/compiler/rustc_borrowck/src/polonius/loan_liveness.rs @@ -1,27 +1,18 @@ -use std::collections::{BTreeMap, BTreeSet}; - use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{ - Body, Local, Location, Place, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, -}; -use rustc_middle::ty::{RegionVid, TyCtxt}; +use rustc_middle::ty::RegionVid; use rustc_mir_dataflow::points::PointIndex; use super::{LiveLoans, LocalizedOutlivesConstraintSet}; +use crate::BorrowSet; use crate::constraints::OutlivesConstraint; -use crate::dataflow::BorrowIndex; use crate::region_infer::values::LivenessValues; use crate::type_check::Locations; -use crate::{BorrowSet, PlaceConflictBias, places_conflict}; -/// Compute loan reachability, stop at kills, and trace loan liveness throughout the CFG, by +/// Compute loan reachability to approximately trace loan liveness throughout the CFG, by /// traversing the full graph of constraints that combines: /// - the localized constraints (the physical edges), /// - with the constraints that hold at all points (the logical edges). pub(super) fn compute_loan_liveness<'tcx>( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, liveness: &LivenessValues, outlives_constraints: impl Iterator>, borrow_set: &BorrowSet<'tcx>, @@ -29,11 +20,6 @@ pub(super) fn compute_loan_liveness<'tcx>( ) -> LiveLoans { let mut live_loans = LiveLoans::new(borrow_set.len()); - // FIXME: it may be preferable for kills to be encoded in the edges themselves, to simplify and - // likely make traversal (and constraint generation) more efficient. We also display kills on - // edges when visualizing the constraint graph anyways. - let kills = collect_kills(body, tcx, borrow_set); - // Create the full graph with the physical edges we've localized earlier, and the logical edges // of constraints that hold at all points. let logical_constraints = @@ -59,15 +45,15 @@ pub(super) fn compute_loan_liveness<'tcx>( continue; } - // Record the loan as being live on entry to this point. - live_loans.insert(node.point, loan_idx); - - // Here, we have a conundrum. There's currently a weakness in our theory, in that - // we're using a single notion of reachability to represent what used to be _two_ - // different transitive closures. It didn't seem impactful when coming up with the - // single-graph and reachability through space (regions) + time (CFG) concepts, but in - // practice the combination of time-traveling with kills is more impactful than - // initially anticipated. + // Record the loan as being live on entry to this point if it reaches a live region + // there. + // + // This is an approximation of liveness (which is the thing we want), in that we're + // using a single notion of reachability to represent what used to be _two_ different + // transitive closures. It didn't seem impactful when coming up with the single-graph + // and reachability through space (regions) + time (CFG) concepts, but in practice the + // combination of time-traveling with kills is more impactful than initially + // anticipated. // // Kills should prevent a loan from reaching its successor points in the CFG, but not // while time-traveling: we're not actually at that CFG point, but looking for @@ -92,40 +78,20 @@ pub(super) fn compute_loan_liveness<'tcx>( // two-step traversal described above: only kills encountered on exit via a backward // edge are ignored. // - // In our test suite, there are a couple of cases where kills are encountered while - // time-traveling, however as far as we can tell, always in cases where they would be - // unreachable. We have reason to believe that this is a property of the single-graph - // approach (but haven't proved it yet): - // - reachable kills while time-traveling would also be encountered via regular - // traversal - // - it makes _some_ sense to ignore unreachable kills, but subtleties around dead code - // in general need to be better thought through (like they were for NLLs). - // - ignoring kills is a conservative approximation: the loan is still live and could - // cause false positive errors at another place access. Soundness issues in this - // domain should look more like the absence of reachability instead. - // - // This is enough in practice to pass tests, and therefore is what we have implemented - // for now. + // This version of the analysis, however, is enough in practice to pass the tests that + // we care about and NLLs reject, without regressions on crater, and is an actionable + // subset of the full analysis. It also naturally points to areas of improvement that we + // wish to explore later, namely handling kills appropriately during traversal, instead + // of continuing traversal to all the reachable nodes. // - // FIXME: all of the above. Analyze potential unsoundness, possibly in concert with a - // borrowck implementation in a-mir-formality, fuzzing, or manually crafting - // counter-examples. + // FIXME: analyze potential unsoundness, possibly in concert with a borrowck + // implementation in a-mir-formality, fuzzing, or manually crafting counter-examples. - // Continuing traversal will depend on whether the loan is killed at this point, and - // whether we're time-traveling. - let current_location = liveness.location_from_point(node.point); - let is_loan_killed = - kills.get(¤t_location).is_some_and(|kills| kills.contains(&loan_idx)); + if liveness.is_live_at(node.region, liveness.location_from_point(node.point)) { + live_loans.insert(node.point, loan_idx); + } for succ in graph.outgoing_edges(node) { - // If the loan is killed at this point, it is killed _on exit_. But only during - // forward traversal. - if is_loan_killed { - let destination = liveness.location_from_point(succ.point); - if current_location.is_predecessor_of(destination, body) { - continue; - } - } stack.push(succ); } } @@ -192,116 +158,3 @@ impl LocalizedConstraintGraph { physical_edges.chain(materialized_edges) } } - -/// Traverses the MIR and collects kills. -fn collect_kills<'tcx>( - body: &Body<'tcx>, - tcx: TyCtxt<'tcx>, - borrow_set: &BorrowSet<'tcx>, -) -> BTreeMap> { - let mut collector = KillsCollector { borrow_set, tcx, body, kills: BTreeMap::default() }; - for (block, data) in body.basic_blocks.iter_enumerated() { - collector.visit_basic_block_data(block, data); - } - collector.kills -} - -struct KillsCollector<'a, 'tcx> { - body: &'a Body<'tcx>, - tcx: TyCtxt<'tcx>, - borrow_set: &'a BorrowSet<'tcx>, - - /// The set of loans killed at each location. - kills: BTreeMap>, -} - -// This visitor has a similar structure to the `Borrows` dataflow computation with respect to kills, -// and the datalog polonius fact generation for the `loan_killed_at` relation. -impl<'tcx> KillsCollector<'_, 'tcx> { - /// Records the borrows on the specified place as `killed`. For example, when assigning to a - /// local, or on a call's return destination. - fn record_killed_borrows_for_place(&mut self, place: Place<'tcx>, location: Location) { - // For the reasons described in graph traversal, we also filter out kills - // unreachable from the loan's introduction point, as they would stop traversal when - // e.g. checking for reachability in the subset graph through invariance constraints - // higher up. - let filter_unreachable_kills = |loan| { - let introduction = self.borrow_set[loan].reserve_location; - let reachable = introduction.is_predecessor_of(location, self.body); - reachable - }; - - let other_borrows_of_local = self - .borrow_set - .local_map - .get(&place.local) - .into_iter() - .flat_map(|bs| bs.iter()) - .copied(); - - // If the borrowed place is a local with no projections, all other borrows of this - // local must conflict. This is purely an optimization so we don't have to call - // `places_conflict` for every borrow. - if place.projection.is_empty() { - if !self.body.local_decls[place.local].is_ref_to_static() { - self.kills - .entry(location) - .or_default() - .extend(other_borrows_of_local.filter(|&loan| filter_unreachable_kills(loan))); - } - return; - } - - // By passing `PlaceConflictBias::NoOverlap`, we conservatively assume that any given - // pair of array indices are not equal, so that when `places_conflict` returns true, we - // will be assured that two places being compared definitely denotes the same sets of - // locations. - let definitely_conflicting_borrows = other_borrows_of_local - .filter(|&i| { - places_conflict( - self.tcx, - self.body, - self.borrow_set[i].borrowed_place, - place, - PlaceConflictBias::NoOverlap, - ) - }) - .filter(|&loan| filter_unreachable_kills(loan)); - - self.kills.entry(location).or_default().extend(definitely_conflicting_borrows); - } - - /// Records the borrows on the specified local as `killed`. - fn record_killed_borrows_for_local(&mut self, local: Local, location: Location) { - if let Some(borrow_indices) = self.borrow_set.local_map.get(&local) { - self.kills.entry(location).or_default().extend(borrow_indices.iter()); - } - } -} - -impl<'tcx> Visitor<'tcx> for KillsCollector<'_, 'tcx> { - fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { - // Make sure there are no remaining borrows for locals that have gone out of scope. - if let StatementKind::StorageDead(local) = statement.kind { - self.record_killed_borrows_for_local(local, location); - } - - self.super_statement(statement, location); - } - - fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, location: Location) { - // When we see `X = ...`, then kill borrows of `(*X).foo` and so forth. - self.record_killed_borrows_for_place(*place, location); - self.super_assign(place, rvalue, location); - } - - fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { - // A `Call` terminator's return value can be a local which has borrows, so we need to record - // those as killed as well. - if let TerminatorKind::Call { destination, .. } = terminator.kind { - self.record_killed_borrows_for_place(destination, location); - } - - self.super_terminator(terminator, location); - } -} diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs index 142ef8ba28eff..a9092b1981e1d 100644 --- a/compiler/rustc_borrowck/src/polonius/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/mod.rs @@ -146,8 +146,8 @@ impl PoloniusContext { /// - converting NLL typeck constraints to be localized /// - encoding liveness constraints /// - /// Then, this graph is traversed, and combined with kills, reachability is recorded as loan - /// liveness, to be used by the loan scope and active loans computations. + /// Then, this graph is traversed, reachability is recorded as loan liveness, to be used by the + /// loan scope and active loans computations. /// /// The constraint data will be used to compute errors and diagnostics. pub(crate) fn compute_loan_liveness<'tcx>( @@ -182,8 +182,6 @@ impl PoloniusContext { // Now that we have a complete graph, we can compute reachability to trace the liveness of // loans for the next step in the chain, the NLL loan scope and active loans computations. let live_loans = compute_loan_liveness( - tcx, - body, regioncx.liveness_constraints(), regioncx.outlives_constraints(), borrow_set, diff --git a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs index 1289b1899eb35..8106d1e4af068 100644 --- a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs @@ -47,9 +47,7 @@ pub(super) fn convert_typeck_constraints<'tcx>( tcx, body, stmt, - liveness, &outlives_constraint, - location, point, universal_regions, ) @@ -78,9 +76,7 @@ fn localize_statement_constraint<'tcx>( tcx: TyCtxt<'tcx>, body: &Body<'tcx>, stmt: &Statement<'tcx>, - liveness: &LivenessValues, outlives_constraint: &OutlivesConstraint<'tcx>, - current_location: Location, current_point: PointIndex, universal_regions: &UniversalRegions<'tcx>, ) -> LocalizedOutlivesConstraint { @@ -119,16 +115,8 @@ fn localize_statement_constraint<'tcx>( "there should be no common regions between the LHS and RHS of an assignment" ); - // As mentioned earlier, we should be tracking these better upstream but: we want to - // relate the types on entry to the type of the place on exit. That is, outlives - // constraints on the RHS are on entry, and outlives constraints to/from the LHS are on - // exit (i.e. on entry to the successor location). let lhs_ty = body.local_decls[lhs.local].ty; - let successor_location = Location { - block: current_location.block, - statement_index: current_location.statement_index + 1, - }; - let successor_point = liveness.point_from_location(successor_location); + let successor_point = current_point; compute_constraint_direction( tcx, outlives_constraint, From 13308988b051ebe014a061b9d595cbb8289348d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 16 Jun 2025 14:39:32 +0000 Subject: [PATCH 08/28] new impl fixes crash test --- tests/crashes/135646.rs | 7 ------- .../ui/nll/polonius/array-literal-index-oob-2024.rs | 12 ++++++++++++ 2 files changed, 12 insertions(+), 7 deletions(-) delete mode 100644 tests/crashes/135646.rs create mode 100644 tests/ui/nll/polonius/array-literal-index-oob-2024.rs diff --git a/tests/crashes/135646.rs b/tests/crashes/135646.rs deleted file mode 100644 index 841ea5b81b41f..0000000000000 --- a/tests/crashes/135646.rs +++ /dev/null @@ -1,7 +0,0 @@ -//@ known-bug: #135646 -//@ compile-flags: -Zpolonius=next -//@ edition: 2024 - -fn main() { - &{ [1, 2, 3][4] }; -} diff --git a/tests/ui/nll/polonius/array-literal-index-oob-2024.rs b/tests/ui/nll/polonius/array-literal-index-oob-2024.rs new file mode 100644 index 0000000000000..2054a32e53553 --- /dev/null +++ b/tests/ui/nll/polonius/array-literal-index-oob-2024.rs @@ -0,0 +1,12 @@ +// This test used to ICE under `-Zpolonius=next` when computing loan liveness +// and taking kills into account during reachability traversal of the localized +// constraint graph. Originally from another test but on edition 2024, as +// seen in issue #135646. + +//@ compile-flags: -Zpolonius=next +//@ edition: 2024 +//@ check-pass + +fn main() { + &{ [1, 2, 3][4] }; +} From d4bbd681bbdb2b47717922e46bd022dbf2535403 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Wed, 18 Jun 2025 09:01:57 +0000 Subject: [PATCH 09/28] turn expensive assert into debug assertion --- compiler/rustc_borrowck/src/polonius/typeck_constraints.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs index 8106d1e4af068..e4e52962bf7f9 100644 --- a/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/typeck_constraints.rs @@ -94,8 +94,8 @@ fn localize_statement_constraint<'tcx>( // - and that should be impossible in MIR // // When we have a more complete implementation in the future, tested with crater, etc, - // we can relax this to a debug assert instead, or remove it. - assert!( + // we can remove this assertion. It's a debug assert because it can be expensive. + debug_assert!( { let mut lhs_regions = FxHashSet::default(); tcx.for_each_free_region(lhs, |region| { @@ -183,6 +183,7 @@ fn localize_terminator_constraint<'tcx>( } } } + /// For a given outlives constraint and CFG edge, returns the localized constraint with the /// appropriate `from`-`to` direction. This is computed according to whether the constraint flows to /// or from a free region in the given `value`, some kind of result for an effectful operation, like From b172980d5c0de4a917e0f28ebd118f20889e6036 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 26 Jun 2025 13:06:48 +0000 Subject: [PATCH 10/28] add some test cases for overlapping yielded items These are just some sanity checks to ensure NLLs, the polonius alpha analysis, and the datalog implementation behave the same on these common examples. --- ...nding-iterator-sanity-checks.legacy.stderr | 28 ++++++++ .../lending-iterator-sanity-checks.nll.stderr | 28 ++++++++ ...ing-iterator-sanity-checks.polonius.stderr | 26 +++++++ .../lending-iterator-sanity-checks.rs | 71 +++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 tests/ui/nll/polonius/lending-iterator-sanity-checks.legacy.stderr create mode 100644 tests/ui/nll/polonius/lending-iterator-sanity-checks.nll.stderr create mode 100644 tests/ui/nll/polonius/lending-iterator-sanity-checks.polonius.stderr create mode 100644 tests/ui/nll/polonius/lending-iterator-sanity-checks.rs diff --git a/tests/ui/nll/polonius/lending-iterator-sanity-checks.legacy.stderr b/tests/ui/nll/polonius/lending-iterator-sanity-checks.legacy.stderr new file mode 100644 index 0000000000000..fa201b89048af --- /dev/null +++ b/tests/ui/nll/polonius/lending-iterator-sanity-checks.legacy.stderr @@ -0,0 +1,28 @@ +error[E0499]: cannot borrow `*t` as mutable more than once at a time + --> $DIR/lending-iterator-sanity-checks.rs:19:19 + | +LL | fn use_live(t: &mut T) -> Option<(T::Item<'_>, T::Item<'_>)> { + | - let's call the lifetime of this reference `'1` +LL | let Some(i) = t.next() else { return None }; + | - first mutable borrow occurs here +LL | let Some(j) = t.next() else { return None }; + | ^ second mutable borrow occurs here +... +LL | Some((i, j)) + | ------------ returning this value requires that `*t` is borrowed for `'1` + +error[E0499]: cannot borrow `*t` as mutable more than once at a time + --> $DIR/lending-iterator-sanity-checks.rs:31:13 + | +LL | let i = t.next(); + | - first mutable borrow occurs here +... +LL | let j = t.next(); + | ^ second mutable borrow occurs here +LL | +LL | } + | - first borrow might be used here, when `i` is dropped and runs the destructor for type `Option<::Item<'_>>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/nll/polonius/lending-iterator-sanity-checks.nll.stderr b/tests/ui/nll/polonius/lending-iterator-sanity-checks.nll.stderr new file mode 100644 index 0000000000000..fa201b89048af --- /dev/null +++ b/tests/ui/nll/polonius/lending-iterator-sanity-checks.nll.stderr @@ -0,0 +1,28 @@ +error[E0499]: cannot borrow `*t` as mutable more than once at a time + --> $DIR/lending-iterator-sanity-checks.rs:19:19 + | +LL | fn use_live(t: &mut T) -> Option<(T::Item<'_>, T::Item<'_>)> { + | - let's call the lifetime of this reference `'1` +LL | let Some(i) = t.next() else { return None }; + | - first mutable borrow occurs here +LL | let Some(j) = t.next() else { return None }; + | ^ second mutable borrow occurs here +... +LL | Some((i, j)) + | ------------ returning this value requires that `*t` is borrowed for `'1` + +error[E0499]: cannot borrow `*t` as mutable more than once at a time + --> $DIR/lending-iterator-sanity-checks.rs:31:13 + | +LL | let i = t.next(); + | - first mutable borrow occurs here +... +LL | let j = t.next(); + | ^ second mutable borrow occurs here +LL | +LL | } + | - first borrow might be used here, when `i` is dropped and runs the destructor for type `Option<::Item<'_>>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/nll/polonius/lending-iterator-sanity-checks.polonius.stderr b/tests/ui/nll/polonius/lending-iterator-sanity-checks.polonius.stderr new file mode 100644 index 0000000000000..bf8546b63bf30 --- /dev/null +++ b/tests/ui/nll/polonius/lending-iterator-sanity-checks.polonius.stderr @@ -0,0 +1,26 @@ +error[E0499]: cannot borrow `*t` as mutable more than once at a time + --> $DIR/lending-iterator-sanity-checks.rs:19:19 + | +LL | let Some(i) = t.next() else { return None }; + | - first mutable borrow occurs here +LL | let Some(j) = t.next() else { return None }; + | ^ second mutable borrow occurs here +... +LL | } + | - first borrow might be used here, when `i` is dropped and runs the destructor for type `::Item<'_>` + +error[E0499]: cannot borrow `*t` as mutable more than once at a time + --> $DIR/lending-iterator-sanity-checks.rs:31:13 + | +LL | let i = t.next(); + | - first mutable borrow occurs here +... +LL | let j = t.next(); + | ^ second mutable borrow occurs here +LL | +LL | } + | - first borrow might be used here, when `i` is dropped and runs the destructor for type `Option<::Item<'_>>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/nll/polonius/lending-iterator-sanity-checks.rs b/tests/ui/nll/polonius/lending-iterator-sanity-checks.rs new file mode 100644 index 0000000000000..ae8cc78957fef --- /dev/null +++ b/tests/ui/nll/polonius/lending-iterator-sanity-checks.rs @@ -0,0 +1,71 @@ +// Some sanity checks for lending iterators with GATs. This is just some non-regression tests +// ensuring the polonius alpha analysis, the datalog implementation, and NLLs agree in these common +// cases of overlapping yielded items. + +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: nll polonius legacy +//@ [polonius] compile-flags: -Z polonius=next +//@ [legacy] compile-flags: -Z polonius=legacy + +trait LendingIterator { + type Item<'a> + where + Self: 'a; + fn next(&mut self) -> Option>; +} + +fn use_live(t: &mut T) -> Option<(T::Item<'_>, T::Item<'_>)> { + let Some(i) = t.next() else { return None }; + let Some(j) = t.next() else { return None }; + //~^ ERROR cannot borrow `*t` as mutable more than once at a time + + // `i` is obviously still (use-)live here, but we called `next` again to get `j`. + Some((i, j)) +} + +fn drop_live(t: &mut T) { + let i = t.next(); + + // Now `i` is use-dead here, but we don't know if the iterator items have a `Drop` impl, so it's + // still drop-live. + let j = t.next(); + //~^ ERROR cannot borrow `*t` as mutable more than once at a time +} + +// But we can still manually serialize the lifetimes with scopes (or preventing the destructor from +// being called), so they're not overlapping. +fn manually_non_overlapping(t: &mut T) { + { + let i = t.next(); + } + + let j = t.next(); // i is dead + + drop(j); + let k = t.next(); // j is dead + + let k = std::mem::ManuallyDrop::new(k); + let l = t.next(); // we told the compiler that k is not drop-live +} + +// The cfg below is because there's a diagnostic ICE trying to explain the source of the error when +// using the datalog implementation. We're not fixing *that*, outside of removing the implementation +// in the future. +#[cfg(not(legacy))] // FIXME: remove this cfg when removing the datalog implementation +fn items_have_no_borrows(t: &mut T) +where + for<'a> T::Item<'a>: 'static, +{ + let i = t.next(); + let j = t.next(); +} + +fn items_are_copy(t: &mut T) +where + for<'a> T::Item<'a>: Copy, +{ + let i = t.next(); + let j = t.next(); +} + +fn main() {} From 48ebae9cef6fdb1af495e692a0811634f308e447 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 26 Jun 2025 15:27:23 +0000 Subject: [PATCH 11/28] add NLL-like imprecision example This test showcases the same imprecision as NLLs, unlike the datalog implementation, when using reachability as a liveness approximation. --- .../flow-sensitive-invariance.nll.stderr | 36 +++++++++++++++++++ .../flow-sensitive-invariance.polonius.stderr | 36 +++++++++++++++++++ .../nll/polonius/flow-sensitive-invariance.rs | 34 ++++++++++++++++++ 3 files changed, 106 insertions(+) create mode 100644 tests/ui/nll/polonius/flow-sensitive-invariance.nll.stderr create mode 100644 tests/ui/nll/polonius/flow-sensitive-invariance.polonius.stderr create mode 100644 tests/ui/nll/polonius/flow-sensitive-invariance.rs diff --git a/tests/ui/nll/polonius/flow-sensitive-invariance.nll.stderr b/tests/ui/nll/polonius/flow-sensitive-invariance.nll.stderr new file mode 100644 index 0000000000000..5756148f4eb2a --- /dev/null +++ b/tests/ui/nll/polonius/flow-sensitive-invariance.nll.stderr @@ -0,0 +1,36 @@ +error: lifetime may not live long enough + --> $DIR/flow-sensitive-invariance.rs:20:17 + | +LL | fn use_it<'a, 'b>(choice: bool) -> Result, Invariant<'b>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let returned_value = create_invariant(); +LL | if choice { Ok(returned_value) } else { Err(returned_value) } + | ^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'l>` is invariant over the parameter `'l` + = help: see for more information about variance + +error: lifetime may not live long enough + --> $DIR/flow-sensitive-invariance.rs:20:45 + | +LL | fn use_it<'a, 'b>(choice: bool) -> Result, Invariant<'b>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let returned_value = create_invariant(); +LL | if choice { Ok(returned_value) } else { Err(returned_value) } + | ^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'l>` is invariant over the parameter `'l` + = help: see for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + +error: aborting due to 2 previous errors + diff --git a/tests/ui/nll/polonius/flow-sensitive-invariance.polonius.stderr b/tests/ui/nll/polonius/flow-sensitive-invariance.polonius.stderr new file mode 100644 index 0000000000000..5756148f4eb2a --- /dev/null +++ b/tests/ui/nll/polonius/flow-sensitive-invariance.polonius.stderr @@ -0,0 +1,36 @@ +error: lifetime may not live long enough + --> $DIR/flow-sensitive-invariance.rs:20:17 + | +LL | fn use_it<'a, 'b>(choice: bool) -> Result, Invariant<'b>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let returned_value = create_invariant(); +LL | if choice { Ok(returned_value) } else { Err(returned_value) } + | ^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'l>` is invariant over the parameter `'l` + = help: see for more information about variance + +error: lifetime may not live long enough + --> $DIR/flow-sensitive-invariance.rs:20:45 + | +LL | fn use_it<'a, 'b>(choice: bool) -> Result, Invariant<'b>> { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | let returned_value = create_invariant(); +LL | if choice { Ok(returned_value) } else { Err(returned_value) } + | ^^^^^^^^^^^^^^^^^^^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a` + | + = help: consider adding the following bound: `'a: 'b` + = note: requirement occurs because of the type `Invariant<'_>`, which makes the generic argument `'_` invariant + = note: the struct `Invariant<'l>` is invariant over the parameter `'l` + = help: see for more information about variance + +help: `'a` and `'b` must be the same: replace one with the other + +error: aborting due to 2 previous errors + diff --git a/tests/ui/nll/polonius/flow-sensitive-invariance.rs b/tests/ui/nll/polonius/flow-sensitive-invariance.rs new file mode 100644 index 0000000000000..c5571f131da3b --- /dev/null +++ b/tests/ui/nll/polonius/flow-sensitive-invariance.rs @@ -0,0 +1,34 @@ +// An example (from @steffahn) of reachability as an approximation of liveness where the polonius +// alpha analysis shows the same imprecision as NLLs, unlike the datalog implementation. + +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: nll polonius legacy +//@ [polonius] compile-flags: -Z polonius=next +//@ [legacy] check-pass +//@ [legacy] compile-flags: -Z polonius=legacy + +use std::cell::Cell; + +struct Invariant<'l>(Cell<&'l ()>); + +fn create_invariant<'l>() -> Invariant<'l> { + Invariant(Cell::new(&())) +} + +fn use_it<'a, 'b>(choice: bool) -> Result, Invariant<'b>> { + let returned_value = create_invariant(); + if choice { Ok(returned_value) } else { Err(returned_value) } + //[nll]~^ ERROR lifetime may not live long enough + //[nll]~| ERROR lifetime may not live long enough + //[polonius]~^^^ ERROR lifetime may not live long enough + //[polonius]~| ERROR lifetime may not live long enough +} + +fn use_it_but_its_the_same_region<'a: 'b, 'b: 'a>( + choice: bool, +) -> Result, Invariant<'b>> { + let returned_value = create_invariant(); + if choice { Ok(returned_value) } else { Err(returned_value) } +} + +fn main() {} From 9badbdf5f9272bf42699edabc14735a1ab42e3d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Thu, 26 Jun 2025 15:29:03 +0000 Subject: [PATCH 12/28] add cursor-like example that works This is an example similar to the linked-list cursor examples where the alpha shows the same imprecision as NLLs, but that can work due to the loans not being live after the loop, or the constraint graph being simple enough that the cfg/subset relationships are the same for reachability and liveness. --- .../iterating-updating-mutref.nll.stderr | 15 ++++ .../nll/polonius/iterating-updating-mutref.rs | 87 +++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 tests/ui/nll/polonius/iterating-updating-mutref.nll.stderr create mode 100644 tests/ui/nll/polonius/iterating-updating-mutref.rs diff --git a/tests/ui/nll/polonius/iterating-updating-mutref.nll.stderr b/tests/ui/nll/polonius/iterating-updating-mutref.nll.stderr new file mode 100644 index 0000000000000..941c736d8d258 --- /dev/null +++ b/tests/ui/nll/polonius/iterating-updating-mutref.nll.stderr @@ -0,0 +1,15 @@ +error[E0499]: cannot borrow `self.buf_read` as mutable more than once at a time + --> $DIR/iterating-updating-mutref.rs:61:23 + | +LL | pub fn next<'a>(&'a mut self) -> &'a str { + | -- lifetime `'a` defined here +LL | loop { +LL | let buf = self.buf_read.fill_buf(); + | ^^^^^^^^^^^^^ `self.buf_read` was mutably borrowed here in the previous iteration of the loop +LL | if let Some(s) = decode(buf) { +LL | return s; + | - returning this value requires that `self.buf_read` is borrowed for `'a` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/nll/polonius/iterating-updating-mutref.rs b/tests/ui/nll/polonius/iterating-updating-mutref.rs new file mode 100644 index 0000000000000..a315bf66279c6 --- /dev/null +++ b/tests/ui/nll/polonius/iterating-updating-mutref.rs @@ -0,0 +1,87 @@ +// These are some examples of iterating through and updating a mutable ref, similar in spirit to the +// linked-list-like pattern of #46859/#48001 where the polonius alpha analysis shows imprecision, +// unlike the datalog implementation. +// +// They differ in that after the loans prior to the loop are either not live after the loop, or with +// control flow and outlives relationships that are simple enough for the reachability +// approximation. They're thus accepted by the alpha analysis, like NLLs did for the simplest cases +// of flow-sensitivity. + +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: nll polonius legacy +//@ [nll] known-bug: #46859 +//@ [polonius] check-pass +//@ [polonius] compile-flags: -Z polonius=next +//@ [legacy] check-pass +//@ [legacy] compile-flags: -Z polonius=legacy + +// The #46859 OP +struct List { + value: T, + next: Option>>, +} + +fn to_refs(mut list: &mut List) -> Vec<&mut T> { + let mut result = vec![]; + loop { + result.push(&mut list.value); + if let Some(n) = list.next.as_mut() { + list = n; + } else { + return result; + } + } +} + +// A similar construction, where paths in the constraint graph are also clearly terminating, so it's +// fine even for NLLs. +fn to_refs2(mut list: &mut List) -> Vec<&mut T> { + let mut result = vec![]; + loop { + result.push(&mut list.value); + if let Some(n) = list.next.as_mut() { + list = n; + } else { + break; + } + } + + result +} + +// Another MCVE from the same issue, but was rejected by NLLs. +pub struct Decoder { + buf_read: BufRead, +} + +impl Decoder { + // NLLs fail here + pub fn next<'a>(&'a mut self) -> &'a str { + loop { + let buf = self.buf_read.fill_buf(); + if let Some(s) = decode(buf) { + return s; + } + // loop to get more input data + + // At this point `buf` is not used anymore. + // With NLL I would expect the borrow to end here, + // such that `self.buf_read` is not borrowed anymore + // by the time we start the next loop iteration. + } + } +} + +struct BufRead; + +impl BufRead { + fn fill_buf(&mut self) -> &[u8] { + unimplemented!() + } +} + +fn decode(_: &[u8]) -> Option<&str> { + unimplemented!() +} + +fn main() {} From b99fe2b72022f4fe7a6f2e55fd70cc8530566473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Fri, 8 Aug 2025 14:29:50 +0000 Subject: [PATCH 13/28] mark polonius=next's NLL imprecisions as known-bugs - linked-list cursor-like patterns - issue-46589 These are known-bugs for the polonius alpha, where they show the same imprecision as NLLs, but are supported by the old datalog implementation. --- tests/ui/nll/issue-46589.nll.stderr | 2 +- tests/ui/nll/issue-46589.polonius.stderr | 15 +++++++++++++ tests/ui/nll/issue-46589.rs | 12 +++++----- ...ng-updating-cursor-issue-108704.nll.stderr | 2 +- ...dating-cursor-issue-108704.polonius.stderr | 12 ++++++++++ .../iterating-updating-cursor-issue-108704.rs | 7 +++--- ...ing-updating-cursor-issue-57165.nll.stderr | 4 ++-- ...pdating-cursor-issue-57165.polonius.stderr | 22 +++++++++++++++++++ .../iterating-updating-cursor-issue-57165.rs | 7 +++--- ...ing-updating-cursor-issue-63908.nll.stderr | 2 +- ...pdating-cursor-issue-63908.polonius.stderr | 18 +++++++++++++++ .../iterating-updating-cursor-issue-63908.rs | 7 +++--- 12 files changed, 90 insertions(+), 20 deletions(-) create mode 100644 tests/ui/nll/issue-46589.polonius.stderr create mode 100644 tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.polonius.stderr create mode 100644 tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.polonius.stderr create mode 100644 tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.polonius.stderr diff --git a/tests/ui/nll/issue-46589.nll.stderr b/tests/ui/nll/issue-46589.nll.stderr index dc80c1d08deca..f2d08d1f4c834 100644 --- a/tests/ui/nll/issue-46589.nll.stderr +++ b/tests/ui/nll/issue-46589.nll.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `**other` as mutable more than once at a time - --> $DIR/issue-46589.rs:24:21 + --> $DIR/issue-46589.rs:25:21 | LL | *other = match (*other).get_self() { | -------- first mutable borrow occurs here diff --git a/tests/ui/nll/issue-46589.polonius.stderr b/tests/ui/nll/issue-46589.polonius.stderr new file mode 100644 index 0000000000000..f2d08d1f4c834 --- /dev/null +++ b/tests/ui/nll/issue-46589.polonius.stderr @@ -0,0 +1,15 @@ +error[E0499]: cannot borrow `**other` as mutable more than once at a time + --> $DIR/issue-46589.rs:25:21 + | +LL | *other = match (*other).get_self() { + | -------- first mutable borrow occurs here +LL | Some(s) => s, +LL | None => (*other).new_self() + | ^^^^^^^^ + | | + | second mutable borrow occurs here + | first borrow later used here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/nll/issue-46589.rs b/tests/ui/nll/issue-46589.rs index 10aff0d7b4ef9..9a23f61b8cb8d 100644 --- a/tests/ui/nll/issue-46589.rs +++ b/tests/ui/nll/issue-46589.rs @@ -1,9 +1,10 @@ //@ ignore-compare-mode-polonius (explicit revisions) -//@ revisions: nll polonius_next polonius -//@ [polonius_next] check-pass -//@ [polonius_next] compile-flags: -Zpolonius=next -//@ [polonius] check-pass -//@ [polonius] compile-flags: -Zpolonius +//@ revisions: nll polonius legacy +//@ [nll] known-bug: #46589 +//@ [polonius] known-bug: #46589 +//@ [polonius] compile-flags: -Zpolonius=next +//@ [legacy] check-pass +//@ [legacy] compile-flags: -Zpolonius=legacy struct Foo; @@ -22,7 +23,6 @@ impl Foo { *other = match (*other).get_self() { Some(s) => s, None => (*other).new_self() - //[nll]~^ ERROR cannot borrow `**other` as mutable more than once at a time [E0499] }; let c = other; diff --git a/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.nll.stderr b/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.nll.stderr index 7ac4e5de28384..b768f60590cb0 100644 --- a/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.nll.stderr +++ b/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.nll.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `*elements` as mutable more than once at a time - --> $DIR/iterating-updating-cursor-issue-108704.rs:40:26 + --> $DIR/iterating-updating-cursor-issue-108704.rs:41:26 | LL | for (idx, el) in elements.iter_mut().enumerate() { | ^^^^^^^^ diff --git a/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.polonius.stderr b/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.polonius.stderr new file mode 100644 index 0000000000000..b768f60590cb0 --- /dev/null +++ b/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.polonius.stderr @@ -0,0 +1,12 @@ +error[E0499]: cannot borrow `*elements` as mutable more than once at a time + --> $DIR/iterating-updating-cursor-issue-108704.rs:41:26 + | +LL | for (idx, el) in elements.iter_mut().enumerate() { + | ^^^^^^^^ + | | + | `*elements` was mutably borrowed here in the previous iteration of the loop + | first borrow used here, in later iteration of loop + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.rs b/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.rs index 420cb73bed283..673efa8f2259a 100644 --- a/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.rs +++ b/tests/ui/nll/polonius/iterating-updating-cursor-issue-108704.rs @@ -1,11 +1,12 @@ #![crate_type = "lib"] -// An example from #108704 of the linked-list cursor-like pattern of #46859/#48001. +// An example from #108704 of the linked-list cursor-like pattern of #46859/#48001, where the +// polonius alpha analysis shows the same imprecision as NLLs, unlike the datalog implementation. //@ ignore-compare-mode-polonius (explicit revisions) //@ revisions: nll polonius legacy //@ [nll] known-bug: #108704 -//@ [polonius] check-pass +//@ [polonius] known-bug: #108704 //@ [polonius] compile-flags: -Z polonius=next //@ [legacy] check-pass //@ [legacy] compile-flags: -Z polonius=legacy @@ -32,7 +33,7 @@ fn merge_tree_ok(root: &mut Root, path: Vec) { } } -// NLLs fail here +// NLLs and polonius alpha fail here fn merge_tree_ko(root: &mut Root, path: Vec) { let mut elements = &mut root.children; diff --git a/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.nll.stderr b/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.nll.stderr index 14e1726e158f4..34b04e707dbd4 100644 --- a/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.nll.stderr +++ b/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.nll.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `p.0` as mutable more than once at a time - --> $DIR/iterating-updating-cursor-issue-57165.rs:29:20 + --> $DIR/iterating-updating-cursor-issue-57165.rs:30:20 | LL | while let Some(now) = p { | ^^^ - first borrow used here, in later iteration of loop @@ -7,7 +7,7 @@ LL | while let Some(now) = p { | `p.0` was mutably borrowed here in the previous iteration of the loop error[E0503]: cannot use `*p` because it was mutably borrowed - --> $DIR/iterating-updating-cursor-issue-57165.rs:29:27 + --> $DIR/iterating-updating-cursor-issue-57165.rs:30:27 | LL | while let Some(now) = p { | --- ^ diff --git a/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.polonius.stderr b/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.polonius.stderr new file mode 100644 index 0000000000000..34b04e707dbd4 --- /dev/null +++ b/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.polonius.stderr @@ -0,0 +1,22 @@ +error[E0499]: cannot borrow `p.0` as mutable more than once at a time + --> $DIR/iterating-updating-cursor-issue-57165.rs:30:20 + | +LL | while let Some(now) = p { + | ^^^ - first borrow used here, in later iteration of loop + | | + | `p.0` was mutably borrowed here in the previous iteration of the loop + +error[E0503]: cannot use `*p` because it was mutably borrowed + --> $DIR/iterating-updating-cursor-issue-57165.rs:30:27 + | +LL | while let Some(now) = p { + | --- ^ + | | | + | | use of borrowed `p.0` + | | borrow later used here + | `p.0` is borrowed here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0499, E0503. +For more information about an error, try `rustc --explain E0499`. diff --git a/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.rs b/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.rs index 63ec89146d4a7..9670fc77e6faa 100644 --- a/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.rs +++ b/tests/ui/nll/polonius/iterating-updating-cursor-issue-57165.rs @@ -1,11 +1,12 @@ #![crate_type = "lib"] -// An example from #57165 of the linked-list cursor-like pattern of #46859/#48001. +// An example from #57165 of the linked-list cursor-like pattern of #46859/#48001, where the +// polonius alpha analysis shows the same imprecision as NLLs, unlike the datalog implementation. //@ ignore-compare-mode-polonius (explicit revisions) //@ revisions: nll polonius legacy //@ [nll] known-bug: #57165 -//@ [polonius] check-pass +//@ [polonius] known-bug: #57165 //@ [polonius] compile-flags: -Z polonius=next //@ [legacy] check-pass //@ [legacy] compile-flags: -Z polonius=legacy @@ -22,7 +23,7 @@ fn no_control_flow() { } } -// NLLs fail here +// NLLs and polonius alpha fail here fn conditional() { let mut b = Some(Box::new(X { next: None })); let mut p = &mut b; diff --git a/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.nll.stderr b/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.nll.stderr index bf38da566c694..b76e4ff639878 100644 --- a/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.nll.stderr +++ b/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.nll.stderr @@ -1,5 +1,5 @@ error[E0506]: cannot assign to `*node_ref` because it is borrowed - --> $DIR/iterating-updating-cursor-issue-63908.rs:42:5 + --> $DIR/iterating-updating-cursor-issue-63908.rs:43:5 | LL | fn remove_last_node_iterative(mut node_ref: &mut List) { | - let's call the lifetime of this reference `'1` diff --git a/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.polonius.stderr b/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.polonius.stderr new file mode 100644 index 0000000000000..b76e4ff639878 --- /dev/null +++ b/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.polonius.stderr @@ -0,0 +1,18 @@ +error[E0506]: cannot assign to `*node_ref` because it is borrowed + --> $DIR/iterating-updating-cursor-issue-63908.rs:43:5 + | +LL | fn remove_last_node_iterative(mut node_ref: &mut List) { + | - let's call the lifetime of this reference `'1` +LL | loop { +LL | let next_ref = &mut node_ref.as_mut().unwrap().next; + | -------- `*node_ref` is borrowed here +... +LL | node_ref = next_ref; + | ------------------- assignment requires that `*node_ref` is borrowed for `'1` +... +LL | *node_ref = None; + | ^^^^^^^^^ `*node_ref` is assigned to here but it was already borrowed + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0506`. diff --git a/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.rs b/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.rs index 00e48b65fed15..6682926c5237a 100644 --- a/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.rs +++ b/tests/ui/nll/polonius/iterating-updating-cursor-issue-63908.rs @@ -1,11 +1,12 @@ #![crate_type = "lib"] -// An example from #63908 of the linked-list cursor-like pattern of #46859/#48001. +// An example from #63908 of the linked-list cursor-like pattern of #46859/#48001, where the +// polonius alpha analysis shows the same imprecision as NLLs, unlike the datalog implementation. //@ ignore-compare-mode-polonius (explicit revisions) //@ revisions: nll polonius legacy //@ [nll] known-bug: #63908 -//@ [polonius] check-pass +//@ [polonius] known-bug: #63908 //@ [polonius] compile-flags: -Z polonius=next //@ [legacy] check-pass //@ [legacy] compile-flags: -Z polonius=legacy @@ -27,7 +28,7 @@ fn remove_last_node_recursive(node_ref: &mut List) { } } -// NLLs fail here +// NLLs and polonius alpha fail here fn remove_last_node_iterative(mut node_ref: &mut List) { loop { let next_ref = &mut node_ref.as_mut().unwrap().next; From dcc1605fba0ad04b8bc2d96d044f2ca3711b2219 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Fri, 8 Aug 2025 09:17:35 -0700 Subject: [PATCH 14/28] [win][arm64ec] Partial fix for raw-dylib-link-ordinal on Arm64EC --- tests/run-make/raw-dylib-link-ordinal/exporter.def | 2 +- tests/run-make/raw-dylib-link-ordinal/rmake.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/run-make/raw-dylib-link-ordinal/exporter.def b/tests/run-make/raw-dylib-link-ordinal/exporter.def index 5d87c580a54d5..0544e9f180332 100644 --- a/tests/run-make/raw-dylib-link-ordinal/exporter.def +++ b/tests/run-make/raw-dylib-link-ordinal/exporter.def @@ -1,5 +1,5 @@ LIBRARY exporter EXPORTS exported_function @13 NONAME - exported_variable @5 NONAME + exported_variable @5 NONAME DATA print_exported_variable @9 NONAME diff --git a/tests/run-make/raw-dylib-link-ordinal/rmake.rs b/tests/run-make/raw-dylib-link-ordinal/rmake.rs index 43274b9765bb1..b9254b167534b 100644 --- a/tests/run-make/raw-dylib-link-ordinal/rmake.rs +++ b/tests/run-make/raw-dylib-link-ordinal/rmake.rs @@ -11,7 +11,7 @@ //@ only-windows -use run_make_support::{cc, diff, is_windows_msvc, run, rustc}; +use run_make_support::{cc, diff, extra_c_flags, is_windows_msvc, run, rustc}; // NOTE: build_native_dynamic lib is not used, as the special `def` files // must be passed to the CC compiler. @@ -24,6 +24,7 @@ fn main() { cc().input("exporter.obj") .arg("exporter.def") .args(&["-link", "-dll", "-noimplib", "-out:exporter.dll"]) + .args(extra_c_flags()) .run(); } else { cc().arg("-v").arg("-c").out_exe("exporter.obj").input("exporter.c").run(); From 87a09b2ad577fb6f9725dbc2e1adc5e75f783638 Mon Sep 17 00:00:00 2001 From: Daniel Paoliello Date: Fri, 8 Aug 2025 12:21:57 -0700 Subject: [PATCH 15/28] [win][arm64ec] Add '/machine:arm64ec' when linking LLVM as Arm64EC --- src/bootstrap/src/core/build_steps/llvm.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 721ba6ca459e4..79772330a6d98 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -421,6 +421,13 @@ impl Step for Llvm { ldflags.shared.push(" -latomic"); } + if target.starts_with("arm64ec") { + // MSVC linker requires the -machine:arm64ec flag to be passed to + // know it's linking as Arm64EC (vs Arm64X). + ldflags.exe.push(" -machine:arm64ec"); + ldflags.shared.push(" -machine:arm64ec"); + } + if target.is_msvc() { cfg.define("CMAKE_MSVC_RUNTIME_LIBRARY", "MultiThreaded"); cfg.static_crt(true); From 339be84d9dbe887ce704a5171e467b4fb363fbf4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 31 Jul 2025 17:14:39 +0200 Subject: [PATCH 16/28] Use new public libtest `ERROR_EXIT_CODE` constant in rustdoc --- src/librustdoc/doctest.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 35ace6566381b..73ce62cdcde6a 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -409,9 +409,7 @@ pub(crate) fn run_tests( // We ensure temp dir destructor is called. std::mem::drop(temp_dir); times.display_times(); - // FIXME(GuillaumeGomez): Uncomment the next line once #144297 has been merged. - // std::process::exit(test::ERROR_EXIT_CODE); - std::process::exit(101); + std::process::exit(test::ERROR_EXIT_CODE); } } From 2736d66a1f76e4829d95145a60b13bf695d5ef44 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 9 Aug 2025 14:17:17 +0800 Subject: [PATCH 17/28] rename `TraitRef::from_method` to `from_assoc` also add a note to `GenericArgs::truncate_to` --- compiler/rustc_const_eval/src/check_consts/ops.rs | 2 +- compiler/rustc_const_eval/src/interpret/call.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 7 ++----- compiler/rustc_middle/src/ty/generic_args.rs | 3 +++ .../src/cfi/typeid/itanium_cxx_abi/transform.rs | 4 ++-- compiler/rustc_trait_selection/src/traits/mod.rs | 2 +- compiler/rustc_ty_utils/src/instance.rs | 4 ++-- compiler/rustc_type_ir/src/predicate.rs | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs index 982e640fa92aa..79e32dcf105c9 100644 --- a/compiler/rustc_const_eval/src/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/check_consts/ops.rs @@ -142,7 +142,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { |err, self_ty, trait_id| { // FIXME(const_trait_impl): Do we need any of this on the non-const codepath? - let trait_ref = TraitRef::from_method(tcx, trait_id, self.args); + let trait_ref = TraitRef::from_assoc(tcx, trait_id, self.args); match self_ty.kind() { Param(param_ty) => { diff --git a/compiler/rustc_const_eval/src/interpret/call.rs b/compiler/rustc_const_eval/src/interpret/call.rs index b8a653698258f..a0160d1188d08 100644 --- a/compiler/rustc_const_eval/src/interpret/call.rs +++ b/compiler/rustc_const_eval/src/interpret/call.rs @@ -732,7 +732,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let tcx = *self.tcx; let trait_def_id = tcx.trait_of_assoc(def_id).unwrap(); - let virtual_trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, virtual_instance.args); + let virtual_trait_ref = ty::TraitRef::from_assoc(tcx, trait_def_id, virtual_instance.args); let existential_trait_ref = ty::ExistentialTraitRef::erase_self_ty(tcx, virtual_trait_ref); let concrete_trait_ref = existential_trait_ref.with_self_ty(tcx, dyn_ty); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index db56082c71aaa..49a4733de3b0a 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -290,11 +290,8 @@ impl<'tcx> Interner for TyCtxt<'tcx> { debug_assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); let trait_def_id = self.parent(def_id); debug_assert_matches!(self.def_kind(trait_def_id), DefKind::Trait); - let trait_generics = self.generics_of(trait_def_id); - ( - ty::TraitRef::new_from_args(self, trait_def_id, args.truncate_to(self, trait_generics)), - &args[trait_generics.count()..], - ) + let trait_ref = ty::TraitRef::from_assoc(self, trait_def_id, args); + (trait_ref, &args[trait_ref.args.len()..]) } fn mk_args(self, args: &[Self::GenericArg]) -> ty::GenericArgsRef<'tcx> { diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 648709e88e6c1..3ade3a3ef51e8 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -585,6 +585,9 @@ impl<'tcx> GenericArgs<'tcx> { tcx.mk_args_from_iter(target_args.iter().chain(self.iter().skip(defs.count()))) } + /// Truncates this list of generic args to have at most the number of args in `generics`. + /// + /// You might be looking for [`TraitRef::from_assoc`](super::TraitRef::from_assoc). pub fn truncate_to(&self, tcx: TyCtxt<'tcx>, generics: &ty::Generics) -> GenericArgsRef<'tcx> { tcx.mk_args(&self[..generics.count()]) } diff --git a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs index 52717d73b8aed..d81fa062e0102 100644 --- a/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs +++ b/compiler/rustc_sanitizers/src/cfi/typeid/itanium_cxx_abi/transform.rs @@ -342,7 +342,7 @@ pub(crate) fn transform_instance<'tcx>( let upcast_ty = match tcx.trait_of_assoc(def_id) { Some(trait_id) => trait_object_ty( tcx, - ty::Binder::dummy(ty::TraitRef::from_method(tcx, trait_id, instance.args)), + ty::Binder::dummy(ty::TraitRef::from_assoc(tcx, trait_id, instance.args)), ), // drop_in_place won't have a defining trait, skip the upcast None => instance.args.type_at(0), @@ -481,7 +481,7 @@ fn implemented_method<'tcx>( trait_method = trait_method_bound; method_id = instance.def_id(); trait_id = tcx.trait_of_assoc(method_id)?; - trait_ref = ty::EarlyBinder::bind(TraitRef::from_method(tcx, trait_id, instance.args)); + trait_ref = ty::EarlyBinder::bind(TraitRef::from_assoc(tcx, trait_id, instance.args)); trait_id } else { return None; diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 08315dbd21fbf..a9fb16b8000a9 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -763,7 +763,7 @@ fn instantiate_and_check_impossible_predicates<'tcx>( // Specifically check trait fulfillment to avoid an error when trying to resolve // associated items. if let Some(trait_def_id) = tcx.trait_of_assoc(key.0) { - let trait_ref = ty::TraitRef::from_method(tcx, trait_def_id, key.1); + let trait_ref = ty::TraitRef::from_assoc(tcx, trait_def_id, key.1); predicates.push(trait_ref.upcast(tcx)); } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index e6c3568620b5d..5c3f7d491a574 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -109,7 +109,7 @@ fn resolve_associated_item<'tcx>( ) -> Result>, ErrorGuaranteed> { debug!(?trait_item_id, ?typing_env, ?trait_id, ?rcvr_args, "resolve_associated_item"); - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args); + let trait_ref = ty::TraitRef::from_assoc(tcx, trait_id, rcvr_args); let input = typing_env.as_query_input(trait_ref); let vtbl = match tcx.codegen_select_candidate(input) { @@ -238,7 +238,7 @@ fn resolve_associated_item<'tcx>( Some(ty::Instance::new_raw(leaf_def.item.def_id, args)) } traits::ImplSource::Builtin(BuiltinImplSource::Object(_), _) => { - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_args); + let trait_ref = ty::TraitRef::from_assoc(tcx, trait_id, rcvr_args); if trait_ref.has_non_region_infer() || trait_ref.has_non_region_param() { // We only resolve totally substituted vtable entries. None diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 9e4447ccd9939..475c9cd40ed60 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -82,7 +82,7 @@ impl TraitRef { Self::new_from_args(interner, trait_def_id, args) } - pub fn from_method(interner: I, trait_id: I::DefId, args: I::GenericArgs) -> TraitRef { + pub fn from_assoc(interner: I, trait_id: I::DefId, args: I::GenericArgs) -> TraitRef { let generics = interner.generics_of(trait_id); TraitRef::new(interner, trait_id, args.iter().take(generics.count())) } From b5e2ba67756896eb76322882cceb979625c0514b Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Sat, 9 Aug 2025 03:44:24 +0500 Subject: [PATCH 18/28] Stabilize feature --- library/core/src/time.rs | 8 ++++---- library/coretests/tests/lib.rs | 1 - .../library-features/duration-constructors-lite.md | 11 ----------- .../src/library-features/duration-constructors.md | 1 - 4 files changed, 4 insertions(+), 17 deletions(-) delete mode 100644 src/doc/unstable-book/src/library-features/duration-constructors-lite.md diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 0fb5c0bac7562..9a0f5e0faefa8 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -373,7 +373,6 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_constructors_lite)] /// use std::time::Duration; /// /// let duration = Duration::from_hours(6); @@ -381,7 +380,8 @@ impl Duration { /// assert_eq!(6 * 60 * 60, duration.as_secs()); /// assert_eq!(0, duration.subsec_nanos()); /// ``` - #[unstable(feature = "duration_constructors_lite", issue = "140881")] + #[stable(feature = "duration_constructors_lite", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "duration_constructors_lite", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_hours(hours: u64) -> Duration { @@ -401,7 +401,6 @@ impl Duration { /// # Examples /// /// ``` - /// #![feature(duration_constructors_lite)] /// use std::time::Duration; /// /// let duration = Duration::from_mins(10); @@ -409,7 +408,8 @@ impl Duration { /// assert_eq!(10 * 60, duration.as_secs()); /// assert_eq!(0, duration.subsec_nanos()); /// ``` - #[unstable(feature = "duration_constructors_lite", issue = "140881")] + #[stable(feature = "duration_constructors_lite", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "duration_constructors_lite", since = "CURRENT_RUSTC_VERSION")] #[must_use] #[inline] pub const fn from_mins(mins: u64) -> Duration { diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index 75679bbac91fc..0c4d49f3c994b 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -36,7 +36,6 @@ #![feature(drop_guard)] #![feature(duration_constants)] #![feature(duration_constructors)] -#![feature(duration_constructors_lite)] #![feature(error_generic_member_access)] #![feature(exact_div)] #![feature(exact_size_is_empty)] diff --git a/src/doc/unstable-book/src/library-features/duration-constructors-lite.md b/src/doc/unstable-book/src/library-features/duration-constructors-lite.md deleted file mode 100644 index 5238b84f77646..0000000000000 --- a/src/doc/unstable-book/src/library-features/duration-constructors-lite.md +++ /dev/null @@ -1,11 +0,0 @@ -# `duration_constructors_lite` - -The tracking issue for this feature is: [#140881] - -[#140881]: https://github.com/rust-lang/rust/issues/140881 - ------------------------- - -Add the methods `from_mins`, `from_hours` to `Duration`. - -For `from_days` and `from_weeks` see [`duration_constructors`](https://github.com/rust-lang/rust/issues/120301). diff --git a/src/doc/unstable-book/src/library-features/duration-constructors.md b/src/doc/unstable-book/src/library-features/duration-constructors.md index 49ad78d196138..2626e0500b545 100644 --- a/src/doc/unstable-book/src/library-features/duration-constructors.md +++ b/src/doc/unstable-book/src/library-features/duration-constructors.md @@ -7,4 +7,3 @@ The tracking issue for this feature is: [#120301] ------------------------ Add the methods `from_days` and `from_weeks` to `Duration`. -For `from_mins` and `from_hours` see [duration-constructors-lite.md](./duration-constructors-lite.md) From a5ddf5da582d2f1810af7045772bd5934884fdc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Ber=C3=A1nek?= Date: Sat, 9 Aug 2025 11:51:20 +0200 Subject: [PATCH 19/28] Override custom Cargo `build-dir` in bootstrap --- src/bootstrap/src/core/builder/cargo.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index e10af2b55f9e1..39f46bf43afc9 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -433,6 +433,15 @@ impl Builder<'_> { let out_dir = self.stage_out(compiler, mode); cargo.env("CARGO_TARGET_DIR", &out_dir); + // Bootstrap makes a lot of assumptions about the artifacts produced in the target + // directory. If users override the "build directory" using `build-dir` + // (https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-dir), then + // bootstrap couldn't find these artifacts. So we forcefully override that option to our + // target directory here. + // In the future, we could attempt to read the build-dir location from Cargo and actually + // respect it. + cargo.env("CARGO_BUILD_BUILD_DIR", &out_dir); + // Found with `rg "init_env_logger\("`. If anyone uses `init_env_logger` // from out of tree it shouldn't matter, since x.py is only used for // building in-tree. From 16765639b30741dde85da0dbcb44c343eb82b1a2 Mon Sep 17 00:00:00 2001 From: Kivooeo Date: Thu, 24 Jul 2025 19:07:20 +0500 Subject: [PATCH 20/28] comments --- .../array-slice-coercion-mismatch-15783.rs | 2 ++ .../array-slice-coercion-mismatch-15783.stderr} | 4 ++-- ...warning-16256.rs => unused-closure-ice-16256.rs} | 2 ++ .../unused-closure-ice-16256.stderr} | 2 +- .../nested-enum-match-optimization-15793.rs} | 2 ++ .../derive-partial-ord-discriminant-64bit.rs | 3 ++- tests/ui/derives/derive-partial-ord-discriminant.rs | 2 ++ tests/ui/drop/enum-drop-impl-15063.rs | 2 ++ tests/ui/drop/generic-drop-trait-bound-15858.rs | 2 ++ .../generic-drop-trait-bound-15858.stderr} | 2 +- ...rn-drop-order.rs => nested-return-drop-order.rs} | 2 ++ ...> same-alloca-reassigned-match-binding-16151.rs} | 2 ++ tests/ui/drop/struct-field-drop-order.rs | 2 ++ tests/ui/extern/empty-struct-extern-fn-16441.rs | 2 ++ ...re.rs => fn-traits-call-once-signature-15094.rs} | 2 ++ .../fn-traits-call-once-signature-15094.stderr} | 2 +- tests/ui/imports/enum-variant-import-path-15774.rs | 2 ++ .../iterator-sum-array-15673.rs | 2 ++ .../inference/return-block-type-inference-15965.rs | 2 ++ .../return-block-type-inference-15965.stderr} | 2 +- ...rn.rs => explicit-deref-non-deref-type-15756.rs} | 2 ++ .../explicit-deref-non-deref-type-15756.stderr} | 2 +- ...rs => nondeterministic-lifetime-errors-15034.rs} | 2 ++ .../nondeterministic-lifetime-errors-15034.stderr} | 2 +- .../ui/lifetimes/struct-lifetime-inference-15735.rs | 2 ++ ...ure-15189.rs => for-loop-macro-rules-hygiene.rs} | 2 ++ tests/ui/macros/macro-hygiene-scope-15167.rs | 2 ++ .../macro-hygiene-scope-15167.stderr} | 8 ++++---- tests/ui/moves/match-move-same-binding-15571.rs | 2 ++ tests/ui/never/never-type-method-call-15207.rs | 2 ++ .../never-type-method-call-15207.stderr} | 2 +- .../generics-rangle-eq-15043.rs} | 2 ++ ...tch.rs => enum-struct-pattern-mismatch-15896.rs} | 2 ++ .../enum-struct-pattern-mismatch-15896.stderr} | 2 +- .../ui/pattern/refutable-pattern-for-loop-15381.rs | 2 ++ .../refutable-pattern-for-loop-15381.stderr} | 2 +- tests/ui/pattern/slice-pattern-recursion-15104.rs | 2 ++ tests/ui/pattern/static-binding-shadow-16149.rs | 2 ++ .../static-binding-shadow-16149.stderr} | 2 +- ...g.rs => struct-field-duplicate-binding-15260.rs} | 2 ++ .../struct-field-duplicate-binding-15260.stderr} | 8 ++++---- tests/ui/pattern/tuple-enum-match-15129.rs | 13 +++++++------ ...s => unit-type-struct-pattern-mismatch-16401.rs} | 2 ++ .../unit-type-struct-pattern-mismatch-16401.stderr} | 2 +- ...n.rs => conditional-static-declaration-16010.rs} | 2 ++ tests/ui/traits/fn-type-trait-impl-15444.rs | 2 ++ ...impls.rs => index-trait-multiple-impls-15734.rs} | 2 ++ ...mpl.rs => lifetime-mismatch-trait-impl-16048.rs} | 2 ++ .../lifetime-mismatch-trait-impl-16048.stderr} | 4 ++-- 49 files changed, 96 insertions(+), 30 deletions(-) rename tests/ui/{coercion => borrowck}/array-slice-coercion-mismatch-15783.rs (85%) rename tests/ui/{issues/issue-15783.stderr => borrowck/array-slice-coercion-mismatch-15783.stderr} (83%) rename tests/ui/closures/{unused-closure-warning-16256.rs => unused-closure-ice-16256.rs} (63%) rename tests/ui/{issues/issue-16256.stderr => closures/unused-closure-ice-16256.stderr} (85%) rename tests/ui/{match/nested-enum-match-optimization.rs => codegen/nested-enum-match-optimization-15793.rs} (87%) rename tests/ui/{issues/issue-15858.stderr => drop/generic-drop-trait-bound-15858.stderr} (83%) rename tests/ui/drop/{early-return-drop-order.rs => nested-return-drop-order.rs} (95%) rename tests/ui/drop/{vec-replace-skip-while-drop.rs => same-alloca-reassigned-match-binding-16151.rs} (89%) rename tests/ui/fn/{fn-traits-call-once-signature.rs => fn-traits-call-once-signature-15094.rs} (89%) rename tests/ui/{issues/issue-15094.stderr => fn/fn-traits-call-once-signature-15094.stderr} (88%) rename tests/ui/{iterators => inference}/iterator-sum-array-15673.rs (69%) rename tests/ui/{issues/issue-15965.stderr => inference/return-block-type-inference-15965.stderr} (81%) rename tests/ui/iterators/{chunk-iterator-mut-pattern.rs => explicit-deref-non-deref-type-15756.rs} (75%) rename tests/ui/{issues/issue-15756.stderr => iterators/explicit-deref-non-deref-type-15756.stderr} (88%) rename tests/ui/lifetimes/{explicit-lifetime-required-15034.rs => nondeterministic-lifetime-errors-15034.rs} (85%) rename tests/ui/{issues/issue-15034.stderr => lifetimes/nondeterministic-lifetime-errors-15034.stderr} (88%) rename tests/ui/macros/{macro-variable-capture-15189.rs => for-loop-macro-rules-hygiene.rs} (73%) rename tests/ui/{issues/issue-15167.stderr => macros/macro-hygiene-scope-15167.stderr} (89%) rename tests/ui/{issues/issue-15207.stderr => never/never-type-method-call-15207.stderr} (84%) rename tests/ui/{structs/static-struct-init-15043.rs => parser/generics-rangle-eq-15043.rs} (72%) rename tests/ui/pattern/{enum-struct-pattern-mismatch.rs => enum-struct-pattern-mismatch-15896.rs} (81%) rename tests/ui/{issues/issue-15896.stderr => pattern/enum-struct-pattern-mismatch-15896.stderr} (85%) rename tests/ui/{issues/issue-15381.stderr => pattern/refutable-pattern-for-loop-15381.stderr} (87%) rename tests/ui/{issues/issue-16149.stderr => pattern/static-binding-shadow-16149.stderr} (89%) rename tests/ui/pattern/{struct-field-duplicate-binding.rs => struct-field-duplicate-binding-15260.rs} (87%) rename tests/ui/{issues/issue-15260.stderr => pattern/struct-field-duplicate-binding-15260.stderr} (79%) rename tests/ui/pattern/{unit-type-struct-pattern-mismatch.rs => unit-type-struct-pattern-mismatch-16401.rs} (83%) rename tests/ui/{issues/issue-16401.stderr => pattern/unit-type-struct-pattern-mismatch-16401.stderr} (87%) rename tests/ui/statics/{conditional-static-declaration.rs => conditional-static-declaration-16010.rs} (65%) rename tests/ui/traits/{index-trait-multiple-impls.rs => index-trait-multiple-impls-15734.rs} (94%) rename tests/ui/traits/{lifetime-mismatch-trait-impl.rs => lifetime-mismatch-trait-impl-16048.rs} (90%) rename tests/ui/{issues/issue-16048.stderr => traits/lifetime-mismatch-trait-impl-16048.stderr} (89%) diff --git a/tests/ui/coercion/array-slice-coercion-mismatch-15783.rs b/tests/ui/borrowck/array-slice-coercion-mismatch-15783.rs similarity index 85% rename from tests/ui/coercion/array-slice-coercion-mismatch-15783.rs rename to tests/ui/borrowck/array-slice-coercion-mismatch-15783.rs index ef948a1a88ce1..3322ed71c60ed 100644 --- a/tests/ui/coercion/array-slice-coercion-mismatch-15783.rs +++ b/tests/ui/borrowck/array-slice-coercion-mismatch-15783.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15783 + //@ dont-require-annotations: NOTE pub fn foo(params: Option<&[&str]>) -> usize { diff --git a/tests/ui/issues/issue-15783.stderr b/tests/ui/borrowck/array-slice-coercion-mismatch-15783.stderr similarity index 83% rename from tests/ui/issues/issue-15783.stderr rename to tests/ui/borrowck/array-slice-coercion-mismatch-15783.stderr index c9c9a723a860b..050eb4baa418c 100644 --- a/tests/ui/issues/issue-15783.stderr +++ b/tests/ui/borrowck/array-slice-coercion-mismatch-15783.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-15783.rs:10:19 + --> $DIR/array-slice-coercion-mismatch-15783.rs:12:19 | LL | let msg = foo(x); | --- ^ expected `Option<&[&str]>`, found `Option<&[&str; 1]>` @@ -9,7 +9,7 @@ LL | let msg = foo(x); = note: expected enum `Option<&[&str]>` found enum `Option<&[&str; 1]>` note: function defined here - --> $DIR/issue-15783.rs:3:8 + --> $DIR/array-slice-coercion-mismatch-15783.rs:5:8 | LL | pub fn foo(params: Option<&[&str]>) -> usize { | ^^^ ----------------------- diff --git a/tests/ui/closures/unused-closure-warning-16256.rs b/tests/ui/closures/unused-closure-ice-16256.rs similarity index 63% rename from tests/ui/closures/unused-closure-warning-16256.rs rename to tests/ui/closures/unused-closure-ice-16256.rs index 1024e4511d639..fd569dd8a0a18 100644 --- a/tests/ui/closures/unused-closure-warning-16256.rs +++ b/tests/ui/closures/unused-closure-ice-16256.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/16256 + //@ run-pass fn main() { diff --git a/tests/ui/issues/issue-16256.stderr b/tests/ui/closures/unused-closure-ice-16256.stderr similarity index 85% rename from tests/ui/issues/issue-16256.stderr rename to tests/ui/closures/unused-closure-ice-16256.stderr index 75c3ec1bd1c7f..9df433add5d55 100644 --- a/tests/ui/issues/issue-16256.stderr +++ b/tests/ui/closures/unused-closure-ice-16256.stderr @@ -1,5 +1,5 @@ warning: unused closure that must be used - --> $DIR/issue-16256.rs:5:5 + --> $DIR/unused-closure-ice-16256.rs:7:5 | LL | |c: u8| buf.push(c); | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/match/nested-enum-match-optimization.rs b/tests/ui/codegen/nested-enum-match-optimization-15793.rs similarity index 87% rename from tests/ui/match/nested-enum-match-optimization.rs rename to tests/ui/codegen/nested-enum-match-optimization-15793.rs index af92e9dfa4c1c..420e3ad82b265 100644 --- a/tests/ui/match/nested-enum-match-optimization.rs +++ b/tests/ui/codegen/nested-enum-match-optimization-15793.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15793 + //@ run-pass #![allow(dead_code)] diff --git a/tests/ui/derives/derive-partial-ord-discriminant-64bit.rs b/tests/ui/derives/derive-partial-ord-discriminant-64bit.rs index 7214a4fb1d517..5b6bf6fbf1f01 100644 --- a/tests/ui/derives/derive-partial-ord-discriminant-64bit.rs +++ b/tests/ui/derives/derive-partial-ord-discriminant-64bit.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15523 + //@ run-pass // Issue 15523: derive(PartialOrd) should use the provided // discriminant values for the derived ordering. @@ -28,7 +30,6 @@ fn main() { assert!(Eu64::Pos2 < Eu64::PosMax); assert!(Eu64::Pos1 < Eu64::PosMax); - assert!(Ei64::Pos2 > Ei64::Pos1); assert!(Ei64::Pos2 > Ei64::Neg1); assert!(Ei64::Pos1 > Ei64::Neg1); diff --git a/tests/ui/derives/derive-partial-ord-discriminant.rs b/tests/ui/derives/derive-partial-ord-discriminant.rs index 9fc2e51c6ab63..28f325ec966c9 100644 --- a/tests/ui/derives/derive-partial-ord-discriminant.rs +++ b/tests/ui/derives/derive-partial-ord-discriminant.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15523 + //@ run-pass // Issue 15523: derive(PartialOrd) should use the provided // discriminant values for the derived ordering. diff --git a/tests/ui/drop/enum-drop-impl-15063.rs b/tests/ui/drop/enum-drop-impl-15063.rs index 969dbe5fad299..a8198abafa008 100644 --- a/tests/ui/drop/enum-drop-impl-15063.rs +++ b/tests/ui/drop/enum-drop-impl-15063.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15063 + //@ run-pass #![allow(dead_code)] #![allow(unused_variables)] diff --git a/tests/ui/drop/generic-drop-trait-bound-15858.rs b/tests/ui/drop/generic-drop-trait-bound-15858.rs index 27887d49e3e8a..682604d17d864 100644 --- a/tests/ui/drop/generic-drop-trait-bound-15858.rs +++ b/tests/ui/drop/generic-drop-trait-bound-15858.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15858 + //@ run-pass // FIXME(static_mut_refs): this could use an atomic #![allow(static_mut_refs)] diff --git a/tests/ui/issues/issue-15858.stderr b/tests/ui/drop/generic-drop-trait-bound-15858.stderr similarity index 83% rename from tests/ui/issues/issue-15858.stderr rename to tests/ui/drop/generic-drop-trait-bound-15858.stderr index 0c082cc086218..86cd6cb60266a 100644 --- a/tests/ui/issues/issue-15858.stderr +++ b/tests/ui/drop/generic-drop-trait-bound-15858.stderr @@ -1,5 +1,5 @@ warning: method `do_something` is never used - --> $DIR/issue-15858.rs:7:8 + --> $DIR/generic-drop-trait-bound-15858.rs:9:8 | LL | trait Bar { | --- method in this trait diff --git a/tests/ui/drop/early-return-drop-order.rs b/tests/ui/drop/nested-return-drop-order.rs similarity index 95% rename from tests/ui/drop/early-return-drop-order.rs rename to tests/ui/drop/nested-return-drop-order.rs index 0ebadd80541f0..67ab52e6250c8 100644 --- a/tests/ui/drop/early-return-drop-order.rs +++ b/tests/ui/drop/nested-return-drop-order.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15763 + //@ run-pass #![allow(unreachable_code)] diff --git a/tests/ui/drop/vec-replace-skip-while-drop.rs b/tests/ui/drop/same-alloca-reassigned-match-binding-16151.rs similarity index 89% rename from tests/ui/drop/vec-replace-skip-while-drop.rs rename to tests/ui/drop/same-alloca-reassigned-match-binding-16151.rs index b18108e0a8ad8..ecc862ec7be6b 100644 --- a/tests/ui/drop/vec-replace-skip-while-drop.rs +++ b/tests/ui/drop/same-alloca-reassigned-match-binding-16151.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/16151 + //@ run-pass // FIXME(static_mut_refs): Do not allow `static_mut_refs` lint diff --git a/tests/ui/drop/struct-field-drop-order.rs b/tests/ui/drop/struct-field-drop-order.rs index cfdba5fda351c..80e3ea616a551 100644 --- a/tests/ui/drop/struct-field-drop-order.rs +++ b/tests/ui/drop/struct-field-drop-order.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/16492 + //@ run-pass #![allow(non_snake_case)] diff --git a/tests/ui/extern/empty-struct-extern-fn-16441.rs b/tests/ui/extern/empty-struct-extern-fn-16441.rs index 58cfb3892975b..82f2eee611d06 100644 --- a/tests/ui/extern/empty-struct-extern-fn-16441.rs +++ b/tests/ui/extern/empty-struct-extern-fn-16441.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/16441 + //@ run-pass #![allow(dead_code)] diff --git a/tests/ui/fn/fn-traits-call-once-signature.rs b/tests/ui/fn/fn-traits-call-once-signature-15094.rs similarity index 89% rename from tests/ui/fn/fn-traits-call-once-signature.rs rename to tests/ui/fn/fn-traits-call-once-signature-15094.rs index 408ab82eb8c87..f550bafe43df2 100644 --- a/tests/ui/fn/fn-traits-call-once-signature.rs +++ b/tests/ui/fn/fn-traits-call-once-signature-15094.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15094 + #![feature(fn_traits, unboxed_closures)] use std::{fmt, ops}; diff --git a/tests/ui/issues/issue-15094.stderr b/tests/ui/fn/fn-traits-call-once-signature-15094.stderr similarity index 88% rename from tests/ui/issues/issue-15094.stderr rename to tests/ui/fn/fn-traits-call-once-signature-15094.stderr index 8e0fc8f177099..bb1d336e84842 100644 --- a/tests/ui/issues/issue-15094.stderr +++ b/tests/ui/fn/fn-traits-call-once-signature-15094.stderr @@ -1,5 +1,5 @@ error[E0053]: method `call_once` has an incompatible type for trait - --> $DIR/issue-15094.rs:11:5 + --> $DIR/fn-traits-call-once-signature-15094.rs:13:5 | LL | fn call_once(self, _args: ()) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "rust-call" fn, found "Rust" fn diff --git a/tests/ui/imports/enum-variant-import-path-15774.rs b/tests/ui/imports/enum-variant-import-path-15774.rs index dadd59cc077b1..583fe4da17969 100644 --- a/tests/ui/imports/enum-variant-import-path-15774.rs +++ b/tests/ui/imports/enum-variant-import-path-15774.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15774 + //@ edition: 2015 //@ run-pass diff --git a/tests/ui/iterators/iterator-sum-array-15673.rs b/tests/ui/inference/iterator-sum-array-15673.rs similarity index 69% rename from tests/ui/iterators/iterator-sum-array-15673.rs rename to tests/ui/inference/iterator-sum-array-15673.rs index bb61c24627643..c3d94415affda 100644 --- a/tests/ui/iterators/iterator-sum-array-15673.rs +++ b/tests/ui/inference/iterator-sum-array-15673.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15673 + //@ run-pass #![allow(stable_features)] diff --git a/tests/ui/inference/return-block-type-inference-15965.rs b/tests/ui/inference/return-block-type-inference-15965.rs index eef4900d432d0..50753e309e8ee 100644 --- a/tests/ui/inference/return-block-type-inference-15965.rs +++ b/tests/ui/inference/return-block-type-inference-15965.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15965 + fn main() { return { return () } diff --git a/tests/ui/issues/issue-15965.stderr b/tests/ui/inference/return-block-type-inference-15965.stderr similarity index 81% rename from tests/ui/issues/issue-15965.stderr rename to tests/ui/inference/return-block-type-inference-15965.stderr index 14727e74334c7..fc4f2defe7ffa 100644 --- a/tests/ui/issues/issue-15965.stderr +++ b/tests/ui/inference/return-block-type-inference-15965.stderr @@ -1,5 +1,5 @@ error[E0282]: type annotations needed - --> $DIR/issue-15965.rs:3:9 + --> $DIR/return-block-type-inference-15965.rs:5:9 | LL | / { return () } LL | | diff --git a/tests/ui/iterators/chunk-iterator-mut-pattern.rs b/tests/ui/iterators/explicit-deref-non-deref-type-15756.rs similarity index 75% rename from tests/ui/iterators/chunk-iterator-mut-pattern.rs rename to tests/ui/iterators/explicit-deref-non-deref-type-15756.rs index e0861dee61ea1..6d4a3bffcf7ef 100644 --- a/tests/ui/iterators/chunk-iterator-mut-pattern.rs +++ b/tests/ui/iterators/explicit-deref-non-deref-type-15756.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15756 + use std::slice::Chunks; use std::slice::ChunksMut; diff --git a/tests/ui/issues/issue-15756.stderr b/tests/ui/iterators/explicit-deref-non-deref-type-15756.stderr similarity index 88% rename from tests/ui/issues/issue-15756.stderr rename to tests/ui/iterators/explicit-deref-non-deref-type-15756.stderr index a487d360bef98..b4f9aab8496a8 100644 --- a/tests/ui/issues/issue-15756.stderr +++ b/tests/ui/iterators/explicit-deref-non-deref-type-15756.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[T]` cannot be known at compilation time - --> $DIR/issue-15756.rs:7:10 + --> $DIR/explicit-deref-non-deref-type-15756.rs:9:10 | LL | &mut something | ^^^^^^^^^ doesn't have a size known at compile-time diff --git a/tests/ui/lifetimes/explicit-lifetime-required-15034.rs b/tests/ui/lifetimes/nondeterministic-lifetime-errors-15034.rs similarity index 85% rename from tests/ui/lifetimes/explicit-lifetime-required-15034.rs rename to tests/ui/lifetimes/nondeterministic-lifetime-errors-15034.rs index 9ea6ed89ca249..e7f9a94231fc0 100644 --- a/tests/ui/lifetimes/explicit-lifetime-required-15034.rs +++ b/tests/ui/lifetimes/nondeterministic-lifetime-errors-15034.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15034 + pub struct Lexer<'a> { input: &'a str, } diff --git a/tests/ui/issues/issue-15034.stderr b/tests/ui/lifetimes/nondeterministic-lifetime-errors-15034.stderr similarity index 88% rename from tests/ui/issues/issue-15034.stderr rename to tests/ui/lifetimes/nondeterministic-lifetime-errors-15034.stderr index 7db8ade2e482c..0762714d259f6 100644 --- a/tests/ui/issues/issue-15034.stderr +++ b/tests/ui/lifetimes/nondeterministic-lifetime-errors-15034.stderr @@ -1,5 +1,5 @@ error[E0621]: explicit lifetime required in the type of `lexer` - --> $DIR/issue-15034.rs:17:9 + --> $DIR/nondeterministic-lifetime-errors-15034.rs:19:9 | LL | Parser { lexer: lexer } | ^^^^^^^^^^^^^^^^^^^^^^^ lifetime `'a` required diff --git a/tests/ui/lifetimes/struct-lifetime-inference-15735.rs b/tests/ui/lifetimes/struct-lifetime-inference-15735.rs index f5b3803f1553f..39e619648eb37 100644 --- a/tests/ui/lifetimes/struct-lifetime-inference-15735.rs +++ b/tests/ui/lifetimes/struct-lifetime-inference-15735.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15735 + //@ check-pass #![allow(dead_code)] struct A<'a> { diff --git a/tests/ui/macros/macro-variable-capture-15189.rs b/tests/ui/macros/for-loop-macro-rules-hygiene.rs similarity index 73% rename from tests/ui/macros/macro-variable-capture-15189.rs rename to tests/ui/macros/for-loop-macro-rules-hygiene.rs index 4dbe2179dd9c1..fcebda1b9da82 100644 --- a/tests/ui/macros/macro-variable-capture-15189.rs +++ b/tests/ui/macros/for-loop-macro-rules-hygiene.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15189 + //@ run-pass macro_rules! third { ($e:expr) => ({let x = 2; $e[x]}) diff --git a/tests/ui/macros/macro-hygiene-scope-15167.rs b/tests/ui/macros/macro-hygiene-scope-15167.rs index a2653c10ea4f7..6578f898a5fb4 100644 --- a/tests/ui/macros/macro-hygiene-scope-15167.rs +++ b/tests/ui/macros/macro-hygiene-scope-15167.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15167 + // macro f should not be able to inject a reference to 'n'. macro_rules! f { () => (n) } diff --git a/tests/ui/issues/issue-15167.stderr b/tests/ui/macros/macro-hygiene-scope-15167.stderr similarity index 89% rename from tests/ui/issues/issue-15167.stderr rename to tests/ui/macros/macro-hygiene-scope-15167.stderr index 53082ea0ec6bb..58112c52df159 100644 --- a/tests/ui/issues/issue-15167.stderr +++ b/tests/ui/macros/macro-hygiene-scope-15167.stderr @@ -1,5 +1,5 @@ error[E0425]: cannot find value `n` in this scope - --> $DIR/issue-15167.rs:3:25 + --> $DIR/macro-hygiene-scope-15167.rs:5:25 | LL | macro_rules! f { () => (n) } | ^ not found in this scope @@ -10,7 +10,7 @@ LL | println!("{}", f!()); = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope - --> $DIR/issue-15167.rs:3:25 + --> $DIR/macro-hygiene-scope-15167.rs:5:25 | LL | macro_rules! f { () => (n) } | ^ not found in this scope @@ -21,7 +21,7 @@ LL | println!("{}", f!()); = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope - --> $DIR/issue-15167.rs:3:25 + --> $DIR/macro-hygiene-scope-15167.rs:5:25 | LL | macro_rules! f { () => (n) } | ^ not found in this scope @@ -32,7 +32,7 @@ LL | println!("{}", f!()); = note: this error originates in the macro `f` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0425]: cannot find value `n` in this scope - --> $DIR/issue-15167.rs:3:25 + --> $DIR/macro-hygiene-scope-15167.rs:5:25 | LL | macro_rules! f { () => (n) } | ^ not found in this scope diff --git a/tests/ui/moves/match-move-same-binding-15571.rs b/tests/ui/moves/match-move-same-binding-15571.rs index cf17113a28260..f6d79c6d76c39 100644 --- a/tests/ui/moves/match-move-same-binding-15571.rs +++ b/tests/ui/moves/match-move-same-binding-15571.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15571 + //@ run-pass fn match_on_local() { diff --git a/tests/ui/never/never-type-method-call-15207.rs b/tests/ui/never/never-type-method-call-15207.rs index 356e55ac912ec..69cdeeabb7c96 100644 --- a/tests/ui/never/never-type-method-call-15207.rs +++ b/tests/ui/never/never-type-method-call-15207.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15207 + fn main() { loop { break.push(1) //~ ERROR no method named `push` found for type `!` diff --git a/tests/ui/issues/issue-15207.stderr b/tests/ui/never/never-type-method-call-15207.stderr similarity index 84% rename from tests/ui/issues/issue-15207.stderr rename to tests/ui/never/never-type-method-call-15207.stderr index a1047e27ba22a..265e7c8611d10 100644 --- a/tests/ui/issues/issue-15207.stderr +++ b/tests/ui/never/never-type-method-call-15207.stderr @@ -1,5 +1,5 @@ error[E0599]: no method named `push` found for type `!` in the current scope - --> $DIR/issue-15207.rs:3:15 + --> $DIR/never-type-method-call-15207.rs:5:15 | LL | break.push(1) | ^^^^ method not found in `!` diff --git a/tests/ui/structs/static-struct-init-15043.rs b/tests/ui/parser/generics-rangle-eq-15043.rs similarity index 72% rename from tests/ui/structs/static-struct-init-15043.rs rename to tests/ui/parser/generics-rangle-eq-15043.rs index a9bb46b649b00..1afc334dfd816 100644 --- a/tests/ui/structs/static-struct-init-15043.rs +++ b/tests/ui/parser/generics-rangle-eq-15043.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15043 + //@ run-pass #![allow(warnings)] diff --git a/tests/ui/pattern/enum-struct-pattern-mismatch.rs b/tests/ui/pattern/enum-struct-pattern-mismatch-15896.rs similarity index 81% rename from tests/ui/pattern/enum-struct-pattern-mismatch.rs rename to tests/ui/pattern/enum-struct-pattern-mismatch-15896.rs index d3153b516e64d..9f7c5084c0e17 100644 --- a/tests/ui/pattern/enum-struct-pattern-mismatch.rs +++ b/tests/ui/pattern/enum-struct-pattern-mismatch-15896.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15896 + // Regression test for #15896. It used to ICE rustc. fn main() { diff --git a/tests/ui/issues/issue-15896.stderr b/tests/ui/pattern/enum-struct-pattern-mismatch-15896.stderr similarity index 85% rename from tests/ui/issues/issue-15896.stderr rename to tests/ui/pattern/enum-struct-pattern-mismatch-15896.stderr index 381f6dc22760e..8dee4c37e2fef 100644 --- a/tests/ui/issues/issue-15896.stderr +++ b/tests/ui/pattern/enum-struct-pattern-mismatch-15896.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-15896.rs:11:11 + --> $DIR/enum-struct-pattern-mismatch-15896.rs:13:11 | LL | let u = match e { | - this expression has type `E` diff --git a/tests/ui/pattern/refutable-pattern-for-loop-15381.rs b/tests/ui/pattern/refutable-pattern-for-loop-15381.rs index bd5f62ddc674f..3c19612c9cc0e 100644 --- a/tests/ui/pattern/refutable-pattern-for-loop-15381.rs +++ b/tests/ui/pattern/refutable-pattern-for-loop-15381.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15381 + fn main() { let values: Vec = vec![1,2,3,4,5,6,7,8]; diff --git a/tests/ui/issues/issue-15381.stderr b/tests/ui/pattern/refutable-pattern-for-loop-15381.stderr similarity index 87% rename from tests/ui/issues/issue-15381.stderr rename to tests/ui/pattern/refutable-pattern-for-loop-15381.stderr index 03a0100f1bdc9..3c1d5fb454ce4 100644 --- a/tests/ui/issues/issue-15381.stderr +++ b/tests/ui/pattern/refutable-pattern-for-loop-15381.stderr @@ -1,5 +1,5 @@ error[E0005]: refutable pattern in `for` loop binding - --> $DIR/issue-15381.rs:4:9 + --> $DIR/refutable-pattern-for-loop-15381.rs:6:9 | LL | for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) { | ^^^^^^^^ patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered diff --git a/tests/ui/pattern/slice-pattern-recursion-15104.rs b/tests/ui/pattern/slice-pattern-recursion-15104.rs index e68c94c370ed4..24e3fe78de0af 100644 --- a/tests/ui/pattern/slice-pattern-recursion-15104.rs +++ b/tests/ui/pattern/slice-pattern-recursion-15104.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15104 + //@ run-pass fn main() { diff --git a/tests/ui/pattern/static-binding-shadow-16149.rs b/tests/ui/pattern/static-binding-shadow-16149.rs index 51b60725c5a0c..a46f78214c70d 100644 --- a/tests/ui/pattern/static-binding-shadow-16149.rs +++ b/tests/ui/pattern/static-binding-shadow-16149.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/16149 + extern "C" { static externalValue: isize; } diff --git a/tests/ui/issues/issue-16149.stderr b/tests/ui/pattern/static-binding-shadow-16149.stderr similarity index 89% rename from tests/ui/issues/issue-16149.stderr rename to tests/ui/pattern/static-binding-shadow-16149.stderr index 9ffd0e7e64536..6d8c7634acddd 100644 --- a/tests/ui/issues/issue-16149.stderr +++ b/tests/ui/pattern/static-binding-shadow-16149.stderr @@ -1,5 +1,5 @@ error[E0530]: match bindings cannot shadow statics - --> $DIR/issue-16149.rs:7:9 + --> $DIR/static-binding-shadow-16149.rs:9:9 | LL | static externalValue: isize; | ---------------------------- the static `externalValue` is defined here diff --git a/tests/ui/pattern/struct-field-duplicate-binding.rs b/tests/ui/pattern/struct-field-duplicate-binding-15260.rs similarity index 87% rename from tests/ui/pattern/struct-field-duplicate-binding.rs rename to tests/ui/pattern/struct-field-duplicate-binding-15260.rs index 64fc3df3d23f1..a3617798cdfbb 100644 --- a/tests/ui/pattern/struct-field-duplicate-binding.rs +++ b/tests/ui/pattern/struct-field-duplicate-binding-15260.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15260 + struct Foo { a: usize, } diff --git a/tests/ui/issues/issue-15260.stderr b/tests/ui/pattern/struct-field-duplicate-binding-15260.stderr similarity index 79% rename from tests/ui/issues/issue-15260.stderr rename to tests/ui/pattern/struct-field-duplicate-binding-15260.stderr index 4a3041122b26d..536904fbcb330 100644 --- a/tests/ui/issues/issue-15260.stderr +++ b/tests/ui/pattern/struct-field-duplicate-binding-15260.stderr @@ -1,5 +1,5 @@ error[E0025]: field `a` bound multiple times in the pattern - --> $DIR/issue-15260.rs:8:9 + --> $DIR/struct-field-duplicate-binding-15260.rs:10:9 | LL | a: _, | ---- first use of `a` @@ -7,7 +7,7 @@ LL | a: _ | ^^^^ multiple uses of `a` in pattern error[E0025]: field `a` bound multiple times in the pattern - --> $DIR/issue-15260.rs:14:9 + --> $DIR/struct-field-duplicate-binding-15260.rs:16:9 | LL | a, | - first use of `a` @@ -15,7 +15,7 @@ LL | a: _ | ^^^^ multiple uses of `a` in pattern error[E0025]: field `a` bound multiple times in the pattern - --> $DIR/issue-15260.rs:20:9 + --> $DIR/struct-field-duplicate-binding-15260.rs:22:9 | LL | a, | - first use of `a` @@ -23,7 +23,7 @@ LL | a: _, | ^^^^ multiple uses of `a` in pattern error[E0025]: field `a` bound multiple times in the pattern - --> $DIR/issue-15260.rs:22:9 + --> $DIR/struct-field-duplicate-binding-15260.rs:24:9 | LL | a, | - first use of `a` diff --git a/tests/ui/pattern/tuple-enum-match-15129.rs b/tests/ui/pattern/tuple-enum-match-15129.rs index e2ddb989072ee..1d6192c4cb317 100644 --- a/tests/ui/pattern/tuple-enum-match-15129.rs +++ b/tests/ui/pattern/tuple-enum-match-15129.rs @@ -1,24 +1,25 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15129 + //@ run-pass pub enum T { T1(()), - T2(()) + T2(()), } pub enum V { V1(isize), - V2(bool) + V2(bool), } fn foo(x: (T, V)) -> String { match x { - (T::T1(()), V::V1(i)) => format!("T1(()), V1({})", i), - (T::T2(()), V::V2(b)) => format!("T2(()), V2({})", b), - _ => String::new() + (T::T1(()), V::V1(i)) => format!("T1(()), V1({})", i), + (T::T2(()), V::V2(b)) => format!("T2(()), V2({})", b), + _ => String::new(), } } - fn main() { assert_eq!(foo((T::T1(()), V::V1(99))), "T1(()), V1(99)".to_string()); assert_eq!(foo((T::T2(()), V::V2(true))), "T2(()), V2(true)".to_string()); diff --git a/tests/ui/pattern/unit-type-struct-pattern-mismatch.rs b/tests/ui/pattern/unit-type-struct-pattern-mismatch-16401.rs similarity index 83% rename from tests/ui/pattern/unit-type-struct-pattern-mismatch.rs rename to tests/ui/pattern/unit-type-struct-pattern-mismatch-16401.rs index 0985a6806d260..2eba33e177e62 100644 --- a/tests/ui/pattern/unit-type-struct-pattern-mismatch.rs +++ b/tests/ui/pattern/unit-type-struct-pattern-mismatch-16401.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/16401 + struct Slice { data: *const T, len: usize, diff --git a/tests/ui/issues/issue-16401.stderr b/tests/ui/pattern/unit-type-struct-pattern-mismatch-16401.stderr similarity index 87% rename from tests/ui/issues/issue-16401.stderr rename to tests/ui/pattern/unit-type-struct-pattern-mismatch-16401.stderr index 6af920ca43970..22c04e439c41a 100644 --- a/tests/ui/issues/issue-16401.stderr +++ b/tests/ui/pattern/unit-type-struct-pattern-mismatch-16401.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/issue-16401.rs:8:9 + --> $DIR/unit-type-struct-pattern-mismatch-16401.rs:10:9 | LL | match () { | -- this expression has type `()` diff --git a/tests/ui/statics/conditional-static-declaration.rs b/tests/ui/statics/conditional-static-declaration-16010.rs similarity index 65% rename from tests/ui/statics/conditional-static-declaration.rs rename to tests/ui/statics/conditional-static-declaration-16010.rs index 4ab74f0905976..0bc5b0ee86f7e 100644 --- a/tests/ui/statics/conditional-static-declaration.rs +++ b/tests/ui/statics/conditional-static-declaration-16010.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/16010 + //@ run-pass #![allow(dead_code)] diff --git a/tests/ui/traits/fn-type-trait-impl-15444.rs b/tests/ui/traits/fn-type-trait-impl-15444.rs index 14708c7733c64..ab91e88b9cd0a 100644 --- a/tests/ui/traits/fn-type-trait-impl-15444.rs +++ b/tests/ui/traits/fn-type-trait-impl-15444.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15444 + //@ run-pass trait MyTrait { diff --git a/tests/ui/traits/index-trait-multiple-impls.rs b/tests/ui/traits/index-trait-multiple-impls-15734.rs similarity index 94% rename from tests/ui/traits/index-trait-multiple-impls.rs rename to tests/ui/traits/index-trait-multiple-impls-15734.rs index 26fb70616640f..a2d5d7c87fc47 100644 --- a/tests/ui/traits/index-trait-multiple-impls.rs +++ b/tests/ui/traits/index-trait-multiple-impls-15734.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/15734 + //@ run-pass //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) diff --git a/tests/ui/traits/lifetime-mismatch-trait-impl.rs b/tests/ui/traits/lifetime-mismatch-trait-impl-16048.rs similarity index 90% rename from tests/ui/traits/lifetime-mismatch-trait-impl.rs rename to tests/ui/traits/lifetime-mismatch-trait-impl-16048.rs index eaf6acff26bf3..9c36b231403fb 100644 --- a/tests/ui/traits/lifetime-mismatch-trait-impl.rs +++ b/tests/ui/traits/lifetime-mismatch-trait-impl-16048.rs @@ -1,3 +1,5 @@ +//! Regression test for https://github.com/rust-lang/rust/issues/16048 + trait NoLifetime { fn get<'p, T : Test<'p>>(&self) -> T; //~^ NOTE lifetimes in impl do not match this method in trait diff --git a/tests/ui/issues/issue-16048.stderr b/tests/ui/traits/lifetime-mismatch-trait-impl-16048.stderr similarity index 89% rename from tests/ui/issues/issue-16048.stderr rename to tests/ui/traits/lifetime-mismatch-trait-impl-16048.stderr index f97f13152bc83..08b69184b7ffc 100644 --- a/tests/ui/issues/issue-16048.stderr +++ b/tests/ui/traits/lifetime-mismatch-trait-impl-16048.stderr @@ -1,5 +1,5 @@ error[E0195]: lifetime parameters or bounds on method `get` do not match the trait declaration - --> $DIR/issue-16048.rs:21:11 + --> $DIR/lifetime-mismatch-trait-impl-16048.rs:23:11 | LL | fn get<'p, T : Test<'p>>(&self) -> T; | ------------------ lifetimes in impl do not match this method in trait @@ -8,7 +8,7 @@ LL | fn get<'p, T: Test<'a> + From>>(&self) -> T { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetimes do not match method in trait error[E0605]: non-primitive cast: `Foo<'a>` as `T` - --> $DIR/issue-16048.rs:24:16 + --> $DIR/lifetime-mismatch-trait-impl-16048.rs:26:16 | LL | return *self as T; | ^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object From ca1e464ac3c7f607336d45517395e4396d90b3bb Mon Sep 17 00:00:00 2001 From: xizheyin Date: Sat, 9 Aug 2025 19:58:58 +0800 Subject: [PATCH 21/28] Change days-threshold to 28 in [behind-upstream] Signed-off-by: xizheyin --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index e8c15bb9bfdbe..2f0153c2bb0c0 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1572,7 +1572,7 @@ changelog-branch = "master" [note] [behind-upstream] -days-threshold = 14 +days-threshold = 28 # Canonicalize issue numbers to avoid closing the wrong issue # when commits are included in subtrees, as well as warning links in commits. From 71f6e537faf861b30a4d863dc56c4ed6a1d4cf4b Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Sat, 9 Aug 2025 13:00:15 +0800 Subject: [PATCH 22/28] some `derive_more` refactors some clauses can be merged together without requiring an attribute for each trait derived. also manually impl `Eq` because the `derive_where` generated code is too much for my comfort --- .../src/solve/inspect/build.rs | 16 ++++-- compiler/rustc_type_ir/src/binder.rs | 21 +++----- compiler/rustc_type_ir/src/canonical.rs | 24 ++++----- compiler/rustc_type_ir/src/const_kind.rs | 8 ++- compiler/rustc_type_ir/src/error.rs | 4 +- compiler/rustc_type_ir/src/generic_arg.rs | 8 ++- compiler/rustc_type_ir/src/infer_ctxt.rs | 4 +- compiler/rustc_type_ir/src/opaque_ty.rs | 4 +- compiler/rustc_type_ir/src/pattern.rs | 4 +- compiler/rustc_type_ir/src/predicate.rs | 52 +++++++++++++------ compiler/rustc_type_ir/src/predicate_kind.rs | 8 ++- compiler/rustc_type_ir/src/region_kind.rs | 4 +- compiler/rustc_type_ir/src/relate.rs | 4 +- compiler/rustc_type_ir/src/solve/inspect.rs | 31 ++++++----- compiler/rustc_type_ir/src/solve/mod.rs | 37 +++++++------ compiler/rustc_type_ir/src/ty_kind.rs | 32 +++++++++--- compiler/rustc_type_ir/src/ty_kind/closure.rs | 19 +++++-- 17 files changed, 180 insertions(+), 100 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index c8521624ebbf9..fc56b006d9429 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -68,7 +68,7 @@ impl From> for DebugSolver { } } -#[derive_where(PartialEq, Eq, Debug; I: Interner)] +#[derive_where(PartialEq, Debug; I: Interner)] struct WipGoalEvaluation { pub uncanonicalized_goal: Goal, pub orig_values: Vec, @@ -78,6 +78,8 @@ struct WipGoalEvaluation { pub result: Option>, } +impl Eq for WipGoalEvaluation {} + impl WipGoalEvaluation { fn finalize(self) -> inspect::GoalEvaluation { inspect::GoalEvaluation { @@ -98,7 +100,7 @@ impl WipGoalEvaluation { /// This only exists during proof tree building and does not have /// a corresponding struct in `inspect`. We need this to track a /// bunch of metadata about the current evaluation. -#[derive_where(PartialEq, Eq, Debug; I: Interner)] +#[derive_where(PartialEq, Debug; I: Interner)] struct WipCanonicalGoalEvaluationStep { /// Unlike `EvalCtxt::var_values`, we append a new /// generic arg here whenever we create a new inference @@ -111,6 +113,8 @@ struct WipCanonicalGoalEvaluationStep { evaluation: WipProbe, } +impl Eq for WipCanonicalGoalEvaluationStep {} + impl WipCanonicalGoalEvaluationStep { fn current_evaluation_scope(&mut self) -> &mut WipProbe { let mut current = &mut self.evaluation; @@ -132,7 +136,7 @@ impl WipCanonicalGoalEvaluationStep { } } -#[derive_where(PartialEq, Eq, Debug; I: Interner)] +#[derive_where(PartialEq, Debug; I: Interner)] struct WipProbe { initial_num_var_values: usize, steps: Vec>, @@ -140,6 +144,8 @@ struct WipProbe { final_state: Option>, } +impl Eq for WipProbe {} + impl WipProbe { fn finalize(self) -> inspect::Probe { inspect::Probe { @@ -150,7 +156,7 @@ impl WipProbe { } } -#[derive_where(PartialEq, Eq, Debug; I: Interner)] +#[derive_where(PartialEq, Debug; I: Interner)] enum WipProbeStep { AddGoal(GoalSource, inspect::CanonicalState>), NestedProbe(WipProbe), @@ -158,6 +164,8 @@ enum WipProbeStep { RecordImplArgs { impl_args: inspect::CanonicalState }, } +impl Eq for WipProbeStep {} + impl WipProbeStep { fn finalize(self) -> inspect::ProbeStep { match self { diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 10d48526fd2a6..6591d3148cb14 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -1,5 +1,3 @@ -use std::fmt::Debug; -use std::hash::Hash; use std::marker::PhantomData; use std::ops::{ControlFlow, Deref}; @@ -23,18 +21,16 @@ use crate::{self as ty, Interner}; /// for more details. /// /// `Decodable` and `Encodable` are implemented for `Binder` using the `impl_binder_encode_decode!` macro. -#[derive_where(Clone; I: Interner, T: Clone)] +#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, T)] #[derive_where(Copy; I: Interner, T: Copy)] -#[derive_where(Hash; I: Interner, T: Hash)] -#[derive_where(PartialEq; I: Interner, T: PartialEq)] -#[derive_where(Eq; I: Interner, T: Eq)] -#[derive_where(Debug; I: Interner, T: Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct Binder { value: T, bound_vars: I::BoundVarKinds, } +impl Eq for Binder {} + // FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't // understand how to turn `T` to `T::Lifted` in the output `type Lifted`. impl Lift for Binder @@ -356,14 +352,9 @@ impl TypeVisitor for ValidateBoundVars { /// `instantiate`. /// /// See for more details. -#[derive_where(Clone; I: Interner, T: Clone)] -#[derive_where(Copy; I: Interner, T: Copy)] -#[derive_where(PartialEq; I: Interner, T: PartialEq)] -#[derive_where(Eq; I: Interner, T: Eq)] -#[derive_where(Ord; I: Interner, T: Ord)] +#[derive_where(Clone, PartialEq, Ord, Hash, Debug; I: Interner, T)] #[derive_where(PartialOrd; I: Interner, T: Ord)] -#[derive_where(Hash; I: Interner, T: Hash)] -#[derive_where(Debug; I: Interner, T: Debug)] +#[derive_where(Copy; I: Interner, T: Copy)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -374,6 +365,8 @@ pub struct EarlyBinder { _tcx: PhantomData I>, } +impl Eq for EarlyBinder {} + /// For early binders, you should first call `instantiate` before using any visitors. #[cfg(feature = "nightly")] impl !TypeFoldable for ty::EarlyBinder {} diff --git a/compiler/rustc_type_ir/src/canonical.rs b/compiler/rustc_type_ir/src/canonical.rs index 0cb8d8902c6ff..de2a9186e7c94 100644 --- a/compiler/rustc_type_ir/src/canonical.rs +++ b/compiler/rustc_type_ir/src/canonical.rs @@ -11,11 +11,7 @@ use crate::data_structures::HashMap; use crate::inherent::*; use crate::{self as ty, Interner, TypingMode, UniverseIndex}; -#[derive_where(Clone; I: Interner, V: Clone)] -#[derive_where(Hash; I: Interner, V: Hash)] -#[derive_where(PartialEq; I: Interner, V: PartialEq)] -#[derive_where(Eq; I: Interner, V: Eq)] -#[derive_where(Debug; I: Interner, V: fmt::Debug)] +#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, V)] #[derive_where(Copy; I: Interner, V: Copy)] #[cfg_attr( feature = "nightly", @@ -26,14 +22,12 @@ pub struct CanonicalQueryInput { pub typing_mode: TypingMode, } +impl Eq for CanonicalQueryInput {} + /// A "canonicalized" type `V` is one where all free inference /// variables have been rewritten to "canonical vars". These are /// numbered starting from 0 in order of first appearance. -#[derive_where(Clone; I: Interner, V: Clone)] -#[derive_where(Hash; I: Interner, V: Hash)] -#[derive_where(PartialEq; I: Interner, V: PartialEq)] -#[derive_where(Eq; I: Interner, V: Eq)] -#[derive_where(Debug; I: Interner, V: fmt::Debug)] +#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, V)] #[derive_where(Copy; I: Interner, V: Copy)] #[cfg_attr( feature = "nightly", @@ -45,6 +39,8 @@ pub struct Canonical { pub variables: I::CanonicalVarKinds, } +impl Eq for Canonical {} + impl Canonical { /// Allows you to map the `value` of a canonical while keeping the /// same set of bound variables. @@ -89,7 +85,7 @@ impl fmt::Display for Canonical { /// canonical value. This is sufficient information for code to create /// a copy of the canonical value in some other inference context, /// with fresh inference variables replacing the canonical values. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[cfg_attr( feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) @@ -116,6 +112,8 @@ pub enum CanonicalVarKind { PlaceholderConst(I::PlaceholderConst), } +impl Eq for CanonicalVarKind {} + impl CanonicalVarKind { pub fn universe(self) -> UniverseIndex { match self { @@ -223,7 +221,7 @@ pub enum CanonicalTyVarKind { /// vectors with the original values that were replaced by canonical /// variables. You will need to supply it later to instantiate the /// canonicalized query response. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -233,6 +231,8 @@ pub struct CanonicalVarValues { pub var_values: I::GenericArgs, } +impl Eq for CanonicalVarValues {} + impl CanonicalVarValues { pub fn is_identity(&self) -> bool { self.var_values.iter().enumerate().all(|(bv, arg)| match arg.kind() { diff --git a/compiler/rustc_type_ir/src/const_kind.rs b/compiler/rustc_type_ir/src/const_kind.rs index 70a8509b51339..6de41b47bde08 100644 --- a/compiler/rustc_type_ir/src/const_kind.rs +++ b/compiler/rustc_type_ir/src/const_kind.rs @@ -10,7 +10,7 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use crate::{self as ty, DebruijnIndex, Interner}; /// Represents a constant in Rust. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -45,6 +45,8 @@ pub enum ConstKind { Expr(I::ExprConst), } +impl Eq for ConstKind {} + impl fmt::Debug for ConstKind { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use ConstKind::*; @@ -63,7 +65,7 @@ impl fmt::Debug for ConstKind { } /// An unevaluated (potentially generic) constant used in the type-system. -#[derive_where(Clone, Copy, Debug, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Debug, Hash, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -74,6 +76,8 @@ pub struct UnevaluatedConst { pub args: I::GenericArgs, } +impl Eq for UnevaluatedConst {} + impl UnevaluatedConst { #[inline] pub fn new(def: I::DefId, args: I::GenericArgs) -> UnevaluatedConst { diff --git a/compiler/rustc_type_ir/src/error.rs b/compiler/rustc_type_ir/src/error.rs index 68b11489ae7c1..e8840bcfaca34 100644 --- a/compiler/rustc_type_ir/src/error.rs +++ b/compiler/rustc_type_ir/src/error.rs @@ -18,7 +18,7 @@ impl ExpectedFound { } // Data structures used in type unification -#[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic)] #[cfg_attr(feature = "nightly", rustc_pass_by_value)] pub enum TypeError { @@ -58,6 +58,8 @@ pub enum TypeError { TargetFeatureCast(I::DefId), } +impl Eq for TypeError {} + impl TypeError { pub fn involves_regions(self) -> bool { match self { diff --git a/compiler/rustc_type_ir/src/generic_arg.rs b/compiler/rustc_type_ir/src/generic_arg.rs index c18cade0e39bc..d6e33f724d0b2 100644 --- a/compiler/rustc_type_ir/src/generic_arg.rs +++ b/compiler/rustc_type_ir/src/generic_arg.rs @@ -4,7 +4,7 @@ use rustc_macros::{Decodable_NoContext, Encodable_NoContext, HashStable_NoContex use crate::Interner; -#[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)] #[cfg_attr( feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) @@ -15,7 +15,9 @@ pub enum GenericArgKind { Const(I::Const), } -#[derive_where(Clone, Copy, PartialEq, Eq, Debug; I: Interner)] +impl Eq for GenericArgKind {} + +#[derive_where(Clone, Copy, PartialEq, Debug; I: Interner)] #[cfg_attr( feature = "nightly", derive(Decodable_NoContext, Encodable_NoContext, HashStable_NoContext) @@ -24,3 +26,5 @@ pub enum TermKind { Ty(I::Ty), Const(I::Const), } + +impl Eq for TermKind {} diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index e6462a97f8ab6..e39b99e992b03 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -18,7 +18,7 @@ use crate::{self as ty, Interner}; /// /// If neither of these functions are available, feel free to reach out to /// t-types for help. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -90,6 +90,8 @@ pub enum TypingMode { PostAnalysis, } +impl Eq for TypingMode {} + impl TypingMode { /// Analysis outside of a body does not define any opaque types. pub fn non_body_analysis() -> TypingMode { diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs index 416d355fd03bd..b6fb9f28930f2 100644 --- a/compiler/rustc_type_ir/src/opaque_ty.rs +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -6,7 +6,7 @@ use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::inherent::*; use crate::{self as ty, Interner}; -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", @@ -17,6 +17,8 @@ pub struct OpaqueTypeKey { pub args: I::GenericArgs, } +impl Eq for OpaqueTypeKey {} + impl OpaqueTypeKey { pub fn iter_captured_args(self, cx: I) -> impl Iterator { let variances = cx.variances_of(self.def_id.into()); diff --git a/compiler/rustc_type_ir/src/pattern.rs b/compiler/rustc_type_ir/src/pattern.rs index 7e56565917c67..d757ac625f2db 100644 --- a/compiler/rustc_type_ir/src/pattern.rs +++ b/compiler/rustc_type_ir/src/pattern.rs @@ -5,7 +5,7 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use crate::Interner; -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -15,3 +15,5 @@ pub enum PatternKind { Range { start: I::Const, end: I::Const }, Or(I::PatList), } + +impl Eq for PatternKind {} diff --git a/compiler/rustc_type_ir/src/predicate.rs b/compiler/rustc_type_ir/src/predicate.rs index 9e4447ccd9939..1f67a03d7eaec 100644 --- a/compiler/rustc_type_ir/src/predicate.rs +++ b/compiler/rustc_type_ir/src/predicate.rs @@ -15,12 +15,8 @@ use crate::visit::TypeVisitableExt as _; use crate::{self as ty, Interner}; /// `A: 'region` -#[derive_where(Clone; I: Interner, A: Clone)] +#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, A)] #[derive_where(Copy; I: Interner, A: Copy)] -#[derive_where(Hash; I: Interner, A: Hash)] -#[derive_where(PartialEq; I: Interner, A: PartialEq)] -#[derive_where(Eq; I: Interner, A: Eq)] -#[derive_where(Debug; I: Interner, A: fmt::Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", @@ -28,6 +24,8 @@ use crate::{self as ty, Interner}; )] pub struct OutlivesPredicate(pub A, pub I::Region); +impl Eq for OutlivesPredicate {} + // FIXME: We manually derive `Lift` because the `derive(Lift_Generic)` doesn't // understand how to turn `A` to `A::Lifted` in the output `type Lifted`. impl Lift for OutlivesPredicate @@ -53,7 +51,7 @@ where /// /// Trait references also appear in object types like `Foo`, but in /// that case the `Self` parameter is absent from the generic parameters. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -67,6 +65,8 @@ pub struct TraitRef { _use_trait_ref_new_instead: (), } +impl Eq for TraitRef {} + impl TraitRef { pub fn new_from_args(interner: I, trait_def_id: I::DefId, args: I::GenericArgs) -> Self { interner.debug_assert_args_compatible(trait_def_id, args); @@ -128,7 +128,7 @@ impl ty::Binder> { } } -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -145,6 +145,8 @@ pub struct TraitPredicate { pub polarity: PredicatePolarity, } +impl Eq for TraitPredicate {} + impl TraitPredicate { pub fn with_replaced_self_ty(self, interner: I, self_ty: I::Ty) -> Self { Self { @@ -271,7 +273,7 @@ impl fmt::Display for PredicatePolarity { } } -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -286,6 +288,8 @@ pub enum ExistentialPredicate { AutoTrait(I::DefId), } +impl Eq for ExistentialPredicate {} + impl ty::Binder> { /// Given an existential predicate like `?Self: PartialEq` (e.g., derived from `dyn PartialEq`), /// and a concrete type `self_ty`, returns a full predicate where the existentially quantified variable `?Self` @@ -319,7 +323,7 @@ impl ty::Binder> { /// ``` /// The generic parameters don't include the erased `Self`, only trait /// type and lifetime parameters (`[X, Y]` and `['a, 'b]` above). -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -333,6 +337,8 @@ pub struct ExistentialTraitRef { _use_existential_trait_ref_new_instead: (), } +impl Eq for ExistentialTraitRef {} + impl ExistentialTraitRef { pub fn new_from_args(interner: I, trait_def_id: I::DefId, args: I::GenericArgs) -> Self { interner.debug_assert_existential_args_compatible(trait_def_id, args); @@ -386,7 +392,7 @@ impl ty::Binder> { } /// A `ProjectionPredicate` for an `ExistentialTraitRef`. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -402,6 +408,8 @@ pub struct ExistentialProjection { use_existential_projection_new_instead: (), } +impl Eq for ExistentialProjection {} + impl ExistentialProjection { pub fn new_from_args( interner: I, @@ -542,7 +550,7 @@ impl From for AliasTermKind { /// * For a projection, this would be `>::N<...>`. /// * For an inherent projection, this would be `Ty::N<...>`. /// * For an opaque type, there is no explicit syntax. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -578,6 +586,8 @@ pub struct AliasTerm { _use_alias_term_new_instead: (), } +impl Eq for AliasTerm {} + impl AliasTerm { pub fn new_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> AliasTerm { interner.debug_assert_args_compatible(def_id, args); @@ -752,7 +762,7 @@ impl From> for AliasTerm { /// equality between arbitrary types. Processing an instance of /// Form #2 eventually yields one of these `ProjectionPredicate` /// instances to normalize the LHS. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -763,6 +773,8 @@ pub struct ProjectionPredicate { pub term: I::Term, } +impl Eq for ProjectionPredicate {} + impl ProjectionPredicate { pub fn self_ty(self) -> I::Ty { self.projection_term.self_ty() @@ -813,7 +825,7 @@ impl fmt::Debug for ProjectionPredicate { /// Used by the new solver to normalize an alias. This always expects the `term` to /// be an unconstrained inference variable which is used as the output. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -824,6 +836,8 @@ pub struct NormalizesTo { pub term: I::Term, } +impl Eq for NormalizesTo {} + impl NormalizesTo { pub fn self_ty(self) -> I::Ty { self.alias.self_ty() @@ -848,7 +862,7 @@ impl fmt::Debug for NormalizesTo { } } -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -859,6 +873,8 @@ pub struct HostEffectPredicate { pub constness: BoundConstness, } +impl Eq for HostEffectPredicate {} + impl HostEffectPredicate { pub fn self_ty(self) -> I::Ty { self.trait_ref.self_ty() @@ -892,7 +908,7 @@ impl ty::Binder> { /// Encodes that `a` must be a subtype of `b`. The `a_is_expected` flag indicates /// whether the `a` type is the type that we should label as "expected" when /// presenting user diagnostics. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -904,8 +920,10 @@ pub struct SubtypePredicate { pub b: I::Ty, } +impl Eq for SubtypePredicate {} + /// Encodes that we have to coerce *from* the `a` type to the `b` type. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -916,6 +934,8 @@ pub struct CoercePredicate { pub b: I::Ty, } +impl Eq for CoercePredicate {} + #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] #[cfg_attr( feature = "nightly", diff --git a/compiler/rustc_type_ir/src/predicate_kind.rs b/compiler/rustc_type_ir/src/predicate_kind.rs index 8bc15ec4ff557..ff92a0070cc5b 100644 --- a/compiler/rustc_type_ir/src/predicate_kind.rs +++ b/compiler/rustc_type_ir/src/predicate_kind.rs @@ -9,7 +9,7 @@ use crate::{self as ty, Interner}; /// A clause is something that can appear in where bounds or be inferred /// by implied bounds. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", @@ -55,7 +55,9 @@ pub enum ClauseKind { ), } -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +impl Eq for ClauseKind {} + +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", @@ -109,6 +111,8 @@ pub enum PredicateKind { AliasRelate(I::Term, I::Term, AliasRelationDirection), } +impl Eq for PredicateKind {} + #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] #[cfg_attr( feature = "nightly", diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 1b5d04e6025fa..cca81dcb4a0b5 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -125,7 +125,7 @@ rustc_index::newtype_index! { /// [1]: https://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/ /// [2]: https://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/ /// [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/hrtb.html -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[cfg_attr(feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext))] pub enum RegionKind { /// A region parameter; for example `'a` in `impl<'a> Trait for &'a ()`. @@ -177,6 +177,8 @@ pub enum RegionKind { ReError(I::ErrorGuaranteed), } +impl Eq for RegionKind {} + impl fmt::Debug for RegionKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { diff --git a/compiler/rustc_type_ir/src/relate.rs b/compiler/rustc_type_ir/src/relate.rs index 3a00fe89360c6..223230fde9e72 100644 --- a/compiler/rustc_type_ir/src/relate.rs +++ b/compiler/rustc_type_ir/src/relate.rs @@ -33,7 +33,7 @@ pub enum StructurallyRelateAliases { /// a miscompilation or unsoundness. /// /// When in doubt, use `VarianceDiagInfo::default()` -#[derive_where(Clone, Copy, PartialEq, Eq, Debug, Default; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Debug, Default; I: Interner)] pub enum VarianceDiagInfo { /// No additional information - this is the default. /// We will not add any additional information to error messages. @@ -51,6 +51,8 @@ pub enum VarianceDiagInfo { }, } +impl Eq for VarianceDiagInfo {} + impl VarianceDiagInfo { /// Mirrors `Variance::xform` - used to 'combine' the existing /// and new `VarianceDiagInfo`s when our variance changes. diff --git a/compiler/rustc_type_ir/src/solve/inspect.rs b/compiler/rustc_type_ir/src/solve/inspect.rs index 089695d0475e8..afb4043648f65 100644 --- a/compiler/rustc_type_ir/src/solve/inspect.rs +++ b/compiler/rustc_type_ir/src/solve/inspect.rs @@ -17,9 +17,6 @@ //! //! [canonicalized]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html -use std::fmt::Debug; -use std::hash::Hash; - use derive_where::derive_where; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; @@ -32,25 +29,23 @@ use crate::{Canonical, CanonicalVarValues, Interner}; /// This is only ever used as [CanonicalState]. Any type information in proof /// trees used mechanically has to be canonicalized as we otherwise leak /// inference variables from a nested `InferCtxt`. -#[derive_where(Clone; I: Interner, T: Clone)] +#[derive_where(Clone, PartialEq, Hash, Debug; I: Interner, T)] #[derive_where(Copy; I: Interner, T: Copy)] -#[derive_where(PartialEq; I: Interner, T: PartialEq)] -#[derive_where(Eq; I: Interner, T: Eq)] -#[derive_where(Hash; I: Interner, T: Hash)] -#[derive_where(Debug; I: Interner, T: Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct State { pub var_values: CanonicalVarValues, pub data: T, } +impl Eq for State {} + pub type CanonicalState = Canonical>; /// When evaluating a goal we also store the original values /// for the `CanonicalVarValues` of the canonicalized goal. /// We use this to map any [CanonicalState] from the local `InferCtxt` /// of the solver query to the `InferCtxt` of the caller. -#[derive_where(PartialEq, Eq, Hash; I: Interner)] +#[derive_where(PartialEq, Hash; I: Interner)] pub struct GoalEvaluation { pub uncanonicalized_goal: Goal, pub orig_values: Vec, @@ -58,7 +53,9 @@ pub struct GoalEvaluation { pub result: QueryResult, } -#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] +impl Eq for GoalEvaluation {} + +#[derive_where(PartialEq, Hash, Debug; I: Interner)] pub enum GoalEvaluationKind { Overflow, Evaluation { @@ -67,10 +64,12 @@ pub enum GoalEvaluationKind { }, } +impl Eq for GoalEvaluationKind {} + /// A self-contained computation during trait solving. This either /// corresponds to a `EvalCtxt::probe(_X)` call or the root evaluation /// of a goal. -#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] +#[derive_where(PartialEq, Hash, Debug; I: Interner)] pub struct Probe { /// What happened inside of this probe in chronological order. pub steps: Vec>, @@ -78,7 +77,9 @@ pub struct Probe { pub final_state: CanonicalState, } -#[derive_where(PartialEq, Eq, Hash, Debug; I: Interner)] +impl Eq for Probe {} + +#[derive_where(PartialEq, Hash, Debug; I: Interner)] pub enum ProbeStep { /// We added a goal to the `EvalCtxt` which will get proven /// the next time `EvalCtxt::try_evaluate_added_goals` is called. @@ -97,10 +98,12 @@ pub enum ProbeStep { MakeCanonicalResponse { shallow_certainty: Certainty }, } +impl Eq for ProbeStep {} + /// What kind of probe we're in. In case the probe represents a candidate, or /// the final result of the current goal - via [ProbeKind::Root] - we also /// store the [QueryResult]. -#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub enum ProbeKind { /// The root inference context while proving a goal. @@ -125,3 +128,5 @@ pub enum ProbeKind { /// Checking that a rigid alias is well-formed. RigidAlias { result: QueryResult }, } + +impl Eq for ProbeKind {} diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index a6571ef261a16..1497236039f3f 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -1,6 +1,5 @@ pub mod inspect; -use std::fmt; use std::hash::Hash; use derive_where::derive_where; @@ -32,12 +31,8 @@ pub struct NoSolution; /// /// Most of the time the `param_env` contains the `where`-bounds of the function /// we're currently typechecking while the `predicate` is some trait bound. -#[derive_where(Clone; I: Interner, P: Clone)] +#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, P)] #[derive_where(Copy; I: Interner, P: Copy)] -#[derive_where(Hash; I: Interner, P: Hash)] -#[derive_where(PartialEq; I: Interner, P: PartialEq)] -#[derive_where(Eq; I: Interner, P: Eq)] -#[derive_where(Debug; I: Interner, P: fmt::Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -48,6 +43,8 @@ pub struct Goal { pub predicate: P, } +impl Eq for Goal {} + impl Goal { pub fn new(cx: I, param_env: I::ParamEnv, predicate: impl Upcast) -> Goal { Goal { param_env, predicate: predicate.upcast(cx) } @@ -98,12 +95,8 @@ pub enum GoalSource { NormalizeGoal(PathKind), } -#[derive_where(Clone; I: Interner, Goal: Clone)] +#[derive_where(Clone, Hash, PartialEq, Debug; I: Interner, Goal)] #[derive_where(Copy; I: Interner, Goal: Copy)] -#[derive_where(Hash; I: Interner, Goal: Hash)] -#[derive_where(PartialEq; I: Interner, Goal: PartialEq)] -#[derive_where(Eq; I: Interner, Goal: Eq)] -#[derive_where(Debug; I: Interner, Goal: fmt::Debug)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", @@ -114,8 +107,10 @@ pub struct QueryInput { pub predefined_opaques_in_body: I::PredefinedOpaques, } +impl Eq for QueryInput {} + /// Opaques that are defined in the inference context before a query is called. -#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)] +#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr( feature = "nightly", @@ -125,8 +120,10 @@ pub struct PredefinedOpaquesData { pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, } +impl Eq for PredefinedOpaquesData {} + /// Possible ways the given goal can be proven. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] pub enum CandidateSource { /// A user written impl. /// @@ -189,6 +186,8 @@ pub enum CandidateSource { CoherenceUnknowable, } +impl Eq for CandidateSource {} + #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] pub enum ParamEnvSource { /// Preferred eagerly. @@ -217,7 +216,7 @@ pub enum BuiltinImplSource { TraitUpcasting(usize), } -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct Response { @@ -227,8 +226,10 @@ pub struct Response { pub external_constraints: I::ExternalConstraints, } +impl Eq for Response {} + /// Additional constraints returned on success. -#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)] +#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct ExternalConstraintsData { @@ -237,6 +238,8 @@ pub struct ExternalConstraintsData { pub normalization_nested_goals: NestedNormalizationGoals, } +impl Eq for ExternalConstraintsData {} + impl ExternalConstraintsData { pub fn is_empty(&self) -> bool { self.region_constraints.is_empty() @@ -245,11 +248,13 @@ impl ExternalConstraintsData { } } -#[derive_where(Clone, Hash, PartialEq, Eq, Debug, Default; I: Interner)] +#[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct NestedNormalizationGoals(pub Vec<(GoalSource, Goal)>); +impl Eq for NestedNormalizationGoals {} + impl NestedNormalizationGoals { pub fn empty() -> Self { NestedNormalizationGoals(vec![]) diff --git a/compiler/rustc_type_ir/src/ty_kind.rs b/compiler/rustc_type_ir/src/ty_kind.rs index 73aeab5092df0..bde506ffd9385 100644 --- a/compiler/rustc_type_ir/src/ty_kind.rs +++ b/compiler/rustc_type_ir/src/ty_kind.rs @@ -69,7 +69,7 @@ impl AliasTyKind { /// Types written by the user start out as `hir::TyKind` and get /// converted to this representation using `::lower_ty`. #[cfg_attr(feature = "nightly", rustc_diagnostic_item = "IrTyKind")] -#[derive_where(Clone, Copy, Hash, PartialEq, Eq; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq; I: Interner)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -268,6 +268,8 @@ pub enum TyKind { Error(I::ErrorGuaranteed), } +impl Eq for TyKind {} + impl TyKind { pub fn fn_sig(self, interner: I) -> ty::Binder> { match self { @@ -404,7 +406,7 @@ impl fmt::Debug for TyKind { /// * For a projection, this would be `>::N<...>`. /// * For an inherent projection, this would be `Ty::N<...>`. /// * For an opaque type, there is no explicit syntax. -#[derive_where(Clone, Copy, Hash, PartialEq, Eq, Debug; I: Interner)] +#[derive_where(Clone, Copy, Hash, PartialEq, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] #[cfg_attr( feature = "nightly", @@ -440,6 +442,8 @@ pub struct AliasTy { pub(crate) _use_alias_ty_new_instead: (), } +impl Eq for AliasTy {} + impl AliasTy { pub fn new_from_args(interner: I, def_id: I::DefId, args: I::GenericArgs) -> AliasTy { interner.debug_assert_args_compatible(def_id, args); @@ -720,7 +724,7 @@ impl fmt::Debug for InferTy { } } -#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -731,7 +735,9 @@ pub struct TypeAndMut { pub mutbl: Mutability, } -#[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)] +impl Eq for TypeAndMut {} + +#[derive_where(Clone, Copy, PartialEq, Hash; I: Interner)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -748,6 +754,8 @@ pub struct FnSig { pub abi: I::Abi, } +impl Eq for FnSig {} + impl FnSig { pub fn inputs(self) -> I::FnInputTys { self.inputs_and_output.inputs() @@ -845,11 +853,13 @@ impl fmt::Debug for FnSig { // FIXME: this is a distinct type because we need to define `Encode`/`Decode` // impls in this crate for `Binder`. -#[derive_where(Clone, Copy, PartialEq, Eq, Hash; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Hash; I: Interner)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct UnsafeBinderInner(ty::Binder); +impl Eq for UnsafeBinderInner {} + impl From> for UnsafeBinderInner { fn from(value: ty::Binder) -> Self { UnsafeBinderInner(value) @@ -906,7 +916,7 @@ where } // This is just a `FnSig` without the `FnHeader` fields. -#[derive_where(Clone, Copy, Debug, PartialEq, Eq, Hash; I: Interner)] +#[derive_where(Clone, Copy, Debug, PartialEq, Hash; I: Interner)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -916,6 +926,8 @@ pub struct FnSigTys { pub inputs_and_output: I::Tys, } +impl Eq for FnSigTys {} + impl FnSigTys { pub fn inputs(self) -> I::FnInputTys { self.inputs_and_output.inputs() @@ -958,7 +970,7 @@ impl ty::Binder> { } } -#[derive_where(Clone, Copy, Debug, PartialEq, Eq, Hash; I: Interner)] +#[derive_where(Clone, Copy, Debug, PartialEq, Hash; I: Interner)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -970,7 +982,9 @@ pub struct FnHeader { pub abi: I::Abi, } -#[derive_where(Clone, Copy, Debug, PartialEq, Eq, Hash; I: Interner)] +impl Eq for FnHeader {} + +#[derive_where(Clone, Copy, Debug, PartialEq, Hash; I: Interner)] #[cfg_attr( feature = "nightly", derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) @@ -980,3 +994,5 @@ pub struct CoroutineWitnessTypes { pub types: I::Tys, pub assumptions: I::RegionAssumptions, } + +impl Eq for CoroutineWitnessTypes {} diff --git a/compiler/rustc_type_ir/src/ty_kind/closure.rs b/compiler/rustc_type_ir/src/ty_kind/closure.rs index c32f8339d0b75..a2e16d917a9e9 100644 --- a/compiler/rustc_type_ir/src/ty_kind/closure.rs +++ b/compiler/rustc_type_ir/src/ty_kind/closure.rs @@ -101,7 +101,7 @@ use crate::{self as ty, Interner}; /// `yield` inside the coroutine. /// * `GR`: The "return type", which is the type of value returned upon /// completion of the coroutine. -#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct ClosureArgs { /// Lifetime and type parameters from the enclosing function, @@ -112,6 +112,8 @@ pub struct ClosureArgs { pub args: I::GenericArgs, } +impl Eq for ClosureArgs {} + /// Struct returned by `split()`. pub struct ClosureArgsParts { /// This is the args of the typeck root. @@ -203,12 +205,14 @@ impl ClosureArgs { } } -#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct CoroutineClosureArgs { pub args: I::GenericArgs, } +impl Eq for CoroutineClosureArgs {} + /// See docs for explanation of how each argument is used. /// /// See [`CoroutineClosureSignature`] for how these arguments are put together @@ -348,7 +352,7 @@ impl TypeVisitor for HasRegionsBoundAt { } } -#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct CoroutineClosureSignature { pub tupled_inputs_ty: I::Ty, @@ -371,6 +375,8 @@ pub struct CoroutineClosureSignature { pub abi: I::Abi, } +impl Eq for CoroutineClosureSignature {} + impl CoroutineClosureSignature { /// Construct a coroutine from the closure signature. Since a coroutine signature /// is agnostic to the type of generator that is returned (by-ref/by-move), @@ -541,7 +547,7 @@ impl TypeFolder for FoldEscapingRegions { } } -#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] pub struct GenSig { pub resume_ty: I::Ty, @@ -549,13 +555,16 @@ pub struct GenSig { pub return_ty: I::Ty, } +impl Eq for GenSig {} /// Similar to `ClosureArgs`; see the above documentation for more. -#[derive_where(Clone, Copy, PartialEq, Eq, Hash, Debug; I: Interner)] +#[derive_where(Clone, Copy, PartialEq, Hash, Debug; I: Interner)] #[derive(TypeVisitable_Generic, TypeFoldable_Generic, Lift_Generic)] pub struct CoroutineArgs { pub args: I::GenericArgs, } +impl Eq for CoroutineArgs {} + pub struct CoroutineArgsParts { /// This is the args of the typeck root. pub parent_args: I::GenericArgsSlice, From f4d3dd03945d2c61fc152a9c8ddc4a785c71d3d6 Mon Sep 17 00:00:00 2001 From: jyn Date: Sat, 9 Aug 2025 11:49:35 -0400 Subject: [PATCH 23/28] Apply suggestions from code review Co-authored-by: Florian Bartels <108917393+flba-eb@users.noreply.github.com> Co-authored-by: Mads Marquart --- .../src/compiler-environment-variables/QNX_TARGET.md | 2 +- .../src/compiler-environment-variables/SDKROOT.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/doc/unstable-book/src/compiler-environment-variables/QNX_TARGET.md b/src/doc/unstable-book/src/compiler-environment-variables/QNX_TARGET.md index cc98fc3b3b284..46511598e7058 100644 --- a/src/doc/unstable-book/src/compiler-environment-variables/QNX_TARGET.md +++ b/src/doc/unstable-book/src/compiler-environment-variables/QNX_TARGET.md @@ -8,4 +8,4 @@ You should [set this variable] by running `source qnxsdp-env.sh`. See [the QNX docs] for more background information. [set this variable]: https://www.qnx.com/developers/docs/qsc/com.qnx.doc.qsc.inst_larg_org/topic/build_server_developer_steps.html -[the QNX docs]: https://www.qnx.com/developers/docs/7.1/index.html#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html. +[the QNX docs]: https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.io_sock/topic/migrate_app.html. diff --git a/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md b/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md index b00c2f773ad6d..be9ed02f54d39 100644 --- a/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md +++ b/src/doc/unstable-book/src/compiler-environment-variables/SDKROOT.md @@ -1,6 +1,6 @@ # `SDKROOT` -This environment variable is used on MacOS targets. -It is passed through to the linker (either as `-isysroot` or `-syslibroot`) without changes. +This environment variable is used on Apple targets. +It is passed through to the linker (currently either as `-isysroot` or `-syslibroot`). Note that this variable is not always respected. When the SDKROOT is clearly wrong (e.g. when the platform of the SDK does not match the `--target` used by rustc), this is ignored and rustc does its own detection. From a59842e4d5ba8424996d25f95da67d912ffbb333 Mon Sep 17 00:00:00 2001 From: binarycat Date: Fri, 8 Aug 2025 14:26:01 -0500 Subject: [PATCH 24/28] improve "Documentation problem" issue template. rustdoc has its own issue template now, mention that. swap the order of the last two sentances so it reads more like a typical if/else chain (base case listed last). adjust some labels and descriptions --- .github/ISSUE_TEMPLATE/documentation.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/documentation.yaml b/.github/ISSUE_TEMPLATE/documentation.yaml index 712b32759ae01..4a79cd4ba97c8 100644 --- a/.github/ISSUE_TEMPLATE/documentation.yaml +++ b/.github/ISSUE_TEMPLATE/documentation.yaml @@ -1,5 +1,5 @@ name: Documentation problem -description: Create a report for a documentation problem. +description: Report an issue with documentation content. labels: ["A-docs"] body: - type: markdown @@ -19,20 +19,20 @@ body: - [The Rustonomicon](https://github.com/rust-lang/nomicon/issues) - [The Embedded Book](https://github.com/rust-embedded/book/issues) - All other documentation issues should be filed here. + Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the rustdoc issue template instead. - Or, if you find an issue related to rustdoc (e.g. doctest, rustdoc UI), please use the bug report or blank issue template instead. + All other documentation issues should be filed here. - type: textarea id: location attributes: - label: Location + label: Location (URL) validations: - required: true + required: true - type: textarea id: summary attributes: label: Summary validations: - required: true \ No newline at end of file + required: true From c0a3e4802a06dd644c59aa7eed4af4bf437d3853 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 9 Aug 2025 14:49:19 +0200 Subject: [PATCH 25/28] `{BTree,Hash}Map`: add "`Entry` API" section heading --- library/alloc/src/collections/btree/map.rs | 2 ++ library/std/src/collections/hash/map.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index acbbb6df9a5a5..c4e599222e501 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -135,6 +135,8 @@ pub(super) const MIN_LEN: usize = node::MIN_LEN_AFTER_SPLIT; /// ]); /// ``` /// +/// ## `Entry` API +/// /// `BTreeMap` implements an [`Entry API`], which allows for complex /// methods of getting, setting, updating and removing keys and their values: /// diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index edbdd0411457f..0c5d41bcee8be 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -135,6 +135,8 @@ use crate::ops::Index; /// ]); /// ``` /// +/// ## `Entry` API +/// /// `HashMap` implements an [`Entry` API](#method.entry), which allows /// for complex methods of getting, setting, updating and removing keys and /// their values: From 06e43655bc57359ece7143d5cd31afc3a0744a59 Mon Sep 17 00:00:00 2001 From: Ada Alakbarova Date: Sat, 9 Aug 2025 19:41:10 +0200 Subject: [PATCH 26/28] `HashMap`: also add "Usage with custom key types" heading --- library/std/src/collections/hash/map.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 0c5d41bcee8be..15a7a770d1a87 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -169,6 +169,8 @@ use crate::ops::Index; /// player_stats.entry("mana").and_modify(|mana| *mana += 200).or_insert(100); /// ``` /// +/// ## Usage with custom key types +/// /// The easiest way to use `HashMap` with a custom key type is to derive [`Eq`] and [`Hash`]. /// We must also derive [`PartialEq`]. /// From feed41c852f5075e0faea506527be1937198fc4d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 9 Aug 2025 15:17:02 -0700 Subject: [PATCH 27/28] Fix an unstable feature comment that wasn't a doc comment Every other feature in the list uses a doc comment; fix one that used a regular comment to use a doc comment. --- compiler/rustc_feature/src/unstable.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_feature/src/unstable.rs b/compiler/rustc_feature/src/unstable.rs index ae1f57c1ef610..acc21f6c6d253 100644 --- a/compiler/rustc_feature/src/unstable.rs +++ b/compiler/rustc_feature/src/unstable.rs @@ -545,7 +545,7 @@ declare_features! ( (incomplete, inherent_associated_types, "1.52.0", Some(8995)), /// Allows using `pointer` and `reference` in intra-doc links (unstable, intra_doc_pointers, "1.51.0", Some(80896)), - // Allows setting the threshold for the `large_assignments` lint. + /// Allows setting the threshold for the `large_assignments` lint. (unstable, large_assignments, "1.52.0", Some(83518)), /// Allow to have type alias types for inter-crate use. (incomplete, lazy_type_alias, "1.72.0", Some(112792)), From a70a312f172c9d74f0b01bd2a6e1d9d77bcf6771 Mon Sep 17 00:00:00 2001 From: dianne Date: Sat, 9 Aug 2025 18:07:37 -0700 Subject: [PATCH 28/28] `suggest_borrow_generic_arg`: use the correct generic args --- .../src/diagnostics/conflict_errors.rs | 29 ++++++++++++++----- ...-correct-generic-args-in-borrow-suggest.rs | 13 +++++++++ ...rect-generic-args-in-borrow-suggest.stderr | 18 ++++++++++++ 3 files changed, 53 insertions(+), 7 deletions(-) create mode 100644 tests/ui/moves/use-correct-generic-args-in-borrow-suggest.rs create mode 100644 tests/ui/moves/use-correct-generic-args-in-borrow-suggest.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index be8b3f0bc1e39..7e20a5133e07f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -410,18 +410,18 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { } let typeck = self.infcx.tcx.typeck(self.mir_def_id()); let parent = self.infcx.tcx.parent_hir_node(expr.hir_id); - let (def_id, call_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent + let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind { let def_id = typeck.type_dependent_def_id(parent_expr.hir_id); - (def_id, Some(parent_expr.hir_id), args, 1) + (def_id, args, 1) } else if let hir::Node::Expr(parent_expr) = parent && let hir::ExprKind::Call(call, args) = parent_expr.kind && let ty::FnDef(def_id, _) = typeck.node_type(call.hir_id).kind() { - (Some(*def_id), Some(call.hir_id), args, 0) + (Some(*def_id), args, 0) } else { - (None, None, &[][..], 0) + (None, &[][..], 0) }; let ty = place.ty(self.body, self.infcx.tcx).ty; @@ -459,11 +459,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { // If the moved place is used generically by the callee and a reference to it // would still satisfy any bounds on its type, suggest borrowing. if let Some(¶m) = arg_param - && let Some(generic_args) = call_id.and_then(|id| typeck.node_args_opt(id)) + && let hir::Node::Expr(call_expr) = parent && let Some(ref_mutability) = self.suggest_borrow_generic_arg( err, + typeck, + call_expr, def_id, - generic_args, param, moved_place, pos + offset, @@ -627,8 +628,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { fn suggest_borrow_generic_arg( &self, err: &mut Diag<'_>, + typeck: &ty::TypeckResults<'tcx>, + call_expr: &hir::Expr<'tcx>, callee_did: DefId, - generic_args: ty::GenericArgsRef<'tcx>, param: ty::ParamTy, moved_place: PlaceRef<'tcx>, moved_arg_pos: usize, @@ -639,6 +641,19 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { let sig = tcx.fn_sig(callee_did).instantiate_identity().skip_binder(); let clauses = tcx.predicates_of(callee_did); + let generic_args = match call_expr.kind { + // For method calls, generic arguments are attached to the call node. + hir::ExprKind::MethodCall(..) => typeck.node_args_opt(call_expr.hir_id)?, + // For normal calls, generic arguments are in the callee's type. + // This diagnostic is only run for `FnDef` callees. + hir::ExprKind::Call(callee, _) + if let &ty::FnDef(_, args) = typeck.node_type(callee.hir_id).kind() => + { + args + } + _ => return None, + }; + // First, is there at least one method on one of `param`'s trait bounds? // This keeps us from suggesting borrowing the argument to `mem::drop`, e.g. if !clauses.instantiate_identity(tcx).predicates.iter().any(|clause| { diff --git a/tests/ui/moves/use-correct-generic-args-in-borrow-suggest.rs b/tests/ui/moves/use-correct-generic-args-in-borrow-suggest.rs new file mode 100644 index 0000000000000..0fb0cee20131e --- /dev/null +++ b/tests/ui/moves/use-correct-generic-args-in-borrow-suggest.rs @@ -0,0 +1,13 @@ +//! Regression test for #145164: For normal calls, make sure the suggestion to borrow generic inputs +//! uses the generic args from the callee's type rather than those attached to the callee's HIR +//! node. In cases where the callee isn't an identifier expression, its HIR node won't have its +//! generic arguments attached, which could lead to ICE when it had other generic args. In this +//! case, the callee expression is `run.clone()`, to which `clone`'s generic arguments are attached. + +fn main() { + let value = String::new(); + run.clone()(value, ()); + run(value, ()); + //~^ ERROR use of moved value: `value` +} +fn run(value: T, f: F) {} diff --git a/tests/ui/moves/use-correct-generic-args-in-borrow-suggest.stderr b/tests/ui/moves/use-correct-generic-args-in-borrow-suggest.stderr new file mode 100644 index 0000000000000..8c29bfbd2902f --- /dev/null +++ b/tests/ui/moves/use-correct-generic-args-in-borrow-suggest.stderr @@ -0,0 +1,18 @@ +error[E0382]: use of moved value: `value` + --> $DIR/use-correct-generic-args-in-borrow-suggest.rs:10:9 + | +LL | let value = String::new(); + | ----- move occurs because `value` has type `String`, which does not implement the `Copy` trait +LL | run.clone()(value, ()); + | ----- value moved here +LL | run(value, ()); + | ^^^^^ value used here after move + | +help: consider borrowing `value` + | +LL | run.clone()(&value, ()); + | + + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0382`.