From e47ea38da854eea3aebd35b43e3a4dfc7d25c651 Mon Sep 17 00:00:00 2001 From: Gurinder Singh Date: Mon, 10 Jun 2024 16:28:05 +0530 Subject: [PATCH 01/48] Make suggestion to change `Fn` to `FnMut` work with methods well --- .../src/diagnostics/mutability_errors.rs | 113 +++++++++++------- .../wrong-closure-arg-suggestion-125325.rs | 29 +++++ ...wrong-closure-arg-suggestion-125325.stderr | 28 +++++ 3 files changed, 126 insertions(+), 44 deletions(-) create mode 100644 tests/ui/closures/wrong-closure-arg-suggestion-125325.rs create mode 100644 tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index df1a1411cf5f..238e4a992a9b 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -937,56 +937,81 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let node = self.infcx.tcx.hir_node(fn_call_id); let def_id = hir.enclosing_body_owner(fn_call_id); let mut look_at_return = true; - // If we can detect the expression to be an `fn` call where the closure was an argument, - // we point at the `fn` definition argument... - if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Call(func, args), .. }) = node { - let arg_pos = args + + // If the HIR node is a function or method call gets the def ID + // of the called function or method and the span and args of the call expr + let get_call_details = || { + let hir::Node::Expr(hir::Expr { hir_id, kind, .. }) = node else { + return None; + }; + + let typeck_results = self.infcx.tcx.typeck(def_id); + + match kind { + hir::ExprKind::Call(expr, args) => { + if let Some(ty::FnDef(def_id, _)) = + typeck_results.node_type_opt(expr.hir_id).as_ref().map(|ty| ty.kind()) + { + Some((*def_id, expr.span, *args)) + } else { + None + } + } + hir::ExprKind::MethodCall(_, _, args, span) => { + if let Some(def_id) = typeck_results.type_dependent_def_id(*hir_id) { + Some((def_id, *span, *args)) + } else { + None + } + } + _ => None, + } + }; + + // If we can detect the expression to be an function or method call where the closure was an argument, + // we point at the function or method definition argument... + if let Some((callee_def_id, call_span, call_args)) = get_call_details() { + let arg_pos = call_args .iter() .enumerate() .filter(|(_, arg)| arg.hir_id == closure_id) .map(|(pos, _)| pos) .next(); - let tables = self.infcx.tcx.typeck(def_id); - if let Some(ty::FnDef(def_id, _)) = - tables.node_type_opt(func.hir_id).as_ref().map(|ty| ty.kind()) - { - let arg = match hir.get_if_local(*def_id) { - Some( - hir::Node::Item(hir::Item { - ident, kind: hir::ItemKind::Fn(sig, ..), .. + + let arg = match hir.get_if_local(callee_def_id) { + Some( + hir::Node::Item(hir::Item { ident, kind: hir::ItemKind::Fn(sig, ..), .. }) + | hir::Node::TraitItem(hir::TraitItem { + ident, + kind: hir::TraitItemKind::Fn(sig, _), + .. + }) + | hir::Node::ImplItem(hir::ImplItem { + ident, + kind: hir::ImplItemKind::Fn(sig, _), + .. + }), + ) => Some( + arg_pos + .and_then(|pos| { + sig.decl.inputs.get( + pos + if sig.decl.implicit_self.has_implicit_self() { + 1 + } else { + 0 + }, + ) }) - | hir::Node::TraitItem(hir::TraitItem { - ident, - kind: hir::TraitItemKind::Fn(sig, _), - .. - }) - | hir::Node::ImplItem(hir::ImplItem { - ident, - kind: hir::ImplItemKind::Fn(sig, _), - .. - }), - ) => Some( - arg_pos - .and_then(|pos| { - sig.decl.inputs.get( - pos + if sig.decl.implicit_self.has_implicit_self() { - 1 - } else { - 0 - }, - ) - }) - .map(|arg| arg.span) - .unwrap_or(ident.span), - ), - _ => None, - }; - if let Some(span) = arg { - err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); - err.span_label(func.span, "expects `Fn` instead of `FnMut`"); - err.span_label(closure_span, "in this closure"); - look_at_return = false; - } + .map(|arg| arg.span) + .unwrap_or(ident.span), + ), + _ => None, + }; + if let Some(span) = arg { + err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); + err.span_label(call_span, "expects `Fn` instead of `FnMut`"); + err.span_label(closure_span, "in this closure"); + look_at_return = false; } } diff --git a/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs b/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs new file mode 100644 index 000000000000..ce575697cf68 --- /dev/null +++ b/tests/ui/closures/wrong-closure-arg-suggestion-125325.rs @@ -0,0 +1,29 @@ +// Regression test for #125325 + +// Tests that we suggest changing an `impl Fn` param +// to `impl FnMut` when the provided closure arg +// is trying to mutate the closure env. +// Ensures that it works that way for both +// functions and methods + +struct S; + +impl S { + fn assoc_func(&self, _f: impl Fn()) -> usize { + 0 + } +} + +fn func(_f: impl Fn()) -> usize { + 0 +} + +fn test_func(s: &S) -> usize { + let mut x = (); + s.assoc_func(|| x = ()); + //~^ cannot assign to `x`, as it is a captured variable in a `Fn` closure + func(|| x = ()) + //~^ cannot assign to `x`, as it is a captured variable in a `Fn` closure +} + +fn main() {} diff --git a/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr b/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr new file mode 100644 index 000000000000..e0cce8c4b314 --- /dev/null +++ b/tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr @@ -0,0 +1,28 @@ +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/wrong-closure-arg-suggestion-125325.rs:23:21 + | +LL | fn assoc_func(&self, _f: impl Fn()) -> usize { + | --------- change this to accept `FnMut` instead of `Fn` +... +LL | s.assoc_func(|| x = ()); + | --------------^^^^^^- + | | | | + | | | cannot assign + | | in this closure + | expects `Fn` instead of `FnMut` + +error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure + --> $DIR/wrong-closure-arg-suggestion-125325.rs:25:13 + | +LL | fn func(_f: impl Fn()) -> usize { + | --------- change this to accept `FnMut` instead of `Fn` +... +LL | func(|| x = ()) + | ---- -- ^^^^^^ cannot assign + | | | + | | in this closure + | expects `Fn` instead of `FnMut` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0594`. From 9bcc133bb7f818958c2882d54400ddafd8aea8f3 Mon Sep 17 00:00:00 2001 From: Ed Page Date: Mon, 10 Jun 2024 21:16:54 -0500 Subject: [PATCH 02/48] docs(change): Don't mention a Cargo 2024 edition change for 1.79 --- RELEASES.md | 1 - 1 file changed, 1 deletion(-) diff --git a/RELEASES.md b/RELEASES.md index c1311ab14c53..d63ebd0a4a90 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -97,7 +97,6 @@ Cargo - [Prevent dashes in `lib.name`, always normalizing to `_`.](https://github.com/rust-lang/cargo/pull/12783/) - [Stabilize MSRV-aware version requirement selection in `cargo add`.](https://github.com/rust-lang/cargo/pull/13608/) - [Switch to using `gitoxide` by default for listing files.](https://github.com/rust-lang/cargo/pull/13696/) -- [Error on `[project]` in Edition 2024; `cargo fix --edition` will change it to `[package]`.](https://github.com/rust-lang/cargo/pull/13747/) From d2268902f7db32c03520f160f2d0e750d4d8d0b1 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 11 Jun 2024 11:37:51 -0400 Subject: [PATCH 03/48] rewrite and rename issue-10971-temps-dir to rmake format --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/issue-10971-temps-dir/Makefile | 10 --------- .../parallel-rustc-no-overwrite/rmake.rs | 22 +++++++++++++++++++ 3 files changed, 22 insertions(+), 11 deletions(-) delete mode 100644 tests/run-make/issue-10971-temps-dir/Makefile create mode 100644 tests/run-make/parallel-rustc-no-overwrite/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index ac89a30f3534..59c836862c5d 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -79,7 +79,6 @@ run-make/invalid-library/Makefile run-make/invalid-so/Makefile run-make/invalid-staticlib/Makefile run-make/issue-107094/Makefile -run-make/issue-10971-temps-dir/Makefile run-make/issue-109934-lto-debuginfo/Makefile run-make/issue-14698/Makefile run-make/issue-15460/Makefile diff --git a/tests/run-make/issue-10971-temps-dir/Makefile b/tests/run-make/issue-10971-temps-dir/Makefile deleted file mode 100644 index 6e1649a58d23..000000000000 --- a/tests/run-make/issue-10971-temps-dir/Makefile +++ /dev/null @@ -1,10 +0,0 @@ -include ../tools.mk - -# Regression test for issue #10971 -# Running two invocations in parallel would overwrite each other's temp files. - -all: - touch $(TMPDIR)/lib.rs - - $(RUSTC) --crate-type=lib -Z temps-dir=$(TMPDIR)/temp1 $(TMPDIR)/lib.rs & \ - $(RUSTC) --crate-type=staticlib -Z temps-dir=$(TMPDIR)/temp2 $(TMPDIR)/lib.rs diff --git a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs new file mode 100644 index 000000000000..d45eb4f29116 --- /dev/null +++ b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs @@ -0,0 +1,22 @@ +// When two instances of rustc are invoked in parallel, they +// can conflict on their temporary files and overwrite each others', +// leading to unsuccessful compilation. The -Z temps-dir flag adds +// separate designated directories for each rustc invocation, preventing +// conflicts. This test uses this flag and checks for successful compilation. +// See https://github.com/rust-lang/rust/pull/83846 + +use run_make_support::{fs_wrapper, rustc}; +use std::thread; + +fn main() { + fs_wrapper::create_file("lib.rs"); + let handle1 = thread::spawn(move || { + rustc().crate_type("lib").arg("-Ztemps-dir=temp1").input("lib.rs"); + }); + + let handle2 = thread::spawn(move || { + rustc().crate_type("staticlib").arg("-Ztemps-dir=temp2").input("lib.rs"); + }); + handle1.join().expect("lib thread panicked"); + handle2.join().expect("staticlib thread panicked"); +} From 03982dae0173f7358dd779aa2a92dd0a2ab0fe59 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 11 Jun 2024 11:57:07 -0400 Subject: [PATCH 04/48] rewrite inaccessible-temp-dir to rmake format --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/inaccessible-temp-dir/Makefile | 32 -------------- tests/run-make/inaccessible-temp-dir/rmake.rs | 44 +++++++++++++++++++ 3 files changed, 44 insertions(+), 33 deletions(-) delete mode 100644 tests/run-make/inaccessible-temp-dir/Makefile create mode 100644 tests/run-make/inaccessible-temp-dir/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 59c836862c5d..dd6e64057b44 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -66,7 +66,6 @@ run-make/foreign-double-unwind/Makefile run-make/foreign-exceptions/Makefile run-make/foreign-rust-exceptions/Makefile run-make/glibc-staticlib-args/Makefile -run-make/inaccessible-temp-dir/Makefile run-make/include_bytes_deps/Makefile run-make/incr-add-rust-src-component/Makefile run-make/incr-foreign-head-span/Makefile diff --git a/tests/run-make/inaccessible-temp-dir/Makefile b/tests/run-make/inaccessible-temp-dir/Makefile deleted file mode 100644 index abdba4eb8614..000000000000 --- a/tests/run-make/inaccessible-temp-dir/Makefile +++ /dev/null @@ -1,32 +0,0 @@ -# only-linux -# ignore-arm - linker error on `armhf-gnu` - -include ../tools.mk - -# Issue #66530: We would ICE if someone compiled with `-o /dev/null`, -# because we would try to generate auxiliary files in `/dev/` (which -# at least the OS X file system rejects). -# -# An attempt to `-Ztemps-dir` into a directory we cannot write into should -# indeed be an error; but not an ICE. -# -# However, some folks run tests as root, which can write `/dev/` and end -# up clobbering `/dev/null`. Instead we'll use an inaccessible path, which -# also used to ICE, but even root can't magically write there. -# -# Note that `-Ztemps-dir` uses `create_dir_all` so it is not sufficient to -# use a directory with non-existing parent like `/does-not-exist/output`. - -all: - # Create an inaccessible directory - mkdir $(TMPDIR)/inaccessible - chmod 000 $(TMPDIR)/inaccessible - - # Run rustc with `-Ztemps-dir` set to a directory - # *inside* the inaccessible one, so that it can't create it - $(RUSTC) program.rs -Ztemps-dir=$(TMPDIR)/inaccessible/tmp 2>&1 \ - | $(CGREP) 'failed to find or create the directory specified by `--temps-dir`' - - # Make the inaccessible directory accessible, - # so that compiletest can delete the temp dir - chmod +rw $(TMPDIR)/inaccessible diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs new file mode 100644 index 000000000000..25c9d363820d --- /dev/null +++ b/tests/run-make/inaccessible-temp-dir/rmake.rs @@ -0,0 +1,44 @@ +// Issue #66530: We would ICE if someone compiled with `-o /dev/null`, +// because we would try to generate auxiliary files in `/dev/` (which +// at least the OS X file system rejects). +// +// An attempt to `-Ztemps-dir` into a directory we cannot write into should +// indeed be an error; but not an ICE. +// +// However, some folks run tests as root, which can write `/dev/` and end +// up clobbering `/dev/null`. Instead we'll use an inaccessible path, which +// also used to ICE, but even root can't magically write there. +// +// Note that `-Ztemps-dir` uses `create_dir_all` so it is not sufficient to +// use a directory with non-existing parent like `/does-not-exist/output`. +// See https://github.com/rust-lang/rust/issues/66530 + +//@ only-linux +// Reason: set_mode is only available on Unix + +//@ ignore-arm +// Reason: linker error on `armhf-gnu` + +use run_make_support::{fs_wrapper, rustc}; + +fn main() { + // Create an inaccessible directory. + fs_wrapper::create_dir("inaccessible"); + let meta = fs_wrapper::metadata("inaccessible"); + let mut perms = meta.permissions(); + perms.set_mode(0o000); // Lock down the directory. + fs_wrapper::set_permissions("inaccessible", perms); + + // Run rustc with `-Z temps-dir` set to a directory *inside* the inaccessible one, + // so that it can't create `tmp`. + rustc() + .input("program.rs") + .arg("-Ztemps-dir=inaccessible/tmp") + .run_fail() + .assert_stderr_contains( + "failed to find or create the directory specified by `--temps-dir`", + ); + + perms.set_mode(0o666); // Unlock the directory, so that compiletest can delete it. + fs_wrapper::set_permissions("inaccessible", perms); +} From 7c2b3b5615cf5e8545c13f7635257cc3fb0eb7bf Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 11 Jun 2024 12:53:33 -0400 Subject: [PATCH 05/48] rewrite output-with-hyphens to rmake format --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/output-with-hyphens/Makefile | 8 ------- tests/run-make/output-with-hyphens/rmake.rs | 17 ++++++++++++++ .../parallel-rustc-no-overwrite/rmake.rs | 22 ++++++++++--------- 4 files changed, 29 insertions(+), 19 deletions(-) delete mode 100644 tests/run-make/output-with-hyphens/Makefile create mode 100644 tests/run-make/output-with-hyphens/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index dd6e64057b44..0d7951bcfffc 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -156,7 +156,6 @@ run-make/optimization-remarks-dir/Makefile run-make/output-filename-conflicts-with-directory/Makefile run-make/output-filename-overwrites-input/Makefile run-make/output-type-permutations/Makefile -run-make/output-with-hyphens/Makefile run-make/override-aliased-flags/Makefile run-make/overwrite-input/Makefile run-make/panic-abort-eh_frame/Makefile diff --git a/tests/run-make/output-with-hyphens/Makefile b/tests/run-make/output-with-hyphens/Makefile deleted file mode 100644 index 846c9a66a89a..000000000000 --- a/tests/run-make/output-with-hyphens/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: - $(RUSTC) foo-bar.rs --crate-type bin - [ -f $(TMPDIR)/$(call BIN,foo-bar) ] - $(RUSTC) foo-bar.rs --crate-type lib - [ -f $(TMPDIR)/libfoo_bar.rlib ] diff --git a/tests/run-make/output-with-hyphens/rmake.rs b/tests/run-make/output-with-hyphens/rmake.rs new file mode 100644 index 000000000000..21c003c628b9 --- /dev/null +++ b/tests/run-make/output-with-hyphens/rmake.rs @@ -0,0 +1,17 @@ +// Rust files with hyphens in their filename should +// not result in compiled libraries keeping that hyphen - +// it should become an underscore. Only bin executables +// should keep the hyphen. This test ensures that this rule +// remains enforced. +// See https://github.com/rust-lang/rust/pull/23786 + +//@ ignore-cross-compile + +use run_make_support::{path, rustc}; + +fn main() { + rustc().input("foo-bar.rs").crate_type("bin").run(); + assert!(path(bin_name("foo-bar")).exists()); + rustc().input("foo-bar.rs").crate_type("lib").run(); + assert!(path(bin_name("libfoo_bar.rlib")).exists()); +} diff --git a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs index d45eb4f29116..40c6ab7ed5eb 100644 --- a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs +++ b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs @@ -6,17 +6,19 @@ // See https://github.com/rust-lang/rust/pull/83846 use run_make_support::{fs_wrapper, rustc}; +use std::sync::{Arc, Barrier}; use std::thread; fn main() { - fs_wrapper::create_file("lib.rs"); - let handle1 = thread::spawn(move || { - rustc().crate_type("lib").arg("-Ztemps-dir=temp1").input("lib.rs"); - }); - - let handle2 = thread::spawn(move || { - rustc().crate_type("staticlib").arg("-Ztemps-dir=temp2").input("lib.rs"); - }); - handle1.join().expect("lib thread panicked"); - handle2.join().expect("staticlib thread panicked"); + let barrier = Arc::new(Barrier::new(2)); + let handle = { + let barrier = Arc::clone(&barrier); + thread::spawn(move || { + barrier.wait(); + rustc().crate_type("lib").arg("-Ztemps-dir=temp1").input("lib.rs"); + }) + }; + barrier.wait(); + rustc().crate_type("staticlib").arg("-Ztemps-dir=temp2").input("lib.rs"); + handle.join().expect("lib thread panicked"); } From c462328382b9fc1c39ffca3f519f7559717b2ccc Mon Sep 17 00:00:00 2001 From: Stefan Lankes Date: Wed, 12 Jun 2024 20:18:33 +0200 Subject: [PATCH 06/48] export std::os::fd module on HermitOS The HermitOS' IO interface is similiar to Unix. Consequently, this PR synchronize the FD implementation between both. --- library/std/src/os/hermit/io/mod.rs | 15 +++------------ library/std/src/os/mod.rs | 2 +- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/library/std/src/os/hermit/io/mod.rs b/library/std/src/os/hermit/io/mod.rs index 524dfae0d63a..df93f63a003c 100644 --- a/library/std/src/os/hermit/io/mod.rs +++ b/library/std/src/os/hermit/io/mod.rs @@ -1,13 +1,4 @@ -#![stable(feature = "os_fd", since = "1.66.0")] +#![stable(feature = "rust1", since = "1.0.0")] -mod net; -#[path = "../../fd/owned.rs"] -mod owned; -#[path = "../../fd/raw.rs"] -mod raw; - -// Export the types and traits for the public API. -#[stable(feature = "os_fd", since = "1.66.0")] -pub use owned::*; -#[stable(feature = "os_fd", since = "1.66.0")] -pub use raw::*; +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::os::fd::*; diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs index ca3584e82f91..d2a7b316b813 100644 --- a/library/std/src/os/mod.rs +++ b/library/std/src/os/mod.rs @@ -160,7 +160,7 @@ pub(crate) mod watchos; #[cfg(target_os = "xous")] pub mod xous; -#[cfg(any(unix, target_os = "wasi", doc))] +#[cfg(any(unix, target_os = "hermit", target_os = "wasi", doc))] pub mod fd; #[cfg(any(target_os = "linux", target_os = "android", doc))] From 9e851041d7b7631217857067f80b461543844c24 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Jun 2024 11:18:32 +0200 Subject: [PATCH 07/48] div_euclid, rem_euclid: clarify/extend documentation --- library/core/src/num/int_macros.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 55bb6166f101..448894849639 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2784,8 +2784,10 @@ macro_rules! int_impl { /// /// In other words, the result is `self / rhs` rounded to the integer `q` /// such that `self >= q * rhs`. - /// If `self > 0`, this is equal to round towards zero (the default in Rust); - /// if `self < 0`, this is equal to round towards +/- infinity. + /// If `self > 0`, this is equal to rounding towards zero (the default in Rust); + /// if `self < 0`, this is equal to rounding away from zero (towards +/- infinity). + /// If `rhs > 0`, this is equal to rounding towards -infinity; + /// if `rhs < 0`, this is equal to rounding towards +infinity. /// /// # Panics /// @@ -2823,8 +2825,8 @@ macro_rules! int_impl { /// Calculates the least nonnegative remainder of `self (mod rhs)`. /// /// This is done as if by the Euclidean division algorithm -- given - /// `r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and - /// `0 <= r < abs(rhs)`. + /// `r = self.rem_euclid(rhs)`, the result satisfies + /// `self = rhs * self.div_euclid(rhs) + r` and `0 <= r < abs(rhs)`. /// /// # Panics /// From 4f97ab54c452400b47e3518e17d18ada7675f07d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 18 May 2024 16:56:08 -0400 Subject: [PATCH 08/48] Resolve elided lifetimes in assoc const to static if no other lifetimes are in scope --- compiler/rustc_lint/messages.ftl | 1 + .../rustc_lint/src/context/diagnostics.rs | 15 ++- compiler/rustc_lint/src/lints.rs | 2 + compiler/rustc_lint_defs/src/builtin.rs | 8 +- compiler/rustc_lint_defs/src/lib.rs | 1 + compiler/rustc_resolve/src/late.rs | 104 +++++++++++------- tests/ui/associated-consts/double-elided.rs | 8 +- .../ui/associated-consts/double-elided.stderr | 47 -------- ...nfer-placeholder-in-non-suggestable-pos.rs | 2 - ...-placeholder-in-non-suggestable-pos.stderr | 16 +-- .../consts/assoc-const-elided-lifetime.stderr | 12 ++ 11 files changed, 101 insertions(+), 115 deletions(-) delete mode 100644 tests/ui/associated-consts/double-elided.stderr diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 733c73bc3d07..ec22da407fa9 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -14,6 +14,7 @@ lint_associated_const_elided_lifetime = {$elided -> *[false] `'_` cannot be used here } .suggestion = use the `'static` lifetime + .note = cannot automatically infer `'static` because of other lifetimes in scope lint_async_fn_in_trait = use of `async fn` in public traits is discouraged as auto trait bounds cannot be specified .note = you can suppress this lint if you plan to use the trait only in your own code, or do not care about auto traits like `Send` on the `Future` diff --git a/compiler/rustc_lint/src/context/diagnostics.rs b/compiler/rustc_lint/src/context/diagnostics.rs index 83640d7210fa..290bb5173dbe 100644 --- a/compiler/rustc_lint/src/context/diagnostics.rs +++ b/compiler/rustc_lint/src/context/diagnostics.rs @@ -319,11 +319,20 @@ pub(super) fn decorate_lint(sess: &Session, diagnostic: BuiltinLintDiag, diag: & BuiltinLintDiag::UnusedQualifications { removal_span } => { lints::UnusedQualifications { removal_span }.decorate_lint(diag); } - BuiltinLintDiag::AssociatedConstElidedLifetime { elided, span: lt_span } => { + BuiltinLintDiag::AssociatedConstElidedLifetime { + elided, + span: lt_span, + lifetimes_in_scope, + } => { let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span }; let code = if elided { "'static " } else { "'static" }; - lints::AssociatedConstElidedLifetime { span: lt_span, code, elided } - .decorate_lint(diag); + lints::AssociatedConstElidedLifetime { + span: lt_span, + code, + elided, + lifetimes_in_scope, + } + .decorate_lint(diag); } BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => { lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index b377da31a581..698317ebf7b9 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2865,6 +2865,8 @@ pub struct AssociatedConstElidedLifetime { pub code: &'static str, pub elided: bool, + #[note] + pub lifetimes_in_scope: MultiSpan, } #[derive(LintDiagnostic)] diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index a12c76037e77..1913b9d6a1c3 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -4593,16 +4593,18 @@ declare_lint! { declare_lint! { /// The `elided_lifetimes_in_associated_constant` lint detects elided lifetimes - /// that were erroneously allowed in associated constants. + /// in associated constants when there are other lifetimes in scope. This was + /// accidentally supported, and this lint was later relaxed to allow eliding + /// lifetimes to `'static` when there are no lifetimes in scope. /// /// ### Example /// /// ```rust,compile_fail /// #![deny(elided_lifetimes_in_associated_constant)] /// - /// struct Foo; + /// struct Foo<'a>(&'a ()); /// - /// impl Foo { + /// impl<'a> Foo<'a> { /// const STR: &str = "hello, world"; /// } /// ``` diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 1ce95df34041..70330c445776 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -696,6 +696,7 @@ pub enum BuiltinLintDiag { AssociatedConstElidedLifetime { elided: bool, span: Span, + lifetimes_in_scope: MultiSpan, }, RedundantImportVisibility { span: Span, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b0adc3775f66..20926366ba5e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -310,9 +310,10 @@ enum LifetimeRibKind { /// error on default object bounds (e.g., `Box`). AnonymousReportError, - /// Resolves elided lifetimes to `'static`, but gives a warning that this behavior - /// is a bug and will be reverted soon. - AnonymousWarn(NodeId), + /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope, + /// otherwise give a warning that the previous behavior of introducing a new early-bound + /// lifetime is a bug and will be removed. + StaticIfNoLifetimeInScope(NodeId), /// Signal we cannot find which should be the anonymous lifetime. ElisionFailure, @@ -1212,7 +1213,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } LifetimeRibKind::AnonymousCreateParameter { .. } | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::AnonymousWarn(_) + | LifetimeRibKind::StaticIfNoLifetimeInScope(_) | LifetimeRibKind::Elided(_) | LifetimeRibKind::ElisionFailure | LifetimeRibKind::ConcreteAnonConst(_) @@ -1580,7 +1581,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // lifetime would be illegal. LifetimeRibKind::Item | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::AnonymousWarn(_) + | LifetimeRibKind::StaticIfNoLifetimeInScope(_) | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many), // An anonymous lifetime is legal here, and bound to the right // place, go ahead. @@ -1643,7 +1644,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { | LifetimeRibKind::Generics { .. } | LifetimeRibKind::ElisionFailure | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::AnonymousWarn(_) => {} + | LifetimeRibKind::StaticIfNoLifetimeInScope(_) => {} } } @@ -1677,16 +1678,36 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.record_lifetime_res(lifetime.id, res, elision_candidate); return; } - LifetimeRibKind::AnonymousWarn(node_id) => { - self.r.lint_buffer.buffer_lint( - lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, - node_id, - lifetime.ident.span, - lint::BuiltinLintDiag::AssociatedConstElidedLifetime { - elided, - span: lifetime.ident.span, - }, - ); + LifetimeRibKind::StaticIfNoLifetimeInScope(node_id) => { + let mut lifetimes_in_scope = vec![]; + for rib in &self.lifetime_ribs[..i] { + lifetimes_in_scope.extend(rib.bindings.iter().map(|(ident, _)| ident.span)); + // Consider any anonymous lifetimes, too + if let LifetimeRibKind::AnonymousCreateParameter { binder, .. } = rib.kind + && let Some(extra) = self.r.extra_lifetime_params_map.get(&binder) + { + lifetimes_in_scope.extend(extra.iter().map(|(ident, _, _)| ident.span)); + } + } + if lifetimes_in_scope.is_empty() { + self.record_lifetime_res( + lifetime.id, + LifetimeRes::Static, + elision_candidate, + ); + return; + } else { + self.r.lint_buffer.buffer_lint( + lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, + node_id, + lifetime.ident.span, + lint::BuiltinLintDiag::AssociatedConstElidedLifetime { + elided, + span: lifetime.ident.span, + lifetimes_in_scope: lifetimes_in_scope.into(), + }, + ); + } } LifetimeRibKind::AnonymousReportError => { if elided { @@ -1904,7 +1925,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // impl Foo for std::cell::Ref // note lack of '_ // async fn foo(_: std::cell::Ref) { ... } LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } - | LifetimeRibKind::AnonymousWarn(_) => { + | LifetimeRibKind::StaticIfNoLifetimeInScope(_) => { let sess = self.r.tcx.sess; let subdiag = rustc_errors::elided_lifetime_in_path_suggestion( sess.source_map(), @@ -3030,30 +3051,33 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { kind: LifetimeBinderKind::ConstItem, }, |this| { - this.with_lifetime_rib(LifetimeRibKind::AnonymousWarn(item.id), |this| { - // If this is a trait impl, ensure the const - // exists in trait - this.check_trait_item( - item.id, - item.ident, - &item.kind, - ValueNS, - item.span, - seen_trait_items, - |i, s, c| ConstNotMemberOfTrait(i, s, c), - ); + this.with_lifetime_rib( + LifetimeRibKind::StaticIfNoLifetimeInScope(item.id), + |this| { + // If this is a trait impl, ensure the const + // exists in trait + this.check_trait_item( + item.id, + item.ident, + &item.kind, + ValueNS, + item.span, + seen_trait_items, + |i, s, c| ConstNotMemberOfTrait(i, s, c), + ); - this.visit_generics(generics); - this.visit_ty(ty); - if let Some(expr) = expr { - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.resolve_const_body(expr, None); - } - }); + this.visit_generics(generics); + this.visit_ty(ty); + if let Some(expr) = expr { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.resolve_const_body(expr, None); + } + }, + ); }, ); } diff --git a/tests/ui/associated-consts/double-elided.rs b/tests/ui/associated-consts/double-elided.rs index fd0317781bb1..6831b599374a 100644 --- a/tests/ui/associated-consts/double-elided.rs +++ b/tests/ui/associated-consts/double-elided.rs @@ -1,12 +1,10 @@ +//@ check-pass + struct S; impl S { const C: &&str = &""; - //~^ WARN `&` without an explicit lifetime name cannot be used here - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| WARN `&` without an explicit lifetime name cannot be used here - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - //~| ERROR in type `&&str`, reference has a longer lifetime than the data it references + // Now resolves to `&'static &'static str`. } fn main() {} diff --git a/tests/ui/associated-consts/double-elided.stderr b/tests/ui/associated-consts/double-elided.stderr deleted file mode 100644 index 67834788ccd4..000000000000 --- a/tests/ui/associated-consts/double-elided.stderr +++ /dev/null @@ -1,47 +0,0 @@ -warning: `&` without an explicit lifetime name cannot be used here - --> $DIR/double-elided.rs:4:14 - | -LL | const C: &&str = &""; - | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #115010 - = note: `#[warn(elided_lifetimes_in_associated_constant)]` on by default -help: use the `'static` lifetime - | -LL | const C: &'static &str = &""; - | +++++++ - -warning: `&` without an explicit lifetime name cannot be used here - --> $DIR/double-elided.rs:4:15 - | -LL | const C: &&str = &""; - | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #115010 -help: use the `'static` lifetime - | -LL | const C: &&'static str = &""; - | +++++++ - -error[E0491]: in type `&&str`, reference has a longer lifetime than the data it references - --> $DIR/double-elided.rs:4:5 - | -LL | const C: &&str = &""; - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: the pointer is valid for the anonymous lifetime as defined here - --> $DIR/double-elided.rs:4:14 - | -LL | const C: &&str = &""; - | ^ -note: but the referenced data is only valid for the anonymous lifetime as defined here - --> $DIR/double-elided.rs:4:14 - | -LL | const C: &&str = &""; - | ^ - -error: aborting due to 1 previous error; 2 warnings emitted - -For more information about this error, try `rustc --explain E0491`. diff --git a/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.rs b/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.rs index 1e0b77b0d3bd..40896c32e111 100644 --- a/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.rs +++ b/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.rs @@ -5,8 +5,6 @@ trait Trait { impl Trait for () { const ASSOC: &dyn Fn(_) = 1i32; //~^ ERROR the placeholder `_` is not allowed within types on item signatures for associated constants - //~| WARN `&` without an explicit lifetime name cannot be used here - //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! } fn main() {} diff --git a/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.stderr b/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.stderr index e946491a0848..6b8ba9af7a07 100644 --- a/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.stderr +++ b/tests/ui/associated-consts/infer-placeholder-in-non-suggestable-pos.stderr @@ -1,23 +1,9 @@ -warning: `&` without an explicit lifetime name cannot be used here - --> $DIR/infer-placeholder-in-non-suggestable-pos.rs:6:18 - | -LL | const ASSOC: &dyn Fn(_) = 1i32; - | ^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #115010 - = note: `#[warn(elided_lifetimes_in_associated_constant)]` on by default -help: use the `'static` lifetime - | -LL | const ASSOC: &'static dyn Fn(_) = 1i32; - | +++++++ - error[E0121]: the placeholder `_` is not allowed within types on item signatures for associated constants --> $DIR/infer-placeholder-in-non-suggestable-pos.rs:6:26 | LL | const ASSOC: &dyn Fn(_) = 1i32; | ^ not allowed in type signatures -error: aborting due to 1 previous error; 1 warning emitted +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0121`. diff --git a/tests/ui/consts/assoc-const-elided-lifetime.stderr b/tests/ui/consts/assoc-const-elided-lifetime.stderr index a1eeaff4ba87..3e847298c356 100644 --- a/tests/ui/consts/assoc-const-elided-lifetime.stderr +++ b/tests/ui/consts/assoc-const-elided-lifetime.stderr @@ -6,6 +6,11 @@ LL | const FOO: Foo<'_> = Foo { x: PhantomData::<&()> }; | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #115010 +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/assoc-const-elided-lifetime.rs:9:6 + | +LL | impl<'a> Foo<'a> { + | ^^ note: the lint level is defined here --> $DIR/assoc-const-elided-lifetime.rs:1:9 | @@ -24,6 +29,13 @@ LL | const BAR: &() = &(); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #115010 +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/assoc-const-elided-lifetime.rs:9:6 + | +LL | impl<'a> Foo<'a> { + | ^^ +LL | const FOO: Foo<'_> = Foo { x: PhantomData::<&()> }; + | ^^ help: use the `'static` lifetime | LL | const BAR: &'static () = &(); From 805397c16f7629f1357d59c676f3a6d4c9e96244 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 13 Jun 2024 20:33:43 -0400 Subject: [PATCH 09/48] Add more tests --- .../elided-lifetime.rs | 23 ++++++++ .../elided-lifetime.stderr | 59 +++++++++++++++++++ .../generic-associated-const.rs | 20 +++++++ .../generic-associated-const.stderr | 57 ++++++++++++++++++ .../static-default-lifetime/inner-item.rs | 21 +++++++ .../static-trait-impl.rs | 20 +++++++ .../static-trait-impl.stderr | 45 ++++++++++++++ 7 files changed, 245 insertions(+) create mode 100644 tests/ui/consts/static-default-lifetime/elided-lifetime.rs create mode 100644 tests/ui/consts/static-default-lifetime/elided-lifetime.stderr create mode 100644 tests/ui/consts/static-default-lifetime/generic-associated-const.rs create mode 100644 tests/ui/consts/static-default-lifetime/generic-associated-const.stderr create mode 100644 tests/ui/consts/static-default-lifetime/inner-item.rs create mode 100644 tests/ui/consts/static-default-lifetime/static-trait-impl.rs create mode 100644 tests/ui/consts/static-default-lifetime/static-trait-impl.stderr diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.rs b/tests/ui/consts/static-default-lifetime/elided-lifetime.rs new file mode 100644 index 000000000000..e1d9791625b3 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.rs @@ -0,0 +1,23 @@ +#![deny(elided_lifetimes_in_associated_constant)] + +struct Foo<'a>(&'a ()); + +impl Foo<'_> { + const STATIC: &str = ""; + //~^ ERROR `&` without an explicit lifetime name cannot be used here + //~| WARN this was previously accepted by the compiler but is being phased out +} + +trait Bar { + const STATIC: &'static str; + // TODO^ +} + +impl Bar for Foo<'_> { + const STATIC: &str = ""; + //~^ ERROR `&` without an explicit lifetime name cannot be used here + //~| WARN this was previously accepted by the compiler but is being phased out + //~| ERROR const not compatible with trait +} + +fn main() {} diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr new file mode 100644 index 000000000000..8be225e2a3ce --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr @@ -0,0 +1,59 @@ +error: `&` without an explicit lifetime name cannot be used here + --> $DIR/elided-lifetime.rs:6:19 + | +LL | const STATIC: &str = ""; + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #115010 +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/elided-lifetime.rs:5:10 + | +LL | impl Foo<'_> { + | ^^ +note: the lint level is defined here + --> $DIR/elided-lifetime.rs:1:9 + | +LL | #![deny(elided_lifetimes_in_associated_constant)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use the `'static` lifetime + | +LL | const STATIC: &'static str = ""; + | +++++++ + +error: `&` without an explicit lifetime name cannot be used here + --> $DIR/elided-lifetime.rs:17:19 + | +LL | const STATIC: &str = ""; + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #115010 +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/elided-lifetime.rs:16:18 + | +LL | impl Bar for Foo<'_> { + | ^^ +help: use the `'static` lifetime + | +LL | const STATIC: &'static str = ""; + | +++++++ + +error[E0308]: const not compatible with trait + --> $DIR/elided-lifetime.rs:17:5 + | +LL | const STATIC: &str = ""; + | ^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected reference `&'static _` + found reference `&_` +note: the anonymous lifetime as defined here... + --> $DIR/elided-lifetime.rs:16:18 + | +LL | impl Bar for Foo<'_> { + | ^^ + = note: ...does not necessarily outlive the static lifetime + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/static-default-lifetime/generic-associated-const.rs b/tests/ui/consts/static-default-lifetime/generic-associated-const.rs new file mode 100644 index 000000000000..50eb9ab16695 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/generic-associated-const.rs @@ -0,0 +1,20 @@ +#![deny(elided_lifetimes_in_associated_constant)] +#![feature(generic_const_items)] +//~^ WARN the feature `generic_const_items` is incomplete + +struct A; +impl A { + const GAC_TYPE: &str = ""; + const GAC_LIFETIME<'a>: &str = ""; + //~^ ERROR `&` without an explicit lifetime name cannot be used here + //~| WARN this was previously accepted by the compiler but is being phased out +} + +trait Trait { + const GAC_TYPE: &str = ""; + //~^ ERROR missing lifetime specifier + const GAC_LIFETIME<'a>: &str = ""; + //~^ ERROR missing lifetime specifier +} + +fn main() {} diff --git a/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr b/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr new file mode 100644 index 000000000000..d6e49c7ac588 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr @@ -0,0 +1,57 @@ +error[E0106]: missing lifetime specifier + --> $DIR/generic-associated-const.rs:14:24 + | +LL | const GAC_TYPE: &str = ""; + | ^ expected named lifetime parameter + | +help: consider introducing a named lifetime parameter + | +LL | const GAC_TYPE<'a, T>: &'a str = ""; + | +++ ++ + +error[E0106]: missing lifetime specifier + --> $DIR/generic-associated-const.rs:16:29 + | +LL | const GAC_LIFETIME<'a>: &str = ""; + | ^ expected named lifetime parameter + | +help: consider using the `'a` lifetime + | +LL | const GAC_LIFETIME<'a>: &'a str = ""; + | ++ + +warning: the feature `generic_const_items` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/generic-associated-const.rs:2:12 + | +LL | #![feature(generic_const_items)] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #113521 for more information + = note: `#[warn(incomplete_features)]` on by default + +error: `&` without an explicit lifetime name cannot be used here + --> $DIR/generic-associated-const.rs:8:29 + | +LL | const GAC_LIFETIME<'a>: &str = ""; + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #115010 +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/generic-associated-const.rs:8:24 + | +LL | const GAC_LIFETIME<'a>: &str = ""; + | ^^ +note: the lint level is defined here + --> $DIR/generic-associated-const.rs:1:9 + | +LL | #![deny(elided_lifetimes_in_associated_constant)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use the `'static` lifetime + | +LL | const GAC_LIFETIME<'a>: &'static str = ""; + | +++++++ + +error: aborting due to 3 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/consts/static-default-lifetime/inner-item.rs b/tests/ui/consts/static-default-lifetime/inner-item.rs new file mode 100644 index 000000000000..061b240a40d8 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/inner-item.rs @@ -0,0 +1,21 @@ +//@ check-pass + +struct Foo<'a>(&'a ()); + +impl<'a> Foo<'a> { + fn hello(self) { + const INNER: &str = ""; + } +} + +impl Foo<'_> { + fn implicit(self) { + const INNER: &str = ""; + } + + fn fn_lifetime(&self) { + const INNER: &str = ""; + } +} + +fn main() {} diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.rs b/tests/ui/consts/static-default-lifetime/static-trait-impl.rs new file mode 100644 index 000000000000..025fda4df581 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.rs @@ -0,0 +1,20 @@ +#![deny(elided_lifetimes_in_associated_constant)] + +trait Bar<'a> { + const STATIC: &'a str; +} + +struct A; +impl Bar<'_> for A { + const STATIC: &str = ""; + //~^ ERROR `&` without an explicit lifetime name cannot be used here + //~| WARN this was previously accepted by the compiler but is being phased out + //~| ERROR const not compatible with trait +} + +struct B; +impl Bar<'static> for B { + const STATIC: &str = ""; +} + +fn main() {} diff --git a/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr new file mode 100644 index 000000000000..8e4c27875ab3 --- /dev/null +++ b/tests/ui/consts/static-default-lifetime/static-trait-impl.stderr @@ -0,0 +1,45 @@ +error: `&` without an explicit lifetime name cannot be used here + --> $DIR/static-trait-impl.rs:9:19 + | +LL | const STATIC: &str = ""; + | ^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #115010 +note: cannot automatically infer `'static` because of other lifetimes in scope + --> $DIR/static-trait-impl.rs:8:10 + | +LL | impl Bar<'_> for A { + | ^^ +note: the lint level is defined here + --> $DIR/static-trait-impl.rs:1:9 + | +LL | #![deny(elided_lifetimes_in_associated_constant)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: use the `'static` lifetime + | +LL | const STATIC: &'static str = ""; + | +++++++ + +error[E0308]: const not compatible with trait + --> $DIR/static-trait-impl.rs:9:5 + | +LL | const STATIC: &str = ""; + | ^^^^^^^^^^^^^^^^^^ lifetime mismatch + | + = note: expected reference `&_` + found reference `&_` +note: the anonymous lifetime as defined here... + --> $DIR/static-trait-impl.rs:8:10 + | +LL | impl Bar<'_> for A { + | ^^ +note: ...does not necessarily outlive the anonymous lifetime as defined here + --> $DIR/static-trait-impl.rs:8:10 + | +LL | impl Bar<'_> for A { + | ^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 5f3357c3c68e555c655c71bb8672db7908622c5b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 13 Jun 2024 20:44:15 -0400 Subject: [PATCH 10/48] Resolve const lifetimes to static in trait too --- compiler/rustc_resolve/src/late.rs | 54 +++++++++++------- .../elided-lifetime.rs | 3 +- .../elided-lifetime.stderr | 8 +-- .../generic-associated-const.rs | 1 - .../generic-associated-const.stderr | 15 +---- ...ifetime-in-assoc-const-type.default.stderr | 56 ++++--------------- ...ssoc-const-type.generic_const_items.stderr | 46 ++++----------- .../missing-lifetime-in-assoc-const-type.rs | 8 +-- 8 files changed, 68 insertions(+), 123 deletions(-) diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 20926366ba5e..f3c27ca857f0 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -312,8 +312,8 @@ enum LifetimeRibKind { /// Resolves elided lifetimes to `'static` if there are no other lifetimes in scope, /// otherwise give a warning that the previous behavior of introducing a new early-bound - /// lifetime is a bug and will be removed. - StaticIfNoLifetimeInScope(NodeId), + /// lifetime is a bug and will be removed (if `emit_lint` is enabled). + StaticIfNoLifetimeInScope { lint_id: NodeId, emit_lint: bool }, /// Signal we cannot find which should be the anonymous lifetime. ElisionFailure, @@ -1213,7 +1213,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast, } LifetimeRibKind::AnonymousCreateParameter { .. } | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::StaticIfNoLifetimeInScope(_) + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } | LifetimeRibKind::Elided(_) | LifetimeRibKind::ElisionFailure | LifetimeRibKind::ConcreteAnonConst(_) @@ -1581,7 +1581,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // lifetime would be illegal. LifetimeRibKind::Item | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::StaticIfNoLifetimeInScope(_) + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } | LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many), // An anonymous lifetime is legal here, and bound to the right // place, go ahead. @@ -1644,7 +1644,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { | LifetimeRibKind::Generics { .. } | LifetimeRibKind::ElisionFailure | LifetimeRibKind::AnonymousReportError - | LifetimeRibKind::StaticIfNoLifetimeInScope(_) => {} + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } => {} } } @@ -1678,7 +1678,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { self.record_lifetime_res(lifetime.id, res, elision_candidate); return; } - LifetimeRibKind::StaticIfNoLifetimeInScope(node_id) => { + LifetimeRibKind::StaticIfNoLifetimeInScope { lint_id: node_id, emit_lint } => { let mut lifetimes_in_scope = vec![]; for rib in &self.lifetime_ribs[..i] { lifetimes_in_scope.extend(rib.bindings.iter().map(|(ident, _)| ident.span)); @@ -1696,7 +1696,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { elision_candidate, ); return; - } else { + } else if emit_lint { self.r.lint_buffer.buffer_lint( lint::builtin::ELIDED_LIFETIMES_IN_ASSOCIATED_CONSTANT, node_id, @@ -1925,7 +1925,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // impl Foo for std::cell::Ref // note lack of '_ // async fn foo(_: std::cell::Ref) { ... } LifetimeRibKind::AnonymousCreateParameter { report_in_path: true, .. } - | LifetimeRibKind::StaticIfNoLifetimeInScope(_) => { + | LifetimeRibKind::StaticIfNoLifetimeInScope { .. } => { let sess = self.r.tcx.sess; let subdiag = rustc_errors::elided_lifetime_in_path_suggestion( sess.source_map(), @@ -2859,19 +2859,27 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { kind: LifetimeBinderKind::ConstItem, }, |this| { - this.visit_generics(generics); - this.visit_ty(ty); + this.with_lifetime_rib( + LifetimeRibKind::StaticIfNoLifetimeInScope { + lint_id: item.id, + emit_lint: false, + }, + |this| { + this.visit_generics(generics); + this.visit_ty(ty); - // Only impose the restrictions of `ConstRibKind` for an - // actual constant expression in a provided default. - if let Some(expr) = expr { - // We allow arbitrary const expressions inside of associated consts, - // even if they are potentially not const evaluatable. - // - // Type parameters can already be used and as associated consts are - // not used as part of the type system, this is far less surprising. - this.resolve_const_body(expr, None); - } + // Only impose the restrictions of `ConstRibKind` for an + // actual constant expression in a provided default. + if let Some(expr) = expr { + // We allow arbitrary const expressions inside of associated consts, + // even if they are potentially not const evaluatable. + // + // Type parameters can already be used and as associated consts are + // not used as part of the type system, this is far less surprising. + this.resolve_const_body(expr, None); + } + }, + ) }, ); } @@ -3052,7 +3060,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { }, |this| { this.with_lifetime_rib( - LifetimeRibKind::StaticIfNoLifetimeInScope(item.id), + LifetimeRibKind::StaticIfNoLifetimeInScope { + lint_id: item.id, + // In impls, it's not a hard error yet due to backcompat. + emit_lint: true, + }, |this| { // If this is a trait impl, ensure the const // exists in trait diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.rs b/tests/ui/consts/static-default-lifetime/elided-lifetime.rs index e1d9791625b3..95d59f9b894e 100644 --- a/tests/ui/consts/static-default-lifetime/elided-lifetime.rs +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.rs @@ -9,8 +9,7 @@ impl Foo<'_> { } trait Bar { - const STATIC: &'static str; - // TODO^ + const STATIC: &str; } impl Bar for Foo<'_> { diff --git a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr index 8be225e2a3ce..d4fc17175389 100644 --- a/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr +++ b/tests/ui/consts/static-default-lifetime/elided-lifetime.stderr @@ -22,7 +22,7 @@ LL | const STATIC: &'static str = ""; | +++++++ error: `&` without an explicit lifetime name cannot be used here - --> $DIR/elided-lifetime.rs:17:19 + --> $DIR/elided-lifetime.rs:16:19 | LL | const STATIC: &str = ""; | ^ @@ -30,7 +30,7 @@ LL | const STATIC: &str = ""; = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #115010 note: cannot automatically infer `'static` because of other lifetimes in scope - --> $DIR/elided-lifetime.rs:16:18 + --> $DIR/elided-lifetime.rs:15:18 | LL | impl Bar for Foo<'_> { | ^^ @@ -40,7 +40,7 @@ LL | const STATIC: &'static str = ""; | +++++++ error[E0308]: const not compatible with trait - --> $DIR/elided-lifetime.rs:17:5 + --> $DIR/elided-lifetime.rs:16:5 | LL | const STATIC: &str = ""; | ^^^^^^^^^^^^^^^^^^ lifetime mismatch @@ -48,7 +48,7 @@ LL | const STATIC: &str = ""; = note: expected reference `&'static _` found reference `&_` note: the anonymous lifetime as defined here... - --> $DIR/elided-lifetime.rs:16:18 + --> $DIR/elided-lifetime.rs:15:18 | LL | impl Bar for Foo<'_> { | ^^ diff --git a/tests/ui/consts/static-default-lifetime/generic-associated-const.rs b/tests/ui/consts/static-default-lifetime/generic-associated-const.rs index 50eb9ab16695..721920bd810c 100644 --- a/tests/ui/consts/static-default-lifetime/generic-associated-const.rs +++ b/tests/ui/consts/static-default-lifetime/generic-associated-const.rs @@ -12,7 +12,6 @@ impl A { trait Trait { const GAC_TYPE: &str = ""; - //~^ ERROR missing lifetime specifier const GAC_LIFETIME<'a>: &str = ""; //~^ ERROR missing lifetime specifier } diff --git a/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr b/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr index d6e49c7ac588..2ecab3442a96 100644 --- a/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr +++ b/tests/ui/consts/static-default-lifetime/generic-associated-const.stderr @@ -1,16 +1,5 @@ error[E0106]: missing lifetime specifier - --> $DIR/generic-associated-const.rs:14:24 - | -LL | const GAC_TYPE: &str = ""; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | const GAC_TYPE<'a, T>: &'a str = ""; - | +++ ++ - -error[E0106]: missing lifetime specifier - --> $DIR/generic-associated-const.rs:16:29 + --> $DIR/generic-associated-const.rs:15:29 | LL | const GAC_LIFETIME<'a>: &str = ""; | ^ expected named lifetime parameter @@ -52,6 +41,6 @@ help: use the `'static` lifetime LL | const GAC_LIFETIME<'a>: &'static str = ""; | +++++++ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0106`. diff --git a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.default.stderr b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.default.stderr index 24e2e0a0f7a2..71ac55bf0448 100644 --- a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.default.stderr +++ b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.default.stderr @@ -1,57 +1,25 @@ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-assoc-const-type.rs:6:14 - | -LL | const A: &str = ""; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL ~ trait ZstAssert<'a>: Sized { -LL ~ const A: &'a str = ""; - | - -error[E0106]: missing lifetime specifier +error[E0726]: implicit elided lifetime not allowed here --> $DIR/missing-lifetime-in-assoc-const-type.rs:7:14 | LL | const B: S = S { s: &() }; - | ^ expected named lifetime parameter + | ^ expected lifetime parameter | -help: consider introducing a named lifetime parameter - | -LL ~ trait ZstAssert<'a>: Sized { -LL | const A: &str = ""; -LL ~ const B: S<'a> = S { s: &() }; +help: indicate the anonymous lifetime | +LL | const B: S<'_> = S { s: &() }; + | ++++ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-assoc-const-type.rs:8:15 - | -LL | const C: &'_ str = ""; - | ^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL ~ trait ZstAssert<'a>: Sized { -LL | const A: &str = ""; -LL | const B: S = S { s: &() }; -LL ~ const C: &'a str = ""; - | - -error[E0106]: missing lifetime specifiers +error[E0726]: implicit elided lifetime not allowed here --> $DIR/missing-lifetime-in-assoc-const-type.rs:9:14 | LL | const D: T = T { a: &(), b: &() }; - | ^ expected 2 lifetime parameters + | ^ expected lifetime parameters | -help: consider introducing a named lifetime parameter - | -LL ~ trait ZstAssert<'a>: Sized { -LL | const A: &str = ""; -LL | const B: S = S { s: &() }; -LL | const C: &'_ str = ""; -LL ~ const D: T<'a, 'a> = T { a: &(), b: &() }; +help: indicate the anonymous lifetimes | +LL | const D: T<'_, '_> = T { a: &(), b: &() }; + | ++++++++ -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0726`. diff --git a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.generic_const_items.stderr b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.generic_const_items.stderr index a97ffe7da79e..71ac55bf0448 100644 --- a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.generic_const_items.stderr +++ b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.generic_const_items.stderr @@ -1,47 +1,25 @@ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-assoc-const-type.rs:6:14 - | -LL | const A: &str = ""; - | ^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | const A<'a>: &'a str = ""; - | ++++ ++ - -error[E0106]: missing lifetime specifier +error[E0726]: implicit elided lifetime not allowed here --> $DIR/missing-lifetime-in-assoc-const-type.rs:7:14 | LL | const B: S = S { s: &() }; - | ^ expected named lifetime parameter + | ^ expected lifetime parameter | -help: consider introducing a named lifetime parameter +help: indicate the anonymous lifetime | -LL | const B<'a>: S<'a> = S { s: &() }; - | ++++ ++++ +LL | const B: S<'_> = S { s: &() }; + | ++++ -error[E0106]: missing lifetime specifier - --> $DIR/missing-lifetime-in-assoc-const-type.rs:8:15 - | -LL | const C: &'_ str = ""; - | ^^ expected named lifetime parameter - | -help: consider introducing a named lifetime parameter - | -LL | const C<'a>: &'a str = ""; - | ++++ ~~ - -error[E0106]: missing lifetime specifiers +error[E0726]: implicit elided lifetime not allowed here --> $DIR/missing-lifetime-in-assoc-const-type.rs:9:14 | LL | const D: T = T { a: &(), b: &() }; - | ^ expected 2 lifetime parameters + | ^ expected lifetime parameters | -help: consider introducing a named lifetime parameter +help: indicate the anonymous lifetimes | -LL | const D<'a>: T<'a, 'a> = T { a: &(), b: &() }; - | ++++ ++++++++ +LL | const D: T<'_, '_> = T { a: &(), b: &() }; + | ++++++++ -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0106`. +For more information about this error, try `rustc --explain E0726`. diff --git a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs index f36a6567e423..a60f0b94587f 100644 --- a/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs +++ b/tests/ui/suggestions/missing-lifetime-in-assoc-const-type.rs @@ -3,10 +3,10 @@ #![cfg_attr(generic_const_items, feature(generic_const_items), allow(incomplete_features))] trait ZstAssert: Sized { - const A: &str = ""; //~ ERROR missing lifetime specifier - const B: S = S { s: &() }; //~ ERROR missing lifetime specifier - const C: &'_ str = ""; //~ ERROR missing lifetime specifier - const D: T = T { a: &(), b: &() }; //~ ERROR missing lifetime specifier + const A: &str = ""; + const B: S = S { s: &() }; //~ ERROR implicit elided lifetime not allowed here + const C: &'_ str = ""; + const D: T = T { a: &(), b: &() }; //~ ERROR implicit elided lifetime not allowed here } struct S<'a> { From f3dd4b16bcb90b96c0617415725aecc57e41f4b9 Mon Sep 17 00:00:00 2001 From: Ana Hobden Date: Wed, 12 Jun 2024 13:16:28 -0700 Subject: [PATCH 11/48] Pass target to run-make issue-47551 --- tests/run-make/issue-47551/Makefile | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-make/issue-47551/Makefile b/tests/run-make/issue-47551/Makefile index 5a6ac725701b..3fe0a6e74e02 100644 --- a/tests/run-make/issue-47551/Makefile +++ b/tests/run-make/issue-47551/Makefile @@ -4,6 +4,7 @@ include ../tools.mk all: - $(RUSTC) eh_frame-terminator.rs + # --target $(TARGET) ensures the right gcc flags are used for cross compilation + $(RUSTC) --target $(TARGET) eh_frame-terminator.rs $(call RUN,eh_frame-terminator) | $(CGREP) '1122334455667788' objdump --dwarf=frames $(TMPDIR)/eh_frame-terminator | $(CGREP) 'ZERO terminator' From 6cce48838b230ed429cb8e69d207993ebff00dd7 Mon Sep 17 00:00:00 2001 From: Slanterns Date: Sun, 16 Jun 2024 06:31:37 +0800 Subject: [PATCH 12/48] update comment --- library/core/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 042a8c9925f3..150e4f3f3185 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -928,7 +928,7 @@ pub(crate) mod tags { /// An `Option` with a type tag `I`. /// /// Since this struct implements `Erased`, the type can be erased to make a dynamically typed -/// option. The type can be checked dynamically using `Erased::tag_id` and since this is statically +/// option. The type can be checked dynamically using `Tagged::tag_id` and since this is statically /// checked for the concrete type, there is some degree of type safety. #[repr(transparent)] pub(crate) struct TaggedOption<'a, I: tags::Type<'a>>(pub Option); From 240478383bfa73e165bb677e6d5ecafe48523f45 Mon Sep 17 00:00:00 2001 From: Slanterns Date: Sun, 16 Jun 2024 07:43:08 +0800 Subject: [PATCH 13/48] add codegen test for `Error::provide` --- tests/codegen/error-provide.rs | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/codegen/error-provide.rs diff --git a/tests/codegen/error-provide.rs b/tests/codegen/error-provide.rs new file mode 100644 index 000000000000..e80905eee110 --- /dev/null +++ b/tests/codegen/error-provide.rs @@ -0,0 +1,48 @@ +// Codegen test for #126242 + +//@ compile-flags: -O +#![crate_type = "lib"] +#![feature(error_generic_member_access)] +use std::error::Request; +use std::fmt; + +#[derive(Debug)] +struct MyBacktrace1 {} + +#[derive(Debug)] +struct MyBacktrace2 {} + +#[derive(Debug)] +struct MyBacktrace3 {} + +#[derive(Debug)] +struct MyError { + backtrace1: MyBacktrace1, + backtrace2: MyBacktrace2, + backtrace3: MyBacktrace3, + other: MyBacktrace3, +} + +impl fmt::Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Example Error") + } +} + +impl std::error::Error for MyError { + // CHECK-LABEL: @provide + #[no_mangle] + fn provide<'a>(&'a self, request: &mut Request<'a>) { + // LLVM should be able to optimize multiple .provide_* calls into a switch table + // and eliminate redundant ones, rather than compare one-by-one. + + // CHECK: switch i64 %{{.*}}, label %{{.*}} [ + // CHECK-COUNT-3: i64 {{.*}}, label %{{.*}} + // CHECK-NEXT: ] + request + .provide_ref::(&self.backtrace1) + .provide_ref::(&self.other) + .provide_ref::(&self.backtrace2) + .provide_ref::(&self.backtrace3); + } +} From e102d2dbd6ce19f1d63d6f88903b0412cd9bb102 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Jun 2024 01:04:40 +1000 Subject: [PATCH 14/48] coverage: More consistent variable names for span processing --- .../rustc_mir_transform/src/coverage/spans.rs | 8 ++-- .../src/coverage/spans/from_mir.rs | 42 +++++++++---------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index bb6a666ff73b..6e3a27ca2614 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -19,11 +19,11 @@ pub(super) fn extract_refined_covspans( basic_coverage_blocks: &CoverageGraph, code_mappings: &mut impl Extend, ) { - let sorted_span_buckets = + let buckets = from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks); - for bucket in sorted_span_buckets { - let refined_spans = refine_sorted_spans(bucket); - code_mappings.extend(refined_spans.into_iter().map(|RefinedCovspan { span, bcb }| { + for covspans in buckets { + let covspans = refine_sorted_spans(covspans); + code_mappings.extend(covspans.into_iter().map(|RefinedCovspan { span, bcb }| { // Each span produced by the refiner represents an ordinary code region. mappings::CodeMapping { span, bcb } })); diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index b1f71035dded..be2e07803164 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -31,7 +31,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( ) -> Vec> { let &ExtractedHirInfo { body_span, .. } = hir_info; - let mut initial_spans = vec![]; + let mut covspans = vec![]; let mut holes = vec![]; for (bcb, bcb_data) in basic_coverage_blocks.iter_enumerated() { @@ -40,36 +40,36 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( body_span, bcb, bcb_data, - &mut initial_spans, + &mut covspans, &mut holes, ); } // Only add the signature span if we found at least one span in the body. - if !initial_spans.is_empty() || !holes.is_empty() { + if !covspans.is_empty() || !holes.is_empty() { // If there is no usable signature span, add a fake one (before refinement) // to avoid an ugly gap between the body start and the first real span. // FIXME: Find a more principled way to solve this problem. let fn_sig_span = hir_info.fn_sig_span_extended.unwrap_or_else(|| body_span.shrink_to_lo()); - initial_spans.push(SpanFromMir::for_fn_sig(fn_sig_span)); + covspans.push(SpanFromMir::for_fn_sig(fn_sig_span)); } - initial_spans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); - remove_unwanted_macro_spans(&mut initial_spans); - split_visible_macro_spans(&mut initial_spans); + covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); + remove_unwanted_macro_spans(&mut covspans); + split_visible_macro_spans(&mut covspans); let compare_covspans = |a: &SpanFromMir, b: &SpanFromMir| { compare_spans(a.span, b.span) // After deduplication, we want to keep only the most-dominated BCB. .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse()) }; - initial_spans.sort_by(compare_covspans); + covspans.sort_by(compare_covspans); // Among covspans with the same span, keep only one, // preferring the one with the most-dominated BCB. // (Ideally we should try to preserve _all_ non-dominating BCBs, but that // requires a lot more complexity in the span refiner, for little benefit.) - initial_spans.dedup_by(|b, a| a.span.source_equal(b.span)); + covspans.dedup_by(|b, a| a.span.source_equal(b.span)); // Sort the holes, and merge overlapping/adjacent holes. holes.sort_by(|a, b| compare_spans(a.span, b.span)); @@ -78,7 +78,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( // Now we're ready to start carving holes out of the initial coverage spans, // and grouping them in buckets separated by the holes. - let mut initial_spans = VecDeque::from(initial_spans); + let mut input_covspans = VecDeque::from(covspans); let mut fragments: Vec = vec![]; // For each hole: @@ -93,10 +93,10 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( // Only inspect spans that precede or overlap this hole, // leaving the rest to be inspected by later holes. // (This relies on the spans and holes both being sorted.) - let relevant_initial_spans = - drain_front_while(&mut initial_spans, |c| c.span.lo() < hole.span.hi()); + let relevant_input_covspans = + drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()); - for covspan in fragments_from_prev.into_iter().chain(relevant_initial_spans) { + for covspan in fragments_from_prev.into_iter().chain(relevant_input_covspans) { let (before, after) = covspan.split_around_hole_span(hole.span); bucket.extend(before); fragments.extend(after); @@ -106,12 +106,12 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( // After finding the spans before each hole, any remaining fragments/spans // form their own final bucket, after the final hole. // (If there were no holes, this will just be all of the initial spans.) - fragments.extend(initial_spans); + fragments.extend(input_covspans); buckets.push(fragments); // Make sure each individual bucket is still internally sorted. - for bucket in &mut buckets { - bucket.sort_by(compare_covspans); + for covspans in &mut buckets { + covspans.sort_by(compare_covspans); } buckets } @@ -143,9 +143,9 @@ fn drain_front_while<'a, T>( /// /// (The input spans should be sorted in BCB dominator order, so that the /// retained "first" span is likely to dominate the others.) -fn remove_unwanted_macro_spans(initial_spans: &mut Vec) { +fn remove_unwanted_macro_spans(covspans: &mut Vec) { let mut seen_macro_spans = FxHashSet::default(); - initial_spans.retain(|covspan| { + covspans.retain(|covspan| { // Ignore (retain) non-macro-expansion spans. if covspan.visible_macro.is_none() { return true; @@ -160,10 +160,10 @@ fn remove_unwanted_macro_spans(initial_spans: &mut Vec) { /// function body, split it into two parts. The first part covers just the /// macro name plus `!`, and the second part covers the rest of the macro /// invocation. This seems to give better results for code that uses macros. -fn split_visible_macro_spans(initial_spans: &mut Vec) { +fn split_visible_macro_spans(covspans: &mut Vec) { let mut extra_spans = vec![]; - initial_spans.retain(|covspan| { + covspans.retain(|covspan| { let Some(visible_macro) = covspan.visible_macro else { return true }; let split_len = visible_macro.as_str().len() as u32 + 1; @@ -183,7 +183,7 @@ fn split_visible_macro_spans(initial_spans: &mut Vec) { // The newly-split spans are added at the end, so any previous sorting // is not preserved. - initial_spans.extend(extra_spans); + covspans.extend(extra_spans); } // Generate a set of coverage spans from the filtered set of `Statement`s and `Terminator`s of From bf74fb1d2f39afa6948e8be39a6a2e72fcc2e83f Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Jun 2024 01:11:32 +1000 Subject: [PATCH 15/48] coverage: Move most span processing back into `coverage::spans` --- .../rustc_mir_transform/src/coverage/spans.rs | 144 ++++++++++++++- .../src/coverage/spans/from_mir.rs | 168 ++---------------- 2 files changed, 157 insertions(+), 155 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 6e3a27ca2614..11fc297911ea 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,9 +1,15 @@ +use std::collections::VecDeque; + +use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashSet; use rustc_middle::mir; use rustc_span::Span; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::mappings; -use crate::coverage::spans::from_mir::SpanFromMir; +use crate::coverage::spans::from_mir::{ + extract_covspans_and_holes_from_mir, ExtractedCovspans, SpanFromMir, +}; use crate::coverage::ExtractedHirInfo; mod from_mir; @@ -19,9 +25,68 @@ pub(super) fn extract_refined_covspans( basic_coverage_blocks: &CoverageGraph, code_mappings: &mut impl Extend, ) { - let buckets = - from_mir::mir_to_initial_sorted_coverage_spans(mir_body, hir_info, basic_coverage_blocks); - for covspans in buckets { + let ExtractedCovspans { mut covspans, mut holes } = + extract_covspans_and_holes_from_mir(mir_body, hir_info, basic_coverage_blocks); + + covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); + remove_unwanted_macro_spans(&mut covspans); + split_visible_macro_spans(&mut covspans); + + let compare_covspans = |a: &SpanFromMir, b: &SpanFromMir| { + compare_spans(a.span, b.span) + // After deduplication, we want to keep only the most-dominated BCB. + .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse()) + }; + covspans.sort_by(compare_covspans); + + // Among covspans with the same span, keep only one, + // preferring the one with the most-dominated BCB. + // (Ideally we should try to preserve _all_ non-dominating BCBs, but that + // requires a lot more complexity in the span refiner, for little benefit.) + covspans.dedup_by(|b, a| a.span.source_equal(b.span)); + + // Sort the holes, and merge overlapping/adjacent holes. + holes.sort_by(|a, b| compare_spans(a.span, b.span)); + holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); + + // Now we're ready to start carving holes out of the initial coverage spans, + // and grouping them in buckets separated by the holes. + + let mut input_covspans = VecDeque::from(covspans); + let mut fragments: Vec = vec![]; + + // For each hole: + // - Identify the spans that are entirely or partly before the hole. + // - Put those spans in a corresponding bucket, truncated to the start of the hole. + // - If one of those spans also extends after the hole, put the rest of it + // in a "fragments" vector that is processed by the next hole. + let mut buckets = (0..holes.len()).map(|_| vec![]).collect::>(); + for (hole, bucket) in holes.iter().zip(&mut buckets) { + let fragments_from_prev = std::mem::take(&mut fragments); + + // Only inspect spans that precede or overlap this hole, + // leaving the rest to be inspected by later holes. + // (This relies on the spans and holes both being sorted.) + let relevant_input_covspans = + drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()); + + for covspan in fragments_from_prev.into_iter().chain(relevant_input_covspans) { + let (before, after) = covspan.split_around_hole_span(hole.span); + bucket.extend(before); + fragments.extend(after); + } + } + + // After finding the spans before each hole, any remaining fragments/spans + // form their own final bucket, after the final hole. + // (If there were no holes, this will just be all of the initial spans.) + fragments.extend(input_covspans); + buckets.push(fragments); + + for mut covspans in buckets { + // Make sure each individual bucket is internally sorted. + covspans.sort_by(compare_covspans); + let covspans = refine_sorted_spans(covspans); code_mappings.extend(covspans.into_iter().map(|RefinedCovspan { span, bcb }| { // Each span produced by the refiner represents an ordinary code region. @@ -30,6 +95,56 @@ pub(super) fn extract_refined_covspans( } } +/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate +/// multiple condition/consequent blocks that have the span of the whole macro +/// invocation, which is unhelpful. Keeping only the first such span seems to +/// give better mappings, so remove the others. +/// +/// (The input spans should be sorted in BCB dominator order, so that the +/// retained "first" span is likely to dominate the others.) +fn remove_unwanted_macro_spans(covspans: &mut Vec) { + let mut seen_macro_spans = FxHashSet::default(); + covspans.retain(|covspan| { + // Ignore (retain) non-macro-expansion spans. + if covspan.visible_macro.is_none() { + return true; + } + + // Retain only the first macro-expanded covspan with this span. + seen_macro_spans.insert(covspan.span) + }); +} + +/// When a span corresponds to a macro invocation that is visible from the +/// function body, split it into two parts. The first part covers just the +/// macro name plus `!`, and the second part covers the rest of the macro +/// invocation. This seems to give better results for code that uses macros. +fn split_visible_macro_spans(covspans: &mut Vec) { + let mut extra_spans = vec![]; + + covspans.retain(|covspan| { + let Some(visible_macro) = covspan.visible_macro else { return true }; + + let split_len = visible_macro.as_str().len() as u32 + 1; + let (before, after) = covspan.span.split_at(split_len); + if !covspan.span.contains(before) || !covspan.span.contains(after) { + // Something is unexpectedly wrong with the split point. + // The debug assertion in `split_at` will have already caught this, + // but in release builds it's safer to do nothing and maybe get a + // bug report for unexpected coverage, rather than risk an ICE. + return true; + } + + extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb)); + extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb)); + false // Discard the original covspan that we just split. + }); + + // The newly-split spans are added at the end, so any previous sorting + // is not preserved. + covspans.extend(extra_spans); +} + #[derive(Debug)] struct RefinedCovspan { span: Span, @@ -47,6 +162,15 @@ impl RefinedCovspan { } } +/// Similar to `.drain(..)`, but stops just before it would remove an item not +/// satisfying the predicate. +fn drain_front_while<'a, T>( + queue: &'a mut VecDeque, + mut pred_fn: impl FnMut(&T) -> bool, +) -> impl Iterator + Captures<'a> { + std::iter::from_fn(move || if pred_fn(queue.front()?) { queue.pop_front() } else { None }) +} + /// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines" /// those spans by removing spans that overlap in unwanted ways, and by merging /// compatible adjacent spans. @@ -94,3 +218,15 @@ fn refine_sorted_spans(sorted_spans: Vec) -> Vec { refined } + +/// Compares two spans in (lo ascending, hi descending) order. +fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering { + // First sort by span start. + Ord::cmp(&a.lo(), &b.lo()) + // If span starts are the same, sort by span end in reverse order. + // This ensures that if spans A and B are adjacent in the list, + // and they overlap but are not equal, then either: + // - Span A extends further left, or + // - Both have the same start and span A extends further right + .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse()) +} diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index be2e07803164..1508a893b582 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -1,7 +1,3 @@ -use std::collections::VecDeque; - -use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashSet; use rustc_middle::bug; use rustc_middle::mir::coverage::CoverageKind; use rustc_middle::mir::{ @@ -15,20 +11,19 @@ use crate::coverage::graph::{ }; use crate::coverage::ExtractedHirInfo; +pub(crate) struct ExtractedCovspans { + pub(crate) covspans: Vec, + pub(crate) holes: Vec, +} + /// Traverses the MIR body to produce an initial collection of coverage-relevant /// spans, each associated with a node in the coverage graph (BCB) and possibly /// other metadata. -/// -/// The returned spans are divided into one or more buckets, such that: -/// - The spans in each bucket are strictly after all spans in previous buckets, -/// and strictly before all spans in subsequent buckets. -/// - The contents of each bucket are also sorted, in a specific order that is -/// expected by the subsequent span-refinement step. -pub(super) fn mir_to_initial_sorted_coverage_spans( +pub(crate) fn extract_covspans_and_holes_from_mir( mir_body: &mir::Body<'_>, hir_info: &ExtractedHirInfo, basic_coverage_blocks: &CoverageGraph, -) -> Vec> { +) -> ExtractedCovspans { let &ExtractedHirInfo { body_span, .. } = hir_info; let mut covspans = vec![]; @@ -54,136 +49,7 @@ pub(super) fn mir_to_initial_sorted_coverage_spans( covspans.push(SpanFromMir::for_fn_sig(fn_sig_span)); } - covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); - remove_unwanted_macro_spans(&mut covspans); - split_visible_macro_spans(&mut covspans); - - let compare_covspans = |a: &SpanFromMir, b: &SpanFromMir| { - compare_spans(a.span, b.span) - // After deduplication, we want to keep only the most-dominated BCB. - .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse()) - }; - covspans.sort_by(compare_covspans); - - // Among covspans with the same span, keep only one, - // preferring the one with the most-dominated BCB. - // (Ideally we should try to preserve _all_ non-dominating BCBs, but that - // requires a lot more complexity in the span refiner, for little benefit.) - covspans.dedup_by(|b, a| a.span.source_equal(b.span)); - - // Sort the holes, and merge overlapping/adjacent holes. - holes.sort_by(|a, b| compare_spans(a.span, b.span)); - holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); - - // Now we're ready to start carving holes out of the initial coverage spans, - // and grouping them in buckets separated by the holes. - - let mut input_covspans = VecDeque::from(covspans); - let mut fragments: Vec = vec![]; - - // For each hole: - // - Identify the spans that are entirely or partly before the hole. - // - Put those spans in a corresponding bucket, truncated to the start of the hole. - // - If one of those spans also extends after the hole, put the rest of it - // in a "fragments" vector that is processed by the next hole. - let mut buckets = (0..holes.len()).map(|_| vec![]).collect::>(); - for (hole, bucket) in holes.iter().zip(&mut buckets) { - let fragments_from_prev = std::mem::take(&mut fragments); - - // Only inspect spans that precede or overlap this hole, - // leaving the rest to be inspected by later holes. - // (This relies on the spans and holes both being sorted.) - let relevant_input_covspans = - drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()); - - for covspan in fragments_from_prev.into_iter().chain(relevant_input_covspans) { - let (before, after) = covspan.split_around_hole_span(hole.span); - bucket.extend(before); - fragments.extend(after); - } - } - - // After finding the spans before each hole, any remaining fragments/spans - // form their own final bucket, after the final hole. - // (If there were no holes, this will just be all of the initial spans.) - fragments.extend(input_covspans); - buckets.push(fragments); - - // Make sure each individual bucket is still internally sorted. - for covspans in &mut buckets { - covspans.sort_by(compare_covspans); - } - buckets -} - -fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering { - // First sort by span start. - Ord::cmp(&a.lo(), &b.lo()) - // If span starts are the same, sort by span end in reverse order. - // This ensures that if spans A and B are adjacent in the list, - // and they overlap but are not equal, then either: - // - Span A extends further left, or - // - Both have the same start and span A extends further right - .then_with(|| Ord::cmp(&a.hi(), &b.hi()).reverse()) -} - -/// Similar to `.drain(..)`, but stops just before it would remove an item not -/// satisfying the predicate. -fn drain_front_while<'a, T>( - queue: &'a mut VecDeque, - mut pred_fn: impl FnMut(&T) -> bool, -) -> impl Iterator + Captures<'a> { - std::iter::from_fn(move || if pred_fn(queue.front()?) { queue.pop_front() } else { None }) -} - -/// Macros that expand into branches (e.g. `assert!`, `trace!`) tend to generate -/// multiple condition/consequent blocks that have the span of the whole macro -/// invocation, which is unhelpful. Keeping only the first such span seems to -/// give better mappings, so remove the others. -/// -/// (The input spans should be sorted in BCB dominator order, so that the -/// retained "first" span is likely to dominate the others.) -fn remove_unwanted_macro_spans(covspans: &mut Vec) { - let mut seen_macro_spans = FxHashSet::default(); - covspans.retain(|covspan| { - // Ignore (retain) non-macro-expansion spans. - if covspan.visible_macro.is_none() { - return true; - } - - // Retain only the first macro-expanded covspan with this span. - seen_macro_spans.insert(covspan.span) - }); -} - -/// When a span corresponds to a macro invocation that is visible from the -/// function body, split it into two parts. The first part covers just the -/// macro name plus `!`, and the second part covers the rest of the macro -/// invocation. This seems to give better results for code that uses macros. -fn split_visible_macro_spans(covspans: &mut Vec) { - let mut extra_spans = vec![]; - - covspans.retain(|covspan| { - let Some(visible_macro) = covspan.visible_macro else { return true }; - - let split_len = visible_macro.as_str().len() as u32 + 1; - let (before, after) = covspan.span.split_at(split_len); - if !covspan.span.contains(before) || !covspan.span.contains(after) { - // Something is unexpectedly wrong with the split point. - // The debug assertion in `split_at` will have already caught this, - // but in release builds it's safer to do nothing and maybe get a - // bug report for unexpected coverage, rather than risk an ICE. - return true; - } - - extra_spans.push(SpanFromMir::new(before, covspan.visible_macro, covspan.bcb)); - extra_spans.push(SpanFromMir::new(after, covspan.visible_macro, covspan.bcb)); - false // Discard the original covspan that we just split. - }); - - // The newly-split spans are added at the end, so any previous sorting - // is not preserved. - covspans.extend(extra_spans); + ExtractedCovspans { covspans, holes } } // Generate a set of coverage spans from the filtered set of `Statement`s and `Terminator`s of @@ -402,12 +268,12 @@ fn unexpand_into_body_span_with_prev( } #[derive(Debug)] -struct Hole { - span: Span, +pub(crate) struct Hole { + pub(crate) span: Span, } impl Hole { - fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool { + pub(crate) fn merge_if_overlapping_or_adjacent(&mut self, other: &mut Self) -> bool { if !self.span.overlaps_or_adjacent(other.span) { return false; } @@ -418,7 +284,7 @@ impl Hole { } #[derive(Debug)] -pub(super) struct SpanFromMir { +pub(crate) struct SpanFromMir { /// A span that has been extracted from MIR and then "un-expanded" back to /// within the current function's `body_span`. After various intermediate /// processing steps, this span is emitted as part of the final coverage @@ -426,9 +292,9 @@ pub(super) struct SpanFromMir { /// /// With the exception of `fn_sig_span`, this should always be contained /// within `body_span`. - pub(super) span: Span, - visible_macro: Option, - pub(super) bcb: BasicCoverageBlock, + pub(crate) span: Span, + pub(crate) visible_macro: Option, + pub(crate) bcb: BasicCoverageBlock, } impl SpanFromMir { @@ -436,14 +302,14 @@ impl SpanFromMir { Self::new(fn_sig_span, None, START_BCB) } - fn new(span: Span, visible_macro: Option, bcb: BasicCoverageBlock) -> Self { + pub(crate) fn new(span: Span, visible_macro: Option, bcb: BasicCoverageBlock) -> Self { Self { span, visible_macro, bcb } } /// Splits this span into 0-2 parts: /// - The part that is strictly before the hole span, if any. /// - The part that is strictly after the hole span, if any. - fn split_around_hole_span(&self, hole_span: Span) -> (Option, Option) { + pub(crate) fn split_around_hole_span(&self, hole_span: Span) -> (Option, Option) { let before = try { let span = self.span.trim_end(hole_span)?; Self { span, ..*self } From 88ade9c740c0f7fad269c51a7ad15baa5cb07115 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Jun 2024 01:25:05 +1000 Subject: [PATCH 16/48] coverage: Eagerly convert coverage spans to a simpler form --- .../rustc_mir_transform/src/coverage/spans.rs | 86 +++++++++++-------- .../src/coverage/spans/from_mir.rs | 18 +--- 2 files changed, 55 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 11fc297911ea..122a7957a1fd 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -28,11 +28,15 @@ pub(super) fn extract_refined_covspans( let ExtractedCovspans { mut covspans, mut holes } = extract_covspans_and_holes_from_mir(mir_body, hir_info, basic_coverage_blocks); + // First, perform the passes that need macro information. covspans.sort_by(|a, b| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb)); remove_unwanted_macro_spans(&mut covspans); split_visible_macro_spans(&mut covspans); - let compare_covspans = |a: &SpanFromMir, b: &SpanFromMir| { + // We no longer need the extra information in `SpanFromMir`, so convert to `Covspan`. + let mut covspans = covspans.into_iter().map(SpanFromMir::into_covspan).collect::>(); + + let compare_covspans = |a: &Covspan, b: &Covspan| { compare_spans(a.span, b.span) // After deduplication, we want to keep only the most-dominated BCB. .then_with(|| basic_coverage_blocks.cmp_in_dominator_order(a.bcb, b.bcb).reverse()) @@ -53,7 +57,7 @@ pub(super) fn extract_refined_covspans( // and grouping them in buckets separated by the holes. let mut input_covspans = VecDeque::from(covspans); - let mut fragments: Vec = vec![]; + let mut fragments = vec![]; // For each hole: // - Identify the spans that are entirely or partly before the hole. @@ -88,7 +92,7 @@ pub(super) fn extract_refined_covspans( covspans.sort_by(compare_covspans); let covspans = refine_sorted_spans(covspans); - code_mappings.extend(covspans.into_iter().map(|RefinedCovspan { span, bcb }| { + code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { // Each span produced by the refiner represents an ordinary code region. mappings::CodeMapping { span, bcb } })); @@ -145,23 +149,6 @@ fn split_visible_macro_spans(covspans: &mut Vec) { covspans.extend(extra_spans); } -#[derive(Debug)] -struct RefinedCovspan { - span: Span, - bcb: BasicCoverageBlock, -} - -impl RefinedCovspan { - fn is_mergeable(&self, other: &Self) -> bool { - self.bcb == other.bcb - } - - fn merge_from(&mut self, other: &Self) { - debug_assert!(self.is_mergeable(other)); - self.span = self.span.to(other.span); - } -} - /// Similar to `.drain(..)`, but stops just before it would remove an item not /// satisfying the predicate. fn drain_front_while<'a, T>( @@ -175,18 +162,18 @@ fn drain_front_while<'a, T>( /// those spans by removing spans that overlap in unwanted ways, and by merging /// compatible adjacent spans. #[instrument(level = "debug")] -fn refine_sorted_spans(sorted_spans: Vec) -> Vec { +fn refine_sorted_spans(sorted_spans: Vec) -> Vec { // Holds spans that have been read from the input vector, but haven't yet // been committed to the output vector. let mut pending = vec![]; let mut refined = vec![]; for curr in sorted_spans { - pending.retain(|prev: &SpanFromMir| { + pending.retain(|prev: &Covspan| { if prev.span.hi() <= curr.span.lo() { // There's no overlap between the previous/current covspans, // so move the previous one into the refined list. - refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb }); + refined.push(prev.clone()); false } else { // Otherwise, retain the previous covspan only if it has the @@ -199,26 +186,55 @@ fn refine_sorted_spans(sorted_spans: Vec) -> Vec { } // Drain the rest of the pending list into the refined list. - for prev in pending { - refined.push(RefinedCovspan { span: prev.span, bcb: prev.bcb }); - } + refined.extend(pending); // Do one last merge pass, to simplify the output. debug!(?refined, "before merge"); - refined.dedup_by(|b, a| { - if a.is_mergeable(b) { - debug!(?a, ?b, "merging list-adjacent refined spans"); - a.merge_from(b); - true - } else { - false - } - }); + refined.dedup_by(|b, a| a.merge_if_eligible(b)); debug!(?refined, "after merge"); refined } +#[derive(Clone, Debug)] +struct Covspan { + span: Span, + bcb: BasicCoverageBlock, +} + +impl Covspan { + /// Splits this covspan into 0-2 parts: + /// - The part that is strictly before the hole span, if any. + /// - The part that is strictly after the hole span, if any. + fn split_around_hole_span(&self, hole_span: Span) -> (Option, Option) { + let before = try { + let span = self.span.trim_end(hole_span)?; + Self { span, ..*self } + }; + let after = try { + let span = self.span.trim_start(hole_span)?; + Self { span, ..*self } + }; + + (before, after) + } + + /// If `self` and `other` can be merged (i.e. they have the same BCB), + /// mutates `self.span` to also include `other.span` and returns true. + /// + /// Note that compatible covspans can be merged even if their underlying + /// spans are not overlapping/adjacent; any space between them will also be + /// part of the merged covspan. + fn merge_if_eligible(&mut self, other: &Self) -> bool { + if self.bcb != other.bcb { + return false; + } + + self.span = self.span.to(other.span); + true + } +} + /// Compares two spans in (lo ascending, hi descending) order. fn compare_spans(a: Span, b: Span) -> std::cmp::Ordering { // First sort by span start. diff --git a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs index 1508a893b582..09deb7534bfd 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans/from_mir.rs @@ -9,6 +9,7 @@ use rustc_span::{ExpnKind, MacroKind, Span, Symbol}; use crate::coverage::graph::{ BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB, }; +use crate::coverage::spans::Covspan; use crate::coverage::ExtractedHirInfo; pub(crate) struct ExtractedCovspans { @@ -306,19 +307,8 @@ impl SpanFromMir { Self { span, visible_macro, bcb } } - /// Splits this span into 0-2 parts: - /// - The part that is strictly before the hole span, if any. - /// - The part that is strictly after the hole span, if any. - pub(crate) fn split_around_hole_span(&self, hole_span: Span) -> (Option, Option) { - let before = try { - let span = self.span.trim_end(hole_span)?; - Self { span, ..*self } - }; - let after = try { - let span = self.span.trim_start(hole_span)?; - Self { span, ..*self } - }; - - (before, after) + pub(crate) fn into_covspan(self) -> Covspan { + let Self { span, visible_macro: _, bcb } = self; + Covspan { span, bcb } } } From 118f66c237acee3f4a1fd4a773d4b2ccabd93851 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Jun 2024 01:28:22 +1000 Subject: [PATCH 17/48] coverage: Split out a function for dividing coverage spans into buckets --- .../rustc_mir_transform/src/coverage/spans.rs | 86 +++++++++++-------- 1 file changed, 52 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 122a7957a1fd..dbc6718636fa 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -8,7 +8,7 @@ use rustc_span::Span; use crate::coverage::graph::{BasicCoverageBlock, CoverageGraph}; use crate::coverage::mappings; use crate::coverage::spans::from_mir::{ - extract_covspans_and_holes_from_mir, ExtractedCovspans, SpanFromMir, + extract_covspans_and_holes_from_mir, ExtractedCovspans, Hole, SpanFromMir, }; use crate::coverage::ExtractedHirInfo; @@ -53,39 +53,8 @@ pub(super) fn extract_refined_covspans( holes.sort_by(|a, b| compare_spans(a.span, b.span)); holes.dedup_by(|b, a| a.merge_if_overlapping_or_adjacent(b)); - // Now we're ready to start carving holes out of the initial coverage spans, - // and grouping them in buckets separated by the holes. - - let mut input_covspans = VecDeque::from(covspans); - let mut fragments = vec![]; - - // For each hole: - // - Identify the spans that are entirely or partly before the hole. - // - Put those spans in a corresponding bucket, truncated to the start of the hole. - // - If one of those spans also extends after the hole, put the rest of it - // in a "fragments" vector that is processed by the next hole. - let mut buckets = (0..holes.len()).map(|_| vec![]).collect::>(); - for (hole, bucket) in holes.iter().zip(&mut buckets) { - let fragments_from_prev = std::mem::take(&mut fragments); - - // Only inspect spans that precede or overlap this hole, - // leaving the rest to be inspected by later holes. - // (This relies on the spans and holes both being sorted.) - let relevant_input_covspans = - drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()); - - for covspan in fragments_from_prev.into_iter().chain(relevant_input_covspans) { - let (before, after) = covspan.split_around_hole_span(hole.span); - bucket.extend(before); - fragments.extend(after); - } - } - - // After finding the spans before each hole, any remaining fragments/spans - // form their own final bucket, after the final hole. - // (If there were no holes, this will just be all of the initial spans.) - fragments.extend(input_covspans); - buckets.push(fragments); + // Split the covspans into separate buckets that don't overlap any holes. + let buckets = divide_spans_into_buckets(covspans, &holes); for mut covspans in buckets { // Make sure each individual bucket is internally sorted. @@ -149,6 +118,55 @@ fn split_visible_macro_spans(covspans: &mut Vec) { covspans.extend(extra_spans); } +/// Uses the holes to divide the given covspans into buckets, such that: +/// - No span in any hole overlaps a bucket (truncating the spans if necessary). +/// - The spans in each bucket are strictly after all spans in previous buckets, +/// and strictly before all spans in subsequent buckets. +/// +/// The resulting buckets are sorted relative to each other, but might not be +/// internally sorted. +#[instrument(level = "debug")] +fn divide_spans_into_buckets(input_covspans: Vec, holes: &[Hole]) -> Vec> { + debug_assert!(input_covspans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); + debug_assert!(holes.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); + + // Now we're ready to start carving holes out of the initial coverage spans, + // and grouping them in buckets separated by the holes. + + let mut input_covspans = VecDeque::from(input_covspans); + let mut fragments = vec![]; + + // For each hole: + // - Identify the spans that are entirely or partly before the hole. + // - Put those spans in a corresponding bucket, truncated to the start of the hole. + // - If one of those spans also extends after the hole, put the rest of it + // in a "fragments" vector that is processed by the next hole. + let mut buckets = (0..holes.len()).map(|_| vec![]).collect::>(); + for (hole, bucket) in holes.iter().zip(&mut buckets) { + let fragments_from_prev = std::mem::take(&mut fragments); + + // Only inspect spans that precede or overlap this hole, + // leaving the rest to be inspected by later holes. + // (This relies on the spans and holes both being sorted.) + let relevant_input_covspans = + drain_front_while(&mut input_covspans, |c| c.span.lo() < hole.span.hi()); + + for covspan in fragments_from_prev.into_iter().chain(relevant_input_covspans) { + let (before, after) = covspan.split_around_hole_span(hole.span); + bucket.extend(before); + fragments.extend(after); + } + } + + // After finding the spans before each hole, any remaining fragments/spans + // form their own final bucket, after the final hole. + // (If there were no holes, this will just be all of the initial spans.) + fragments.extend(input_covspans); + buckets.push(fragments); + + buckets +} + /// Similar to `.drain(..)`, but stops just before it would remove an item not /// satisfying the predicate. fn drain_front_while<'a, T>( From 2d3e6c88048fd19921346c9e945ccdf64fe97939 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sat, 15 Jun 2024 23:39:04 +1000 Subject: [PATCH 18/48] coverage: Split span refinement into two separate steps --- .../rustc_mir_transform/src/coverage/spans.rs | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index dbc6718636fa..84a70d1f02d7 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -59,8 +59,15 @@ pub(super) fn extract_refined_covspans( for mut covspans in buckets { // Make sure each individual bucket is internally sorted. covspans.sort_by(compare_covspans); + let _span = debug_span!("processing bucket", ?covspans).entered(); + + let mut covspans = remove_unwanted_overlapping_spans(covspans); + debug!(?covspans, "after removing overlaps"); + + // Do one last merge pass, to simplify the output. + covspans.dedup_by(|b, a| a.merge_if_eligible(b)); + debug!(?covspans, "after merge"); - let covspans = refine_sorted_spans(covspans); code_mappings.extend(covspans.into_iter().map(|Covspan { span, bcb }| { // Each span produced by the refiner represents an ordinary code region. mappings::CodeMapping { span, bcb } @@ -177,10 +184,11 @@ fn drain_front_while<'a, T>( } /// Takes one of the buckets of (sorted) spans extracted from MIR, and "refines" -/// those spans by removing spans that overlap in unwanted ways, and by merging -/// compatible adjacent spans. +/// those spans by removing spans that overlap in unwanted ways. #[instrument(level = "debug")] -fn refine_sorted_spans(sorted_spans: Vec) -> Vec { +fn remove_unwanted_overlapping_spans(sorted_spans: Vec) -> Vec { + debug_assert!(sorted_spans.is_sorted_by(|a, b| compare_spans(a.span, b.span).is_le())); + // Holds spans that have been read from the input vector, but haven't yet // been committed to the output vector. let mut pending = vec![]; @@ -205,12 +213,6 @@ fn refine_sorted_spans(sorted_spans: Vec) -> Vec { // Drain the rest of the pending list into the refined list. refined.extend(pending); - - // Do one last merge pass, to simplify the output. - debug!(?refined, "before merge"); - refined.dedup_by(|b, a| a.merge_if_eligible(b)); - debug!(?refined, "after merge"); - refined } From 5eb30f06993ea1dab0926d81f6d407d894b593e8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Jun 2024 14:44:28 +1000 Subject: [PATCH 19/48] coverage: Remove some old low-value unit tests for graph traversal These tests might have originally been useful as an implementation aid, but now they don't provide enough value to justify the burden of updating them as the underlying code changes. The code they test is still exercised by the main end-to-end coverage tests. --- .../src/coverage/counters.rs | 5 - .../rustc_mir_transform/src/coverage/tests.rs | 106 ------------------ 2 files changed, 111 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index b5968517d772..a8b0f4a8d6df 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -168,11 +168,6 @@ impl CoverageCounters { self.counter_increment_sites.len() } - #[cfg(test)] - pub(super) fn num_expressions(&self) -> usize { - self.expressions.len() - } - fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> BcbCounter { if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) { bug!( diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index ca64688e6b87..048547dc9f54 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -24,7 +24,6 @@ //! globals is comparatively simpler. The easiest way is to wrap the test in a closure argument //! to: `rustc_span::create_default_session_globals_then(|| { test_here(); })`. -use super::counters; use super::graph::{self, BasicCoverageBlock}; use itertools::Itertools; @@ -551,108 +550,3 @@ fn test_covgraph_switchint_loop_then_inner_loop_else_break() { assert_successors(&basic_coverage_blocks, bcb(5), &[bcb(1)]); assert_successors(&basic_coverage_blocks, bcb(6), &[bcb(4)]); } - -#[test] -fn test_find_loop_backedges_none() { - let mir_body = goto_switchint(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - if false { - eprintln!( - "basic_coverage_blocks = {:?}", - basic_coverage_blocks.iter_enumerated().collect::>() - ); - eprintln!("successors = {:?}", basic_coverage_blocks.successors); - } - let backedges = graph::find_loop_backedges(&basic_coverage_blocks); - assert_eq!( - backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), - 0, - "backedges: {:?}", - backedges - ); -} - -#[test] -fn test_find_loop_backedges_one() { - let mir_body = switchint_then_loop_else_return(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - let backedges = graph::find_loop_backedges(&basic_coverage_blocks); - assert_eq!( - backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), - 1, - "backedges: {:?}", - backedges - ); - - assert_eq!(backedges[bcb(1)], &[bcb(3)]); -} - -#[test] -fn test_find_loop_backedges_two() { - let mir_body = switchint_loop_then_inner_loop_else_break(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - let backedges = graph::find_loop_backedges(&basic_coverage_blocks); - assert_eq!( - backedges.iter_enumerated().map(|(_bcb, backedges)| backedges.len()).sum::(), - 2, - "backedges: {:?}", - backedges - ); - - assert_eq!(backedges[bcb(1)], &[bcb(5)]); - assert_eq!(backedges[bcb(4)], &[bcb(6)]); -} - -#[test] -fn test_traverse_coverage_with_loops() { - let mir_body = switchint_loop_then_inner_loop_else_break(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - let mut traversed_in_order = Vec::new(); - let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks); - while let Some(bcb) = traversal.next() { - traversed_in_order.push(bcb); - } - - // bcb0 is visited first. Then bcb1 starts the first loop, and all remaining nodes, *except* - // bcb6 are inside the first loop. - assert_eq!( - *traversed_in_order.last().expect("should have elements"), - bcb(6), - "bcb6 should not be visited until all nodes inside the first loop have been visited" - ); -} - -#[test] -fn test_make_bcb_counters() { - rustc_span::create_default_session_globals_then(|| { - let mir_body = goto_switchint(); - let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); - // Historically this test would use `spans` internals to set up fake - // coverage spans for BCBs 1 and 2. Now we skip that step and just tell - // BCB counter construction that those BCBs have spans. - let bcb_has_coverage_spans = |bcb: BasicCoverageBlock| (1..=2).contains(&bcb.as_usize()); - let coverage_counters = counters::CoverageCounters::make_bcb_counters( - &basic_coverage_blocks, - bcb_has_coverage_spans, - ); - assert_eq!(coverage_counters.num_expressions(), 0); - - assert_eq!( - 0, // bcb1 has a `Counter` with id = 0 - match coverage_counters.bcb_counter(bcb(1)).expect("should have a counter") { - counters::BcbCounter::Counter { id, .. } => id, - _ => panic!("expected a Counter"), - } - .as_u32() - ); - - assert_eq!( - 1, // bcb2 has a `Counter` with id = 1 - match coverage_counters.bcb_counter(bcb(2)).expect("should have a counter") { - counters::BcbCounter::Counter { id, .. } => id, - _ => panic!("expected a Counter"), - } - .as_u32() - ); - }); -} From 917b455a872050b90474043f31ef657b338526ba Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Jun 2024 14:04:36 +1000 Subject: [PATCH 20/48] coverage: Reduce/simplify visibility in `coverage::graph` Using `pub(super)` makes it harder to move code between modules, and doesn't provide much privacy benefit over `pub(crate)`. --- .../rustc_mir_transform/src/coverage/graph.rs | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index fd74a2a97e2c..544195a80fca 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -14,16 +14,16 @@ use std::ops::{Index, IndexMut}; /// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s /// nodes are `BasicCoverageBlock`s, which encompass one or more MIR `BasicBlock`s. #[derive(Debug)] -pub(super) struct CoverageGraph { +pub(crate) struct CoverageGraph { bcbs: IndexVec, bb_to_bcb: IndexVec>, - pub successors: IndexVec>, - pub predecessors: IndexVec>, + pub(crate) successors: IndexVec>, + pub(crate) predecessors: IndexVec>, dominators: Option>, } impl CoverageGraph { - pub fn from_mir(mir_body: &mir::Body<'_>) -> Self { + pub(crate) fn from_mir(mir_body: &mir::Body<'_>) -> Self { let (bcbs, bb_to_bcb) = Self::compute_basic_coverage_blocks(mir_body); // Pre-transform MIR `BasicBlock` successors and predecessors into the BasicCoverageBlock @@ -135,24 +135,28 @@ impl CoverageGraph { } #[inline(always)] - pub fn iter_enumerated( + pub(crate) fn iter_enumerated( &self, ) -> impl Iterator { self.bcbs.iter_enumerated() } #[inline(always)] - pub fn bcb_from_bb(&self, bb: BasicBlock) -> Option { + pub(crate) fn bcb_from_bb(&self, bb: BasicBlock) -> Option { if bb.index() < self.bb_to_bcb.len() { self.bb_to_bcb[bb] } else { None } } #[inline(always)] - pub fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { + pub(crate) fn dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { self.dominators.as_ref().unwrap().dominates(dom, node) } #[inline(always)] - pub fn cmp_in_dominator_order(&self, a: BasicCoverageBlock, b: BasicCoverageBlock) -> Ordering { + pub(crate) fn cmp_in_dominator_order( + &self, + a: BasicCoverageBlock, + b: BasicCoverageBlock, + ) -> Ordering { self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b) } @@ -166,7 +170,7 @@ impl CoverageGraph { /// /// FIXME: That assumption might not be true for [`TerminatorKind::Yield`]? #[inline(always)] - pub(super) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool { + pub(crate) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool { // Even though bcb0 conceptually has an extra virtual in-edge due to // being the entry point, we've already asserted that it has no _other_ // in-edges, so there's no possibility of it having _multiple_ in-edges. @@ -227,7 +231,7 @@ rustc_index::newtype_index! { /// A node in the control-flow graph of CoverageGraph. #[orderable] #[debug_format = "bcb{}"] - pub(super) struct BasicCoverageBlock { + pub(crate) struct BasicCoverageBlock { const START_BCB = 0; } } @@ -259,23 +263,23 @@ rustc_index::newtype_index! { /// queries (`dominates()`, `predecessors`, `successors`, etc.) have branch (control flow) /// significance. #[derive(Debug, Clone)] -pub(super) struct BasicCoverageBlockData { - pub basic_blocks: Vec, +pub(crate) struct BasicCoverageBlockData { + pub(crate) basic_blocks: Vec, } impl BasicCoverageBlockData { - pub fn from(basic_blocks: Vec) -> Self { + fn from(basic_blocks: Vec) -> Self { assert!(basic_blocks.len() > 0); Self { basic_blocks } } #[inline(always)] - pub fn leader_bb(&self) -> BasicBlock { + pub(crate) fn leader_bb(&self) -> BasicBlock { self.basic_blocks[0] } #[inline(always)] - pub fn last_bb(&self) -> BasicBlock { + pub(crate) fn last_bb(&self) -> BasicBlock { *self.basic_blocks.last().unwrap() } } @@ -364,7 +368,7 @@ fn bcb_filtered_successors<'a, 'tcx>(terminator: &'a Terminator<'tcx>) -> Covera /// CoverageGraph outside all loops. This supports traversing the BCB CFG in a way that /// ensures a loop is completely traversed before processing Blocks after the end of the loop. #[derive(Debug)] -pub(super) struct TraversalContext { +struct TraversalContext { /// BCB with one or more incoming loop backedges, indicating which loop /// this context is for. /// @@ -375,7 +379,7 @@ pub(super) struct TraversalContext { worklist: VecDeque, } -pub(super) struct TraverseCoverageGraphWithLoops<'a> { +pub(crate) struct TraverseCoverageGraphWithLoops<'a> { basic_coverage_blocks: &'a CoverageGraph, backedges: IndexVec>, @@ -384,7 +388,7 @@ pub(super) struct TraverseCoverageGraphWithLoops<'a> { } impl<'a> TraverseCoverageGraphWithLoops<'a> { - pub(super) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { + pub(crate) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { let backedges = find_loop_backedges(basic_coverage_blocks); let worklist = VecDeque::from([basic_coverage_blocks.start_node()]); @@ -400,7 +404,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { /// For each loop on the loop context stack (top-down), yields a list of BCBs /// within that loop that have an outgoing edge back to the loop header. - pub(super) fn reloop_bcbs_per_loop(&self) -> impl Iterator { + pub(crate) fn reloop_bcbs_per_loop(&self) -> impl Iterator { self.context_stack .iter() .rev() @@ -408,7 +412,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { .map(|header_bcb| self.backedges[header_bcb].as_slice()) } - pub(super) fn next(&mut self) -> Option { + pub(crate) fn next(&mut self) -> Option { debug!( "TraverseCoverageGraphWithLoops::next - context_stack: {:?}", self.context_stack.iter().rev().collect::>() @@ -440,7 +444,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { None } - pub fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) { + fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) { let successors = &self.basic_coverage_blocks.successors[bcb]; debug!("{:?} has {} successors:", bcb, successors.len()); @@ -494,11 +498,11 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { } } - pub fn is_complete(&self) -> bool { + pub(crate) fn is_complete(&self) -> bool { self.visited.count() == self.visited.domain_size() } - pub fn unvisited(&self) -> Vec { + pub(crate) fn unvisited(&self) -> Vec { let mut unvisited_set: BitSet = BitSet::new_filled(self.visited.domain_size()); unvisited_set.subtract(&self.visited); @@ -506,7 +510,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { } } -pub(super) fn find_loop_backedges( +fn find_loop_backedges( basic_coverage_blocks: &CoverageGraph, ) -> IndexVec> { let num_bcbs = basic_coverage_blocks.num_nodes(); From dca6b5eeade5f369c4cb021f1f405b453db35870 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Jun 2024 13:01:41 +1000 Subject: [PATCH 21/48] coverage: Flatten some graph code with let-else --- .../rustc_mir_transform/src/coverage/graph.rs | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 544195a80fca..607cb14f4c3a 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -419,26 +419,25 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { ); while let Some(context) = self.context_stack.last_mut() { - if let Some(bcb) = context.worklist.pop_front() { - if !self.visited.insert(bcb) { - debug!("Already visited: {bcb:?}"); - continue; - } - debug!("Visiting {bcb:?}"); - - if self.backedges[bcb].len() > 0 { - debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); - self.context_stack.push(TraversalContext { - loop_header: Some(bcb), - worklist: VecDeque::new(), - }); - } - self.add_successors_to_worklists(bcb); - return Some(bcb); - } else { - // Strip contexts with empty worklists from the top of the stack + let Some(bcb) = context.worklist.pop_front() else { + // This stack level is exhausted; pop it and try the next one. self.context_stack.pop(); + continue; + }; + + if !self.visited.insert(bcb) { + debug!("Already visited: {bcb:?}"); + continue; } + debug!("Visiting {bcb:?}"); + + if self.backedges[bcb].len() > 0 { + debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); + self.context_stack + .push(TraversalContext { loop_header: Some(bcb), worklist: VecDeque::new() }); + } + self.add_successors_to_worklists(bcb); + return Some(bcb); } None From e5b43c33d8c729022218fe4e8515aea5799f3660 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 16 Jun 2024 15:51:00 +1000 Subject: [PATCH 22/48] coverage: Prefer `Iterator::copied` --- compiler/rustc_mir_transform/src/coverage/graph.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 607cb14f4c3a..360dccb240dc 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -216,7 +216,7 @@ impl graph::StartNode for CoverageGraph { impl graph::Successors for CoverageGraph { #[inline] fn successors(&self, node: Self::Node) -> impl Iterator { - self.successors[node].iter().cloned() + self.successors[node].iter().copied() } } From 51d95464169751604a3cf70b1c8c524450258427 Mon Sep 17 00:00:00 2001 From: Slanterns Date: Sun, 16 Jun 2024 15:56:13 +0800 Subject: [PATCH 23/48] Apply suggestion. Co-authored-by: Jubilee <46493976+workingjubilee@users.noreply.github.com> --- tests/codegen/error-provide.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/codegen/error-provide.rs b/tests/codegen/error-provide.rs index e80905eee110..68dd383e5cce 100644 --- a/tests/codegen/error-provide.rs +++ b/tests/codegen/error-provide.rs @@ -36,7 +36,9 @@ impl std::error::Error for MyError { // LLVM should be able to optimize multiple .provide_* calls into a switch table // and eliminate redundant ones, rather than compare one-by-one. - // CHECK: switch i64 %{{.*}}, label %{{.*}} [ + // CHECK-NEXT: start: + // CHECK-NEXT: %[[SCRUTINEE:[^ ]+]] = load i64, ptr + // CHECK-NEXT: switch i64 %[[SCRUTINEE]], label %{{.*}} [ // CHECK-COUNT-3: i64 {{.*}}, label %{{.*}} // CHECK-NEXT: ] request From 587173374ec222bf9f5f30d17acef53a3daf5c06 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 13:57:56 -0400 Subject: [PATCH 24/48] Uplift Reveal to rustc_type_ir --- compiler/rustc_middle/src/traits/mod.rs | 49 +------------------------ compiler/rustc_type_ir/src/solve.rs | 48 ++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 48 deletions(-) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 202d587f0ad2..b4e3fae1b43b 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -32,54 +32,7 @@ use std::hash::{Hash, Hasher}; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; // FIXME: Remove this import and import via `solve::` -pub use rustc_type_ir::solve::BuiltinImplSource; - -/// Depending on the stage of compilation, we want projection to be -/// more or less conservative. -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, HashStable, Encodable, Decodable)] -pub enum Reveal { - /// At type-checking time, we refuse to project any associated - /// type that is marked `default`. Non-`default` ("final") types - /// are always projected. This is necessary in general for - /// soundness of specialization. However, we *could* allow - /// projections in fully-monomorphic cases. We choose not to, - /// because we prefer for `default type` to force the type - /// definition to be treated abstractly by any consumers of the - /// impl. Concretely, that means that the following example will - /// fail to compile: - /// - /// ```compile_fail,E0308 - /// #![feature(specialization)] - /// trait Assoc { - /// type Output; - /// } - /// - /// impl Assoc for T { - /// default type Output = bool; - /// } - /// - /// fn main() { - /// let x: <() as Assoc>::Output = true; - /// } - /// ``` - /// - /// We also do not reveal the hidden type of opaque types during - /// type-checking. - UserFacing, - - /// At codegen time, all monomorphic projections will succeed. - /// Also, `impl Trait` is normalized to the concrete type, - /// which has to be already collected by type-checking. - /// - /// NOTE: as `impl Trait`'s concrete type should *never* - /// be observable directly by the user, `Reveal::All` - /// should not be used by checks which may expose - /// type equality or type contents to the user. - /// There are some exceptions, e.g., around auto traits and - /// transmute-checking, which expose some details, but - /// not the whole concrete type of the `impl Trait`. - All, -} +pub use rustc_type_ir::solve::{BuiltinImplSource, Reveal}; /// The reason why we incurred this obligation; used for error reporting. /// diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index 6a89a8a4cc30..cff62ee3d1ec 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -9,6 +9,54 @@ use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Gen use crate::{Canonical, CanonicalVarValues, Interner, Upcast}; +/// Depending on the stage of compilation, we want projection to be +/// more or less conservative. +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "nightly", derive(TyDecodable, TyEncodable, HashStable_NoContext))] +pub enum Reveal { + /// At type-checking time, we refuse to project any associated + /// type that is marked `default`. Non-`default` ("final") types + /// are always projected. This is necessary in general for + /// soundness of specialization. However, we *could* allow + /// projections in fully-monomorphic cases. We choose not to, + /// because we prefer for `default type` to force the type + /// definition to be treated abstractly by any consumers of the + /// impl. Concretely, that means that the following example will + /// fail to compile: + /// + /// ```compile_fail,E0308 + /// #![feature(specialization)] + /// trait Assoc { + /// type Output; + /// } + /// + /// impl Assoc for T { + /// default type Output = bool; + /// } + /// + /// fn main() { + /// let x: <() as Assoc>::Output = true; + /// } + /// ``` + /// + /// We also do not reveal the hidden type of opaque types during + /// type-checking. + UserFacing, + + /// At codegen time, all monomorphic projections will succeed. + /// Also, `impl Trait` is normalized to the concrete type, + /// which has to be already collected by type-checking. + /// + /// NOTE: as `impl Trait`'s concrete type should *never* + /// be observable directly by the user, `Reveal::All` + /// should not be used by checks which may expose + /// type equality or type contents to the user. + /// There are some exceptions, e.g., around auto traits and + /// transmute-checking, which expose some details, but + /// not the whole concrete type of the `impl Trait`. + All, +} + pub type CanonicalInput::Predicate> = Canonical>; pub type CanonicalResponse = Canonical>; /// The result of evaluating a canonical query. From b65d735f1c4dbb0677884c97ff1b09d0c38d2cc5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 13:59:45 -0400 Subject: [PATCH 25/48] Move InferCtxtSelectExt out of eval_ctxt module --- compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs | 2 -- compiler/rustc_trait_selection/src/solve/mod.rs | 4 +++- .../rustc_trait_selection/src/solve/{eval_ctxt => }/select.rs | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename compiler/rustc_trait_selection/src/solve/{eval_ctxt => }/select.rs (100%) diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 6b8375b53e8f..8dc6b31f8d14 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -29,11 +29,9 @@ use super::inspect::ProofTreeBuilder; use super::{search_graph, GoalEvaluationKind, FIXPOINT_STEP_LIMIT}; use super::{search_graph::SearchGraph, Goal}; use super::{GoalSource, SolverMode}; -pub use select::InferCtxtSelectExt; pub(super) mod canonical; mod probe; -mod select; pub struct EvalCtxt<'a, Infcx, I = ::Interner> where diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index fdcf4ff11e46..4f1be5cbc853 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -37,12 +37,14 @@ mod normalize; mod normalizes_to; mod project_goals; mod search_graph; +mod select; mod trait_goals; -pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt, InferCtxtSelectExt}; +pub use eval_ctxt::{EvalCtxt, GenerateProofTree, InferCtxtEvalExt}; pub use fulfill::{FulfillmentCtxt, NextSolverError}; pub(crate) use normalize::deeply_normalize_for_diagnostics; pub use normalize::{deeply_normalize, deeply_normalize_with_skipped_universes}; +pub use select::InferCtxtSelectExt; /// How many fixpoint iterations we should attempt inside of the solver before bailing /// with overflow. diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs similarity index 100% rename from compiler/rustc_trait_selection/src/solve/eval_ctxt/select.rs rename to compiler/rustc_trait_selection/src/solve/select.rs From a333943890315776f3be83988511f495dc10efbd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 14:04:52 -0400 Subject: [PATCH 26/48] Stop using AssocKind in new solver --- .../src/solve/normalizes_to/mod.rs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 60a15392e0be..5c5923e9d396 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -10,13 +10,13 @@ use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::inspect::ProbeKind; use rustc_infer::traits::solve::MaybeCause; use rustc_infer::traits::Reveal; +use rustc_middle::bug; use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal, QueryResult}; use rustc_middle::traits::BuiltinImplSource; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; use rustc_middle::ty::NormalizesTo; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeVisitableExt, Upcast}; -use rustc_middle::{bug, span_bug}; use rustc_span::{ErrorGuaranteed, DUMMY_SP}; mod anon_const; @@ -200,14 +200,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let error_response = |ecx: &mut EvalCtxt<'_, InferCtxt<'tcx>>, reason| { let guar = tcx.dcx().span_delayed_bug(tcx.def_span(assoc_def.item.def_id), reason); - let error_term = match assoc_def.item.kind { - ty::AssocKind::Const => ty::Const::new_error(tcx, guar).into(), - ty::AssocKind::Type => Ty::new_error(tcx, guar).into(), - // This makes no sense... - ty::AssocKind::Fn => span_bug!( - tcx.def_span(assoc_def.item.def_id), - "cannot project to an associated function" - ), + let error_term = match goal.predicate.alias.kind(tcx) { + ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(), + ty::AliasTermKind::ProjectionConst => ty::Const::new_error(tcx, guar).into(), + kind => bug!("expected projection, found {kind:?}"), }; ecx.instantiate_normalizes_to_term(goal, error_term); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -238,9 +234,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { } // Finally we construct the actual value of the associated type. - let term = match assoc_def.item.kind { - ty::AssocKind::Type => tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()), - ty::AssocKind::Const => { + let term = match goal.predicate.alias.kind(tcx) { + ty::AliasTermKind::ProjectionTy => { + tcx.type_of(assoc_def.item.def_id).map_bound(|ty| ty.into()) + } + ty::AliasTermKind::ProjectionConst => { if tcx.features().associated_const_equality { bug!("associated const projection is not supported yet") } else { @@ -254,7 +252,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { ) } } - ty::AssocKind::Fn => unreachable!("we should never project to a fn"), + kind => bug!("expected projection, found {kind:?}"), }; ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, associated_item_args)); From f93ee19fd7cd7016a8d6829b40ad7c087a6cd5c4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 14:59:03 -0400 Subject: [PATCH 27/48] Make ExternalConstraints just carry outlives --- compiler/rustc_middle/src/traits/solve.rs | 3 +- .../src/solve/eval_ctxt/canonical.rs | 40 ++++++++++--------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 0d9ce402c64e..fea673eed772 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -4,7 +4,6 @@ use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; use rustc_type_ir as ir; pub use rustc_type_ir::solve::*; -use crate::infer::canonical::QueryRegionConstraints; use crate::ty::{ self, FallibleTypeFolder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor, }; @@ -52,7 +51,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { #[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)] pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. - pub region_constraints: QueryRegionConstraints<'tcx>, + pub region_constraints: Vec>>, pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, pub normalization_nested_goals: NestedNormalizationGoals<'tcx>, } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 0e0b9e983391..ffbdc639f084 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -135,8 +135,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // Remove any trivial region constraints once we've resolved regions external_constraints .region_constraints - .outlives - .retain(|(outlives, _)| outlives.0.as_region().map_or(true, |re| re != outlives.1)); + .retain(|outlives| outlives.0.as_region().map_or(true, |re| re != outlives.1)); let canonical = Canonicalizer::canonicalize( self.infcx, @@ -193,19 +192,23 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // Cannot use `take_registered_region_obligations` as we may compute the response // inside of a `probe` whenever we have multiple choices inside of the solver. let region_obligations = self.infcx.inner.borrow().region_obligations().to_owned(); - let mut region_constraints = self.infcx.with_region_constraints(|region_constraints| { - make_query_region_constraints( - self.interner(), - region_obligations.iter().map(|r_o| { - (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()) - }), - region_constraints, - ) - }); - + let QueryRegionConstraints { outlives, member_constraints } = + self.infcx.with_region_constraints(|region_constraints| { + make_query_region_constraints( + self.interner(), + region_obligations.iter().map(|r_o| { + (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category()) + }), + region_constraints, + ) + }); + assert_eq!(member_constraints, vec![]); let mut seen = FxHashSet::default(); - region_constraints.outlives.retain(|outlives| seen.insert(*outlives)); - region_constraints + outlives + .into_iter() + .filter(|(outlives, _)| seen.insert(*outlives)) + .map(|(outlives, _origin)| outlives) + .collect() } else { Default::default() }; @@ -369,16 +372,17 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } - fn register_region_constraints(&mut self, region_constraints: &QueryRegionConstraints<'tcx>) { - for &(ty::OutlivesPredicate(lhs, rhs), _) in ®ion_constraints.outlives { + fn register_region_constraints( + &mut self, + outlives: &[ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>], + ) { + for &ty::OutlivesPredicate(lhs, rhs) in outlives { match lhs.unpack() { GenericArgKind::Lifetime(lhs) => self.register_region_outlives(lhs, rhs), GenericArgKind::Type(lhs) => self.register_ty_outlives(lhs, rhs), GenericArgKind::Const(_) => bug!("const outlives: {lhs:?}: {rhs:?}"), } } - - assert!(region_constraints.member_constraints.is_empty()); } fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) { From 9d207cfbc803e1c8fe263639dffc309941ed1723 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 15:16:47 -0400 Subject: [PATCH 28/48] Uplift ExternalConstraintData --- compiler/rustc_middle/src/arena.rs | 2 +- compiler/rustc_middle/src/traits/solve.rs | 29 +++---------- compiler/rustc_middle/src/ty/context.rs | 5 ++- .../src/solve/eval_ctxt/canonical.rs | 38 ++++++++++------ .../src/solve/eval_ctxt/mod.rs | 4 +- compiler/rustc_type_ir/src/interner.rs | 1 + compiler/rustc_type_ir/src/solve.rs | 43 ++++++++++++++++++- 7 files changed, 79 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index de786c38326f..3d4e5caa9b27 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -110,7 +110,7 @@ macro_rules! arena_types { rustc_hir::def_id::DefId, rustc_middle::ty::EarlyBinder<'tcx, rustc_middle::ty::Ty<'tcx>> >, - [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>, + [] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData>, [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>, [decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap, [] stripped_cfg_items: rustc_ast::expand::StrippedCfgItem, diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index fea673eed772..9e979620a440 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -1,6 +1,6 @@ use rustc_ast_ir::try_visit; use rustc_data_structures::intern::Interned; -use rustc_macros::{HashStable, TypeFoldable, TypeVisitable}; +use rustc_macros::HashStable; use rustc_type_ir as ir; pub use rustc_type_ir::solve::*; @@ -37,37 +37,18 @@ impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> { } #[derive(Debug, PartialEq, Eq, Copy, Clone, Hash, HashStable)] -pub struct ExternalConstraints<'tcx>(pub(crate) Interned<'tcx, ExternalConstraintsData<'tcx>>); +pub struct ExternalConstraints<'tcx>( + pub(crate) Interned<'tcx, ExternalConstraintsData>>, +); impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { - type Target = ExternalConstraintsData<'tcx>; + type Target = ExternalConstraintsData>; fn deref(&self) -> &Self::Target { &self.0 } } -/// Additional constraints returned on success. -#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)] -pub struct ExternalConstraintsData<'tcx> { - // FIXME: implement this. - pub region_constraints: Vec>>, - pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, - pub normalization_nested_goals: NestedNormalizationGoals<'tcx>, -} - -#[derive(Debug, PartialEq, Eq, Clone, Hash, HashStable, Default, TypeVisitable, TypeFoldable)] -pub struct NestedNormalizationGoals<'tcx>(pub Vec<(GoalSource, Goal<'tcx, ty::Predicate<'tcx>>)>); -impl<'tcx> NestedNormalizationGoals<'tcx> { - pub fn empty() -> Self { - NestedNormalizationGoals(vec![]) - } - - pub fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - // FIXME: Having to clone `region_constraints` for folding feels bad and // probably isn't great wrt performance. // diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3651c990c979..e2f15dac0198 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -88,6 +88,7 @@ use std::ops::{Bound, Deref}; #[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Interner for TyCtxt<'tcx> { type DefId = DefId; + type LocalDefId = LocalDefId; type AdtDef = ty::AdtDef<'tcx>; type GenericArgs = ty::GenericArgsRef<'tcx>; @@ -382,7 +383,7 @@ pub struct CtxtInterners<'tcx> { bound_variable_kinds: InternedSet<'tcx, List>, layout: InternedSet<'tcx, LayoutS>, adt_def: InternedSet<'tcx, AdtDefData>, - external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>, + external_constraints: InternedSet<'tcx, ExternalConstraintsData>>, predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>, fields: InternedSet<'tcx, List>, local_def_ids: InternedSet<'tcx, List>, @@ -2093,7 +2094,7 @@ direct_interners! { const_allocation: pub mk_const_alloc(Allocation): ConstAllocation -> ConstAllocation<'tcx>, layout: pub mk_layout(LayoutS): Layout -> Layout<'tcx>, adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>, - external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>): + external_constraints: pub mk_external_constraints(ExternalConstraintsData>): ExternalConstraints -> ExternalConstraints<'tcx>, predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>): PredefinedOpaques -> PredefinedOpaques<'tcx>, diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index ffbdc639f084..2e020b03c5da 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -14,6 +14,7 @@ use crate::solve::{ inspect, response_no_constraints_raw, CanonicalResponse, QueryResult, Response, }; use rustc_data_structures::fx::FxHashSet; +use rustc_hir::def_id::LocalDefId; use rustc_index::IndexVec; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; @@ -178,8 +179,8 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { fn compute_external_query_constraints( &self, certainty: Certainty, - normalization_nested_goals: NestedNormalizationGoals<'tcx>, - ) -> ExternalConstraintsData<'tcx> { + normalization_nested_goals: NestedNormalizationGoals>, + ) -> ExternalConstraintsData> { // We only return region constraints once the certainty is `Yes`. This // is necessary as we may drop nested goals on ambiguity, which may result // in unconstrained inference variables in the region constraints. It also @@ -213,13 +214,20 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { Default::default() }; - let mut opaque_types = self.infcx.clone_opaque_types_for_query_response(); - // Only return opaque type keys for newly-defined opaques - opaque_types.retain(|(a, _)| { - self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) - }); - - ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } + ExternalConstraintsData { + region_constraints, + opaque_types: self + .infcx + .clone_opaque_types_for_query_response() + .into_iter() + // Only return *newly defined* opaque types. + .filter(|(a, _)| { + self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) + }) + .map(|(key, value)| (key.def_id, key.args, value)) + .collect(), + normalization_nested_goals, + } } /// After calling a canonical query, we apply the constraints returned @@ -235,7 +243,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { param_env: ty::ParamEnv<'tcx>, original_values: Vec>, response: CanonicalResponse<'tcx>, - ) -> (NestedNormalizationGoals<'tcx>, Certainty) { + ) -> (NestedNormalizationGoals>, Certainty) { let instantiation = Self::compute_query_response_instantiation_values( self.infcx, &original_values, @@ -385,10 +393,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } - fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) { - for &(key, ty) in opaque_types { + fn register_new_opaque_types( + &mut self, + opaque_types: &[(LocalDefId, ty::GenericArgsRef<'tcx>, Ty<'tcx>)], + ) { + for &(def_id, args, ty) in opaque_types { let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; - self.infcx.inject_new_hidden_type_unchecked(key, hidden_ty); + self.infcx + .inject_new_hidden_type_unchecked(ty::OpaqueTypeKey { def_id, args }, hidden_ty); } } } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 8dc6b31f8d14..74938d2bbd70 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -337,7 +337,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { goal_evaluation_kind: GoalEvaluationKind, _source: GoalSource, goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) -> Result<(NestedNormalizationGoals<'tcx>, bool, Certainty), NoSolution> { + ) -> Result<(NestedNormalizationGoals>, bool, Certainty), NoSolution> { let (orig_values, canonical_goal) = self.canonicalize_goal(goal); let mut goal_evaluation = self.inspect.new_goal_evaluation(goal, &orig_values, goal_evaluation_kind); @@ -380,7 +380,7 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { param_env: ty::ParamEnv<'tcx>, original_values: Vec>, response: CanonicalResponse<'tcx>, - ) -> (NestedNormalizationGoals<'tcx>, Certainty, bool) { + ) -> (NestedNormalizationGoals>, Certainty, bool) { if let Certainty::Maybe(MaybeCause::Overflow { .. }) = response.value.certainty { return (NestedNormalizationGoals::empty(), response.value.certainty, false); } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index a2b71e1fc257..30beb4480e92 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -29,6 +29,7 @@ pub trait Interner: + IrPrint> { type DefId: Copy + Debug + Hash + Eq + TypeFoldable; + type LocalDefId: Copy + Debug + Hash + Eq + TypeFoldable; type AdtDef: AdtDef; type GenericArgs: GenericArgs; diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index cff62ee3d1ec..d4e43716c17a 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -7,7 +7,7 @@ use std::hash::Hash; use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; -use crate::{Canonical, CanonicalVarValues, Interner, Upcast}; +use crate::{self as ty, Canonical, CanonicalVarValues, Interner, Upcast}; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -254,6 +254,47 @@ pub struct Response { pub external_constraints: I::ExternalConstraints, } +/// Additional constraints returned on success. +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Default(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub struct ExternalConstraintsData { + pub region_constraints: Vec>, + pub opaque_types: Vec<(I::LocalDefId, I::GenericArgs, I::Ty)>, + pub normalization_nested_goals: NestedNormalizationGoals, +} + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Default(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub struct NestedNormalizationGoals(pub Vec<(GoalSource, Goal)>); + +impl NestedNormalizationGoals { + pub fn empty() -> Self { + NestedNormalizationGoals(vec![]) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + #[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub enum Certainty { From 4c2d888a507cf28ecec80e630b61a2700b9d060d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 14 Jun 2024 15:19:12 -0400 Subject: [PATCH 29/48] Add a note --- compiler/rustc_next_trait_solver/src/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_next_trait_solver/src/lib.rs b/compiler/rustc_next_trait_solver/src/lib.rs index b913a05095c2..144caf36ee53 100644 --- a/compiler/rustc_next_trait_solver/src/lib.rs +++ b/compiler/rustc_next_trait_solver/src/lib.rs @@ -1,3 +1,9 @@ +//! Crate containing the implementation of the next-generation trait solver. +//! +//! This crate may also contain things that are used by the old trait solver, +//! but were uplifted in the process of making the new trait solver generic. +//! So if you got to this crate from the old solver, it's totally normal. + pub mod canonicalizer; pub mod resolve; pub mod solve; From ff154c7122caa5a56c71e1dfa5e49e87e6f26428 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 15 Jun 2024 17:41:49 -0400 Subject: [PATCH 30/48] Uplift OpaqueTypeKey too, use it in response --- compiler/rustc_middle/src/ty/mod.rs | 40 +-------------- compiler/rustc_middle/src/ty/opaque_types.rs | 2 + .../src/solve/eval_ctxt/canonical.rs | 12 ++--- compiler/rustc_type_ir/src/interner.rs | 8 ++- compiler/rustc_type_ir/src/lib.rs | 2 + compiler/rustc_type_ir/src/opaque_ty.rs | 51 +++++++++++++++++++ compiler/rustc_type_ir/src/solve.rs | 2 +- 7 files changed, 66 insertions(+), 51 deletions(-) create mode 100644 compiler/rustc_type_ir/src/opaque_ty.rs diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5a94a53e175e..4e388de6fb8a 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -94,6 +94,7 @@ pub use self::context::{ }; pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams}; pub use self::list::{List, ListWithCachedTypeInfo}; +pub use self::opaque_types::OpaqueTypeKey; pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; pub use self::predicate::{ @@ -758,45 +759,6 @@ impl<'a, 'tcx> IntoIterator for &'a InstantiatedPredicates<'tcx> { } } -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)] -#[derive(TypeFoldable, TypeVisitable)] -pub struct OpaqueTypeKey<'tcx> { - pub def_id: LocalDefId, - pub args: GenericArgsRef<'tcx>, -} - -impl<'tcx> OpaqueTypeKey<'tcx> { - pub fn iter_captured_args( - self, - tcx: TyCtxt<'tcx>, - ) -> impl Iterator)> { - std::iter::zip(self.args, tcx.variances_of(self.def_id)).enumerate().filter_map( - |(i, (arg, v))| match (arg.unpack(), v) { - (_, ty::Invariant) => Some((i, arg)), - (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None, - _ => bug!("unexpected opaque type arg variance"), - }, - ) - } - - pub fn fold_captured_lifetime_args( - self, - tcx: TyCtxt<'tcx>, - mut f: impl FnMut(Region<'tcx>) -> Region<'tcx>, - ) -> Self { - let Self { def_id, args } = self; - let args = std::iter::zip(args, tcx.variances_of(def_id)).map(|(arg, v)| { - match (arg.unpack(), v) { - (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, - (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(), - _ => arg, - } - }); - let args = tcx.mk_args_from_iter(args); - Self { def_id, args } - } -} - #[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)] pub struct OpaqueHiddenType<'tcx> { /// The span of this particular definition of the opaque type. So diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 52902aadd7c7..08b2f9e89203 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -7,6 +7,8 @@ use rustc_span::def_id::DefId; use rustc_span::Span; use tracing::{debug, instrument, trace}; +pub type OpaqueTypeKey<'tcx> = rustc_type_ir::OpaqueTypeKey>; + /// Converts generic params of a TypeFoldable from one /// item's generics to another. Usually from a function's generics /// list to the opaque type's own generics. diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs index 2e020b03c5da..b5753d60f599 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs @@ -14,7 +14,6 @@ use crate::solve::{ inspect, response_no_constraints_raw, CanonicalResponse, QueryResult, Response, }; use rustc_data_structures::fx::FxHashSet; -use rustc_hir::def_id::LocalDefId; use rustc_index::IndexVec; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints}; @@ -224,7 +223,6 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { .filter(|(a, _)| { self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a) }) - .map(|(key, value)| (key.def_id, key.args, value)) .collect(), normalization_nested_goals, } @@ -393,14 +391,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } - fn register_new_opaque_types( - &mut self, - opaque_types: &[(LocalDefId, ty::GenericArgsRef<'tcx>, Ty<'tcx>)], - ) { - for &(def_id, args, ty) in opaque_types { + fn register_new_opaque_types(&mut self, opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)]) { + for &(key, ty) in opaque_types { let hidden_ty = ty::OpaqueHiddenType { ty, span: DUMMY_SP }; - self.infcx - .inject_new_hidden_type_unchecked(ty::OpaqueTypeKey { def_id, args }, hidden_ty); + self.infcx.inject_new_hidden_type_unchecked(key, hidden_ty); } } } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index 30beb4480e92..11c1f73fef33 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -29,7 +29,7 @@ pub trait Interner: + IrPrint> { type DefId: Copy + Debug + Hash + Eq + TypeFoldable; - type LocalDefId: Copy + Debug + Hash + Eq + TypeFoldable; + type LocalDefId: Copy + Debug + Hash + Eq + Into + TypeFoldable; type AdtDef: AdtDef; type GenericArgs: GenericArgs; @@ -104,7 +104,11 @@ pub trait Interner: type GenericsOf: GenericsOf; fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf; - type VariancesOf: Copy + Debug + Deref; + type VariancesOf: Copy + + Debug + + Deref + // FIXME: This is terrible! + + IntoIterator>; fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf; // FIXME: Remove after uplifting `EarlyBinder` diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 4775a0f8cbbe..ac9b2808804c 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -47,6 +47,7 @@ mod flags; mod generic_arg; mod infcx; mod interner; +mod opaque_ty; mod predicate; mod predicate_kind; mod region_kind; @@ -63,6 +64,7 @@ pub use flags::*; pub use generic_arg::*; pub use infcx::InferCtxtLike; pub use interner::*; +pub use opaque_ty::*; pub use predicate::*; pub use predicate_kind::*; pub use region_kind::*; diff --git a/compiler/rustc_type_ir/src/opaque_ty.rs b/compiler/rustc_type_ir/src/opaque_ty.rs new file mode 100644 index 000000000000..607370665975 --- /dev/null +++ b/compiler/rustc_type_ir/src/opaque_ty.rs @@ -0,0 +1,51 @@ +use rustc_macros::{HashStable_NoContext, TyDecodable, TyEncodable}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; + +use crate::inherent::*; +use crate::{self as ty, Interner}; + +#[derive(derivative::Derivative)] +#[derivative( + Clone(bound = ""), + Hash(bound = ""), + PartialEq(bound = ""), + Eq(bound = ""), + Debug(bound = ""), + Copy(bound = "") +)] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +#[cfg_attr(feature = "nightly", derive(TyEncodable, TyDecodable, HashStable_NoContext))] +pub struct OpaqueTypeKey { + pub def_id: I::LocalDefId, + pub args: I::GenericArgs, +} + +impl OpaqueTypeKey { + pub fn iter_captured_args(self, tcx: I) -> impl Iterator { + let variances = tcx.variances_of(self.def_id.into()); + std::iter::zip(self.args, variances.into_iter()).enumerate().filter_map(|(i, (arg, v))| { + match (arg.kind(), *v) { + (_, ty::Invariant) => Some((i, arg)), + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => None, + _ => panic!("unexpected opaque type arg variance"), + } + }) + } + + pub fn fold_captured_lifetime_args( + self, + tcx: I, + mut f: impl FnMut(I::Region) -> I::Region, + ) -> Self { + let Self { def_id, args } = self; + let variances = tcx.variances_of(def_id.into()); + let args = + std::iter::zip(args, variances.into_iter()).map(|(arg, v)| match (arg.kind(), *v) { + (ty::GenericArgKind::Lifetime(_), ty::Bivariant) => arg, + (ty::GenericArgKind::Lifetime(lt), _) => f(lt).into(), + _ => arg, + }); + let args = tcx.mk_args_from_iter(args); + Self { def_id, args } + } +} diff --git a/compiler/rustc_type_ir/src/solve.rs b/compiler/rustc_type_ir/src/solve.rs index d4e43716c17a..99d2fa744947 100644 --- a/compiler/rustc_type_ir/src/solve.rs +++ b/compiler/rustc_type_ir/src/solve.rs @@ -268,7 +268,7 @@ pub struct Response { #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct ExternalConstraintsData { pub region_constraints: Vec>, - pub opaque_types: Vec<(I::LocalDefId, I::GenericArgs, I::Ty)>, + pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, pub normalization_nested_goals: NestedNormalizationGoals, } From fe9154c64ee0e226a7f0009796b98f9fbec3862d Mon Sep 17 00:00:00 2001 From: Rayyan Khan <163682431+x4exr@users.noreply.github.com> Date: Tue, 11 Jun 2024 19:35:29 -0400 Subject: [PATCH 31/48] doc: Added commas where needed --- library/core/src/ptr/mod.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 6661f6ee78b4..a8a47b69632f 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -237,7 +237,7 @@ //! pointer. For code which *does* cast a usize to a pointer, the scope of the change depends //! on exactly what you're doing. //! -//! In general you just need to make sure that if you want to convert a usize address to a +//! In general, you just need to make sure that if you want to convert a usize address to a //! pointer and then use that pointer to read/write memory, you need to keep around a pointer //! that has sufficient provenance to perform that read/write itself. In this way all of your //! casts from an address to a pointer are essentially just applying offsets/indexing. @@ -309,7 +309,7 @@ //! i.e. the usual "ZSTs are fake, do what you want" rules apply *but* this only applies //! for actual forgery (integers cast to pointers). If you borrow some struct's field //! that *happens* to be zero-sized, the resulting pointer will have provenance tied to -//! that allocation and it will still get invalidated if the allocation gets deallocated. +//! that allocation, and it will still get invalidated if the allocation gets deallocated. //! In the future we may introduce an API to make such a forged allocation explicit. //! //! * [`wrapping_offset`][] a pointer outside its provenance. This includes pointers @@ -698,7 +698,7 @@ pub const fn dangling_mut() -> *mut T { /// /// If there is no 'exposed' provenance that justifies the way this pointer will be used, /// the program has undefined behavior. In particular, the aliasing rules still apply: pointers -/// and references that have been invalidated due to aliasing accesses cannot be used any more, +/// and references that have been invalidated due to aliasing accesses cannot be used anymore, /// even if they have been exposed! /// /// Note that there is no algorithm that decides which provenance will be used. You can think of this @@ -1097,7 +1097,7 @@ const unsafe fn swap_nonoverlapping_simple_untyped(x: *mut T, y: *mut T, coun // If we end up here, it's because we're using a simple type -- like // a small power-of-two-sized thing -- or a special type with particularly // large alignment, particularly SIMD types. - // Thus we're fine just reading-and-writing it, as either it's small + // Thus, we're fine just reading-and-writing it, as either it's small // and that works well anyway or it's special and the type's author // presumably wanted things to be done in the larger chunk. @@ -1290,7 +1290,7 @@ pub const unsafe fn read(src: *const T) -> T { // provides enough information to know that this is a typed operation. // However, as of March 2023 the compiler was not capable of taking advantage - // of that information. Thus the implementation here switched to an intrinsic, + // of that information. Thus, the implementation here switched to an intrinsic, // which lowers to `_0 = *src` in MIR, to address a few issues: // // - Using `MaybeUninit::assume_init` after a `copy_nonoverlapping` was not @@ -1570,7 +1570,7 @@ pub const unsafe fn write(dst: *mut T, src: T) { /// As a result, using `&packed.unaligned as *const FieldType` causes immediate /// *undefined behavior* in your program. /// -/// Instead you must use the [`ptr::addr_of_mut!`](addr_of_mut) +/// Instead, you must use the [`ptr::addr_of_mut!`](addr_of_mut) /// macro to create the pointer. You may use that returned pointer together with /// this function. /// From 342c1b03d6d0f9aa1e8119a2556d819af024faaf Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 16 Jun 2024 21:35:16 -0400 Subject: [PATCH 32/48] Rename InstanceDef -> InstanceKind --- .../src/diagnostics/mutability_errors.rs | 4 +- .../rustc_codegen_cranelift/src/abi/mod.rs | 14 +- .../rustc_codegen_cranelift/src/constant.rs | 2 +- .../src/intrinsics/mod.rs | 2 +- compiler/rustc_codegen_cranelift/src/lib.rs | 2 +- .../src/back/symbol_export.rs | 10 +- compiler/rustc_codegen_ssa/src/mir/block.rs | 12 +- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 2 +- .../src/check_consts/check.rs | 4 +- .../src/const_eval/eval_queries.rs | 2 +- .../src/const_eval/machine.rs | 8 +- .../src/interpret/eval_context.rs | 2 +- .../rustc_const_eval/src/interpret/machine.rs | 2 +- .../src/interpret/terminator.rs | 36 ++-- .../rustc_const_eval/src/interpret/util.rs | 2 +- compiler/rustc_interface/src/passes.rs | 2 +- .../src/rmeta/decoder/cstore_impl.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- .../src/middle/exported_symbols.rs | 2 +- compiler/rustc_middle/src/mir/graphviz.rs | 2 +- compiler/rustc_middle/src/mir/mod.rs | 8 +- compiler/rustc_middle/src/mir/mono.rs | 38 ++-- compiler/rustc_middle/src/mir/pretty.rs | 6 +- compiler/rustc_middle/src/mir/visit.rs | 32 +-- compiler/rustc_middle/src/query/erase.rs | 2 +- compiler/rustc_middle/src/query/keys.rs | 4 +- compiler/rustc_middle/src/query/mod.rs | 12 +- compiler/rustc_middle/src/ty/instance.rs | 204 +++++++++--------- compiler/rustc_middle/src/ty/layout.rs | 4 +- compiler/rustc_middle/src/ty/mod.rs | 34 +-- compiler/rustc_mir_transform/src/coroutine.rs | 4 +- .../src/coroutine/by_move_body.rs | 6 +- .../rustc_mir_transform/src/coverage/query.rs | 2 +- compiler/rustc_mir_transform/src/inline.rs | 38 ++-- .../rustc_mir_transform/src/inline/cycle.rs | 32 +-- compiler/rustc_mir_transform/src/lib.rs | 2 +- compiler/rustc_mir_transform/src/shim.rs | 55 ++--- .../src/shim/async_destructor_ctor.rs | 2 +- compiler/rustc_mir_transform/src/validate.rs | 6 +- compiler/rustc_monomorphize/src/collector.rs | 34 +-- .../rustc_monomorphize/src/partitioning.rs | 64 +++--- .../rustc_monomorphize/src/polymorphize.rs | 8 +- .../cfi/typeid/itanium_cxx_abi/transform.rs | 12 +- .../rustc_sanitizers/src/kcfi/typeid/mod.rs | 4 +- compiler/rustc_smir/src/rustc_smir/builder.rs | 2 +- compiler/rustc_smir/src/rustc_smir/context.rs | 6 +- .../rustc_smir/src/rustc_smir/convert/ty.rs | 28 +-- compiler/rustc_smir/src/rustc_smir/mod.rs | 6 +- compiler/rustc_symbol_mangling/src/legacy.rs | 14 +- compiler/rustc_symbol_mangling/src/v0.rs | 14 +- compiler/rustc_ty_utils/src/abi.rs | 12 +- compiler/rustc_ty_utils/src/instance.rs | 28 +-- src/tools/miri/src/intrinsics/mod.rs | 2 +- 53 files changed, 421 insertions(+), 418 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index df1a1411cf5f..b729a9000487 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -8,7 +8,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::{self as hir, BindingMode, ByRef, Node}; use rustc_middle::bug; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; -use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, Upcast}; +use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, Upcast}; use rustc_middle::{ hir::place::PlaceBase, mir::{self, BindingForm, Local, LocalDecl, LocalInfo, LocalKind, Location}, @@ -1020,7 +1020,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn suggest_using_iter_mut(&self, err: &mut Diag<'_>) { let source = self.body.source; let hir = self.infcx.tcx.hir(); - if let InstanceDef::Item(def_id) = source.instance + if let InstanceKind::Item(def_id) = source.instance && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id) && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind && let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id) diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs index bd5a88769059..695dbaf2804b 100644 --- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs @@ -399,7 +399,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( } match instance.def { - InstanceDef::Intrinsic(_) => { + InstanceKind::Intrinsic(_) => { match crate::intrinsics::codegen_intrinsic_call( fx, instance, @@ -412,7 +412,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( Err(instance) => Some(instance), } } - InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) => { + InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) => { // empty drop glue - a nop. let dest = target.expect("Non terminating drop_in_place_real???"); let ret_block = fx.get_block(dest); @@ -494,7 +494,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( let (func_ref, first_arg_override) = match instance { // Trait object call - Some(Instance { def: InstanceDef::Virtual(_, idx), .. }) => { + Some(Instance { def: InstanceKind::Virtual(_, idx), .. }) => { if fx.clif_comments.enabled() { let nop_inst = fx.bcx.ins().nop(); fx.add_comment( @@ -598,7 +598,7 @@ pub(crate) fn codegen_drop<'tcx>( let ty = drop_place.layout().ty; let drop_instance = Instance::resolve_drop_in_place(fx.tcx, ty).polymorphize(fx.tcx); - if let ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) = + if let ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) = drop_instance.def { // we don't actually need to drop anything @@ -630,7 +630,7 @@ pub(crate) fn codegen_drop<'tcx>( // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), + def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0), args: drop_instance.args, }; let fn_abi = @@ -673,7 +673,7 @@ pub(crate) fn codegen_drop<'tcx>( fx.bcx.switch_to_block(continued); let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_instance.def_id(), 0), + def: ty::InstanceKind::Virtual(drop_instance.def_id(), 0), args: drop_instance.args, }; let fn_abi = @@ -684,7 +684,7 @@ pub(crate) fn codegen_drop<'tcx>( fx.bcx.ins().call_indirect(sig, drop_fn, &[data]); } _ => { - assert!(!matches!(drop_instance.def, InstanceDef::Virtual(_, _))); + assert!(!matches!(drop_instance.def, InstanceKind::Virtual(_, _))); let fn_abi = RevealAllLayoutCx(fx.tcx).fn_abi_of_instance(drop_instance, ty::List::empty()); diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index a53598018f4a..87c5da3b7c3e 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -50,7 +50,7 @@ pub(crate) fn codegen_tls_ref<'tcx>( ) -> CValue<'tcx> { let tls_ptr = if !def_id.is_local() && fx.tcx.needs_thread_local_shim(def_id) { let instance = ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), + def: ty::InstanceKind::ThreadLocalShim(def_id), args: ty::GenericArgs::empty(), }; let func_ref = fx.get_function_ref(instance); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index cafdc051db5a..b21c559e6686 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -1261,7 +1261,7 @@ fn codegen_regular_intrinsic_call<'tcx>( } // Unimplemented intrinsics must have a fallback body. The fallback body is obtained - // by converting the `InstanceDef::Intrinsic` to an `InstanceDef::Item`. + // by converting the `InstanceKind::Intrinsic` to an `InstanceKind::Item`. _ => { let intrinsic = fx.tcx.intrinsic(instance.def_id()).unwrap(); if intrinsic.must_be_overridden { diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index 0fea3fd42539..2edb34e7c20d 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -98,7 +98,7 @@ mod prelude { pub(crate) use rustc_middle::mir::{self, *}; pub(crate) use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; pub(crate) use rustc_middle::ty::{ - self, FloatTy, Instance, InstanceDef, IntTy, ParamEnv, Ty, TyCtxt, UintTy, + self, FloatTy, Instance, InstanceKind, IntTy, ParamEnv, Ty, TyCtxt, UintTy, }; pub(crate) use rustc_span::Span; pub(crate) use rustc_target::abi::{Abi, FieldIdx, Scalar, Size, VariantIdx, FIRST_VARIANT}; diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index a6df8950b351..1d61c1564091 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -310,7 +310,7 @@ fn exported_symbols_provider_local( if tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics() { use rustc_middle::mir::mono::{Linkage, MonoItem, Visibility}; - use rustc_middle::ty::InstanceDef; + use rustc_middle::ty::InstanceKind; // Normally, we require that shared monomorphizations are not hidden, // because if we want to re-use a monomorphization from a Rust dylib, it @@ -337,7 +337,7 @@ fn exported_symbols_provider_local( } match *mono_item { - MonoItem::Fn(Instance { def: InstanceDef::Item(def), args }) => { + MonoItem::Fn(Instance { def: InstanceKind::Item(def), args }) => { if args.non_erasable_generics(tcx, def).next().is_some() { let symbol = ExportedSymbol::Generic(def, args); symbols.push(( @@ -350,7 +350,7 @@ fn exported_symbols_provider_local( )); } } - MonoItem::Fn(Instance { def: InstanceDef::DropGlue(def_id, Some(ty)), args }) => { + MonoItem::Fn(Instance { def: InstanceKind::DropGlue(def_id, Some(ty)), args }) => { // A little sanity-check debug_assert_eq!( args.non_erasable_generics(tcx, def_id).next(), @@ -366,7 +366,7 @@ fn exported_symbols_provider_local( )); } MonoItem::Fn(Instance { - def: InstanceDef::AsyncDropGlueCtorShim(def_id, Some(ty)), + def: InstanceKind::AsyncDropGlueCtorShim(def_id, Some(ty)), args, }) => { // A little sanity-check @@ -556,7 +556,7 @@ pub fn symbol_name_for_instance_in_crate<'tcx>( rustc_symbol_mangling::symbol_name_for_instance_in_crate( tcx, ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), + def: ty::InstanceKind::ThreadLocalShim(def_id), args: ty::GenericArgs::empty(), }, instantiating_crate, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index bd9704b37aea..57138d3b9dbd 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -510,7 +510,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = self.monomorphize(ty); let drop_fn = Instance::resolve_drop_in_place(bx.tcx(), ty); - if let ty::InstanceDef::DropGlue(_, None) = drop_fn.def { + if let ty::InstanceKind::DropGlue(_, None) = drop_fn.def { // we don't actually need to drop anything. return helper.funclet_br(self, bx, target, mergeable_succ); } @@ -541,7 +541,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // \-------/ // let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function + def: ty::InstanceKind::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function args: drop_fn.args, }; debug!("ty = {:?}", ty); @@ -583,7 +583,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // // SO THEN WE CAN USE THE ABOVE CODE. let virtual_drop = Instance { - def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function + def: ty::InstanceKind::Virtual(drop_fn.def_id(), 0), // idx 0: the drop function args: drop_fn.args, }; debug!("ty = {:?}", ty); @@ -855,7 +855,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let def = instance.map(|i| i.def); if let Some( - ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None), + ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None), ) = def { // Empty drop glue; a no-op. @@ -871,7 +871,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Handle intrinsics old codegen wants Expr's for, ourselves. let intrinsic = match def { - Some(ty::InstanceDef::Intrinsic(def_id)) => Some(bx.tcx().intrinsic(def_id).unwrap()), + Some(ty::InstanceKind::Intrinsic(def_id)) => Some(bx.tcx().intrinsic(def_id).unwrap()), _ => None, }; @@ -1026,7 +1026,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { 'make_args: for (i, arg) in first_args.iter().enumerate() { let mut op = self.codegen_operand(bx, &arg.node); - if let (0, Some(ty::InstanceDef::Virtual(_, idx))) = (i, def) { + if let (0, Some(ty::InstanceKind::Virtual(_, idx))) = (i, def) { match op.val { Pair(data_ptr, meta) => { // In the case of Rc, we need to explicitly pass a diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index ad6b3f1159de..3dc7dc355115 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -704,7 +704,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let static_ = if !def_id.is_local() && bx.cx().tcx().needs_thread_local_shim(def_id) { let instance = ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), + def: ty::InstanceKind::ThreadLocalShim(def_id), args: ty::GenericArgs::empty(), }; let fn_ptr = bx.get_fn_addr(instance); diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index 0818d9425e20..ab60cc379209 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC use rustc_middle::mir::*; use rustc_middle::span_bug; use rustc_middle::ty::{self, adjustment::PointerCoercion, Ty, TyCtxt}; -use rustc_middle::ty::{Instance, InstanceDef, TypeVisitableExt}; +use rustc_middle::ty::{Instance, InstanceKind, TypeVisitableExt}; use rustc_mir_dataflow::Analysis; use rustc_span::{sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; @@ -769,7 +769,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { if let Ok(Some(instance)) = Instance::resolve(tcx, param_env, callee, fn_args) - && let InstanceDef::Item(def) = instance.def + && let InstanceKind::Item(def) = instance.def { // Resolve a trait method call to its concrete implementation, which may be in a // `const` trait impl. This is only used for the const stability check below, since diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 4b8145eb4855..c60df06bb0ef 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -289,7 +289,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>( // We call `const_eval` for zero arg intrinsics, too, in order to cache their value. // Catch such calls and evaluate them instead of trying to load a constant's MIR. - if let ty::InstanceDef::Intrinsic(def_id) = key.value.instance.def { + if let ty::InstanceKind::Intrinsic(def_id) = key.value.instance.def { let ty = key.value.instance.ty(tcx, key.param_env); let ty::FnDef(_, args) = ty.kind() else { bug!("intrinsic with type {:?}", ty); diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index d3631e0d7232..99276bac0350 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -398,10 +398,10 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { fn load_mir( ecx: &InterpCx<'tcx, Self>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { match instance { - ty::InstanceDef::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)), + ty::InstanceKind::Item(def) => Ok(ecx.tcx.mir_for_ctfe(def)), _ => Ok(ecx.tcx.instance_mir(instance)), } } @@ -424,7 +424,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { }; // Only check non-glue functions - if let ty::InstanceDef::Item(def) = instance.def { + if let ty::InstanceKind::Item(def) = instance.def { // Execution might have wandered off into other crates, so we cannot do a stability- // sensitive check here. But we can at least rule out functions that are not const at // all. That said, we have to allow calling functions inside a trait marked with @@ -540,7 +540,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { ); } return Ok(Some(ty::Instance { - def: ty::InstanceDef::Item(instance.def_id()), + def: ty::InstanceKind::Item(instance.def_id()), args: instance.args, })); } diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 4d93038a81e4..86325c5ae240 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -562,7 +562,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { pub fn load_mir( &self, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, promoted: Option, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { trace!("load mir(instance={:?}, promoted={:?})", instance, promoted); diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 4ae0aca5a0c0..e91ab7c17916 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -177,7 +177,7 @@ pub trait Machine<'tcx>: Sized { /// constants, ... fn load_mir( ecx: &InterpCx<'tcx, Self>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, ) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> { Ok(ecx.tcx.instance_mir(instance)) } diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs index 8f76a1486795..74521d0f4934 100644 --- a/compiler/rustc_const_eval/src/interpret/terminator.rs +++ b/compiler/rustc_const_eval/src/interpret/terminator.rs @@ -175,7 +175,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Drop { place, target, unwind, replace: _ } => { let place = self.eval_place(place)?; let instance = Instance::resolve_drop_in_place(*self.tcx, place.layout.ty); - if let ty::InstanceDef::DropGlue(_, None) = instance.def { + if let ty::InstanceKind::DropGlue(_, None) = instance.def { // This is the branch we enter if and only if the dropped type has no drop glue // whatsoever. This can happen as a result of monomorphizing a drop of a // generic. In order to make sure that generic and non-generic code behaves @@ -550,7 +550,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { }; match instance.def { - ty::InstanceDef::Intrinsic(def_id) => { + ty::InstanceKind::Intrinsic(def_id) => { assert!(self.tcx.intrinsic(def_id).is_some()); // FIXME: Should `InPlace` arguments be reset to uninit? if let Some(fallback) = M::call_intrinsic( @@ -562,7 +562,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { unwind, )? { assert!(!self.tcx.intrinsic(fallback.def_id()).unwrap().must_be_overridden); - assert!(matches!(fallback.def, ty::InstanceDef::Item(_))); + assert!(matches!(fallback.def, ty::InstanceKind::Item(_))); return self.eval_fn_call( FnVal::Instance(fallback), (caller_abi, caller_fn_abi), @@ -576,18 +576,18 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(()) } } - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::AsyncDropGlueCtorShim(..) - | ty::InstanceDef::Item(_) => { + ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::DropGlue(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) + | ty::InstanceKind::ThreadLocalShim(..) + | ty::InstanceKind::AsyncDropGlueCtorShim(..) + | ty::InstanceKind::Item(_) => { // We need MIR for this fn let Some((body, instance)) = M::find_mir_or_eval_fn( self, @@ -786,9 +786,9 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { Ok(()) => Ok(()), } } - // `InstanceDef::Virtual` does not have callable MIR. Calls to `Virtual` instances must be + // `InstanceKind::Virtual` does not have callable MIR. Calls to `Virtual` instances must be // codegen'd / interpreted as virtual calls through the vtable. - ty::InstanceDef::Virtual(def_id, idx) => { + ty::InstanceKind::Virtual(def_id, idx) => { let mut args = args.to_vec(); // We have to implement all "object safe receivers". So we have to go search for a // pointer or `dyn Trait` type, but it could be wrapped in newtypes. So recursively @@ -965,7 +965,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let place = self.force_allocation(place)?; // We behave a bit different from codegen here. - // Codegen creates an `InstanceDef::Virtual` with index 0 (the slot of the drop method) and + // Codegen creates an `InstanceKind::Virtual` with index 0 (the slot of the drop method) and // then dispatches that to the normal call machinery. However, our call machinery currently // only supports calling `VtblEntry::Method`; it would choke on a `MetadataDropInPlace`. So // instead we do the virtual call stuff ourselves. It's easier here than in `eval_fn_call` diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index f6537ed6ea9e..bbe5e5fe3edb 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -44,7 +44,7 @@ where | ty::CoroutineClosure(def_id, args, ..) | ty::Coroutine(def_id, args, ..) | ty::FnDef(def_id, args) => { - let instance = ty::InstanceDef::Item(def_id); + let instance = ty::InstanceKind::Item(def_id); let unused_params = self.tcx.unused_generic_params(instance); for (index, arg) in args.into_iter().enumerate() { let index = index diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index d52286d5887d..f881d53858a2 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -756,7 +756,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { || tcx.hir().body_const_context(def_id).is_some() { tcx.ensure().mir_drops_elaborated_and_const_checked(def_id); - tcx.ensure().unused_generic_params(ty::InstanceDef::Item(def_id.to_def_id())); + tcx.ensure().unused_generic_params(ty::InstanceKind::Item(def_id.to_def_id())); } } }); diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 1cef35f082b9..c9450142cd3b 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -191,7 +191,7 @@ impl IntoArgs for (CrateNum, DefId) { } } -impl<'tcx> IntoArgs for ty::InstanceDef<'tcx> { +impl<'tcx> IntoArgs for ty::InstanceKind<'tcx> { type Other = (); fn into_args(self) -> (DefId, ()) { (self.def_id(), ()) diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index d7840a2d516f..4bd2ec09a6e6 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1693,7 +1693,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses); } - let instance = ty::InstanceDef::Item(def_id.to_def_id()); + let instance = ty::InstanceKind::Item(def_id.to_def_id()); let unused = tcx.unused_generic_params(instance); self.tables.unused_generic_params.set(def_id.local_def_index, unused); } diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 3b6eecb7fa04..b35cc83cb8e8 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -64,7 +64,7 @@ impl<'tcx> ExportedSymbol<'tcx> { tcx.symbol_name(ty::Instance::resolve_async_drop_in_place(tcx, ty)) } ExportedSymbol::ThreadLocalShim(def_id) => tcx.symbol_name(ty::Instance { - def: ty::InstanceDef::ThreadLocalShim(def_id), + def: ty::InstanceKind::ThreadLocalShim(def_id), args: ty::GenericArgs::empty(), }), ExportedSymbol::NoDefId(symbol_name) => symbol_name, diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs index 96bef40dac51..2eadc4d553cc 100644 --- a/compiler/rustc_middle/src/mir/graphviz.rs +++ b/compiler/rustc_middle/src/mir/graphviz.rs @@ -19,7 +19,7 @@ where if tcx.is_const_fn_raw(*def_id) { vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)] } else { - vec![tcx.instance_mir(ty::InstanceDef::Item(*def_id))] + vec![tcx.instance_mir(ty::InstanceKind::Item(*def_id))] } }) .collect::>(); diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 02e5174a715d..01cefc75194f 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -10,7 +10,7 @@ use crate::ty::print::{pretty_print_const, with_no_trimmed_paths}; use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::visit::TypeVisitableExt; use crate::ty::{self, List, Ty, TyCtxt}; -use crate::ty::{AdtDef, Instance, InstanceDef, UserTypeAnnotationIndex}; +use crate::ty::{AdtDef, Instance, InstanceKind, UserTypeAnnotationIndex}; use crate::ty::{GenericArg, GenericArgsRef}; use rustc_data_structures::captures::Captures; @@ -233,7 +233,7 @@ impl RuntimePhase { #[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(HashStable, TyEncodable, TyDecodable, TypeFoldable, TypeVisitable)] pub struct MirSource<'tcx> { - pub instance: InstanceDef<'tcx>, + pub instance: InstanceKind<'tcx>, /// If `Some`, this is a promoted rvalue within the parent function. pub promoted: Option, @@ -241,10 +241,10 @@ pub struct MirSource<'tcx> { impl<'tcx> MirSource<'tcx> { pub fn item(def_id: DefId) -> Self { - MirSource { instance: InstanceDef::Item(def_id), promoted: None } + MirSource { instance: InstanceKind::Item(def_id), promoted: None } } - pub fn from_instance(instance: InstanceDef<'tcx>) -> Self { + pub fn from_instance(instance: InstanceKind<'tcx>) -> Self { MirSource { instance, promoted: None } } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 3d79ec0092f8..146cd6dfbeb7 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,5 +1,5 @@ use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; -use crate::ty::{GenericArgs, Instance, InstanceDef, SymbolName, TyCtxt}; +use crate::ty::{GenericArgs, Instance, InstanceKind, SymbolName, TyCtxt}; use rustc_attr::InlineAttr; use rustc_data_structures::base_n::BaseNString; use rustc_data_structures::base_n::ToBaseN; @@ -56,7 +56,7 @@ impl<'tcx> MonoItem<'tcx> { /// Returns `true` if the mono item is user-defined (i.e. not compiler-generated, like shims). pub fn is_user_defined(&self) -> bool { match *self { - MonoItem::Fn(instance) => matches!(instance.def, InstanceDef::Item(..)), + MonoItem::Fn(instance) => matches!(instance.def, InstanceKind::Item(..)), MonoItem::Static(..) | MonoItem::GlobalAsm(..) => true, } } @@ -69,9 +69,9 @@ impl<'tcx> MonoItem<'tcx> { match instance.def { // "Normal" functions size estimate: the number of // statements, plus one for the terminator. - InstanceDef::Item(..) - | InstanceDef::DropGlue(..) - | InstanceDef::AsyncDropGlueCtorShim(..) => { + InstanceKind::Item(..) + | InstanceKind::DropGlue(..) + | InstanceKind::AsyncDropGlueCtorShim(..) => { let mir = tcx.instance_mir(instance.def); mir.basic_blocks.iter().map(|bb| bb.statements.len() + 1).sum() } @@ -407,20 +407,20 @@ impl<'tcx> CodegenUnit<'tcx> { // instances into account. The others don't matter for // the codegen tests and can even make item order // unstable. - InstanceDef::Item(def) => def.as_local().map(Idx::index), - InstanceDef::VTableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineKindShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) - | InstanceDef::ThreadLocalShim(..) - | InstanceDef::FnPtrAddrShim(..) - | InstanceDef::AsyncDropGlueCtorShim(..) => None, + InstanceKind::Item(def) => def.as_local().map(Idx::index), + InstanceKind::VTableShim(..) + | InstanceKind::ReifyShim(..) + | InstanceKind::Intrinsic(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::Virtual(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::CoroutineKindShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::CloneShim(..) + | InstanceKind::ThreadLocalShim(..) + | InstanceKind::FnPtrAddrShim(..) + | InstanceKind::AsyncDropGlueCtorShim(..) => None, } } MonoItem::Static(def_id) => def_id.as_local().map(Idx::index), diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f1c3cb698969..4657f4dcf813 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -177,7 +177,7 @@ fn dump_path<'tcx>( // All drop shims have the same DefId, so we have to add the type // to get unique file names. let shim_disambiguator = match source.instance { - ty::InstanceDef::DropGlue(_, Some(ty)) => { + ty::InstanceKind::DropGlue(_, Some(ty)) => { // Unfortunately, pretty-printed typed are not very filename-friendly. // We dome some filtering. let mut s = ".".to_owned(); @@ -188,7 +188,7 @@ fn dump_path<'tcx>( })); s } - ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(ty)) => { + ty::InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)) => { // Unfortunately, pretty-printed typed are not very filename-friendly. // We dome some filtering. let mut s = ".".to_owned(); @@ -280,7 +280,7 @@ pub fn write_mir_pretty<'tcx>( // are shared between mir_for_ctfe and optimized_mir write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?; } else { - let instance_mir = tcx.instance_mir(ty::InstanceDef::Item(def_id)); + let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id)); render_body(w, instance_mir)?; } } diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 10609e56f2c4..7628a1ed2fe2 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -337,27 +337,27 @@ macro_rules! make_mir_visitor { let ty::Instance { def: callee_def, args: callee_args } = callee; match callee_def { - ty::InstanceDef::Item(_def_id) => {} + ty::InstanceKind::Item(_def_id) => {} - ty::InstanceDef::Intrinsic(_def_id) | - ty::InstanceDef::VTableShim(_def_id) | - ty::InstanceDef::ReifyShim(_def_id, _) | - ty::InstanceDef::Virtual(_def_id, _) | - ty::InstanceDef::ThreadLocalShim(_def_id) | - ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } | - ty::InstanceDef::ConstructCoroutineInClosureShim { + ty::InstanceKind::Intrinsic(_def_id) | + ty::InstanceKind::VTableShim(_def_id) | + ty::InstanceKind::ReifyShim(_def_id, _) | + ty::InstanceKind::Virtual(_def_id, _) | + ty::InstanceKind::ThreadLocalShim(_def_id) | + ty::InstanceKind::ClosureOnceShim { call_once: _def_id, track_caller: _ } | + ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, receiver_by_ref: _, } | - ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id } | - ty::InstanceDef::AsyncDropGlueCtorShim(_def_id, None) | - ty::InstanceDef::DropGlue(_def_id, None) => {} + ty::InstanceKind::CoroutineKindShim { coroutine_def_id: _def_id } | + ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, None) | + ty::InstanceKind::DropGlue(_def_id, None) => {} - ty::InstanceDef::FnPtrShim(_def_id, ty) | - ty::InstanceDef::DropGlue(_def_id, Some(ty)) | - ty::InstanceDef::CloneShim(_def_id, ty) | - ty::InstanceDef::FnPtrAddrShim(_def_id, ty) | - ty::InstanceDef::AsyncDropGlueCtorShim(_def_id, Some(ty)) => { + ty::InstanceKind::FnPtrShim(_def_id, ty) | + ty::InstanceKind::DropGlue(_def_id, Some(ty)) | + ty::InstanceKind::CloneShim(_def_id, ty) | + ty::InstanceKind::FnPtrAddrShim(_def_id, ty) | + ty::InstanceKind::AsyncDropGlueCtorShim(_def_id, Some(ty)) => { // FIXME(eddyb) use a better `TyContext` here. self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); } diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index b29a86d58ed6..301c9911b44c 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -365,7 +365,7 @@ tcx_lifetime! { rustc_middle::ty::GenericPredicates, rustc_middle::ty::inhabitedness::InhabitedPredicate, rustc_middle::ty::Instance, - rustc_middle::ty::InstanceDef, + rustc_middle::ty::InstanceKind, rustc_middle::ty::layout::FnAbiError, rustc_middle::ty::layout::LayoutError, rustc_middle::ty::ParamEnv, diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 5452e1dff3ef..add88491f846 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -62,7 +62,7 @@ impl Key for () { } } -impl<'tcx> Key for ty::InstanceDef<'tcx> { +impl<'tcx> Key for ty::InstanceKind<'tcx> { type Cache = DefaultCache; fn default_span(&self, tcx: TyCtxt<'_>) -> Span { @@ -70,7 +70,7 @@ impl<'tcx> Key for ty::InstanceDef<'tcx> { } } -impl<'tcx> AsLocalKey for ty::InstanceDef<'tcx> { +impl<'tcx> AsLocalKey for ty::InstanceKind<'tcx> { type LocalKey = Self; #[inline(always)] diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 8ba930f493e2..0f08694c4eab 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -575,7 +575,7 @@ rustc_queries! { /// Summarizes coverage IDs inserted by the `InstrumentCoverage` MIR pass /// (for compiler option `-Cinstrument-coverage`), after MIR optimizations /// have had a chance to potentially remove some of them. - query coverage_ids_info(key: ty::InstanceDef<'tcx>) -> &'tcx mir::CoverageIdsInfo { + query coverage_ids_info(key: ty::InstanceKind<'tcx>) -> &'tcx mir::CoverageIdsInfo { desc { |tcx| "retrieving coverage IDs info from MIR for `{}`", tcx.def_path_str(key.def_id()) } arena_cache } @@ -1033,7 +1033,7 @@ rustc_queries! { } /// Obtain all the calls into other local functions - query mir_inliner_callees(key: ty::InstanceDef<'tcx>) -> &'tcx [(DefId, GenericArgsRef<'tcx>)] { + query mir_inliner_callees(key: ty::InstanceKind<'tcx>) -> &'tcx [(DefId, GenericArgsRef<'tcx>)] { fatal_cycle desc { |tcx| "computing all local function calls in `{}`", @@ -1140,7 +1140,7 @@ rustc_queries! { } /// Generates a MIR body for the shim. - query mir_shims(key: ty::InstanceDef<'tcx>) -> &'tcx mir::Body<'tcx> { + query mir_shims(key: ty::InstanceKind<'tcx>) -> &'tcx mir::Body<'tcx> { arena_cache desc { |tcx| "generating MIR shim for `{}`", tcx.def_path_str(key.def_id()) } } @@ -1410,7 +1410,7 @@ rustc_queries! { /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. /// /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance` - /// instead, where the instance is an `InstanceDef::Virtual`. + /// instead, where the instance is an `InstanceKind::Virtual`. query fn_abi_of_fn_ptr( key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List>)> ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> { @@ -1421,7 +1421,7 @@ rustc_queries! { /// direct calls to an `fn`. /// /// NB: that includes virtual calls, which are represented by "direct calls" - /// to an `InstanceDef::Virtual` instance (of `::fn`). + /// to an `InstanceKind::Virtual` instance (of `::fn`). query fn_abi_of_instance( key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List>)> ) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, &'tcx ty::layout::FnAbiError<'tcx>> { @@ -1918,7 +1918,7 @@ rustc_queries! { desc { "getting codegen unit `{sym}`" } } - query unused_generic_params(key: ty::InstanceDef<'tcx>) -> UnusedGenericParams { + query unused_generic_params(key: ty::InstanceKind<'tcx>) -> UnusedGenericParams { cache_on_disk_if { key.def_id().is_local() } desc { |tcx| "determining which generic parameters are unused by `{}`", diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index bdf90cbb25bb..5718264c9446 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -19,10 +19,10 @@ use tracing::{debug, instrument}; use std::assert_matches::assert_matches; use std::fmt; -/// A monomorphized `InstanceDef`. +/// An `InstanceKind` along with the args that are needed to substitute the instance. /// /// Monomorphization happens on-the-fly and no monomorphized MIR is ever created. Instead, this type -/// simply couples a potentially generic `InstanceDef` with some args, and codegen and const eval +/// simply couples a potentially generic `InstanceKind` with some args, and codegen and const eval /// will do all required instantiations as they run. /// /// Note: the `Lift` impl is currently not used by rustc, but is used by @@ -30,7 +30,7 @@ use std::fmt; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, TyEncodable, TyDecodable)] #[derive(HashStable, Lift, TypeFoldable, TypeVisitable)] pub struct Instance<'tcx> { - pub def: InstanceDef<'tcx>, + pub def: InstanceKind<'tcx>, pub args: GenericArgsRef<'tcx>, } @@ -58,7 +58,7 @@ pub enum ReifyReason { #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable, Lift)] -pub enum InstanceDef<'tcx> { +pub enum InstanceKind<'tcx> { /// A user-defined callable item. /// /// This includes: @@ -69,7 +69,7 @@ pub enum InstanceDef<'tcx> { /// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI). /// - /// Alongside `Virtual`, this is the only `InstanceDef` that does not have its own callable MIR. + /// Alongside `Virtual`, this is the only `InstanceKind` that does not have its own callable MIR. /// Instead, codegen and const eval "magically" evaluate calls to intrinsics purely in the /// caller. Intrinsic(DefId), @@ -85,7 +85,7 @@ pub enum InstanceDef<'tcx> { /// /// One example is `::fn`, where the shim contains /// a virtual call, which codegen supports only via a direct call to the - /// `::fn` instance (an `InstanceDef::Virtual`). + /// `::fn` instance (an `InstanceKind::Virtual`). /// /// Another example is functions annotated with `#[track_caller]`, which /// must have their implicit caller location argument populated for a call. @@ -107,7 +107,7 @@ pub enum InstanceDef<'tcx> { /// Dynamic dispatch to `::fn`. /// - /// This `InstanceDef` does not have callable MIR. Calls to `Virtual` instances must be + /// This `InstanceKind` does not have callable MIR. Calls to `Virtual` instances must be /// codegen'd as virtual calls through the vtable. /// /// If this is reified to a `fn` pointer, a `ReifyShim` is used (see `ReifyShim` above for more @@ -216,10 +216,10 @@ impl<'tcx> Instance<'tcx> { } match self.def { - InstanceDef::Item(def) => tcx + InstanceKind::Item(def) => tcx .upstream_monomorphizations_for(def) .and_then(|monos| monos.get(&self.args).cloned()), - InstanceDef::DropGlue(_, Some(_)) | InstanceDef::AsyncDropGlueCtorShim(_, _) => { + InstanceKind::DropGlue(_, Some(_)) | InstanceKind::AsyncDropGlueCtorShim(_, _) => { tcx.upstream_drop_glue_for(self.args) } _ => None, @@ -227,48 +227,48 @@ impl<'tcx> Instance<'tcx> { } } -impl<'tcx> InstanceDef<'tcx> { +impl<'tcx> InstanceKind<'tcx> { #[inline] pub fn def_id(self) -> DefId { match self { - InstanceDef::Item(def_id) - | InstanceDef::VTableShim(def_id) - | InstanceDef::ReifyShim(def_id, _) - | InstanceDef::FnPtrShim(def_id, _) - | InstanceDef::Virtual(def_id, _) - | InstanceDef::Intrinsic(def_id) - | InstanceDef::ThreadLocalShim(def_id) - | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ } - | ty::InstanceDef::ConstructCoroutineInClosureShim { + InstanceKind::Item(def_id) + | InstanceKind::VTableShim(def_id) + | InstanceKind::ReifyShim(def_id, _) + | InstanceKind::FnPtrShim(def_id, _) + | InstanceKind::Virtual(def_id, _) + | InstanceKind::Intrinsic(def_id) + | InstanceKind::ThreadLocalShim(def_id) + | InstanceKind::ClosureOnceShim { call_once: def_id, track_caller: _ } + | ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id: def_id, receiver_by_ref: _, } - | ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id } - | InstanceDef::DropGlue(def_id, _) - | InstanceDef::CloneShim(def_id, _) - | InstanceDef::FnPtrAddrShim(def_id, _) - | InstanceDef::AsyncDropGlueCtorShim(def_id, _) => def_id, + | ty::InstanceKind::CoroutineKindShim { coroutine_def_id: def_id } + | InstanceKind::DropGlue(def_id, _) + | InstanceKind::CloneShim(def_id, _) + | InstanceKind::FnPtrAddrShim(def_id, _) + | InstanceKind::AsyncDropGlueCtorShim(def_id, _) => def_id, } } /// Returns the `DefId` of instances which might not require codegen locally. pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option { match self { - ty::InstanceDef::Item(def) => Some(def), - ty::InstanceDef::DropGlue(def_id, Some(_)) - | InstanceDef::AsyncDropGlueCtorShim(def_id, _) - | InstanceDef::ThreadLocalShim(def_id) => Some(def_id), - InstanceDef::VTableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) - | InstanceDef::FnPtrAddrShim(..) => None, + ty::InstanceKind::Item(def) => Some(def), + ty::InstanceKind::DropGlue(def_id, Some(_)) + | InstanceKind::AsyncDropGlueCtorShim(def_id, _) + | InstanceKind::ThreadLocalShim(def_id) => Some(def_id), + InstanceKind::VTableShim(..) + | InstanceKind::ReifyShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::Virtual(..) + | InstanceKind::Intrinsic(..) + | InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::CloneShim(..) + | InstanceKind::FnPtrAddrShim(..) => None, } } @@ -289,10 +289,10 @@ impl<'tcx> InstanceDef<'tcx> { pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool { use rustc_hir::definitions::DefPathData; let def_id = match *self { - ty::InstanceDef::Item(def) => def, - ty::InstanceDef::DropGlue(_, Some(_)) => return false, - ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(_)) => return false, - ty::InstanceDef::ThreadLocalShim(_) => return false, + ty::InstanceKind::Item(def) => def, + ty::InstanceKind::DropGlue(_, Some(_)) => return false, + ty::InstanceKind::AsyncDropGlueCtorShim(_, Some(_)) => return false, + ty::InstanceKind::ThreadLocalShim(_) => return false, _ => return true, }; matches!( @@ -312,7 +312,7 @@ impl<'tcx> InstanceDef<'tcx> { if self.requires_inline(tcx) { return true; } - if let ty::InstanceDef::DropGlue(.., Some(ty)) = *self { + if let ty::InstanceKind::DropGlue(.., Some(ty)) = *self { // Drop glue generally wants to be instantiated at every codegen // unit, but without an #[inline] hint. We should make this // available to normal end-users. @@ -332,7 +332,7 @@ impl<'tcx> InstanceDef<'tcx> { .map_or_else(|| adt_def.is_enum(), |dtor| tcx.cross_crate_inlinable(dtor.did)) }); } - if let ty::InstanceDef::ThreadLocalShim(..) = *self { + if let ty::InstanceKind::ThreadLocalShim(..) = *self { return false; } tcx.cross_crate_inlinable(self.def_id()) @@ -340,10 +340,10 @@ impl<'tcx> InstanceDef<'tcx> { pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool { match *self { - InstanceDef::Item(def_id) | InstanceDef::Virtual(def_id, _) => { + InstanceKind::Item(def_id) | InstanceKind::Virtual(def_id, _) => { tcx.body_codegen_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER) } - InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller, + InstanceKind::ClosureOnceShim { call_once: _, track_caller } => track_caller, _ => false, } } @@ -356,22 +356,22 @@ impl<'tcx> InstanceDef<'tcx> { /// body should perform necessary instantiations. pub fn has_polymorphic_mir_body(&self) -> bool { match *self { - InstanceDef::CloneShim(..) - | InstanceDef::ThreadLocalShim(..) - | InstanceDef::FnPtrAddrShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::DropGlue(_, Some(_)) - | InstanceDef::AsyncDropGlueCtorShim(_, Some(_)) => false, - InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineKindShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::AsyncDropGlueCtorShim(..) - | InstanceDef::Item(_) - | InstanceDef::Intrinsic(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::VTableShim(..) => true, + InstanceKind::CloneShim(..) + | InstanceKind::ThreadLocalShim(..) + | InstanceKind::FnPtrAddrShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::DropGlue(_, Some(_)) + | InstanceKind::AsyncDropGlueCtorShim(_, Some(_)) => false, + InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::CoroutineKindShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::AsyncDropGlueCtorShim(..) + | InstanceKind::Item(_) + | InstanceKind::Intrinsic(..) + | InstanceKind::ReifyShim(..) + | InstanceKind::Virtual(..) + | InstanceKind::VTableShim(..) => true, } } } @@ -395,24 +395,24 @@ fn fmt_instance( })?; match instance.def { - InstanceDef::Item(_) => Ok(()), - InstanceDef::VTableShim(_) => write!(f, " - shim(vtable)"), - InstanceDef::ReifyShim(_, None) => write!(f, " - shim(reify)"), - InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => write!(f, " - shim(reify-fnptr)"), - InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => write!(f, " - shim(reify-vtable)"), - InstanceDef::ThreadLocalShim(_) => write!(f, " - shim(tls)"), - InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), - InstanceDef::Virtual(_, num) => write!(f, " - virtual#{num}"), - InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({ty})"), - InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"), - InstanceDef::ConstructCoroutineInClosureShim { .. } => write!(f, " - shim"), - InstanceDef::CoroutineKindShim { .. } => write!(f, " - shim"), - InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"), - InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), - InstanceDef::CloneShim(_, ty) => write!(f, " - shim({ty})"), - InstanceDef::FnPtrAddrShim(_, ty) => write!(f, " - shim({ty})"), - InstanceDef::AsyncDropGlueCtorShim(_, None) => write!(f, " - shim(None)"), - InstanceDef::AsyncDropGlueCtorShim(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), + InstanceKind::Item(_) => Ok(()), + InstanceKind::VTableShim(_) => write!(f, " - shim(vtable)"), + InstanceKind::ReifyShim(_, None) => write!(f, " - shim(reify)"), + InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr)) => write!(f, " - shim(reify-fnptr)"), + InstanceKind::ReifyShim(_, Some(ReifyReason::Vtable)) => write!(f, " - shim(reify-vtable)"), + InstanceKind::ThreadLocalShim(_) => write!(f, " - shim(tls)"), + InstanceKind::Intrinsic(_) => write!(f, " - intrinsic"), + InstanceKind::Virtual(_, num) => write!(f, " - virtual#{num}"), + InstanceKind::FnPtrShim(_, ty) => write!(f, " - shim({ty})"), + InstanceKind::ClosureOnceShim { .. } => write!(f, " - shim"), + InstanceKind::ConstructCoroutineInClosureShim { .. } => write!(f, " - shim"), + InstanceKind::CoroutineKindShim { .. } => write!(f, " - shim"), + InstanceKind::DropGlue(_, None) => write!(f, " - shim(None)"), + InstanceKind::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), + InstanceKind::CloneShim(_, ty) => write!(f, " - shim({ty})"), + InstanceKind::FnPtrAddrShim(_, ty) => write!(f, " - shim({ty})"), + InstanceKind::AsyncDropGlueCtorShim(_, None) => write!(f, " - shim(None)"), + InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)) => write!(f, " - shim(Some({ty}))"), } } @@ -434,9 +434,9 @@ impl<'tcx> Instance<'tcx> { pub fn new(def_id: DefId, args: GenericArgsRef<'tcx>) -> Instance<'tcx> { assert!( !args.has_escaping_bound_vars(), - "args of instance {def_id:?} not normalized for codegen: {args:?}" + "args of instance {def_id:?} has escaping bound vars: {args:?}" ); - Instance { def: InstanceDef::Item(def_id), args } + Instance { def: InstanceKind::Item(def_id), args } } pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> { @@ -526,13 +526,13 @@ impl<'tcx> Instance<'tcx> { let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::FnPtr); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { - InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => { + InstanceKind::Item(def) if resolved.def.requires_caller_location(tcx) => { debug!(" => fn pointer created for function with #[track_caller]"); - resolved.def = InstanceDef::ReifyShim(def, reason); + resolved.def = InstanceKind::ReifyShim(def, reason); } - InstanceDef::Virtual(def_id, _) => { + InstanceKind::Virtual(def_id, _) => { debug!(" => fn pointer created for virtual call"); - resolved.def = InstanceDef::ReifyShim(def_id, reason); + resolved.def = InstanceKind::ReifyShim(def_id, reason); } // Reify `Trait::method` implementations if KCFI is enabled // FIXME(maurer) only reify it if it is a vtable-safe function @@ -544,7 +544,7 @@ impl<'tcx> Instance<'tcx> { { // If this function could also go in a vtable, we need to `ReifyShim` it with // KCFI because it can only attach one type per function. - resolved.def = InstanceDef::ReifyShim(resolved.def_id(), reason) + resolved.def = InstanceKind::ReifyShim(resolved.def_id(), reason) } // Reify `::call`-like method implementations if KCFI is enabled _ if tcx.sess.is_sanitizer_kcfi_enabled() @@ -553,7 +553,7 @@ impl<'tcx> Instance<'tcx> { // Reroute through a reify via the *unresolved* instance. The resolved one can't // be directly reified because it's closure-like. The reify can handle the // unresolved instance. - resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args } + resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args } } _ => {} } @@ -575,12 +575,12 @@ impl<'tcx> Instance<'tcx> { && tcx.generics_of(def_id).has_self; if is_vtable_shim { debug!(" => associated item with unsizeable self: Self"); - Some(Instance { def: InstanceDef::VTableShim(def_id), args }) + Some(Instance { def: InstanceKind::VTableShim(def_id), args }) } else { let reason = tcx.sess.is_sanitizer_kcfi_enabled().then_some(ReifyReason::Vtable); Instance::resolve(tcx, param_env, def_id, args).ok().flatten().map(|mut resolved| { match resolved.def { - InstanceDef::Item(def) => { + InstanceKind::Item(def) => { // We need to generate a shim when we cannot guarantee that // the caller of a trait object method will be aware of // `#[track_caller]` - this ensures that the caller @@ -614,18 +614,18 @@ impl<'tcx> Instance<'tcx> { // Create a shim for the `FnOnce/FnMut/Fn` method we are calling // - unlike functions, invoking a closure always goes through a // trait. - resolved = Instance { def: InstanceDef::ReifyShim(def_id, reason), args }; + resolved = Instance { def: InstanceKind::ReifyShim(def_id, reason), args }; } else { debug!( " => vtable fn pointer created for function with #[track_caller]: {:?}", def ); - resolved.def = InstanceDef::ReifyShim(def, reason); + resolved.def = InstanceKind::ReifyShim(def, reason); } } } - InstanceDef::Virtual(def_id, _) => { + InstanceKind::Virtual(def_id, _) => { debug!(" => vtable fn pointer created for virtual call"); - resolved.def = InstanceDef::ReifyShim(def_id, reason) + resolved.def = InstanceKind::ReifyShim(def_id, reason) } _ => {} } @@ -676,7 +676,7 @@ impl<'tcx> Instance<'tcx> { .def_id; let track_caller = tcx.codegen_fn_attrs(closure_did).flags.contains(CodegenFnAttrFlags::TRACK_CALLER); - let def = ty::InstanceDef::ClosureOnceShim { call_once, track_caller }; + let def = ty::InstanceKind::ClosureOnceShim { call_once, track_caller }; let self_ty = Ty::new_closure(tcx, closure_did, args); @@ -733,10 +733,10 @@ impl<'tcx> Instance<'tcx> { // If the closure's kind ty disagrees with the identity closure's kind ty, // then this must be a coroutine generated by one of the `ConstructCoroutineInClosureShim`s. if args.as_coroutine().kind_ty() == id_args.as_coroutine().kind_ty() { - Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args }) + Some(Instance { def: ty::InstanceKind::Item(coroutine_def_id), args }) } else { Some(Instance { - def: ty::InstanceDef::CoroutineKindShim { coroutine_def_id }, + def: ty::InstanceKind::CoroutineKindShim { coroutine_def_id }, args, }) } @@ -749,7 +749,7 @@ impl<'tcx> Instance<'tcx> { } } - /// Depending on the kind of `InstanceDef`, the MIR body associated with an + /// Depending on the kind of `InstanceKind`, the MIR body associated with an /// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other /// cases the MIR body is expressed in terms of the types found in the generic parameter array. /// In the former case, we want to instantiate those generic types and replace them with the @@ -832,7 +832,7 @@ impl<'tcx> Instance<'tcx> { fn polymorphize<'tcx>( tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, args: GenericArgsRef<'tcx>, ) -> GenericArgsRef<'tcx> { debug!("polymorphize({:?}, {:?})", instance, args); @@ -873,7 +873,7 @@ fn polymorphize<'tcx>( match *ty.kind() { ty::Closure(def_id, args) => { let polymorphized_args = - polymorphize(self.tcx, ty::InstanceDef::Item(def_id), args); + polymorphize(self.tcx, ty::InstanceKind::Item(def_id), args); if args == polymorphized_args { ty } else { @@ -882,7 +882,7 @@ fn polymorphize<'tcx>( } ty::Coroutine(def_id, args) => { let polymorphized_args = - polymorphize(self.tcx, ty::InstanceDef::Item(def_id), args); + polymorphize(self.tcx, ty::InstanceKind::Item(def_id), args); if args == polymorphized_args { ty } else { diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 02c0d41f6190..cf7610bb4f61 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1302,7 +1302,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { /// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers. /// /// NB: this doesn't handle virtual calls - those should use `fn_abi_of_instance` - /// instead, where the instance is an `InstanceDef::Virtual`. + /// instead, where the instance is an `InstanceKind::Virtual`. #[inline] fn fn_abi_of_fn_ptr( &self, @@ -1322,7 +1322,7 @@ pub trait FnAbiOf<'tcx>: FnAbiOfHelpers<'tcx> { /// direct calls to an `fn`. /// /// NB: that includes virtual calls, which are represented by "direct calls" - /// to an `InstanceDef::Virtual` instance (of `::fn`). + /// to an `InstanceKind::Virtual` instance (of `::fn`). #[inline] #[tracing::instrument(level = "debug", skip(self))] fn fn_abi_of_instance( diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 5a94a53e175e..fb3dcac47287 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -92,7 +92,7 @@ pub use self::context::{ tls, CtxtInterners, CurrentGcx, DeducedParamAttrs, Feed, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed, }; -pub use self::instance::{Instance, InstanceDef, ReifyReason, ShortInstance, UnusedGenericParams}; +pub use self::instance::{Instance, InstanceKind, ReifyReason, ShortInstance, UnusedGenericParams}; pub use self::list::{List, ListWithCachedTypeInfo}; pub use self::parameterized::ParameterizedOverTcx; pub use self::pattern::{Pattern, PatternKind}; @@ -1731,11 +1731,11 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Returns the possibly-auto-generated MIR of a [`ty::InstanceDef`]. + /// Returns the possibly-auto-generated MIR of a [`ty::InstanceKind`]. #[instrument(skip(self), level = "debug")] - pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> { + pub fn instance_mir(self, instance: ty::InstanceKind<'tcx>) -> &'tcx Body<'tcx> { match instance { - ty::InstanceDef::Item(def) => { + ty::InstanceKind::Item(def) => { debug!("calling def_kind on def: {:?}", def); let def_kind = self.def_kind(def); debug!("returned from def_kind: {:?}", def_kind); @@ -1751,19 +1751,19 @@ impl<'tcx> TyCtxt<'tcx> { _ => self.optimized_mir(def), } } - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) - | ty::InstanceDef::AsyncDropGlueCtorShim(..) => self.mir_shims(instance), + ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::Intrinsic(..) + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::Virtual(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | ty::InstanceKind::DropGlue(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::ThreadLocalShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) + | ty::InstanceKind::AsyncDropGlueCtorShim(..) => self.mir_shims(instance), } } diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 84512e81637e..bf79b4e133a9 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -68,7 +68,7 @@ use rustc_index::{Idx, IndexVec}; use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::CoroutineArgs; -use rustc_middle::ty::InstanceDef; +use rustc_middle::ty::InstanceKind; use rustc_middle::ty::{self, CoroutineArgsExt, Ty, TyCtxt}; use rustc_middle::{bug, span_bug}; use rustc_mir_dataflow::impls::{ @@ -1276,7 +1276,7 @@ fn create_coroutine_drop_shim<'tcx>( // Update the body's def to become the drop glue. let coroutine_instance = body.source.instance; let drop_in_place = tcx.require_lang_item(LangItem::DropInPlace, None); - let drop_instance = InstanceDef::DropGlue(drop_in_place, Some(coroutine_ty)); + let drop_instance = InstanceKind::DropGlue(drop_in_place, Some(coroutine_ty)); // Temporary change MirSource to coroutine's instance so that dump_mir produces more sensible // filename. diff --git a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs index 10c0567eb4b7..69d21a63f557 100644 --- a/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs +++ b/compiler/rustc_mir_transform/src/coroutine/by_move_body.rs @@ -75,7 +75,7 @@ use rustc_middle::bug; use rustc_middle::hir::place::{Projection, ProjectionKind}; use rustc_middle::mir::visit::MutVisitor; use rustc_middle::mir::{self, dump_mir, MirPass}; -use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt, TypeVisitableExt}; +use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt, TypeVisitableExt}; use rustc_target::abi::{FieldIdx, VariantIdx}; pub struct ByMoveBody; @@ -102,7 +102,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { // We don't need to generate a by-move coroutine if the coroutine body was // produced by the `CoroutineKindShim`, since it's already by-move. - if matches!(body.source.instance, ty::InstanceDef::CoroutineKindShim { .. }) { + if matches!(body.source.instance, ty::InstanceKind::CoroutineKindShim { .. }) { return; } @@ -193,7 +193,7 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody { MakeByMoveBody { tcx, field_remapping, by_move_coroutine_ty }.visit_body(&mut by_move_body); dump_mir(tcx, false, "coroutine_by_move", &0, &by_move_body, |_, _| Ok(())); // FIXME: use query feeding to generate the body right here and then only store the `DefId` of the new body. - by_move_body.source = mir::MirSource::from_instance(InstanceDef::CoroutineKindShim { + by_move_body.source = mir::MirSource::from_instance(InstanceKind::CoroutineKindShim { coroutine_def_id: coroutine_def_id.to_def_id(), }); body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body); diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index 65715253647a..25744009be8b 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -49,7 +49,7 @@ fn is_eligible_for_coverage(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { /// Query implementation for `coverage_ids_info`. fn coverage_ids_info<'tcx>( tcx: TyCtxt<'tcx>, - instance_def: ty::InstanceDef<'tcx>, + instance_def: ty::InstanceKind<'tcx>, ) -> CoverageIdsInfo { let mir_body = tcx.instance_mir(instance_def); diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index 2cbe0a01e9ec..d04bb8d302e2 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -10,7 +10,7 @@ use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs} use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; +use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt}; use rustc_session::config::{DebugInfo, OptLevel}; use rustc_span::source_map::Spanned; use rustc_span::sym; @@ -293,7 +293,7 @@ impl<'tcx> Inliner<'tcx> { } match callee.def { - InstanceDef::Item(_) => { + InstanceKind::Item(_) => { // If there is no MIR available (either because it was not in metadata or // because it has no MIR because it's an extern function), then the inliner // won't cause cycles on this. @@ -302,24 +302,24 @@ impl<'tcx> Inliner<'tcx> { } } // These have no own callable MIR. - InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => { + InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => { return Err("instance without MIR (intrinsic / virtual)"); } // This cannot result in an immediate cycle since the callee MIR is a shim, which does // not get any optimizations run on it. Any subsequent inlining may cause cycles, but we // do not need to catch this here, we can wait until the inliner decides to continue // inlining a second time. - InstanceDef::VTableShim(_) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineKindShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::CloneShim(..) - | InstanceDef::ThreadLocalShim(..) - | InstanceDef::FnPtrAddrShim(..) - | InstanceDef::AsyncDropGlueCtorShim(..) => return Ok(()), + InstanceKind::VTableShim(_) + | InstanceKind::ReifyShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::CoroutineKindShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::CloneShim(..) + | InstanceKind::ThreadLocalShim(..) + | InstanceKind::FnPtrAddrShim(..) + | InstanceKind::AsyncDropGlueCtorShim(..) => return Ok(()), } if self.tcx.is_constructor(callee_def_id) { @@ -372,7 +372,7 @@ impl<'tcx> Inliner<'tcx> { let callee = Instance::resolve(self.tcx, self.param_env, def_id, args).ok().flatten()?; - if let InstanceDef::Virtual(..) | InstanceDef::Intrinsic(_) = callee.def { + if let InstanceKind::Virtual(..) | InstanceKind::Intrinsic(_) = callee.def { return None; } @@ -384,7 +384,7 @@ impl<'tcx> Inliner<'tcx> { // Additionally, check that the body that we're inlining actually agrees // with the ABI of the trait that the item comes from. - if let InstanceDef::Item(instance_def_id) = callee.def + if let InstanceKind::Item(instance_def_id) = callee.def && self.tcx.def_kind(instance_def_id) == DefKind::AssocFn && let instance_fn_sig = self.tcx.fn_sig(instance_def_id).skip_binder() && instance_fn_sig.abi() != fn_sig.abi() @@ -1063,10 +1063,10 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { #[instrument(skip(tcx), level = "debug")] fn try_instance_mir<'tcx>( tcx: TyCtxt<'tcx>, - instance: InstanceDef<'tcx>, + instance: InstanceKind<'tcx>, ) -> Result<&'tcx Body<'tcx>, &'static str> { - if let ty::InstanceDef::DropGlue(_, Some(ty)) - | ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(ty)) = instance + if let ty::InstanceKind::DropGlue(_, Some(ty)) + | ty::InstanceKind::AsyncDropGlueCtorShim(_, Some(ty)) = instance && let ty::Adt(def, args) = ty.kind() { let fields = def.all_fields(); diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs index 8c5f965108bd..35bcd24ce95b 100644 --- a/compiler/rustc_mir_transform/src/inline/cycle.rs +++ b/compiler/rustc_mir_transform/src/inline/cycle.rs @@ -3,7 +3,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::mir::TerminatorKind; use rustc_middle::ty::TypeVisitableExt; -use rustc_middle::ty::{self, GenericArgsRef, InstanceDef, TyCtxt}; +use rustc_middle::ty::{self, GenericArgsRef, InstanceKind, TyCtxt}; use rustc_session::Limit; use rustc_span::sym; @@ -22,7 +22,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( "you should not call `mir_callgraph_reachable` on immediate self recursion" ); assert!( - matches!(root.def, InstanceDef::Item(_)), + matches!(root.def, InstanceKind::Item(_)), "you should not call `mir_callgraph_reachable` on shims" ); assert!( @@ -70,7 +70,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( } match callee.def { - InstanceDef::Item(_) => { + InstanceKind::Item(_) => { // If there is no MIR available (either because it was not in metadata or // because it has no MIR because it's an extern function), then the inliner // won't cause cycles on this. @@ -80,24 +80,24 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( } } // These have no own callable MIR. - InstanceDef::Intrinsic(_) | InstanceDef::Virtual(..) => continue, + InstanceKind::Intrinsic(_) | InstanceKind::Virtual(..) => continue, // These have MIR and if that MIR is inlined, instantiated and then inlining is run // again, a function item can end up getting inlined. Thus we'll be able to cause // a cycle that way - InstanceDef::VTableShim(_) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineKindShim { .. } - | InstanceDef::ThreadLocalShim { .. } - | InstanceDef::CloneShim(..) => {} + InstanceKind::VTableShim(_) + | InstanceKind::ReifyShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::CoroutineKindShim { .. } + | InstanceKind::ThreadLocalShim { .. } + | InstanceKind::CloneShim(..) => {} // This shim does not call any other functions, thus there can be no recursion. - InstanceDef::FnPtrAddrShim(..) => { + InstanceKind::FnPtrAddrShim(..) => { continue; } - InstanceDef::DropGlue(..) | InstanceDef::AsyncDropGlueCtorShim(..) => { + InstanceKind::DropGlue(..) | InstanceKind::AsyncDropGlueCtorShim(..) => { // FIXME: A not fully instantiated drop shim can cause ICEs if one attempts to // have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this // needs some more analysis. @@ -151,12 +151,12 @@ pub(crate) fn mir_callgraph_reachable<'tcx>( pub(crate) fn mir_inliner_callees<'tcx>( tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, ) -> &'tcx [(DefId, GenericArgsRef<'tcx>)] { let steal; let guard; let body = match (instance, instance.def_id().as_local()) { - (InstanceDef::Item(_), Some(def_id)) => { + (InstanceKind::Item(_), Some(def_id)) => { steal = tcx.mir_promoted(def_id).0; guard = steal.borrow(); &*guard diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 3c0f4e9142b1..afba6781a703 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -398,7 +398,7 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> & if is_fn_like { // Do not compute the mir call graph without said call graph actually being used. if pm::should_run_pass(tcx, &inline::Inline) { - tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def.to_def_id())); + tcx.ensure_with_value().mir_inliner_callees(ty::InstanceKind::Item(def.to_def_id())); } } diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index d03c2d18c0c3..825f8957187e 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -29,16 +29,16 @@ pub fn provide(providers: &mut Providers) { providers.mir_shims = make_shim; } -fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> { +fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceKind<'tcx>) -> Body<'tcx> { debug!("make_shim({:?})", instance); let mut result = match instance { - ty::InstanceDef::Item(..) => bug!("item {:?} passed to make_shim", instance), - ty::InstanceDef::VTableShim(def_id) => { + ty::InstanceKind::Item(..) => bug!("item {:?} passed to make_shim", instance), + ty::InstanceKind::VTableShim(def_id) => { let adjustment = Adjustment::Deref { source: DerefSource::MutPtr }; build_call_shim(tcx, instance, Some(adjustment), CallKind::Direct(def_id)) } - ty::InstanceDef::FnPtrShim(def_id, ty) => { + ty::InstanceKind::FnPtrShim(def_id, ty) => { let trait_ = tcx.trait_of_item(def_id).unwrap(); // Supports `Fn` or `async Fn` traits. let adjustment = match tcx @@ -58,10 +58,10 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // a virtual call, or a direct call to a function for which // indirect calls must be codegen'd differently than direct ones // (such as `#[track_caller]`). - ty::InstanceDef::ReifyShim(def_id, _) => { + ty::InstanceKind::ReifyShim(def_id, _) => { build_call_shim(tcx, instance, None, CallKind::Direct(def_id)) } - ty::InstanceDef::ClosureOnceShim { call_once: _, track_caller: _ } => { + ty::InstanceKind::ClosureOnceShim { call_once: _, track_caller: _ } => { let fn_mut = tcx.require_lang_item(LangItem::FnMut, None); let call_mut = tcx .associated_items(fn_mut) @@ -73,16 +73,16 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut)) } - ty::InstanceDef::ConstructCoroutineInClosureShim { + ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, receiver_by_ref, } => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref), - ty::InstanceDef::CoroutineKindShim { coroutine_def_id } => { + ty::InstanceKind::CoroutineKindShim { coroutine_def_id } => { return tcx.optimized_mir(coroutine_def_id).coroutine_by_move_body().unwrap().clone(); } - ty::InstanceDef::DropGlue(def_id, ty) => { + ty::InstanceKind::DropGlue(def_id, ty) => { // FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end // of this function. Is this intentional? if let Some(ty::Coroutine(coroutine_def_id, args)) = ty.map(Ty::kind) { @@ -127,16 +127,16 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' build_drop_shim(tcx, def_id, ty) } - ty::InstanceDef::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance), - ty::InstanceDef::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), - ty::InstanceDef::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty), - ty::InstanceDef::AsyncDropGlueCtorShim(def_id, ty) => { + ty::InstanceKind::ThreadLocalShim(..) => build_thread_local_shim(tcx, instance), + ty::InstanceKind::CloneShim(def_id, ty) => build_clone_shim(tcx, def_id, ty), + ty::InstanceKind::FnPtrAddrShim(def_id, ty) => build_fn_ptr_addr_shim(tcx, def_id, ty), + ty::InstanceKind::AsyncDropGlueCtorShim(def_id, ty) => { async_destructor_ctor::build_async_destructor_ctor_shim(tcx, def_id, ty) } - ty::InstanceDef::Virtual(..) => { - bug!("InstanceDef::Virtual ({:?}) is for direct calls only", instance) + ty::InstanceKind::Virtual(..) => { + bug!("InstanceKind::Virtual ({:?}) is for direct calls only", instance) } - ty::InstanceDef::Intrinsic(_) => { + ty::InstanceKind::Intrinsic(_) => { bug!("creating shims from intrinsics ({:?}) is unsupported", instance) } }; @@ -240,7 +240,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) block(&mut blocks, TerminatorKind::Goto { target: return_block }); block(&mut blocks, TerminatorKind::Return); - let source = MirSource::from_instance(ty::InstanceDef::DropGlue(def_id, ty)); + let source = MirSource::from_instance(ty::InstanceKind::DropGlue(def_id, ty)); let mut body = new_body(source, blocks, local_decls_for_sig(&sig, span), sig.inputs().len(), span); @@ -392,7 +392,10 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { } } -fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'tcx> { +fn build_thread_local_shim<'tcx>( + tcx: TyCtxt<'tcx>, + instance: ty::InstanceKind<'tcx>, +) -> Body<'tcx> { let def_id = instance.def_id(); let span = tcx.def_span(def_id); @@ -472,7 +475,7 @@ impl<'tcx> CloneShimBuilder<'tcx> { } fn into_mir(self) -> Body<'tcx> { - let source = MirSource::from_instance(ty::InstanceDef::CloneShim( + let source = MirSource::from_instance(ty::InstanceKind::CloneShim( self.def_id, self.sig.inputs_and_output[0], )); @@ -682,14 +685,14 @@ impl<'tcx> CloneShimBuilder<'tcx> { #[instrument(level = "debug", skip(tcx), ret)] fn build_call_shim<'tcx>( tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, rcvr_adjustment: Option, call_kind: CallKind<'tcx>, ) -> Body<'tcx> { // `FnPtrShim` contains the fn pointer type that a call shim is being built for - this is used // to instantiate into the signature of the shim. It is not necessary for users of this - // MIR body to perform further instantiations (see `InstanceDef::has_polymorphic_mir_body`). - let (sig_args, untuple_args) = if let ty::InstanceDef::FnPtrShim(_, ty) = instance { + // MIR body to perform further instantiations (see `InstanceKind::has_polymorphic_mir_body`). + let (sig_args, untuple_args) = if let ty::InstanceKind::FnPtrShim(_, ty) = instance { let sig = tcx.instantiate_bound_regions_with_erased(ty.fn_sig(tcx)); let untuple_args = sig.inputs(); @@ -741,8 +744,8 @@ fn build_call_shim<'tcx>( } // FIXME(eddyb) avoid having this snippet both here and in - // `Instance::fn_sig` (introduce `InstanceDef::fn_sig`?). - if let ty::InstanceDef::VTableShim(..) = instance { + // `Instance::fn_sig` (introduce `InstanceKind::fn_sig`?). + if let ty::InstanceKind::VTableShim(..) = instance { // Modify fn(self, ...) to fn(self: *mut Self, ...) let mut inputs_and_output = sig.inputs_and_output.to_vec(); let self_arg = &mut inputs_and_output[0]; @@ -1007,7 +1010,7 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t terminator: Some(Terminator { source_info, kind: TerminatorKind::Return }), is_cleanup: false, }; - let source = MirSource::from_instance(ty::InstanceDef::FnPtrAddrShim(def_id, self_ty)); + let source = MirSource::from_instance(ty::InstanceKind::FnPtrAddrShim(def_id, self_ty)); new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span) } @@ -1087,7 +1090,7 @@ fn build_construct_coroutine_by_move_shim<'tcx>( is_cleanup: false, }; - let source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim { + let source = MirSource::from_instance(ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, receiver_by_ref, }); diff --git a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs index 41643f202851..ea4f5fca59e6 100644 --- a/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs +++ b/compiler/rustc_mir_transform/src/shim/async_destructor_ctor.rs @@ -529,7 +529,7 @@ impl<'tcx> AsyncDestructorCtorShimBuilder<'tcx> { last_bb.terminator = Some(Terminator { source_info, kind: TerminatorKind::Return }); - let source = MirSource::from_instance(ty::InstanceDef::AsyncDropGlueCtorShim( + let source = MirSource::from_instance(ty::InstanceKind::AsyncDropGlueCtorShim( self.def_id, self.self_ty, )); diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index ea23bbc2a38e..2cca1a6f507b 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -10,7 +10,7 @@ use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::{ - self, CoroutineArgsExt, InstanceDef, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt, + self, CoroutineArgsExt, InstanceKind, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt, Variance, }; use rustc_middle::{bug, span_bug}; @@ -44,7 +44,7 @@ impl<'tcx> MirPass<'tcx> for Validator { // terribly important that they pass the validator. However, I think other passes might // still see them, in which case they might be surprised. It would probably be better if we // didn't put this through the MIR pipeline at all. - if matches!(body.source.instance, InstanceDef::Intrinsic(..) | InstanceDef::Virtual(..)) { + if matches!(body.source.instance, InstanceKind::Intrinsic(..) | InstanceKind::Virtual(..)) { return; } let def_id = body.source.def_id(); @@ -95,7 +95,7 @@ impl<'tcx> MirPass<'tcx> for Validator { } if let MirPhase::Runtime(_) = body.phase { - if let ty::InstanceDef::Item(_) = body.source.instance { + if let ty::InstanceKind::Item(_) = body.source.instance { if body.has_free_regions() { cfg_checker.fail( Location::START, diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 04de1654c1a4..235743fccc89 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -224,7 +224,7 @@ use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCoercion}; use rustc_middle::ty::layout::ValidityRequirement; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{ - self, AssocKind, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, + self, AssocKind, GenericParamDefKind, Instance, InstanceKind, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, VtblEntry, }; use rustc_middle::ty::{GenericArgKind, GenericArgs}; @@ -420,7 +420,7 @@ fn collect_items_rec<'tcx>( used_items.push(respan( starting_item.span, MonoItem::Fn(Instance { - def: InstanceDef::ThreadLocalShim(def_id), + def: InstanceKind::ThreadLocalShim(def_id), args: GenericArgs::empty(), }), )); @@ -938,7 +938,7 @@ fn visit_instance_use<'tcx>( if !should_codegen_locally(tcx, instance) { return; } - if let ty::InstanceDef::Intrinsic(def_id) = instance.def { + if let ty::InstanceKind::Intrinsic(def_id) = instance.def { let name = tcx.item_name(def_id); if let Some(_requirement) = ValidityRequirement::from_intrinsic(name) { // The intrinsics assert_inhabited, assert_zero_valid, and assert_mem_uninitialized_valid will @@ -960,31 +960,31 @@ fn visit_instance_use<'tcx>( } match instance.def { - ty::InstanceDef::Virtual(..) | ty::InstanceDef::Intrinsic(_) => { + ty::InstanceKind::Virtual(..) | ty::InstanceKind::Intrinsic(_) => { if !is_direct_call { bug!("{:?} being reified", instance); } } - ty::InstanceDef::ThreadLocalShim(..) => { + ty::InstanceKind::ThreadLocalShim(..) => { bug!("{:?} being reified", instance); } - ty::InstanceDef::DropGlue(_, None) | ty::InstanceDef::AsyncDropGlueCtorShim(_, None) => { + ty::InstanceKind::DropGlue(_, None) | ty::InstanceKind::AsyncDropGlueCtorShim(_, None) => { // Don't need to emit noop drop glue if we are calling directly. if !is_direct_call { output.push(create_fn_mono_item(tcx, instance, source)); } } - ty::InstanceDef::DropGlue(_, Some(_)) - | ty::InstanceDef::AsyncDropGlueCtorShim(_, Some(_)) - | ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::Item(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) => { + ty::InstanceKind::DropGlue(_, Some(_)) + | ty::InstanceKind::AsyncDropGlueCtorShim(_, Some(_)) + | ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | ty::InstanceKind::Item(..) + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) => { output.push(create_fn_mono_item(tcx, instance, source)); } } diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 14b5b22dc648..9a7c488833a1 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -114,7 +114,7 @@ use rustc_middle::mir::mono::{ }; use rustc_middle::query::Providers; use rustc_middle::ty::print::{characteristic_def_id_of_type, with_no_trimmed_paths}; -use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceDef, TyCtxt}; +use rustc_middle::ty::{self, visit::TypeVisitableExt, InstanceKind, TyCtxt}; use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; use rustc_session::CodegenUnits; use rustc_span::symbol::Symbol; @@ -620,20 +620,20 @@ fn characteristic_def_id_of_mono_item<'tcx>( match mono_item { MonoItem::Fn(instance) => { let def_id = match instance.def { - ty::InstanceDef::Item(def) => def, - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::Virtual(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) - | ty::InstanceDef::AsyncDropGlueCtorShim(..) => return None, + ty::InstanceKind::Item(def) => def, + ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | ty::InstanceKind::Intrinsic(..) + | ty::InstanceKind::DropGlue(..) + | ty::InstanceKind::Virtual(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::ThreadLocalShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) + | ty::InstanceKind::AsyncDropGlueCtorShim(..) => return None, }; // If this is a method, we want to put it into the same module as @@ -777,28 +777,28 @@ fn mono_item_visibility<'tcx>( }; let def_id = match instance.def { - InstanceDef::Item(def_id) - | InstanceDef::DropGlue(def_id, Some(_)) - | InstanceDef::AsyncDropGlueCtorShim(def_id, Some(_)) => def_id, + InstanceKind::Item(def_id) + | InstanceKind::DropGlue(def_id, Some(_)) + | InstanceKind::AsyncDropGlueCtorShim(def_id, Some(_)) => def_id, // We match the visibility of statics here - InstanceDef::ThreadLocalShim(def_id) => { + InstanceKind::ThreadLocalShim(def_id) => { return static_visibility(tcx, can_be_internalized, def_id); } // These are all compiler glue and such, never exported, always hidden. - InstanceDef::VTableShim(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::FnPtrShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::Intrinsic(..) - | InstanceDef::ClosureOnceShim { .. } - | InstanceDef::ConstructCoroutineInClosureShim { .. } - | InstanceDef::CoroutineKindShim { .. } - | InstanceDef::DropGlue(..) - | InstanceDef::AsyncDropGlueCtorShim(..) - | InstanceDef::CloneShim(..) - | InstanceDef::FnPtrAddrShim(..) => return Visibility::Hidden, + InstanceKind::VTableShim(..) + | InstanceKind::ReifyShim(..) + | InstanceKind::FnPtrShim(..) + | InstanceKind::Virtual(..) + | InstanceKind::Intrinsic(..) + | InstanceKind::ClosureOnceShim { .. } + | InstanceKind::ConstructCoroutineInClosureShim { .. } + | InstanceKind::CoroutineKindShim { .. } + | InstanceKind::DropGlue(..) + | InstanceKind::AsyncDropGlueCtorShim(..) + | InstanceKind::CloneShim(..) + | InstanceKind::FnPtrAddrShim(..) => return Visibility::Hidden, }; // The `start_fn` lang item is actually a monomorphized instance of a @@ -813,7 +813,7 @@ fn mono_item_visibility<'tcx>( // internalization, but we have to understand that it's referenced // from the `main` symbol we'll generate later. // - // This may be fixable with a new `InstanceDef` perhaps? Unsure! + // This may be fixable with a new `InstanceKind` perhaps? Unsure! if tcx.is_lang_item(def_id, LangItem::Start) { *can_be_internalized = false; return Visibility::Hidden; diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index c187cb63ee18..2d69bfa4da8e 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -33,7 +33,7 @@ pub fn provide(providers: &mut Providers) { /// parameters are used). fn unused_generic_params<'tcx>( tcx: TyCtxt<'tcx>, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, ) -> UnusedGenericParams { assert!(instance.def_id().is_local()); @@ -88,7 +88,7 @@ fn unused_generic_params<'tcx>( fn should_polymorphize<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, - instance: ty::InstanceDef<'tcx>, + instance: ty::InstanceKind<'tcx>, ) -> bool { // If an instance's MIR body is not polymorphic then the modified generic parameters that are // derived from polymorphization's result won't make any difference. @@ -97,7 +97,7 @@ fn should_polymorphize<'tcx>( } // Don't polymorphize intrinsics or virtual calls - calling `instance_mir` will panic. - if matches!(instance, ty::InstanceDef::Intrinsic(..) | ty::InstanceDef::Virtual(..)) { + if matches!(instance, ty::InstanceKind::Intrinsic(..) | ty::InstanceKind::Virtual(..)) { return false; } @@ -230,7 +230,7 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> { /// a closure, coroutine or constant). #[instrument(level = "debug", skip(self, def_id, args))] fn visit_child_body(&mut self, def_id: DefId, args: GenericArgsRef<'tcx>) { - let instance = ty::InstanceDef::Item(def_id); + let instance = ty::InstanceKind::Item(def_id); let unused = self.tcx.unused_generic_params(instance); debug!(?self.unused_parameters, ?unused); for (i, arg) in args.iter().enumerate() { 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 2cb0c06e3361..832efb119992 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 @@ -288,9 +288,9 @@ pub fn transform_instance<'tcx>( mut instance: Instance<'tcx>, options: TransformTyOptions, ) -> Instance<'tcx> { - if (matches!(instance.def, ty::InstanceDef::Virtual(..)) + if (matches!(instance.def, ty::InstanceKind::Virtual(..)) && tcx.is_lang_item(instance.def_id(), LangItem::DropInPlace)) - || matches!(instance.def, ty::InstanceDef::DropGlue(..)) + || matches!(instance.def, ty::InstanceKind::DropGlue(..)) { // Adjust the type ids of DropGlues // @@ -316,7 +316,7 @@ pub fn transform_instance<'tcx>( let predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(predicate)]); let self_ty = Ty::new_dynamic(tcx, predicates, tcx.lifetimes.re_erased, ty::Dyn); instance.args = tcx.mk_args_trait(self_ty, List::empty()); - } else if let ty::InstanceDef::Virtual(def_id, _) = instance.def { + } else if let ty::InstanceKind::Virtual(def_id, _) = instance.def { // Transform self into a trait object of the trait that defines the method for virtual // functions to match the type erasure done below. let upcast_ty = match tcx.trait_of_item(def_id) { @@ -343,7 +343,7 @@ pub fn transform_instance<'tcx>( tcx.types.unit }; instance.args = tcx.mk_args_trait(self_ty, instance.args.into_iter().skip(1)); - } else if let ty::InstanceDef::VTableShim(def_id) = instance.def + } else if let ty::InstanceKind::VTableShim(def_id) = instance.def && let Some(trait_id) = tcx.trait_of_item(def_id) { // Adjust the type ids of VTableShims to the type id expected in the call sites for the @@ -387,7 +387,7 @@ pub fn transform_instance<'tcx>( // If we ever *do* start encoding the vtable index, we will need to generate an alias set // based on which vtables we are putting this method into, as there will be more than one // index value when supertraits are involved. - instance.def = ty::InstanceDef::Virtual(method_id, 0); + instance.def = ty::InstanceKind::Virtual(method_id, 0); let abstract_trait_args = tcx.mk_args_trait(invoke_ty, trait_ref.args.into_iter().skip(1)); instance.args = instance.args.rebase_onto(tcx, impl_id, abstract_trait_args); @@ -442,7 +442,7 @@ pub fn transform_instance<'tcx>( .expect("No call-family function on closure-like Fn trait?") .def_id; - instance.def = ty::InstanceDef::Virtual(call, 0); + instance.def = ty::InstanceKind::Virtual(call, 0); instance.args = abstract_args; } } diff --git a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs index 436c398e39b0..651ba6124696 100644 --- a/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs +++ b/compiler/rustc_sanitizers/src/kcfi/typeid/mod.rs @@ -3,7 +3,7 @@ //! //! For more information about LLVM KCFI and cross-language LLVM KCFI support for the Rust compiler, //! see the tracking issue #123479. -use rustc_middle::ty::{Instance, InstanceDef, ReifyReason, Ty, TyCtxt}; +use rustc_middle::ty::{Instance, InstanceKind, ReifyReason, Ty, TyCtxt}; use rustc_target::abi::call::FnAbi; use std::hash::Hasher; use twox_hash::XxHash64; @@ -44,7 +44,7 @@ pub fn typeid_for_instance<'tcx>( // // This was implemented for KCFI support in #123106 and #123052 (which introduced the // ReifyReason). The tracking issue for KCFI support for Rust is #123479. - if matches!(instance.def, InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr))) { + if matches!(instance.def, InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr))) { options.insert(TypeIdOptions::USE_CONCRETE_SELF); } // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the diff --git a/compiler/rustc_smir/src/rustc_smir/builder.rs b/compiler/rustc_smir/src/rustc_smir/builder.rs index 577373cbc958..42fa6989ddcf 100644 --- a/compiler/rustc_smir/src/rustc_smir/builder.rs +++ b/compiler/rustc_smir/src/rustc_smir/builder.rs @@ -19,7 +19,7 @@ impl<'tcx> BodyBuilder<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, instance: ty::Instance<'tcx>) -> Self { let instance = match instance.def { // To get the fallback body of an intrinsic, we need to convert it to an item. - ty::InstanceDef::Intrinsic(def_id) => ty::Instance::new(def_id, instance.args), + ty::InstanceKind::Intrinsic(def_id) => ty::Instance::new(def_id, instance.args), _ => instance, }; BodyBuilder { tcx, instance } diff --git a/compiler/rustc_smir/src/rustc_smir/context.rs b/compiler/rustc_smir/src/rustc_smir/context.rs index 4348bc31bf9e..9afd507ce113 100644 --- a/compiler/rustc_smir/src/rustc_smir/context.rs +++ b/compiler/rustc_smir/src/rustc_smir/context.rs @@ -60,7 +60,7 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn mir_body(&self, item: stable_mir::DefId) -> stable_mir::mir::Body { let mut tables = self.0.borrow_mut(); let def_id = tables[item]; - tables.tcx.instance_mir(rustc_middle::ty::InstanceDef::Item(def_id)).stable(&mut tables) + tables.tcx.instance_mir(rustc_middle::ty::InstanceKind::Item(def_id)).stable(&mut tables) } fn has_body(&self, def: DefId) -> bool { @@ -548,13 +548,13 @@ impl<'tcx> Context for TablesWrapper<'tcx> { fn is_empty_drop_shim(&self, def: InstanceDef) -> bool { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; - matches!(instance.def, ty::InstanceDef::DropGlue(_, None)) + matches!(instance.def, ty::InstanceKind::DropGlue(_, None)) } fn is_empty_async_drop_ctor_shim(&self, def: InstanceDef) -> bool { let tables = self.0.borrow_mut(); let instance = tables.instances[def]; - matches!(instance.def, ty::InstanceDef::AsyncDropGlueCtorShim(_, None)) + matches!(instance.def, ty::InstanceKind::AsyncDropGlueCtorShim(_, None)) } fn mono_instance(&self, def_id: stable_mir::DefId) -> stable_mir::mir::mono::Instance { diff --git a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs index e3cd7187e773..9cd841bba109 100644 --- a/compiler/rustc_smir/src/rustc_smir/convert/ty.rs +++ b/compiler/rustc_smir/src/rustc_smir/convert/ty.rs @@ -839,22 +839,22 @@ impl<'tcx> Stable<'tcx> for ty::Instance<'tcx> { fn stable(&self, tables: &mut Tables<'_>) -> Self::T { let def = tables.instance_def(tables.tcx.lift(*self).unwrap()); let kind = match self.def { - ty::InstanceDef::Item(..) => stable_mir::mir::mono::InstanceKind::Item, - ty::InstanceDef::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic, - ty::InstanceDef::Virtual(_def_id, idx) => { + ty::InstanceKind::Item(..) => stable_mir::mir::mono::InstanceKind::Item, + ty::InstanceKind::Intrinsic(..) => stable_mir::mir::mono::InstanceKind::Intrinsic, + ty::InstanceKind::Virtual(_def_id, idx) => { stable_mir::mir::mono::InstanceKind::Virtual { idx } } - ty::InstanceDef::VTableShim(..) - | ty::InstanceDef::ReifyShim(..) - | ty::InstanceDef::FnPtrAddrShim(..) - | ty::InstanceDef::ClosureOnceShim { .. } - | ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } - | ty::InstanceDef::ThreadLocalShim(..) - | ty::InstanceDef::DropGlue(..) - | ty::InstanceDef::CloneShim(..) - | ty::InstanceDef::FnPtrShim(..) - | ty::InstanceDef::AsyncDropGlueCtorShim(..) => { + ty::InstanceKind::VTableShim(..) + | ty::InstanceKind::ReifyShim(..) + | ty::InstanceKind::FnPtrAddrShim(..) + | ty::InstanceKind::ClosureOnceShim { .. } + | ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } + | ty::InstanceKind::ThreadLocalShim(..) + | ty::InstanceKind::DropGlue(..) + | ty::InstanceKind::CloneShim(..) + | ty::InstanceKind::FnPtrShim(..) + | ty::InstanceKind::AsyncDropGlueCtorShim(..) => { stable_mir::mir::mono::InstanceKind::Shim } }; diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 89f9adfcfd66..82522e995d63 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -60,9 +60,9 @@ impl<'tcx> Tables<'tcx> { self.item_has_body(def_id) || !matches!( instance.def, - ty::InstanceDef::Virtual(..) - | ty::InstanceDef::Intrinsic(..) - | ty::InstanceDef::Item(..) + ty::InstanceKind::Virtual(..) + | ty::InstanceKind::Intrinsic(..) + | ty::InstanceKind::Item(..) ) } diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 75cac6c7992a..9edd2ff9b1a5 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -56,8 +56,8 @@ pub(super) fn mangle<'tcx>( printer .print_def_path( def_id, - if let ty::InstanceDef::DropGlue(_, _) | ty::InstanceDef::AsyncDropGlueCtorShim(_, _) = - instance.def + if let ty::InstanceKind::DropGlue(_, _) + | ty::InstanceKind::AsyncDropGlueCtorShim(_, _) = instance.def { // Add the name of the dropped type to the symbol name &*instance.args @@ -68,13 +68,13 @@ pub(super) fn mangle<'tcx>( .unwrap(); match instance.def { - ty::InstanceDef::ThreadLocalShim(..) => { + ty::InstanceKind::ThreadLocalShim(..) => { printer.write_str("{{tls-shim}}").unwrap(); } - ty::InstanceDef::VTableShim(..) => { + ty::InstanceKind::VTableShim(..) => { printer.write_str("{{vtable-shim}}").unwrap(); } - ty::InstanceDef::ReifyShim(_, reason) => { + ty::InstanceKind::ReifyShim(_, reason) => { printer.write_str("{{reify-shim").unwrap(); match reason { Some(ReifyReason::FnPtr) => printer.write_str("-fnptr").unwrap(), @@ -85,8 +85,8 @@ pub(super) fn mangle<'tcx>( } // FIXME(async_closures): This shouldn't be needed when we fix // `Instance::ty`/`Instance::def_id`. - ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } => { + ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } => { printer.write_str("{{fn-once-shim}}").unwrap(); } _ => {} diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 55479bce6fc8..42c4fa83d1bf 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -43,14 +43,14 @@ pub(super) fn mangle<'tcx>( // Append `::{shim:...#0}` to shims that can coexist with a non-shim instance. let shim_kind = match instance.def { - ty::InstanceDef::ThreadLocalShim(_) => Some("tls"), - ty::InstanceDef::VTableShim(_) => Some("vtable"), - ty::InstanceDef::ReifyShim(_, None) => Some("reify"), - ty::InstanceDef::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify_fnptr"), - ty::InstanceDef::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify_vtable"), + ty::InstanceKind::ThreadLocalShim(_) => Some("tls"), + ty::InstanceKind::VTableShim(_) => Some("vtable"), + ty::InstanceKind::ReifyShim(_, None) => Some("reify"), + ty::InstanceKind::ReifyShim(_, Some(ReifyReason::FnPtr)) => Some("reify_fnptr"), + ty::InstanceKind::ReifyShim(_, Some(ReifyReason::Vtable)) => Some("reify_vtable"), - ty::InstanceDef::ConstructCoroutineInClosureShim { .. } - | ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"), + ty::InstanceKind::ConstructCoroutineInClosureShim { .. } + | ty::InstanceKind::CoroutineKindShim { .. } => Some("fn_once"), _ => None, }; diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index c5ea85c90dc5..f1dd94839fe1 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -5,7 +5,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout, }; -use rustc_middle::ty::{self, InstanceDef, Ty, TyCtxt}; +use rustc_middle::ty::{self, InstanceKind, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::def_id::DefId; use rustc_target::abi::call::{ @@ -33,7 +33,7 @@ fn fn_sig_for_fn_abi<'tcx>( instance: ty::Instance<'tcx>, param_env: ty::ParamEnv<'tcx>, ) -> ty::PolyFnSig<'tcx> { - if let InstanceDef::ThreadLocalShim(..) = instance.def { + if let InstanceKind::ThreadLocalShim(..) = instance.def { return ty::Binder::dummy(tcx.mk_fn_sig( [], tcx.thread_local_ptr_ty(instance.def_id()), @@ -63,7 +63,7 @@ fn fn_sig_for_fn_abi<'tcx>( _ => unreachable!(), }; - if let ty::InstanceDef::VTableShim(..) = instance.def { + if let ty::InstanceKind::VTableShim(..) = instance.def { // Modify `fn(self, ...)` to `fn(self: *mut Self, ...)`. sig = sig.map_bound(|mut sig| { let mut inputs_and_output = sig.inputs_and_output.to_vec(); @@ -121,7 +121,7 @@ fn fn_sig_for_fn_abi<'tcx>( let mut coroutine_kind = args.as_coroutine_closure().kind(); let env_ty = - if let InstanceDef::ConstructCoroutineInClosureShim { receiver_by_ref, .. } = + if let InstanceKind::ConstructCoroutineInClosureShim { receiver_by_ref, .. } = instance.def { coroutine_kind = ty::ClosureKind::FnOnce; @@ -174,7 +174,7 @@ fn fn_sig_for_fn_abi<'tcx>( // make sure we respect the `target_kind` in that shim. // FIXME(async_closures): This shouldn't be needed, and we should be populating // a separate def-id for these bodies. - if let InstanceDef::CoroutineKindShim { .. } = instance.def { + if let InstanceKind::CoroutineKindShim { .. } = instance.def { // Grab the parent coroutine-closure. It has the same args for the purposes // of instantiation, so this will be okay to do. let ty::CoroutineClosure(_, coroutine_closure_args) = *tcx @@ -386,7 +386,7 @@ fn fn_abi_of_instance<'tcx>( extra_args, caller_location, Some(instance.def_id()), - matches!(instance.def, ty::InstanceDef::Virtual(..)), + matches!(instance.def, ty::InstanceKind::Virtual(..)), ) } diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index fcd808b59464..c50a490a9dc0 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -34,7 +34,7 @@ fn resolve_instance<'tcx>( } else { let def = if tcx.intrinsic(def_id).is_some() { debug!(" => intrinsic"); - ty::InstanceDef::Intrinsic(def_id) + ty::InstanceKind::Intrinsic(def_id) } else if tcx.is_lang_item(def_id, LangItem::DropInPlace) { let ty = args.type_at(0); @@ -53,10 +53,10 @@ fn resolve_instance<'tcx>( _ => return Ok(None), } - ty::InstanceDef::DropGlue(def_id, Some(ty)) + ty::InstanceKind::DropGlue(def_id, Some(ty)) } else { debug!(" => trivial drop glue"); - ty::InstanceDef::DropGlue(def_id, None) + ty::InstanceKind::DropGlue(def_id, None) } } else if tcx.is_lang_item(def_id, LangItem::AsyncDropInPlace) { let ty = args.type_at(0); @@ -75,15 +75,15 @@ fn resolve_instance<'tcx>( _ => return Ok(None), } debug!(" => nontrivial async drop glue ctor"); - ty::InstanceDef::AsyncDropGlueCtorShim(def_id, Some(ty)) + ty::InstanceKind::AsyncDropGlueCtorShim(def_id, Some(ty)) } else { debug!(" => trivial async drop glue ctor"); - ty::InstanceDef::AsyncDropGlueCtorShim(def_id, None) + ty::InstanceKind::AsyncDropGlueCtorShim(def_id, None) } } else { debug!(" => free item"); // FIXME(effects): we may want to erase the effect param if that is present on this item. - ty::InstanceDef::Item(def_id) + ty::InstanceKind::Item(def_id) }; Ok(Some(Instance { def, args })) @@ -226,7 +226,7 @@ fn resolve_associated_item<'tcx>( .copied() .position(|def_id| def_id == trait_item_id); offset.map(|offset| Instance { - def: ty::InstanceDef::Virtual(trait_item_id, vtable_base + offset), + def: ty::InstanceKind::Virtual(trait_item_id, vtable_base + offset), args: rcvr_args, }) } @@ -248,7 +248,7 @@ fn resolve_associated_item<'tcx>( }; Some(Instance { - def: ty::InstanceDef::CloneShim(trait_item_id, self_ty), + def: ty::InstanceKind::CloneShim(trait_item_id, self_ty), args: rcvr_args, }) } else { @@ -265,7 +265,7 @@ fn resolve_associated_item<'tcx>( return Ok(None); } Some(Instance { - def: ty::InstanceDef::FnPtrAddrShim(trait_item_id, self_ty), + def: ty::InstanceKind::FnPtrAddrShim(trait_item_id, self_ty), args: rcvr_args, }) } else { @@ -283,7 +283,7 @@ fn resolve_associated_item<'tcx>( { // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`, // you either need to generate a shim body, or perhaps return - // `InstanceDef::Item` pointing to a trait default method body if + // `InstanceKind::Item` pointing to a trait default method body if // it is given a default implementation by the trait. bug!( "no definition for `{trait_ref}::{}` for built-in callable type", @@ -295,7 +295,7 @@ fn resolve_associated_item<'tcx>( Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { - def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), + def: ty::InstanceKind::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), args: rcvr_args, }), ty::CoroutineClosure(coroutine_closure_def_id, args) => { @@ -308,7 +308,7 @@ fn resolve_associated_item<'tcx>( Some(Instance::new(coroutine_closure_def_id, args)) } else { Some(Instance { - def: ty::InstanceDef::ConstructCoroutineInClosureShim { + def: ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, receiver_by_ref: target_kind != ty::ClosureKind::FnOnce, }, @@ -331,7 +331,7 @@ fn resolve_associated_item<'tcx>( // If we're computing `AsyncFnOnce` for a by-ref closure then // construct a new body that has the right return types. Some(Instance { - def: ty::InstanceDef::ConstructCoroutineInClosureShim { + def: ty::InstanceKind::ConstructCoroutineInClosureShim { coroutine_closure_def_id, receiver_by_ref: false, }, @@ -345,7 +345,7 @@ fn resolve_associated_item<'tcx>( Some(Instance::resolve_closure(tcx, closure_def_id, args, target_kind)) } ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { - def: ty::InstanceDef::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), + def: ty::InstanceKind::FnPtrShim(trait_item_id, rcvr_args.type_at(0)), args: rcvr_args, }), _ => bug!( diff --git a/src/tools/miri/src/intrinsics/mod.rs b/src/tools/miri/src/intrinsics/mod.rs index 74e39ffd9332..313eac363372 100644 --- a/src/tools/miri/src/intrinsics/mod.rs +++ b/src/tools/miri/src/intrinsics/mod.rs @@ -57,7 +57,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { ); } Ok(Some(ty::Instance { - def: ty::InstanceDef::Item(instance.def_id()), + def: ty::InstanceKind::Item(instance.def_id()), args: instance.args, })) } From 2f17535584947abdfa75c8ba7d7e01056790b686 Mon Sep 17 00:00:00 2001 From: bohan Date: Mon, 17 Jun 2024 11:00:44 +0800 Subject: [PATCH 33/48] mark undetermined if target binding in current ns is not got --- compiler/rustc_resolve/src/ident.rs | 25 ++++++++++++------- tests/crashes/126376.rs | 14 ----------- tests/crashes/126389.rs | 15 ----------- .../shadow-glob-module-resolution-3.rs | 19 ++++++++++++++ .../shadow-glob-module-resolution-3.stderr | 23 +++++++++++++++++ .../shadow-glob-module-resolution-4.rs | 20 +++++++++++++++ .../shadow-glob-module-resolution-4.stderr | 23 +++++++++++++++++ 7 files changed, 101 insertions(+), 38 deletions(-) delete mode 100644 tests/crashes/126376.rs delete mode 100644 tests/crashes/126389.rs create mode 100644 tests/ui/imports/shadow-glob-module-resolution-3.rs create mode 100644 tests/ui/imports/shadow-glob-module-resolution-3.stderr create mode 100644 tests/ui/imports/shadow-glob-module-resolution-4.rs create mode 100644 tests/ui/imports/shadow-glob-module-resolution-4.stderr diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index b6a23317dc99..7d531385e212 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -966,7 +966,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { for single_import in &resolution.single_imports { let Some(import_vis) = single_import.vis.get() else { // This branch handles a cycle in single imports, which occurs - // when we've previously captured the `vis` value during an import + // when we've previously **steal** the `vis` value during an import // process. // // For example: @@ -998,21 +998,28 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let Some(module) = single_import.imported_module.get() else { return Err((Undetermined, Weak::No)); }; - let ImportKind::Single { source: ident, target, target_bindings, .. } = - &single_import.kind + let ImportKind::Single { source, target, target_bindings, .. } = &single_import.kind else { unreachable!(); }; - if (ident != target) && target_bindings.iter().all(|binding| binding.get().is_none()) { + if source != target { // This branch allows the binding to be defined or updated later if the target name - // can hide the source but these bindings are not obtained. - // avoiding module inconsistency between the resolve process and the finalize process. - // See more details in #124840 - return Err((Undetermined, Weak::No)); + // can hide the source. + if target_bindings.iter().all(|binding| binding.get().is_none()) { + // None of the target bindings are available, so we can't determine + // if this binding is correct or not. + // See more details in #124840 + return Err((Undetermined, Weak::No)); + } else if target_bindings[ns].get().is_none() && binding.is_some() { + // `binding.is_some()` avoids the condition where the binding + // truly doesn't exist in this namespace and should return `Err(Determined)`. + return Err((Undetermined, Weak::No)); + } } + match self.resolve_ident_in_module( module, - *ident, + *source, ns, &single_import.parent_scope, None, diff --git a/tests/crashes/126376.rs b/tests/crashes/126376.rs deleted file mode 100644 index 028dde6d438e..000000000000 --- a/tests/crashes/126376.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ known-bug: rust-lang/rust#126376 -mod a { - pub mod b { - pub mod c { - pub trait D {} - } - } -} - -use a::*; -use e as b; -use b::c::D as e; - -fn e() {} diff --git a/tests/crashes/126389.rs b/tests/crashes/126389.rs deleted file mode 100644 index 7aa6ecad9a31..000000000000 --- a/tests/crashes/126389.rs +++ /dev/null @@ -1,15 +0,0 @@ -//@ known-bug: rust-lang/rust#126389 - -mod a { - pub mod b { - pub mod c {} - } -} - -use a::*; - -use b::c; - -use c as b; - -fn c() {} diff --git a/tests/ui/imports/shadow-glob-module-resolution-3.rs b/tests/ui/imports/shadow-glob-module-resolution-3.rs new file mode 100644 index 000000000000..f5a43373261b --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-3.rs @@ -0,0 +1,19 @@ +// https://github.com/rust-lang/rust/issues/126389 + +mod a { + pub mod b { + pub mod c {} + } +} + +use a::*; + +use b::c; +//~^ ERROR: unresolved import `b::c` +//~| ERROR: cannot determine resolution for the import +//~| ERROR: cannot determine resolution for the import +use c as b; + +fn c() {} + +fn main() { } diff --git a/tests/ui/imports/shadow-glob-module-resolution-3.stderr b/tests/ui/imports/shadow-glob-module-resolution-3.stderr new file mode 100644 index 000000000000..ab853c715828 --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-3.stderr @@ -0,0 +1,23 @@ +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-3.rs:11:5 + | +LL | use b::c; + | ^^^^ + +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-3.rs:11:5 + | +LL | use b::c; + | ^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0432]: unresolved import `b::c` + --> $DIR/shadow-glob-module-resolution-3.rs:11:5 + | +LL | use b::c; + | ^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/shadow-glob-module-resolution-4.rs b/tests/ui/imports/shadow-glob-module-resolution-4.rs new file mode 100644 index 000000000000..581cdc185d3f --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-4.rs @@ -0,0 +1,20 @@ +// https://github.com/rust-lang/rust/issues/126376 + +mod a { + pub mod b { + pub trait C {} + } +} + +use a::*; + +use e as b; + +use b::C as e; +//~^ ERROR: unresolved import `b::C` +//~| ERROR: cannot determine resolution for the import +//~| ERROR: cannot determine resolution for the import + +fn e() {} + +fn main() { } diff --git a/tests/ui/imports/shadow-glob-module-resolution-4.stderr b/tests/ui/imports/shadow-glob-module-resolution-4.stderr new file mode 100644 index 000000000000..063beb612b13 --- /dev/null +++ b/tests/ui/imports/shadow-glob-module-resolution-4.stderr @@ -0,0 +1,23 @@ +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-4.rs:13:5 + | +LL | use b::C as e; + | ^^^^^^^^^ + +error: cannot determine resolution for the import + --> $DIR/shadow-glob-module-resolution-4.rs:13:5 + | +LL | use b::C as e; + | ^^^^^^^^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0432]: unresolved import `b::C` + --> $DIR/shadow-glob-module-resolution-4.rs:13:5 + | +LL | use b::C as e; + | ^^^^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. From bd32c4c21ee30abc3795e5537245f157c31214e8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 17 Jun 2024 14:03:26 +1000 Subject: [PATCH 34/48] Convert a `span_bug` to a `span_delayed_bug`. PR #121208 converted this from a `span_delayed_bug` to a `span_bug` because nothing in the test suite caused execution to hit this path. But now fuzzing has found a test case that does hit it. So this commit converts it back to `span_delayed_bug` and adds the relevant test. Fixes #126385. --- .../src/diagnostics/region_name.rs | 4 +-- tests/crashes/126385.rs | 10 ------ .../unmatched-arg-and-hir-arg-issue-126385.rs | 14 ++++++++ ...atched-arg-and-hir-arg-issue-126385.stderr | 34 +++++++++++++++++++ 4 files changed, 49 insertions(+), 13 deletions(-) delete mode 100644 tests/crashes/126385.rs create mode 100644 tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.rs create mode 100644 tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 2cf548e28b18..77fb9fb43151 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -628,9 +628,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { | GenericArgKind::Const(_), _, ) => { - // This was previously a `span_delayed_bug` and could be - // reached by the test for #82126, but no longer. - self.dcx().span_bug( + self.dcx().span_delayed_bug( hir_arg.span(), format!("unmatched arg and hir arg: found {kind:?} vs {hir_arg:?}"), ); diff --git a/tests/crashes/126385.rs b/tests/crashes/126385.rs deleted file mode 100644 index 9e74e88c1ffe..000000000000 --- a/tests/crashes/126385.rs +++ /dev/null @@ -1,10 +0,0 @@ -//@ known-bug: rust-lang/rust#126385 -pub struct MyStruct<'field> { - field: &'_ [u32], -} - -impl MyStruct<'_> { - pub fn _<'a>(field: &'a[u32]) -> Self { - Self{field} - } -} diff --git a/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.rs b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.rs new file mode 100644 index 000000000000..637c47f29396 --- /dev/null +++ b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.rs @@ -0,0 +1,14 @@ +// This test was triggering a `span_bug` crash, which was then fixed by +// downgrading it to a `span_delayed_bug`. + +pub struct MyStruct<'field> { + field: &'field [u32], +} + +impl MyStruct<'_> { + pub fn f(field: &[u32]) -> Self { //~ ERROR type arguments are not allowed on self type + Self { field } //~ ERROR lifetime may not live long enough + } +} + +fn main() {} diff --git a/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr new file mode 100644 index 000000000000..0ae301b2090a --- /dev/null +++ b/tests/ui/borrowck/unmatched-arg-and-hir-arg-issue-126385.stderr @@ -0,0 +1,34 @@ +error[E0109]: type arguments are not allowed on self type + --> $DIR/unmatched-arg-and-hir-arg-issue-126385.rs:9:37 + | +LL | pub fn f(field: &[u32]) -> Self { + | ---- ^^^ type argument not allowed + | | + | not allowed on self type + | +note: `Self` is of type `MyStruct<'_>` + --> $DIR/unmatched-arg-and-hir-arg-issue-126385.rs:4:12 + | +LL | pub struct MyStruct<'field> { + | ^^^^^^^^ `Self` corresponds to this type +... +LL | impl MyStruct<'_> { + | ----------------- `Self` is on type `MyStruct` in this `impl` +help: the `Self` type doesn't accept type parameters, use the concrete type's name `MyStruct` instead if you want to specify its type parameters + | +LL | pub fn f(field: &[u32]) -> MyStruct { + | ~~~~~~~~ + +error: lifetime may not live long enough + --> $DIR/unmatched-arg-and-hir-arg-issue-126385.rs:10:9 + | +LL | pub fn f(field: &[u32]) -> Self { + | - --------- return type is MyStruct<'2> + | | + | let's call the lifetime of this reference `'1` +LL | Self { field } + | ^^^^^^^^^^^^^^ associated function was supposed to return data with lifetime `'2` but it is returning data with lifetime `'1` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0109`. From 450943b0d6271fe06512c5107f89f096e71367bc Mon Sep 17 00:00:00 2001 From: ChoKyuWon Date: Mon, 17 Jun 2024 18:09:56 +0900 Subject: [PATCH 35/48] Fix broken documentation link Signed-off-by: ChoKyuWon --- compiler/rustc_type_ir/src/region_kind.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_type_ir/src/region_kind.rs b/compiler/rustc_type_ir/src/region_kind.rs index 37c9532ad894..7abcc370c886 100644 --- a/compiler/rustc_type_ir/src/region_kind.rs +++ b/compiler/rustc_type_ir/src/region_kind.rs @@ -154,7 +154,7 @@ pub enum RegionKind { /// parameters via `tcx.liberate_late_bound_regions`. They are then treated /// the same way as `ReEarlyParam` while inside of the function. /// - /// See for + /// See for /// more info about early and late bound lifetime parameters. ReLateParam(I::LateParamRegion), From 20d6485e94c2106ce424e6e48653dea4809d41bd Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Mon, 17 Jun 2024 11:14:28 +0200 Subject: [PATCH 36/48] Add missing test annotation --- tests/run-make/const_fn_mir/rmake.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-make/const_fn_mir/rmake.rs b/tests/run-make/const_fn_mir/rmake.rs index a4cc4299b1b0..1ba93421855d 100644 --- a/tests/run-make/const_fn_mir/rmake.rs +++ b/tests/run-make/const_fn_mir/rmake.rs @@ -1,5 +1,7 @@ // The `needs-unwind -Cpanic=abort` gives a different MIR output. +//@ needs-unwind + use run_make_support::{cwd, diff, rustc}; fn main() { From 9074427c69773ca20eef8b6e9613402882f8fb0b Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Mon, 17 Jun 2024 10:06:13 +0000 Subject: [PATCH 37/48] Do not ICE in privacy when type inference fails. --- compiler/rustc_privacy/src/lib.rs | 8 ++++-- .../privacy/no-ice-on-inference-failure.rs} | 2 +- .../no-ice-on-inference-failure.stderr | 27 +++++++++++++++++++ 3 files changed, 34 insertions(+), 3 deletions(-) rename tests/{crashes/122736.rs => ui/privacy/no-ice-on-inference-failure.rs} (80%) create mode 100644 tests/ui/privacy/no-ice-on-inference-failure.stderr diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index fb57d42f6df1..d37056269385 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -973,8 +973,12 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { impl<'tcx> Visitor<'tcx> for NamePrivacyVisitor<'tcx> { fn visit_nested_body(&mut self, body_id: hir::BodyId) { - let old_maybe_typeck_results = - self.maybe_typeck_results.replace(self.tcx.typeck_body(body_id)); + let new_typeck_results = self.tcx.typeck_body(body_id); + // Do not try reporting privacy violations if we failed to infer types. + if new_typeck_results.tainted_by_errors.is_some() { + return; + } + let old_maybe_typeck_results = self.maybe_typeck_results.replace(new_typeck_results); self.visit_body(self.tcx.hir().body(body_id)); self.maybe_typeck_results = old_maybe_typeck_results; } diff --git a/tests/crashes/122736.rs b/tests/ui/privacy/no-ice-on-inference-failure.rs similarity index 80% rename from tests/crashes/122736.rs rename to tests/ui/privacy/no-ice-on-inference-failure.rs index 83b60444c2f4..e63b7bff9bc4 100644 --- a/tests/crashes/122736.rs +++ b/tests/ui/privacy/no-ice-on-inference-failure.rs @@ -1,9 +1,9 @@ -//@ known-bug: #122736 fn main_ref() { let array = [(); { let mut x = &0; let mut n = 0; while n < 5 { + //~^ ERROR constant evaluation is taking a long time x = &0; } 0 diff --git a/tests/ui/privacy/no-ice-on-inference-failure.stderr b/tests/ui/privacy/no-ice-on-inference-failure.stderr new file mode 100644 index 000000000000..67476e6e2189 --- /dev/null +++ b/tests/ui/privacy/no-ice-on-inference-failure.stderr @@ -0,0 +1,27 @@ +error: constant evaluation is taking a long time + --> $DIR/no-ice-on-inference-failure.rs:5:9 + | +LL | / while n < 5 { +LL | | +LL | | x = &0; +LL | | } + | |_________^ + | + = note: this lint makes sure the compiler doesn't get stuck due to infinite loops in const eval. + If your compilation actually takes a long time, you can safely allow the lint. +help: the constant being evaluated + --> $DIR/no-ice-on-inference-failure.rs:2:22 + | +LL | let array = [(); { + | ______________________^ +LL | | let mut x = &0; +LL | | let mut n = 0; +LL | | while n < 5 { +... | +LL | | 0 +LL | | }]; + | |_____^ + = note: `#[deny(long_running_const_eval)]` on by default + +error: aborting due to 1 previous error + From 97372c8c885bf66a502b88ee7b29e59fb27327e6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 14 Jun 2024 09:20:05 +0000 Subject: [PATCH 38/48] Add regression test --- tests/ui/statics/const_generics.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/ui/statics/const_generics.rs diff --git a/tests/ui/statics/const_generics.rs b/tests/ui/statics/const_generics.rs new file mode 100644 index 000000000000..70d9b933a765 --- /dev/null +++ b/tests/ui/statics/const_generics.rs @@ -0,0 +1,26 @@ +//! Check that we lose the information that `BAR` points to `FOO` +//! when going through a const generic. +//! This is not an intentional guarantee, it just describes the status quo. + +//@ run-pass +// With optimizations, LLVM will deduplicate the constant `X` whose +// value is `&42` to just be a reference to the static. This is correct, +// but obscures the issue we're trying to show. +//@ revisions: opt noopt +//@[noopt] compile-flags: -Copt-level=0 +//@[opt] compile-flags: -O + +#![feature(const_refs_to_static)] +#![feature(adt_const_params)] +#![allow(incomplete_features)] + +static FOO: usize = 42; +const BAR: &usize = &FOO; +fn foo() { + // Without optimizations, `X` ends up pointing to a copy of `FOO` instead of `FOO` itself. + assert_eq!(cfg!(opt), std::ptr::eq(X, &FOO)); +} + +fn main() { + foo::(); +} From 4e5dfb61e449940f0a9bf97e2df6cfeef38d2f30 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 14 Jun 2024 10:11:33 +0000 Subject: [PATCH 39/48] Remove an unused validation error variant --- compiler/rustc_const_eval/messages.ftl | 2 -- compiler/rustc_const_eval/src/errors.rs | 4 ---- compiler/rustc_middle/src/mir/interpret/error.rs | 3 --- 3 files changed, 9 deletions(-) diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl index 2dbeb7d5e0ca..cb5aac7e5601 100644 --- a/compiler/rustc_const_eval/messages.ftl +++ b/compiler/rustc_const_eval/messages.ftl @@ -399,7 +399,6 @@ const_eval_unwind_past_top = ## The `front_matter`s here refer to either `const_eval_front_matter_invalid_value` or `const_eval_front_matter_invalid_value_with_path`. ## (We'd love to sort this differently to make that more clear but tidy won't let us...) -const_eval_validation_box_to_static = {$front_matter}: encountered a box pointing to a static variable in a constant const_eval_validation_box_to_uninhabited = {$front_matter}: encountered a box pointing to uninhabited type {$ty} const_eval_validation_const_ref_to_extern = {$front_matter}: encountered reference to `extern` static in `const` @@ -454,7 +453,6 @@ const_eval_validation_out_of_range = {$front_matter}: encountered {$value}, but const_eval_validation_partial_pointer = {$front_matter}: encountered a partial pointer or a mix of pointers const_eval_validation_pointer_as_int = {$front_matter}: encountered a pointer, but {$expected} const_eval_validation_ptr_out_of_range = {$front_matter}: encountered a pointer, but expected something that cannot possibly fail to be {$in_range} -const_eval_validation_ref_to_static = {$front_matter}: encountered a reference pointing to a static variable in a constant const_eval_validation_ref_to_uninhabited = {$front_matter}: encountered a reference pointing to uninhabited type {$ty} const_eval_validation_unaligned_box = {$front_matter}: encountered an unaligned box (required {$required_bytes} byte alignment but found {$found_bytes}) const_eval_validation_unaligned_ref = {$front_matter}: encountered an unaligned reference (required {$required_bytes} byte alignment but found {$found_bytes}) diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs index e5ea4c3442ea..91d17fdd8959 100644 --- a/compiler/rustc_const_eval/src/errors.rs +++ b/compiler/rustc_const_eval/src/errors.rs @@ -640,9 +640,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { const_eval_validation_ref_to_uninhabited } - PtrToStatic { ptr_kind: PointerKind::Box } => const_eval_validation_box_to_static, - PtrToStatic { ptr_kind: PointerKind::Ref(_) } => const_eval_validation_ref_to_static, - PointerAsInt { .. } => const_eval_validation_pointer_as_int, PartialPointer => const_eval_validation_partial_pointer, ConstRefToMutable => const_eval_validation_const_ref_to_mutable, @@ -807,7 +804,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> { ); } NullPtr { .. } - | PtrToStatic { .. } | ConstRefToMutable | ConstRefToExtern | MutableRefToImmutable diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index eabbcc2033f1..23680f143970 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -438,9 +438,6 @@ pub enum ValidationErrorKind<'tcx> { ptr_kind: PointerKind, ty: Ty<'tcx>, }, - PtrToStatic { - ptr_kind: PointerKind, - }, ConstRefToMutable, ConstRefToExtern, MutableRefToImmutable, From 94f549502f4bf6fae35f17c823924f041217c8f4 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 10 Jun 2024 10:15:37 +0000 Subject: [PATCH 40/48] Use subtyping instead of equality, since method resolution also uses subtyping --- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 9 +++------ tests/crashes/126062.rs | 11 ---------- ...rojection-self-ty-invalid-bivariant-arg.rs | 10 ++++++++++ ...ction-self-ty-invalid-bivariant-arg.stderr | 12 +++++++++++ ...ojection-self-ty-invalid-bivariant-arg2.rs | 17 ++++++++++++++++ ...tion-self-ty-invalid-bivariant-arg2.stderr | 20 +++++++++++++++++++ ...erce-issue-49593-box-never.fallback.stderr | 11 ++++++++++ ...ce-issue-49593-box-never.nofallback.stderr | 8 ++++---- .../coercion/coerce-issue-49593-box-never.rs | 9 +++++---- .../generic_arg_infer/issue-91614.stderr | 2 +- .../need_type_info/type-alias-indirect.stderr | 2 +- .../need_type_info/type-alias.stderr | 6 +++--- .../suggestions/mut-borrow-needed-by-trait.rs | 1 + .../mut-borrow-needed-by-trait.stderr | 16 ++++++++++++--- 14 files changed, 101 insertions(+), 33 deletions(-) delete mode 100644 tests/crashes/126062.rs create mode 100644 tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs create mode 100644 tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr create mode 100644 tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs create mode 100644 tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr create mode 100644 tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9531c002829e..061afd030623 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -750,16 +750,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Resolves an associated value path into a base type and associated constant, or method /// resolution. The newly resolved definition is written into `type_dependent_defs`. + #[instrument(level = "trace", skip(self), ret)] pub fn resolve_ty_and_res_fully_qualified_call( &self, qpath: &'tcx QPath<'tcx>, hir_id: HirId, span: Span, ) -> (Res, Option>, &'tcx [hir::PathSegment<'tcx>]) { - debug!( - "resolve_ty_and_res_fully_qualified_call: qpath={:?} hir_id={:?} span={:?}", - qpath, hir_id, span - ); let (ty, qself, item_segment) = match *qpath { QPath::Resolved(ref opt_qself, path) => { return ( @@ -1417,10 +1414,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This also occurs for an enum variant on a type alias. let impl_ty = self.normalize(span, tcx.type_of(impl_def_id).instantiate(tcx, args)); let self_ty = self.normalize(span, self_ty); - match self.at(&self.misc(span), self.param_env).eq( + match self.at(&self.misc(span), self.param_env).sub( DefineOpaqueTypes::Yes, - impl_ty, self_ty, + impl_ty, ) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { diff --git a/tests/crashes/126062.rs b/tests/crashes/126062.rs deleted file mode 100644 index 9f1bec1d46e4..000000000000 --- a/tests/crashes/126062.rs +++ /dev/null @@ -1,11 +0,0 @@ -//@ known-bug: rust-lang/rust#126062 -struct Fail(Fail); -impl Fail { - const C: () = panic!(); -} - -fn f() { - if false { - let _val = &Fail::::C; - } -} diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs new file mode 100644 index 000000000000..e2fc2961a448 --- /dev/null +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.rs @@ -0,0 +1,10 @@ +struct Fail; +//~^ ERROR: type parameter `T` is never used + +impl Fail { + const C: () = (); +} + +fn main() { + Fail::<()>::C +} diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr new file mode 100644 index 000000000000..f0a6ccf243a9 --- /dev/null +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg.stderr @@ -0,0 +1,12 @@ +error[E0392]: type parameter `T` is never used + --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg.rs:1:13 + | +LL | struct Fail; + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0392`. diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs new file mode 100644 index 000000000000..cb53d902ba18 --- /dev/null +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.rs @@ -0,0 +1,17 @@ +trait Proj { + type Assoc; +} +impl Proj for T { + type Assoc = T; +} + +struct Fail, U>(T); + +impl Fail { + const C: () = (); +} + +fn main() { + Fail::::C + //~^ ERROR: type mismatch +} diff --git a/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr new file mode 100644 index 000000000000..0d63b7f5b293 --- /dev/null +++ b/tests/ui/associated-consts/wrong-projection-self-ty-invalid-bivariant-arg2.stderr @@ -0,0 +1,20 @@ +error[E0271]: type mismatch resolving `::Assoc == u32` + --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:15:5 + | +LL | Fail::::C + | ^^^^^^^^^^^^^^^^ type mismatch resolving `::Assoc == u32` + | +note: expected this to be `u32` + --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:5:18 + | +LL | type Assoc = T; + | ^ +note: required by a bound in `Fail` + --> $DIR/wrong-projection-self-ty-invalid-bivariant-arg2.rs:8:21 + | +LL | struct Fail, U>(T); + | ^^^^^^^^^ required by this bound in `Fail` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr new file mode 100644 index 000000000000..e9b43d6145c2 --- /dev/null +++ b/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `(): std::error::Error` is not satisfied + --> $DIR/coerce-issue-49593-box-never.rs:19:5 + | +LL | Box::<_ /* ! */>::new(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` + | + = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr index 0d98fa93e5a4..1215f5f9d885 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr +++ b/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr @@ -1,13 +1,13 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never.rs:18:53 + --> $DIR/coerce-issue-49593-box-never.rs:19:5 | -LL | /* *mut $0 is coerced to Box here */ Box::<_ /* ! */>::new(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` +LL | Box::<_ /* ! */>::new(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never.rs:23:49 + --> $DIR/coerce-issue-49593-box-never.rs:24:49 | LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.rs b/tests/ui/coercion/coerce-issue-49593-box-never.rs index 19a2c036fbcb..f93fbb70dce6 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never.rs +++ b/tests/ui/coercion/coerce-issue-49593-box-never.rs @@ -1,7 +1,6 @@ //@ revisions: nofallback fallback //@ ignore-windows - the number of `Error` impls is platform-dependent -//@[fallback] check-pass -//@[nofallback] check-fail +//@check-fail #![feature(never_type)] #![cfg_attr(fallback, feature(never_type_fallback))] @@ -15,8 +14,10 @@ fn raw_ptr_box(t: T) -> *mut T { } fn foo(x: !) -> Box { - /* *mut $0 is coerced to Box here */ Box::<_ /* ! */>::new(x) - //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied + // Subtyping during method resolution will generate new inference vars and + // subtype them. Thus fallback will not fall back to `!`, but `()` instead. + Box::<_ /* ! */>::new(x) + //~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn foo_raw_ptr(x: !) -> *mut dyn Error { diff --git a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr index 5ee42c19dd3d..563406ad5eaa 100644 --- a/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr +++ b/tests/ui/const-generics/generic_arg_infer/issue-91614.stderr @@ -15,7 +15,7 @@ note: required by a bound in `Mask::::splat` --> $SRC_DIR/core/src/../../portable-simd/crates/core_simd/src/masks.rs:LL:COL help: consider giving `y` an explicit type, where the type for type parameter `T` is specified | -LL | let y: Mask<_, N> = Mask::<_, _>::splat(false); +LL | let y: Mask = Mask::<_, _>::splat(false); | ++++++++++++ error: aborting due to 1 previous error diff --git a/tests/ui/inference/need_type_info/type-alias-indirect.stderr b/tests/ui/inference/need_type_info/type-alias-indirect.stderr index 535c0044aec0..5c5b4c149c17 100644 --- a/tests/ui/inference/need_type_info/type-alias-indirect.stderr +++ b/tests/ui/inference/need_type_info/type-alias-indirect.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed --> $DIR/type-alias-indirect.rs:14:5 | LL | IndirectAlias::new(); - | ^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` error: aborting due to 1 previous error diff --git a/tests/ui/inference/need_type_info/type-alias.stderr b/tests/ui/inference/need_type_info/type-alias.stderr index 2c39a3f56466..fd9bcf2fe3f3 100644 --- a/tests/ui/inference/need_type_info/type-alias.stderr +++ b/tests/ui/inference/need_type_info/type-alias.stderr @@ -2,19 +2,19 @@ error[E0282]: type annotations needed --> $DIR/type-alias.rs:12:5 | LL | DirectAlias::new() - | ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` + | ^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `DirectAlias` error[E0282]: type annotations needed --> $DIR/type-alias.rs:18:5 | LL | IndirectAlias::new(); - | ^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` + | ^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `IndirectAlias` error[E0282]: type annotations needed --> $DIR/type-alias.rs:32:5 | LL | DirectButWithDefaultAlias::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `T` declared on the type alias `DirectButWithDefaultAlias` error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.rs b/tests/ui/suggestions/mut-borrow-needed-by-trait.rs index 66e1e77c905e..924bfd82eb83 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.rs +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.rs @@ -17,6 +17,7 @@ fn main() { let fp = BufWriter::new(fp); //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied + //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied writeln!(fp, "hello world").unwrap(); //~ ERROR the method } diff --git a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr index 09a9b1d3b348..b2f9150142fe 100644 --- a/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/tests/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -10,6 +10,16 @@ LL | let fp = BufWriter::new(fp); note: required by a bound in `BufWriter::::new` --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL +error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied + --> $DIR/mut-borrow-needed-by-trait.rs:17:14 + | +LL | let fp = BufWriter::new(fp); + | ^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` + | + = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` +note: required by a bound in `BufWriter` + --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL + error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied --> $DIR/mut-borrow-needed-by-trait.rs:17:14 | @@ -21,13 +31,13 @@ note: required by a bound in `BufWriter` --> $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn Write>`, but its trait bounds were not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:21:14 + --> $DIR/mut-borrow-needed-by-trait.rs:22:14 | LL | writeln!(fp, "hello world").unwrap(); | ---------^^---------------- method cannot be called on `BufWriter<&dyn Write>` due to unsatisfied trait bounds | note: must implement `io::Write`, `fmt::Write`, or have a `write_fmt` method - --> $DIR/mut-borrow-needed-by-trait.rs:21:14 + --> $DIR/mut-borrow-needed-by-trait.rs:22:14 | LL | writeln!(fp, "hello world").unwrap(); | ^^ @@ -35,7 +45,7 @@ LL | writeln!(fp, "hello world").unwrap(); `&dyn std::io::Write: std::io::Write` which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors Some errors have detailed explanations: E0277, E0599. For more information about an error, try `rustc --explain E0277`. From 3e6e6b190d005b9cb8d1eca529598a89d7c2f23f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 17 Jun 2024 09:21:25 +0000 Subject: [PATCH 41/48] Remove windows-specific copy of test --- ...-49593-box-never-windows.nofallback.stderr | 19 ------ .../coerce-issue-49593-box-never-windows.rs | 58 ------------------- ...erce-issue-49593-box-never.fallback.stderr | 2 +- ...ce-issue-49593-box-never.nofallback.stderr | 8 +-- .../coercion/coerce-issue-49593-box-never.rs | 11 ++-- 5 files changed, 10 insertions(+), 88 deletions(-) delete mode 100644 tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr delete mode 100644 tests/ui/coercion/coerce-issue-49593-box-never-windows.rs diff --git a/tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr deleted file mode 100644 index b976f70acf76..000000000000 --- a/tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr +++ /dev/null @@ -1,19 +0,0 @@ -error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never-windows.rs:18:53 - | -LL | /* *mut $0 is coerced to Box here */ Box::<_ /* ! */>::new(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` - | - = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` - -error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never-windows.rs:23:49 - | -LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` - | - = note: required for the cast from `*mut ()` to `*mut (dyn std::error::Error + 'static)` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/coercion/coerce-issue-49593-box-never-windows.rs b/tests/ui/coercion/coerce-issue-49593-box-never-windows.rs deleted file mode 100644 index b317841ab6e7..000000000000 --- a/tests/ui/coercion/coerce-issue-49593-box-never-windows.rs +++ /dev/null @@ -1,58 +0,0 @@ -//@ revisions: nofallback fallback -//@ only-windows - the number of `Error` impls is platform-dependent -//@[fallback] check-pass -//@[nofallback] check-fail - -#![feature(never_type)] -#![cfg_attr(fallback, feature(never_type_fallback))] -#![allow(unreachable_code)] - -use std::error::Error; -use std::mem; - -fn raw_ptr_box(t: T) -> *mut T { - panic!() -} - -fn foo(x: !) -> Box { - /* *mut $0 is coerced to Box here */ Box::<_ /* ! */>::new(x) - //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied -} - -fn foo_raw_ptr(x: !) -> *mut dyn Error { - /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) - //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied -} - -fn no_coercion(d: *mut dyn Error) -> *mut dyn Error { - /* an unsize coercion won't compile here, and it is indeed not used - because there is nothing requiring the _ to be Sized */ - d as *mut _ -} - -trait Xyz {} -struct S; -struct T; -impl Xyz for S {} -impl Xyz for T {} - -fn foo_no_never() { - let mut x /* : Option */ = None; - let mut first_iter = false; - loop { - if !first_iter { - let y: Box - = /* Box<$0> is coerced to Box here */ Box::new(x.unwrap()); - } - - x = Some(S); - first_iter = true; - } - - let mut y : Option = None; - // assert types are equal - mem::swap(&mut x, &mut y); -} - -fn main() { -} diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr index e9b43d6145c2..ef5633f71348 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr +++ b/tests/ui/coercion/coerce-issue-49593-box-never.fallback.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never.rs:19:5 + --> $DIR/coerce-issue-49593-box-never.rs:18:5 | LL | Box::<_ /* ! */>::new(x) | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr index 1215f5f9d885..7222af43b013 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr +++ b/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never.rs:19:5 + --> $DIR/coerce-issue-49593-box-never.rs:18:5 | LL | Box::<_ /* ! */>::new(x) | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` @@ -7,10 +7,10 @@ LL | Box::<_ /* ! */>::new(x) = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` error[E0277]: the trait bound `(): std::error::Error` is not satisfied - --> $DIR/coerce-issue-49593-box-never.rs:24:49 + --> $DIR/coerce-issue-49593-box-never.rs:24:5 | -LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` +LL | raw_ptr_box::<_ /* ! */>(x) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | = note: required for the cast from `*mut ()` to `*mut (dyn std::error::Error + 'static)` diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.rs b/tests/ui/coercion/coerce-issue-49593-box-never.rs index f93fbb70dce6..53071be47dcb 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never.rs +++ b/tests/ui/coercion/coerce-issue-49593-box-never.rs @@ -1,5 +1,4 @@ //@ revisions: nofallback fallback -//@ ignore-windows - the number of `Error` impls is platform-dependent //@check-fail #![feature(never_type)] @@ -21,13 +20,14 @@ fn foo(x: !) -> Box { } fn foo_raw_ptr(x: !) -> *mut dyn Error { - /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) + /* *mut $0 is coerced to *mut Error here */ + raw_ptr_box::<_ /* ! */>(x) //[nofallback]~^ ERROR trait bound `(): std::error::Error` is not satisfied } fn no_coercion(d: *mut dyn Error) -> *mut dyn Error { /* an unsize coercion won't compile here, and it is indeed not used - because there is nothing requiring the _ to be Sized */ + because there is nothing requiring the _ to be Sized */ d as *mut _ } @@ -50,10 +50,9 @@ fn foo_no_never() { first_iter = true; } - let mut y : Option = None; + let mut y: Option = None; // assert types are equal mem::swap(&mut x, &mut y); } -fn main() { -} +fn main() {} From e3e71404ca9b1c441cbea0c74ab780695ac52907 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Jun 2024 08:42:27 +0200 Subject: [PATCH 42/48] fix checking git submodules during a commit hook --- src/bootstrap/src/lib.rs | 37 ++++++++++++++---------------- src/bootstrap/src/utils/helpers.rs | 10 ++++++++ 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs index abf407ea91e6..449d8c128ec6 100644 --- a/src/bootstrap/src/lib.rs +++ b/src/bootstrap/src/lib.rs @@ -520,10 +520,12 @@ impl Build { return; } - // check_submodule - let checked_out_hash = - output(helpers::git(Some(&absolute_path)).args(["rev-parse", "HEAD"])); - // update_submodules + let submodule_git = || helpers::git(Some(&absolute_path)); + + // Determine commit checked out in submodule. + let checked_out_hash = output(submodule_git().args(["rev-parse", "HEAD"])); + let checked_out_hash = checked_out_hash.trim_end(); + // Determine commit that the submodule *should* have. let recorded = output(helpers::git(Some(&self.src)).args(["ls-tree", "HEAD"]).arg(relative_path)); let actual_hash = recorded @@ -531,8 +533,7 @@ impl Build { .nth(2) .unwrap_or_else(|| panic!("unexpected output `{}`", recorded)); - // update_submodule - if actual_hash == checked_out_hash.trim_end() { + if actual_hash == checked_out_hash { // already checked out return; } @@ -581,26 +582,22 @@ impl Build { // Save any local changes, but avoid running `git stash pop` if there are none (since it will exit with an error). // diff-index reports the modifications through the exit status let has_local_modifications = !self.run_cmd( - BootstrapCommand::from(helpers::git(Some(&absolute_path)).args([ - "diff-index", - "--quiet", - "HEAD", - ])) - .allow_failure() - .output_mode(match self.is_verbose() { - true => OutputMode::PrintAll, - false => OutputMode::PrintOutput, - }), + BootstrapCommand::from(submodule_git().args(["diff-index", "--quiet", "HEAD"])) + .allow_failure() + .output_mode(match self.is_verbose() { + true => OutputMode::PrintAll, + false => OutputMode::PrintOutput, + }), ); if has_local_modifications { - self.run(helpers::git(Some(&absolute_path)).args(["stash", "push"])); + self.run(submodule_git().args(["stash", "push"])); } - self.run(helpers::git(Some(&absolute_path)).args(["reset", "-q", "--hard"])); - self.run(helpers::git(Some(&absolute_path)).args(["clean", "-qdfx"])); + self.run(submodule_git().args(["reset", "-q", "--hard"])); + self.run(submodule_git().args(["clean", "-qdfx"])); if has_local_modifications { - self.run(helpers::git(Some(&absolute_path)).args(["stash", "pop"])); + self.run(submodule_git().args(["stash", "pop"])); } } diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs index 13d1346b3d9a..4b6dc45b436d 100644 --- a/src/bootstrap/src/utils/helpers.rs +++ b/src/bootstrap/src/utils/helpers.rs @@ -501,6 +501,16 @@ pub fn git(source_dir: Option<&Path>) -> Command { if let Some(source_dir) = source_dir { git.current_dir(source_dir); + // If we are running inside git (e.g. via a hook), `GIT_DIR` is set and takes precedence + // over the current dir. Un-set it to make the current dir matter. + git.env_remove("GIT_DIR"); + // Also un-set some other variables, to be on the safe side (based on cargo's + // `fetch_with_cli`). In particular un-setting `GIT_INDEX_FILE` is required to fix some odd + // misbehavior. + git.env_remove("GIT_WORK_TREE") + .env_remove("GIT_INDEX_FILE") + .env_remove("GIT_OBJECT_DIRECTORY") + .env_remove("GIT_ALTERNATE_OBJECT_DIRECTORIES"); } git From a6a78d28e63c535e5b8b5d695eb5bcac0751d47d Mon Sep 17 00:00:00 2001 From: Daria Sukhonina Date: Mon, 17 Jun 2024 17:20:13 +0300 Subject: [PATCH 43/48] Add tracking issue to async_drop API --- library/core/src/future/async_drop.rs | 24 ++++++++++++------------ library/core/src/future/mod.rs | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/library/core/src/future/async_drop.rs b/library/core/src/future/async_drop.rs index 5c3a0a98b105..63193bbfb35e 100644 --- a/library/core/src/future/async_drop.rs +++ b/library/core/src/future/async_drop.rs @@ -1,4 +1,4 @@ -#![unstable(feature = "async_drop", issue = "none")] +#![unstable(feature = "async_drop", issue = "126482")] use crate::fmt; use crate::future::{Future, IntoFuture}; @@ -10,27 +10,27 @@ use crate::task::{ready, Context, Poll}; /// Asynchronously drops a value by running `AsyncDrop::async_drop` /// on a value and its fields recursively. -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] pub fn async_drop(value: T) -> AsyncDropOwning { AsyncDropOwning { value: MaybeUninit::new(value), dtor: None, _pinned: PhantomPinned } } /// A future returned by the [`async_drop`]. -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] pub struct AsyncDropOwning { value: MaybeUninit, dtor: Option>, _pinned: PhantomPinned, } -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] impl fmt::Debug for AsyncDropOwning { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AsyncDropOwning").finish_non_exhaustive() } } -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] impl Future for AsyncDropOwning { type Output = (); @@ -86,24 +86,24 @@ unsafe fn async_drop_in_place_raw( /// returned future stores the `to_drop` pointer and user is required /// to guarantee that dropped value doesn't move. /// -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] pub unsafe fn async_drop_in_place(to_drop: *mut T) -> AsyncDropInPlace { // SAFETY: `async_drop_in_place_raw` has the same safety requirements unsafe { AsyncDropInPlace(async_drop_in_place_raw(to_drop)) } } /// A future returned by the [`async_drop_in_place`]. -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] pub struct AsyncDropInPlace(::AsyncDestructor); -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] impl fmt::Debug for AsyncDropInPlace { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AsyncDropInPlace").finish_non_exhaustive() } } -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] impl Future for AsyncDropInPlace { type Output = (); @@ -117,18 +117,18 @@ impl Future for AsyncDropInPlace { // FIXME(zetanumbers): Add same restrictions on AsyncDrop impls as // with Drop impls /// Custom code within the asynchronous destructor. -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] #[lang = "async_drop"] pub trait AsyncDrop { /// A future returned by the [`AsyncDrop::async_drop`] to be part /// of the async destructor. - #[unstable(feature = "async_drop", issue = "none")] + #[unstable(feature = "async_drop", issue = "126482")] type Dropper<'a>: Future where Self: 'a; /// Constructs the asynchronous destructor for this type. - #[unstable(feature = "async_drop", issue = "none")] + #[unstable(feature = "async_drop", issue = "126482")] fn async_drop(self: Pin<&mut Self>) -> Self::Dropper<'_>; } diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 873cccc7e96f..3a1451abfa40 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -37,7 +37,7 @@ pub use ready::{ready, Ready}; #[stable(feature = "future_poll_fn", since = "1.64.0")] pub use poll_fn::{poll_fn, PollFn}; -#[unstable(feature = "async_drop", issue = "none")] +#[unstable(feature = "async_drop", issue = "126482")] pub use async_drop::{async_drop, async_drop_in_place, AsyncDrop, AsyncDropInPlace}; /// This type is needed because: From 553204d26d800084431f328612da01c3d15ea01f Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 24 May 2024 10:02:53 -0400 Subject: [PATCH 44/48] Rewrite `link-arg` in rmake.rs --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/link-arg/Makefile | 5 ---- tests/run-make/link-arg/rmake.rs | 24 +++++++++++++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) delete mode 100644 tests/run-make/link-arg/Makefile create mode 100644 tests/run-make/link-arg/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index fdd0be79a4de..4ef23a19e79e 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -109,7 +109,6 @@ run-make/libtest-json/Makefile run-make/libtest-junit/Makefile run-make/libtest-padding/Makefile run-make/libtest-thread-limit/Makefile -run-make/link-arg/Makefile run-make/link-args-order/Makefile run-make/link-cfg/Makefile run-make/link-dedup/Makefile diff --git a/tests/run-make/link-arg/Makefile b/tests/run-make/link-arg/Makefile deleted file mode 100644 index 103527c3e14d..000000000000 --- a/tests/run-make/link-arg/Makefile +++ /dev/null @@ -1,5 +0,0 @@ -include ../tools.mk -RUSTC_FLAGS = -C link-arg="-lfoo" -C link-arg="-lbar" --print link-args - -all: - $(RUSTC) $(RUSTC_FLAGS) empty.rs | $(CGREP) lfoo lbar diff --git a/tests/run-make/link-arg/rmake.rs b/tests/run-make/link-arg/rmake.rs new file mode 100644 index 000000000000..dd496101f6a7 --- /dev/null +++ b/tests/run-make/link-arg/rmake.rs @@ -0,0 +1,24 @@ +// In 2016, the rustc flag "-C link-arg" was introduced - it can be repeatedly used +// to add single arguments to the linker. This test passes 2 arguments to the linker using it, +// then checks that the compiler's output contains the arguments passed to it. +// This ensures that the compiler successfully parses this flag. +// See https://github.com/rust-lang/rust/pull/36574 + +use run_make_support::rustc; + +fn main() { + let output = String::from_utf8( + rustc() + .input("empty.rs") + .link_arg("-lfoo") + .link_arg("-lbar") + .print("link-args") + .command_output() + .stdout, + ) + .unwrap(); + assert!( + output.contains("lfoo") || output.contains("lbar"), + "The output did not contain the expected \"lfoo\" or \"lbar\" strings." + ); +} From 5f44f9511d95c8efbae0e1c312e130d91acd1134 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 24 May 2024 11:22:04 -0400 Subject: [PATCH 45/48] rewrite `link-dedup` to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/link-dedup/rmake.rs | 32 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/run-make/link-dedup/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 4ef23a19e79e..6a1809951fd1 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -111,7 +111,6 @@ run-make/libtest-padding/Makefile run-make/libtest-thread-limit/Makefile run-make/link-args-order/Makefile run-make/link-cfg/Makefile -run-make/link-dedup/Makefile run-make/link-framework/Makefile run-make/link-path-order/Makefile run-make/linkage-attr-on-static/Makefile diff --git a/tests/run-make/link-dedup/rmake.rs b/tests/run-make/link-dedup/rmake.rs new file mode 100644 index 000000000000..a0d3ac865426 --- /dev/null +++ b/tests/run-make/link-dedup/rmake.rs @@ -0,0 +1,32 @@ +// When native libraries are passed to the linker, there used to be an annoyance +// where multiple instances of the same library in a row would cause duplication in +// outputs. This has been fixed, and this test checks that it stays fixed. +// With the --cfg flag, -ltestb gets added to the output, breaking up the chain of -ltesta. +// Without the --cfg flag, there should be a single -ltesta, no more, no less. +// See https://github.com/rust-lang/rust/pull/84794 + +//@ ignore-msvc + +fn main() { + rustc().input("depa.rs").run(); + rustc().input("depb.rs").run(); + rustc().input("depc.rs").run(); + let output = + String::from_utf8(rustc().input("empty.rs").cfg("bar").command_output().stderr).unwrap(); + let pos_a1 = + output.find("-ltesta").expect("empty.rs, compiled with --cfg, should contain -ltesta"); + let pos_b = output[pos_a1..] + .find("-ltestb") + .map(|pos| pos + pos_a1) + .expect("empty.rs, compiled with --cfg, should contain -ltestb"); + let _ = output[pos_b..] + .find("-ltesta") + .map(|pos| pos + pos_b) + .expect("empty.rs, compiled with --cfg, should contain a second -ltesta"); + let output = String::from_utf8(rustc().input("empty.rs").command_output().stderr).unwrap(); + assert!(output.contains("-ltesta")); + let output = String::from_utf8(rustc().input("empty.rs").command_output().stderr).unwrap(); + assert!(!output.contains("-ltestb")); + let output = String::from_utf8(rustc().input("empty.rs").command_output().stderr).unwrap(); + assert_eq!(output.matches("-ltesta").count, 1); +} From d1e2386215e8a4bfc1a0434a75eee259e1d74b94 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 17 Jun 2024 13:00:31 -0400 Subject: [PATCH 46/48] Update books --- src/doc/book | 2 +- src/doc/edition-guide | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book b/src/doc/book index 5228bfac8267..45c1a6d69edf 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit 5228bfac8267ad24659a81b92ec5417976b5edbc +Subproject commit 45c1a6d69edfd1fc91fb7504cb73958dbd09441e diff --git a/src/doc/edition-guide b/src/doc/edition-guide index bbaabbe088e2..cb58c430b4e8 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit bbaabbe088e21a81a0d9ae6757705020d5d7b416 +Subproject commit cb58c430b4e8054c2cb81d2d4434092c482a93d8 diff --git a/src/doc/reference b/src/doc/reference index 6019b76f5b28..0b805c658040 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 6019b76f5b28938565b251bbba0bf5cc5c43d863 +Subproject commit 0b805c65804019b0ac8f2fe3117afad82a6069b8 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 4840dca06cad..b1d97bd6113a 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 4840dca06cadf48b305d3ce0aeafde7f80933f80 +Subproject commit b1d97bd6113aba732b2091ce093c76f2d05bb8a0 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 6a7374bd87cb..aec82168dd31 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 6a7374bd87cbac0f8be4fd4877d8186d9c313985 +Subproject commit aec82168dd3121289a194b381f56076fc789a4d2 From 6228b3e40e78ca0a29fd4599c9b7a3e340bb1572 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Fri, 24 May 2024 11:50:35 -0400 Subject: [PATCH 47/48] Rewrite and rename `issue-26092` to rmake --- src/tools/run-make-support/src/command.rs | 44 ++++++++++++------- src/tools/run-make-support/src/lib.rs | 21 +++++++++ .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs | 1 - .../blank.rs | 0 .../clear-error-blank-output/rmake.rs | 13 ++++++ tests/run-make/issue-26092/Makefile | 6 --- tests/run-make/link-arg/rmake.rs | 24 +++++----- tests/run-make/link-dedup/Makefile | 12 ----- tests/run-make/link-dedup/rmake.rs | 28 +++++------- 10 files changed, 83 insertions(+), 67 deletions(-) rename tests/run-make/{issue-26092 => clear-error-blank-output}/blank.rs (100%) create mode 100644 tests/run-make/clear-error-blank-output/rmake.rs delete mode 100644 tests/run-make/issue-26092/Makefile delete mode 100644 tests/run-make/link-dedup/Makefile diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index dab18dca2ff9..f39bcfd60dfb 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::process::{Command as StdCommand, ExitStatus, Output, Stdio}; use crate::drop_bomb::DropBomb; -use crate::{assert_contains, assert_not_contains, handle_failed_output}; +use crate::{assert_contains, assert_equals, assert_not_contains, handle_failed_output}; /// This is a custom command wrapper that simplifies working with commands and makes it easier to /// ensure that we check the exit status of executed processes. @@ -21,6 +21,7 @@ use crate::{assert_contains, assert_not_contains, handle_failed_output}; /// /// [`run`]: Self::run /// [`run_fail`]: Self::run_fail +/// [`run_unchecked`]: Self::run_unchecked #[derive(Debug)] pub struct Command { cmd: StdCommand, @@ -116,6 +117,15 @@ impl Command { output } + /// Run the command but do not check its exit status. + /// Only use if you explicitly don't care about the exit status. + /// Prefer to use [`Self::run`] and [`Self::run_fail`] + /// whenever possible. + #[track_caller] + pub fn run_unchecked(&mut self) -> CompletedProcess { + self.command_output() + } + #[track_caller] fn command_output(&mut self) -> CompletedProcess { self.drop_bomb.defuse(); @@ -163,41 +173,45 @@ impl CompletedProcess { self.output.status } - /// Checks that trimmed `stdout` matches trimmed `content`. + /// Checks that trimmed `stdout` matches trimmed `expected`. #[track_caller] - pub fn assert_stdout_equals>(&self, content: S) -> &Self { - assert_eq!(self.stdout_utf8().trim(), content.as_ref().trim()); + pub fn assert_stdout_equals>(&self, expected: S) -> &Self { + assert_equals(self.stdout_utf8().trim(), expected.as_ref().trim()); self } + /// Checks that `stdout` does not contain `unexpected`. #[track_caller] - pub fn assert_stdout_contains>(self, needle: S) -> Self { - assert_contains(&self.stdout_utf8(), needle.as_ref()); + pub fn assert_stdout_not_contains>(&self, unexpected: S) -> &Self { + assert_not_contains(&self.stdout_utf8(), unexpected.as_ref()); self } + /// Checks that `stdout` contains `expected`. #[track_caller] - pub fn assert_stdout_not_contains>(&self, needle: S) -> &Self { - assert_not_contains(&self.stdout_utf8(), needle.as_ref()); + pub fn assert_stdout_contains>(&self, expected: S) -> &Self { + assert_contains(&self.stdout_utf8(), expected.as_ref()); self } - /// Checks that trimmed `stderr` matches trimmed `content`. + /// Checks that trimmed `stderr` matches trimmed `expected`. #[track_caller] - pub fn assert_stderr_equals>(&self, content: S) -> &Self { - assert_eq!(self.stderr_utf8().trim(), content.as_ref().trim()); + pub fn assert_stderr_equals>(&self, expected: S) -> &Self { + assert_equals(self.stderr_utf8().trim(), expected.as_ref().trim()); self } + /// Checks that `stderr` contains `expected`. #[track_caller] - pub fn assert_stderr_contains>(&self, needle: S) -> &Self { - assert_contains(&self.stderr_utf8(), needle.as_ref()); + pub fn assert_stderr_contains>(&self, expected: S) -> &Self { + assert_contains(&self.stderr_utf8(), expected.as_ref()); self } + /// Checks that `stderr` does not contain `unexpected`. #[track_caller] - pub fn assert_stderr_not_contains>(&self, needle: S) -> &Self { - assert_not_contains(&self.stdout_utf8(), needle.as_ref()); + pub fn assert_stderr_not_contains>(&self, unexpected: S) -> &Self { + assert_not_contains(&self.stdout_utf8(), unexpected.as_ref()); self } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index ba4524c150c4..84b0a4f61eea 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -332,6 +332,18 @@ pub fn read_dir(dir: impl AsRef, callback: F) { } } +/// Check that `actual` is equal to `expected`. Panic otherwise. +#[track_caller] +pub fn assert_equals(actual: &str, expected: &str) { + if actual != expected { + eprintln!("=== ACTUAL TEXT ==="); + eprintln!("{}", actual); + eprintln!("=== EXPECTED ==="); + eprintln!("{}", expected); + panic!("expected text was not found in actual text"); + } +} + /// Check that `haystack` contains `needle`. Panic otherwise. #[track_caller] pub fn assert_contains(haystack: &str, needle: &str) { @@ -468,6 +480,15 @@ macro_rules! impl_common_helpers { self.cmd.run_fail() } + /// Run the command but do not check its exit status. + /// Only use if you explicitly don't care about the exit status. + /// Prefer to use [`Self::run`] and [`Self::run_fail`] + /// whenever possible. + #[track_caller] + pub fn run_unchecked(&mut self) -> crate::command::CompletedProcess { + self.cmd.run_unchecked() + } + /// Set the path where the command will be run. pub fn current_dir>(&mut self, path: P) -> &mut Self { self.cmd.current_dir(path); diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 6a1809951fd1..69a8aa05360f 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -83,7 +83,6 @@ run-make/issue-20626/Makefile run-make/issue-22131/Makefile run-make/issue-25581/Makefile run-make/issue-26006/Makefile -run-make/issue-26092/Makefile run-make/issue-28595/Makefile run-make/issue-33329/Makefile run-make/issue-35164/Makefile diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs index b3227b795598..d937514c2ca2 100644 --- a/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs +++ b/tests/run-make/CURRENT_RUSTC_VERSION/rmake.rs @@ -12,7 +12,6 @@ fn main() { let output = rustc().input("main.rs").emit("metadata").extern_("stable", "libstable.rmeta").run(); - let version = fs_wrapper::read_to_string(source_root().join("src/version")); let expected_string = format!("stable since {}", version.trim()); output.assert_stderr_contains(expected_string); diff --git a/tests/run-make/issue-26092/blank.rs b/tests/run-make/clear-error-blank-output/blank.rs similarity index 100% rename from tests/run-make/issue-26092/blank.rs rename to tests/run-make/clear-error-blank-output/blank.rs diff --git a/tests/run-make/clear-error-blank-output/rmake.rs b/tests/run-make/clear-error-blank-output/rmake.rs new file mode 100644 index 000000000000..e0f042cf805b --- /dev/null +++ b/tests/run-make/clear-error-blank-output/rmake.rs @@ -0,0 +1,13 @@ +// When an empty output file is passed to rustc, the ensuing error message +// should be clear. However, calling file_stem on an empty path returns None, +// which, when unwrapped, causes a panic, stopping execution of rustc +// and printing an obscure message instead of reaching the helpful +// error message. This test checks that the panic does not occur. +// See https://github.com/rust-lang/rust/pull/26199 + +use run_make_support::rustc; + +fn main() { + let output = rustc().output("").stdin(b"fn main() {}").run_fail(); + output.assert_stderr_not_contains("panic"); +} diff --git a/tests/run-make/issue-26092/Makefile b/tests/run-make/issue-26092/Makefile deleted file mode 100644 index 96822e7690be..000000000000 --- a/tests/run-make/issue-26092/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -include ../tools.mk - -# This test ensures that rustc does not panic with `-o ""` option. - -all: - $(RUSTC) -o "" blank.rs 2>&1 | $(CGREP) -i 'panic' && exit 1 || exit 0 diff --git a/tests/run-make/link-arg/rmake.rs b/tests/run-make/link-arg/rmake.rs index dd496101f6a7..a6d68800792f 100644 --- a/tests/run-make/link-arg/rmake.rs +++ b/tests/run-make/link-arg/rmake.rs @@ -7,18 +7,14 @@ use run_make_support::rustc; fn main() { - let output = String::from_utf8( - rustc() - .input("empty.rs") - .link_arg("-lfoo") - .link_arg("-lbar") - .print("link-args") - .command_output() - .stdout, - ) - .unwrap(); - assert!( - output.contains("lfoo") || output.contains("lbar"), - "The output did not contain the expected \"lfoo\" or \"lbar\" strings." - ); + // We are only checking for the output of --print=link-args, + // rustc failing or succeeding does not matter. + let out = rustc() + .input("empty.rs") + .link_arg("-lfoo") + .link_arg("-lbar") + .print("link-args") + .run_unchecked(); + out.assert_stdout_contains("lfoo"); + out.assert_stdout_contains("lbar"); } diff --git a/tests/run-make/link-dedup/Makefile b/tests/run-make/link-dedup/Makefile deleted file mode 100644 index eff18ab48ab4..000000000000 --- a/tests/run-make/link-dedup/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-msvc - -include ../tools.mk - -all: - $(RUSTC) depa.rs - $(RUSTC) depb.rs - $(RUSTC) depc.rs - $(RUSTC) empty.rs --cfg bar 2>&1 | $(CGREP) '"-ltesta" "-ltestb" "-ltesta"' - $(RUSTC) empty.rs 2>&1 | $(CGREP) '"-ltesta"' - $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltestb"' - $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltesta" "-ltesta" "-ltesta"' diff --git a/tests/run-make/link-dedup/rmake.rs b/tests/run-make/link-dedup/rmake.rs index a0d3ac865426..9bff3a4b44c7 100644 --- a/tests/run-make/link-dedup/rmake.rs +++ b/tests/run-make/link-dedup/rmake.rs @@ -7,26 +7,18 @@ //@ ignore-msvc +use run_make_support::rustc; + fn main() { rustc().input("depa.rs").run(); rustc().input("depb.rs").run(); rustc().input("depc.rs").run(); - let output = - String::from_utf8(rustc().input("empty.rs").cfg("bar").command_output().stderr).unwrap(); - let pos_a1 = - output.find("-ltesta").expect("empty.rs, compiled with --cfg, should contain -ltesta"); - let pos_b = output[pos_a1..] - .find("-ltestb") - .map(|pos| pos + pos_a1) - .expect("empty.rs, compiled with --cfg, should contain -ltestb"); - let _ = output[pos_b..] - .find("-ltesta") - .map(|pos| pos + pos_b) - .expect("empty.rs, compiled with --cfg, should contain a second -ltesta"); - let output = String::from_utf8(rustc().input("empty.rs").command_output().stderr).unwrap(); - assert!(output.contains("-ltesta")); - let output = String::from_utf8(rustc().input("empty.rs").command_output().stderr).unwrap(); - assert!(!output.contains("-ltestb")); - let output = String::from_utf8(rustc().input("empty.rs").command_output().stderr).unwrap(); - assert_eq!(output.matches("-ltesta").count, 1); + let output = rustc().input("empty.rs").cfg("bar").run_fail(); + output.assert_stderr_contains(r#""-ltesta" "-ltestb" "-ltesta""#); + let output = rustc().input("empty.rs").run_fail(); + output.assert_stderr_contains(r#""-ltesta""#); + let output = rustc().input("empty.rs").run_fail(); + output.assert_stderr_not_contains(r#""-ltestb""#); + let output = rustc().input("empty.rs").run_fail(); + output.assert_stderr_not_contains(r#""-ltesta" "-ltesta" "-ltesta""#); } From 03f19d632ad896be77a0dabfe1298f164c78067c Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 11 Jun 2024 16:12:36 -0400 Subject: [PATCH 48/48] Add new test_while_readonly helper function to run-make-support --- src/tools/run-make-support/src/lib.rs | 32 +++++++++++++++++ tests/run-make/inaccessible-temp-dir/rmake.rs | 36 ++++++++----------- tests/run-make/output-with-hyphens/rmake.rs | 4 +-- .../parallel-rustc-no-overwrite/rmake.rs | 5 +-- 4 files changed, 52 insertions(+), 25 deletions(-) diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index b920f9a07db8..6a89a75d7159 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -169,6 +169,38 @@ pub fn cwd() -> PathBuf { env::current_dir().unwrap() } +// FIXME(Oneirical): This will no longer be required after compiletest receives the ability +// to manipulate read-only files. See https://github.com/rust-lang/rust/issues/126334 +/// Ensure that the path P is read-only while the test runs, and restore original permissions +/// at the end so compiletest can clean up. +/// This will panic on Windows if the path is a directory (as it would otherwise do nothing) +#[track_caller] +pub fn test_while_readonly, F: FnOnce() + std::panic::UnwindSafe>( + path: P, + closure: F, +) { + let path = path.as_ref(); + if is_windows() && path.is_dir() { + eprintln!("This helper function cannot be used on Windows to make directories readonly."); + eprintln!( + "See the official documentation: + https://doc.rust-lang.org/std/fs/struct.Permissions.html#method.set_readonly" + ); + panic!("`test_while_readonly` on directory detected while on Windows."); + } + let metadata = fs_wrapper::metadata(&path); + let original_perms = metadata.permissions(); + + let mut new_perms = original_perms.clone(); + new_perms.set_readonly(true); + fs_wrapper::set_permissions(&path, new_perms); + + let success = std::panic::catch_unwind(closure); + + fs_wrapper::set_permissions(&path, original_perms); + success.unwrap(); +} + /// Use `cygpath -w` on a path to get a Windows path string back. This assumes that `cygpath` is /// available on the platform! #[track_caller] diff --git a/tests/run-make/inaccessible-temp-dir/rmake.rs b/tests/run-make/inaccessible-temp-dir/rmake.rs index 25c9d363820d..be24e47b6dec 100644 --- a/tests/run-make/inaccessible-temp-dir/rmake.rs +++ b/tests/run-make/inaccessible-temp-dir/rmake.rs @@ -13,32 +13,26 @@ // use a directory with non-existing parent like `/does-not-exist/output`. // See https://github.com/rust-lang/rust/issues/66530 -//@ only-linux -// Reason: set_mode is only available on Unix - //@ ignore-arm // Reason: linker error on `armhf-gnu` +//@ ignore-windows +// Reason: `set_readonly` has no effect on directories +// and does not prevent modification. -use run_make_support::{fs_wrapper, rustc}; +use run_make_support::{fs_wrapper, rustc, test_while_readonly}; fn main() { // Create an inaccessible directory. fs_wrapper::create_dir("inaccessible"); - let meta = fs_wrapper::metadata("inaccessible"); - let mut perms = meta.permissions(); - perms.set_mode(0o000); // Lock down the directory. - fs_wrapper::set_permissions("inaccessible", perms); - - // Run rustc with `-Z temps-dir` set to a directory *inside* the inaccessible one, - // so that it can't create `tmp`. - rustc() - .input("program.rs") - .arg("-Ztemps-dir=inaccessible/tmp") - .run_fail() - .assert_stderr_contains( - "failed to find or create the directory specified by `--temps-dir`", - ); - - perms.set_mode(0o666); // Unlock the directory, so that compiletest can delete it. - fs_wrapper::set_permissions("inaccessible", perms); + test_while_readonly("inaccessible", || { + // Run rustc with `-Z temps-dir` set to a directory *inside* the inaccessible one, + // so that it can't create `tmp`. + rustc() + .input("program.rs") + .arg("-Ztemps-dir=inaccessible/tmp") + .run_fail() + .assert_stderr_contains( + "failed to find or create the directory specified by `--temps-dir`", + ); + }); } diff --git a/tests/run-make/output-with-hyphens/rmake.rs b/tests/run-make/output-with-hyphens/rmake.rs index 21c003c628b9..79deb772bc5d 100644 --- a/tests/run-make/output-with-hyphens/rmake.rs +++ b/tests/run-make/output-with-hyphens/rmake.rs @@ -7,11 +7,11 @@ //@ ignore-cross-compile -use run_make_support::{path, rustc}; +use run_make_support::{bin_name, path, rust_lib_name, rustc}; fn main() { rustc().input("foo-bar.rs").crate_type("bin").run(); assert!(path(bin_name("foo-bar")).exists()); rustc().input("foo-bar.rs").crate_type("lib").run(); - assert!(path(bin_name("libfoo_bar.rlib")).exists()); + assert!(path(rust_lib_name("foo_bar")).exists()); } diff --git a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs index 40c6ab7ed5eb..3f032cf3762a 100644 --- a/tests/run-make/parallel-rustc-no-overwrite/rmake.rs +++ b/tests/run-make/parallel-rustc-no-overwrite/rmake.rs @@ -10,15 +10,16 @@ use std::sync::{Arc, Barrier}; use std::thread; fn main() { + fs_wrapper::create_file("lib.rs"); let barrier = Arc::new(Barrier::new(2)); let handle = { let barrier = Arc::clone(&barrier); thread::spawn(move || { barrier.wait(); - rustc().crate_type("lib").arg("-Ztemps-dir=temp1").input("lib.rs"); + rustc().crate_type("lib").arg("-Ztemps-dir=temp1").input("lib.rs").run(); }) }; barrier.wait(); - rustc().crate_type("staticlib").arg("-Ztemps-dir=temp2").input("lib.rs"); + rustc().crate_type("staticlib").arg("-Ztemps-dir=temp2").input("lib.rs").run(); handle.join().expect("lib thread panicked"); }