From c528cca785e6f83293160d4589af15c5ddaa7ddc Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 30 Mar 2026 11:40:03 +0800 Subject: [PATCH 1/8] Fix alias path for rustdoc --- src/bootstrap/src/core/build_steps/check.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 2 +- src/bootstrap/src/core/build_steps/tool.rs | 2 +- .../builder/cli_paths/snapshots/x_bench.snap | 3 +-- .../builder/cli_paths/snapshots/x_build.snap | 3 +-- .../builder/cli_paths/snapshots/x_check.snap | 3 +-- ...eck_compiletest_include_default_paths.snap | 3 +-- .../builder/cli_paths/snapshots/x_fix.snap | 3 +-- .../builder/cli_paths/snapshots/x_test.snap | 3 +-- .../snapshots/x_test_librustdoc_rustdoc.snap | 3 +-- .../snapshots/x_test_skip_coverage.snap | 3 +-- .../snapshots/x_test_skip_tests.snap | 3 +-- .../snapshots/x_test_skip_tests_etc.snap | 3 +-- src/bootstrap/src/core/builder/mod.rs | 23 +++++++++++++++---- src/bootstrap/src/core/builder/tests.rs | 23 +++++++++++++++++++ 15 files changed, 55 insertions(+), 27 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 55426bfffc73..3356f0b04b52 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -706,7 +706,7 @@ impl Step for $name { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path($path) $( .path( $alt_path ) )* + run.path_aliases(&[$path $(, $alt_path )*]) } fn is_default_step(_builder: &Builder<'_>) -> bool { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 7be45c5fa9d4..6b4eb75d8a38 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3189,7 +3189,7 @@ impl Step for CrateRustdoc { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/librustdoc").path("src/tools/rustdoc") + run.path_aliases(&["src/librustdoc", "src/tools/rustdoc"]) } fn is_default_step(_builder: &Builder<'_>) -> bool { diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index e6148af61767..9956dfd04595 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -689,7 +689,7 @@ impl Step for Rustdoc { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/tools/rustdoc").path("src/librustdoc") + run.path_aliases(&["src/tools/rustdoc", "src/librustdoc"]) } fn is_default_step(_builder: &Builder<'_>) -> bool { diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_bench.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_bench.snap index 294623f07386..3ae8d3de6b55 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_bench.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_bench.snap @@ -96,5 +96,4 @@ expression: bench - Set({bench::compiler/rustc_windows_rc}) [Bench] test::CrateRustdoc targets: [x86_64-unknown-linux-gnu] - - Set({bench::src/librustdoc}) - - Set({bench::src/tools/rustdoc}) + - Set({bench::src/librustdoc, bench::src/tools/rustdoc}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_build.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_build.snap index f8c6deccb3bc..7180c337df99 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_build.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_build.snap @@ -19,5 +19,4 @@ expression: build - Set({build::library/unwind}) [Build] tool::Rustdoc targets: [x86_64-unknown-linux-gnu] - - Set({build::src/librustdoc}) - - Set({build::src/tools/rustdoc}) + - Set({build::src/librustdoc, build::src/tools/rustdoc}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check.snap index 242a2272b4d1..89ec347d4169 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check.snap @@ -80,8 +80,7 @@ expression: check - Set({check::compiler/rustc_windows_rc}) [Check] check::Rustdoc targets: [x86_64-unknown-linux-gnu] - - Set({check::src/librustdoc}) - - Set({check::src/tools/rustdoc}) + - Set({check::src/librustdoc, check::src/tools/rustdoc}) [Check] check::CraneliftCodegenBackend targets: [x86_64-unknown-linux-gnu] - Set({check::cg_clif}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiletest_include_default_paths.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiletest_include_default_paths.snap index e43d5380a398..16a88aca0e2d 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiletest_include_default_paths.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_check_compiletest_include_default_paths.snap @@ -80,8 +80,7 @@ expression: check compiletest --include-default-paths - Set({check::compiler/rustc_windows_rc}) [Check] check::Rustdoc targets: [x86_64-unknown-linux-gnu] - - Set({check::src/librustdoc}) - - Set({check::src/tools/rustdoc}) + - Set({check::src/librustdoc, check::src/tools/rustdoc}) [Check] check::CraneliftCodegenBackend targets: [x86_64-unknown-linux-gnu] - Set({check::cg_clif}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fix.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fix.snap index d380cb416acf..eca161986f69 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fix.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_fix.snap @@ -80,8 +80,7 @@ expression: fix - Set({fix::compiler/rustc_windows_rc}) [Fix] check::Rustdoc targets: [x86_64-unknown-linux-gnu] - - Set({fix::src/librustdoc}) - - Set({fix::src/tools/rustdoc}) + - Set({fix::src/librustdoc, fix::src/tools/rustdoc}) [Fix] check::CraneliftCodegenBackend targets: [x86_64-unknown-linux-gnu] - Set({fix::cg_clif}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap index ac2f315d39d9..25ff1e64e76b 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test.snap @@ -146,8 +146,7 @@ expression: test - Set({test::compiler/rustc_windows_rc}) [Test] test::CrateRustdoc targets: [x86_64-unknown-linux-gnu] - - Set({test::src/librustdoc}) - - Set({test::src/tools/rustdoc}) + - Set({test::src/librustdoc, test::src/tools/rustdoc}) [Test] test::CrateRustdocJsonTypes targets: [x86_64-unknown-linux-gnu] - Set({test::src/rustdoc-json-types}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap index 8dcdce0c17ab..c8eee72aec42 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_librustdoc_rustdoc.snap @@ -4,8 +4,7 @@ expression: test librustdoc rustdoc --- [Test] test::CrateRustdoc targets: [x86_64-unknown-linux-gnu] - - Set({test::src/librustdoc}) - - Set({test::src/tools/rustdoc}) + - Set({test::src/librustdoc, test::src/tools/rustdoc}) [Test] test::RustdocBook targets: [x86_64-unknown-linux-gnu] - Set({test::src/doc/rustdoc}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap index 09adbb0041ae..2f1ee9386ed7 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_coverage.snap @@ -145,8 +145,7 @@ expression: test --skip=coverage - Set({test::compiler/rustc_windows_rc}) [Test] test::CrateRustdoc targets: [x86_64-unknown-linux-gnu] - - Set({test::src/librustdoc}) - - Set({test::src/tools/rustdoc}) + - Set({test::src/librustdoc, test::src/tools/rustdoc}) [Test] test::CrateRustdocJsonTypes targets: [x86_64-unknown-linux-gnu] - Set({test::src/rustdoc-json-types}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap index b5fccfcb966b..8f5e842d28a1 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests.snap @@ -109,8 +109,7 @@ expression: test --skip=tests - Set({test::compiler/rustc_windows_rc}) [Test] test::CrateRustdoc targets: [x86_64-unknown-linux-gnu] - - Set({test::src/librustdoc}) - - Set({test::src/tools/rustdoc}) + - Set({test::src/librustdoc, test::src/tools/rustdoc}) [Test] test::CrateRustdocJsonTypes targets: [x86_64-unknown-linux-gnu] - Set({test::src/rustdoc-json-types}) diff --git a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap index 9ad8914f58e3..6aaa2a9592b0 100644 --- a/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap +++ b/src/bootstrap/src/core/builder/cli_paths/snapshots/x_test_skip_tests_etc.snap @@ -89,8 +89,7 @@ expression: test --skip=tests --skip=coverage-map --skip=coverage-run --skip=lib - Set({test::compiler/rustc_windows_rc}) [Test] test::CrateRustdoc targets: [x86_64-unknown-linux-gnu] - - Set({test::src/librustdoc}) - - Set({test::src/tools/rustdoc}) + - Set({test::src/librustdoc, test::src/tools/rustdoc}) [Test] test::CrateRustdocJsonTypes targets: [x86_64-unknown-linux-gnu] - Set({test::src/rustdoc-json-types}) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index ae91b2040629..a9d6d3880deb 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -555,10 +555,7 @@ pub fn alias(mut self, alias: &str) -> Self { self } - /// single, non-aliased path - /// - /// Must be an on-disk path; use `alias` for names that do not correspond to on-disk paths. - pub fn path(mut self, path: &str) -> Self { + fn assert_valid_path(&self, path: &str) { let submodules_paths = self.builder.submodule_paths(); // assert only if `p` isn't submodule @@ -568,12 +565,30 @@ pub fn path(mut self, path: &str) -> Self { "`should_run.path` should correspond to a real on-disk path - use `alias` if there is no relevant path: {path}" ); } + } + + /// single, non-aliased path + /// + /// Must be an on-disk path; use `alias` for names that do not correspond to on-disk paths. + pub fn path(mut self, path: &str) -> Self { + self.assert_valid_path(path); let task = TaskPath { path: path.into(), kind: Some(self.kind) }; self.paths.insert(PathSet::Set(BTreeSet::from_iter([task]))); self } + /// Multiple on-disk paths that should be treated as aliases of one another. + pub fn path_aliases(mut self, paths: &[&str]) -> Self { + let mut set = BTreeSet::new(); + for path in paths { + self.assert_valid_path(path); + set.insert(TaskPath { path: (*path).into(), kind: Some(self.kind) }); + } + self.paths.insert(PathSet::Set(set)); + self + } + /// Handles individual files (not directories) within a test suite. fn is_suite_path(&self, requested_path: &Path) -> Option<&PathSet> { self.paths.iter().find(|pathset| match pathset { diff --git a/src/bootstrap/src/core/builder/tests.rs b/src/bootstrap/src/core/builder/tests.rs index f34b284dbb9c..618129e27b8a 100644 --- a/src/bootstrap/src/core/builder/tests.rs +++ b/src/bootstrap/src/core/builder/tests.rs @@ -2400,6 +2400,29 @@ fn test_exclude_kind() { steps.assert_contains_fuzzy(StepMetadata::build("rustc", host)); } + #[test] + fn test_exclude_rustdoc_aliases() { + let ctx = TestCtx::new(); + let host = TargetSelection::from_user(&host_target()); + + let get_steps = |args: &[&str]| ctx.config("build").args(args).get_steps(); + + for args in [ + ["--skip", "rustdoc"].as_slice(), + ["--skip", "src/tools/rustdoc"].as_slice(), + ["--skip", "src/librustdoc"].as_slice(), + ] { + let steps = get_steps(args); + + steps.assert_contains_fuzzy(StepMetadata::build("rustc", host)); + steps.assert_no_match(|metadata| { + metadata.name == "rustdoc" + && metadata.kind == Kind::Build + && metadata.target == host + }); + } + } + #[test] fn test_cargo_stage_1() { let ctx = TestCtx::new(); From f14ce2a0c7a9326d3bfe33aae96d1bffe0c8853d Mon Sep 17 00:00:00 2001 From: Yukang Date: Sun, 5 Apr 2026 18:19:51 +0800 Subject: [PATCH 2/8] fix comment for alias MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: 许杰友 Jieyou Xu (Joe) <39484203+jieyouxu@users.noreply.github.com> --- src/bootstrap/src/core/builder/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index a9d6d3880deb..43553e23f8b9 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -569,7 +569,7 @@ fn assert_valid_path(&self, path: &str) { /// single, non-aliased path /// - /// Must be an on-disk path; use `alias` for names that do not correspond to on-disk paths. + /// Must be an on-disk path; use [`path_aliases`][Self::path_aliases] for names that do not correspond to on-disk paths. pub fn path(mut self, path: &str) -> Self { self.assert_valid_path(path); From 7439d71a106ad58438fd4f5624a578d778e0cc85 Mon Sep 17 00:00:00 2001 From: yukang Date: Sun, 19 Apr 2026 12:53:44 +0800 Subject: [PATCH 3/8] rename path_aliases to selectors --- src/bootstrap/src/core/build_steps/check.rs | 2 +- src/bootstrap/src/core/build_steps/test.rs | 2 +- src/bootstrap/src/core/build_steps/tool.rs | 2 +- src/bootstrap/src/core/builder/mod.rs | 11 ++++++----- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs index 3356f0b04b52..9d958f7d1007 100644 --- a/src/bootstrap/src/core/build_steps/check.rs +++ b/src/bootstrap/src/core/build_steps/check.rs @@ -706,7 +706,7 @@ impl Step for $name { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path_aliases(&[$path $(, $alt_path )*]) + run.selectors(&[$path $(, $alt_path )*]) } fn is_default_step(_builder: &Builder<'_>) -> bool { diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 6b4eb75d8a38..929869d52895 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3189,7 +3189,7 @@ impl Step for CrateRustdoc { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path_aliases(&["src/librustdoc", "src/tools/rustdoc"]) + run.selectors(&["src/librustdoc", "src/tools/rustdoc"]) } fn is_default_step(_builder: &Builder<'_>) -> bool { diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index 9956dfd04595..ed5c2586a5ed 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -689,7 +689,7 @@ impl Step for Rustdoc { const IS_HOST: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path_aliases(&["src/tools/rustdoc", "src/librustdoc"]) + run.selectors(&["src/tools/rustdoc", "src/librustdoc"]) } fn is_default_step(_builder: &Builder<'_>) -> bool { diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs index 43553e23f8b9..bc402313367f 100644 --- a/src/bootstrap/src/core/builder/mod.rs +++ b/src/bootstrap/src/core/builder/mod.rs @@ -356,7 +356,7 @@ pub enum PathSet { /// command-line value of `std` will match if `library/std` is in the /// set. /// - /// NOTE: the paths within a set should always be aliases of one another. + /// NOTE: the paths within a set should all select the same unit of work. /// For example, `src/librustdoc` and `src/tools/rustdoc` should be in the same set, /// but `library/core` and `library/std` generally should not, unless there's no way (for that Step) /// to build them separately. @@ -567,9 +567,10 @@ fn assert_valid_path(&self, path: &str) { } } - /// single, non-aliased path + /// A single path /// - /// Must be an on-disk path; use [`path_aliases`][Self::path_aliases] for names that do not correspond to on-disk paths. + /// Must be an on-disk path; use [`alias`][Self::alias] for names that do not + /// correspond to on-disk paths. pub fn path(mut self, path: &str) -> Self { self.assert_valid_path(path); @@ -578,8 +579,8 @@ pub fn path(mut self, path: &str) -> Self { self } - /// Multiple on-disk paths that should be treated as aliases of one another. - pub fn path_aliases(mut self, paths: &[&str]) -> Self { + /// Multiple on-disk paths that should select the same unit of work. + pub fn selectors(mut self, paths: &[&str]) -> Self { let mut set = BTreeSet::new(); for path in paths { self.assert_valid_path(path); From 51e3797ebc8268c61b50bb1eac858efdae992f67 Mon Sep 17 00:00:00 2001 From: Austin Henriksen Date: Thu, 30 Apr 2026 23:31:14 -0400 Subject: [PATCH 4/8] `bufreader::Buffer`: Remove leftover note about `initialized` field https://github.com/rust-lang/rust/pull/150129 reworked this field to use `bool` instead of `usize`, which is awesome! But the field's comment has a leftover note in it which is no longer true, and that needs to be removed. --- library/std/src/io/buffered/bufreader/buffer.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/library/std/src/io/buffered/bufreader/buffer.rs b/library/std/src/io/buffered/bufreader/buffer.rs index 314f39225e65..f2efcc5ab860 100644 --- a/library/std/src/io/buffered/bufreader/buffer.rs +++ b/library/std/src/io/buffered/bufreader/buffer.rs @@ -23,9 +23,8 @@ pub struct Buffer { filled: usize, // Whether `buf` has been fully initialized. We track this so that we can accurately tell // `read_buf` how many bytes of buf are initialized, to bypass as much of its defensive - // initialization as possible. Note that while this often the same as `filled`, it doesn't need - // to be. Calls to `fill_buf` are not required to actually fill the buffer, and omitting this - // is a huge perf regression for `Read` impls that do not. + // initialization as possible. Calls to `fill_buf` are not required to actually fill the buffer, + // and omitting this is a huge perf regression for `Read` impls that do not. initialized: bool, } From e43a1b5b449e5f629efd7242c081e98a1ca02d33 Mon Sep 17 00:00:00 2001 From: Shoyu Vanilla Date: Sat, 25 Apr 2026 01:52:34 +0900 Subject: [PATCH 5/8] `-Znext-solver` Ignore region constraints from the nested goals in leakcheck --- .../src/type_check/constraint_conversion.rs | 4 +- .../rustc_hir_analysis/src/check/wfcheck.rs | 1 + .../src/coherence/builtin.rs | 7 +- .../src/infer/canonical/query_response.rs | 28 ++-- compiler/rustc_infer/src/infer/context.rs | 18 ++- .../src/infer/lexical_region_resolve/mod.rs | 6 +- compiler/rustc_infer/src/infer/mod.rs | 6 +- .../src/infer/outlives/obligations.rs | 12 +- .../infer/region_constraints/leak_check.rs | 21 ++- .../src/infer/region_constraints/mod.rs | 126 ++++++++++++++---- .../src/infer/relate/type_relating.rs | 33 ++--- compiler/rustc_middle/src/infer/canonical.rs | 4 +- compiler/rustc_middle/src/ty/mod.rs | 2 +- .../src/canonical/mod.rs | 17 ++- .../rustc_next_trait_solver/src/delegate.rs | 6 +- .../src/solve/eval_ctxt/mod.rs | 33 ++++- .../rustc_next_trait_solver/src/solve/mod.rs | 2 +- .../src/solve/delegate.rs | 32 +++-- .../src/traits/auto_trait.rs | 2 +- .../src/traits/fulfill.rs | 6 +- .../src/traits/outlives_bounds.rs | 6 +- .../rustc_traits/src/coroutine_witnesses.rs | 2 +- compiler/rustc_type_ir/src/infer_ctxt.rs | 3 + compiler/rustc_type_ir/src/macros.rs | 1 + .../src/relate/solver_relating.rs | 8 +- compiler/rustc_type_ir/src/solve/mod.rs | 43 +++++- tests/crashes/140577.rs | 32 ----- ...st-prove-where-clauses-on-norm.next.stderr | 8 +- ...-from-env-universe-err-project.next.stderr | 13 +- ...candidate-from-env-universe-err-project.rs | 2 +- ...wf-candidate-behind-stalled-coroutine-1.rs | 45 +++++++ ...wf-candidate-behind-stalled-coroutine-2.rs | 50 +++++++ ...wf-candidate-behind-stalled-coroutine-3.rs | 36 +++++ ...implied-bounds-for-opaque-types-unsound.rs | 48 +++++++ 34 files changed, 509 insertions(+), 154 deletions(-) delete mode 100644 tests/crashes/140577.rs create mode 100644 tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-1.rs create mode 100644 tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-2.rs create mode 100644 tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-3.rs create mode 100644 tests/ui/traits/vtable/lack-of-implied-bounds-for-opaque-types-unsound.rs diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 868c6f11b68d..bca2de041b65 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -74,7 +74,7 @@ pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints< let assumptions = elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied()); - for &(constraint, constraint_category) in constraints { + for &(constraint, constraint_category, _) in constraints { constraint.iter_outlives().for_each(|predicate| { self.convert(predicate, constraint_category, &assumptions); }); @@ -296,7 +296,7 @@ fn normalize_and_add_type_outlives_constraints( // FIXME(higher_ranked_auto): What should we do with the assumptions here? if let Some(QueryRegionConstraints { constraints, assumptions: _ }) = constraints { next_outlives_predicates.extend(constraints.iter().flat_map( - |(constraint, category)| { + |(constraint, category, _)| { constraint.iter_outlives().map(|outlives| (outlives, *category)) }, )); diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 05d16d2ddb49..3242fe30d016 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -728,6 +728,7 @@ fn region_known_to_outlive<'tcx>( SubregionOrigin::RelateRegionParamBound(DUMMY_SP, None), region_b, region_a, + ty::VisibleForLeakCheck::Unreachable, ); }) } diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 4a10bde4d6da..c983a03f613b 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -496,7 +496,12 @@ pub(crate) fn coerce_unsized_info<'tcx>( } (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { - infcx.sub_regions(SubregionOrigin::RelateObjectBound(span), r_b, r_a); + infcx.sub_regions( + SubregionOrigin::RelateObjectBound(span), + r_b, + r_a, + ty::VisibleForLeakCheck::Yes, + ); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; let mt_b = ty::TypeAndMut { ty: ty_b, mutbl: mutbl_b }; check_mutbl(mt_a, mt_b, &|ty| Ty::new_imm_ref(tcx, r_b, ty)) diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 5203b4ee5d99..bc159ee8a004 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -188,14 +188,14 @@ pub fn instantiate_query_response_and_region_obligations( let InferOk { value: result_args, obligations } = self.query_response_instantiation(cause, param_env, original_values, query_response)?; - for (constraint, _category) in &query_response.value.region_constraints.constraints { + for (constraint, _category, vis) in &query_response.value.region_constraints.constraints { let constraint = instantiate_value(self.tcx, &result_args, *constraint); match constraint { ty::RegionConstraint::Outlives(predicate) => { - self.register_outlives_constraint(predicate, cause); + self.register_outlives_constraint(predicate, *vis, cause); } ty::RegionConstraint::Eq(predicate) => { - self.register_region_eq_constraint(predicate, cause); + self.register_region_eq_constraint(predicate, *vis, cause); } } } @@ -288,6 +288,7 @@ pub fn instantiate_nll_query_response_and_region_obligations( output_query_region_constraints.constraints.push(( ty::RegionEqPredicate(v_o.into(), v_r).into(), constraint_category, + ty::VisibleForLeakCheck::Yes, )); } } @@ -586,6 +587,7 @@ fn unify_canonical_vars( SubregionOrigin::RelateRegionParamBound(cause.span, None), v1, v2, + ty::VisibleForLeakCheck::Yes, ); } (GenericArgKind::Const(v1), GenericArgKind::Const(v2)) => { @@ -623,20 +625,24 @@ pub fn make_query_region_constraints<'tcx>( | ConstraintKind::RegSubReg => { // Swap regions because we are going from sub (<=) to outlives (>=). let constraint = ty::OutlivesPredicate(c.sup.into(), c.sub).into(); - (constraint, origin.to_constraint_category()) + (constraint, origin.to_constraint_category(), c.visible_for_leak_check) } ConstraintKind::VarEqVar | ConstraintKind::VarEqReg | ConstraintKind::RegEqReg => { let constraint = ty::RegionEqPredicate(c.sup, c.sub).into(); - (constraint, origin.to_constraint_category()) + (constraint, origin.to_constraint_category(), c.visible_for_leak_check) } }) - .chain(outlives_obligations.into_iter().map(|obl| { - ( - ty::OutlivesPredicate(obl.sup_type.into(), obl.sub_region).into(), - obl.origin.to_constraint_category(), - ) - })) + .chain(outlives_obligations.into_iter().map( + |TypeOutlivesConstraint { sub_region, sup_type, origin }| { + ( + ty::OutlivesPredicate(sup_type.into(), sub_region).into(), + origin.to_constraint_category(), + // We don't do leak checks for type outlives + ty::VisibleForLeakCheck::Unreachable, + ) + }, + )) .collect(); QueryRegionConstraints { constraints, assumptions } diff --git a/compiler/rustc_infer/src/infer/context.rs b/compiler/rustc_infer/src/infer/context.rs index fada30ff3063..74da4d4c6db8 100644 --- a/compiler/rustc_infer/src/infer/context.rs +++ b/compiler/rustc_infer/src/infer/context.rs @@ -256,19 +256,33 @@ fn probe(&self, probe: impl FnOnce() -> T) -> T { self.probe(|_| probe()) } - fn sub_regions(&self, sub: ty::Region<'tcx>, sup: ty::Region<'tcx>, span: Span) { + fn sub_regions( + &self, + sub: ty::Region<'tcx>, + sup: ty::Region<'tcx>, + vis: ty::VisibleForLeakCheck, + span: Span, + ) { self.inner.borrow_mut().unwrap_region_constraints().make_subregion( SubregionOrigin::RelateRegionParamBound(span, None), sub, sup, + vis, ); } - fn equate_regions(&self, a: ty::Region<'tcx>, b: ty::Region<'tcx>, span: Span) { + fn equate_regions( + &self, + a: ty::Region<'tcx>, + b: ty::Region<'tcx>, + vis: ty::VisibleForLeakCheck, + span: Span, + ) { self.inner.borrow_mut().unwrap_region_constraints().make_eqregion( SubregionOrigin::RelateRegionParamBound(span, None), a, b, + vis, ); } diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs index 9e5c31eecbe7..e6af7b30f4ad 100644 --- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs +++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs @@ -149,7 +149,11 @@ fn infer_variable_values( // Deduplicating constraints is shown to have a positive perf impact. let mut seen = UnordSet::default(); - self.data.constraints.retain(|(constraint, _)| seen.insert(*constraint)); + self.data.constraints.retain_mut(|(constraint, _)| { + // We don't want to discern constraints by leak check visibility here + constraint.visible_for_leak_check = ty::VisibleForLeakCheck::Unreachable; + seen.insert(*constraint) + }); if cfg!(debug_assertions) { self.dump_constraints(); diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 26c03066c7e4..05043f8617a9 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -698,8 +698,9 @@ pub fn sub_regions( origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, + vis: ty::VisibleForLeakCheck, ) { - self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b); + self.inner.borrow_mut().unwrap_region_constraints().make_subregion(origin, a, b, vis); } #[instrument(skip(self), level = "debug")] @@ -708,8 +709,9 @@ pub fn equate_regions( origin: SubregionOrigin<'tcx>, a: ty::Region<'tcx>, b: ty::Region<'tcx>, + vis: ty::VisibleForLeakCheck, ) { - self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(origin, a, b); + self.inner.borrow_mut().unwrap_region_constraints().make_eqregion(origin, a, b, vis); } /// Processes a `Coerce` predicate from the fulfillment context. diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index e98bee3b12cd..d0234cc2621a 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -85,11 +85,12 @@ impl<'tcx> InferCtxt<'tcx> { pub fn register_outlives_constraint( &self, ty::OutlivesPredicate(arg, r2): ty::ArgOutlivesPredicate<'tcx>, + vis: ty::VisibleForLeakCheck, cause: &ObligationCause<'tcx>, ) { match arg.kind() { ty::GenericArgKind::Lifetime(r1) => { - self.register_region_outlives_constraint(ty::OutlivesPredicate(r1, r2), cause); + self.register_region_outlives_constraint(ty::OutlivesPredicate(r1, r2), vis, cause); } ty::GenericArgKind::Type(ty1) => { self.register_type_outlives_constraint(ty1, r2, cause); @@ -101,24 +102,26 @@ pub fn register_outlives_constraint( pub fn register_region_eq_constraint( &self, ty::RegionEqPredicate(r_a, r_b): ty::RegionEqPredicate<'tcx>, + vis: ty::VisibleForLeakCheck, cause: &ObligationCause<'tcx>, ) { let origin = SubregionOrigin::from_obligation_cause(cause, || { SubregionOrigin::RelateRegionParamBound(cause.span, None) }); - self.equate_regions(origin, r_a, r_b); + self.equate_regions(origin, r_a, r_b, vis); } pub fn register_region_outlives_constraint( &self, ty::OutlivesPredicate(r_a, r_b): ty::RegionOutlivesPredicate<'tcx>, + vis: ty::VisibleForLeakCheck, cause: &ObligationCause<'tcx>, ) { let origin = SubregionOrigin::from_obligation_cause(cause, || { SubregionOrigin::RelateRegionParamBound(cause.span, None) }); // `'a: 'b` ==> `'b <= 'a` - self.sub_regions(origin, r_b, r_a); + self.sub_regions(origin, r_b, r_a, vis); } /// Registers that the given region obligation must be resolved @@ -577,7 +580,8 @@ fn push_sub_region_constraint( b: ty::Region<'tcx>, _constraint_category: ConstraintCategory<'tcx>, ) { - self.sub_regions(origin, a, b) + // We don't do leak check in lexical region resolution + self.sub_regions(origin, a, b, ty::VisibleForLeakCheck::Unreachable) } fn push_verify( diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs index 81a3ca6755d2..a1c32a3c0396 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs @@ -392,10 +392,15 @@ fn iterate_region_constraints( { match undo_entry { &AddConstraint(i) => { - region_constraints.data().constraints[i] - .0 - .iter_outlives() - .for_each(|c| each_edge(c.sub, c.sup)); + region_constraints.data().constraints[i].0.iter_outlives().for_each( + |Constraint { kind: _, sub, sup, visible_for_leak_check }| { + match visible_for_leak_check { + ty::VisibleForLeakCheck::Yes => each_edge(sub, sup), + ty::VisibleForLeakCheck::No => {} + ty::VisibleForLeakCheck::Unreachable => unreachable!(), + } + }, + ); } &AddVerify(i) => span_bug!( region_constraints.data().verifys[i].origin.span(), @@ -410,7 +415,13 @@ fn iterate_region_constraints( .constraints .iter() .flat_map(|(c, _)| c.iter_outlives()) - .for_each(|c| each_edge(c.sub, c.sup)) + .for_each(|Constraint { kind: _, sub, sup, visible_for_leak_check }| { + match visible_for_leak_check { + ty::VisibleForLeakCheck::Yes => each_edge(sub, sup), + ty::VisibleForLeakCheck::No => {} + ty::VisibleForLeakCheck::Unreachable => unreachable!(), + } + }) } } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 38b87eb7a986..03bcb5215ee1 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -115,10 +115,11 @@ pub enum ConstraintKind { #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] pub struct Constraint<'tcx> { pub kind: ConstraintKind, - // If `kind` is `VarSubVar` or `VarSubReg`, this must be a `ReVar`. + // If `kind` is `VarSubVar`, `VarSubReg`, `VarEqVar` or `VarEqReg`, this must be a `ReVar`. pub sub: Region<'tcx>, - // If `kind` is `VarSubVar` or `RegSubVar`, this must be a `ReVar`. + // If `kind` is `VarSubVar`, `RegSubVar` or `VarEqVar`, this must be a `ReVar`. pub sup: Region<'tcx>, + pub visible_for_leak_check: ty::VisibleForLeakCheck, } impl Constraint<'_> { @@ -127,7 +128,7 @@ pub fn involves_placeholders(&self) -> bool { } pub fn iter_outlives(self) -> impl Iterator { - let Constraint { kind, sub, sup } = self; + let Constraint { kind, sub, sup, visible_for_leak_check } = self; match kind { ConstraintKind::VarSubVar @@ -135,18 +136,42 @@ pub fn iter_outlives(self) -> impl Iterator { | ConstraintKind::VarSubReg | ConstraintKind::RegSubReg => iter::once(self).chain(None), - ConstraintKind::VarEqVar => { - iter::once(Constraint { kind: ConstraintKind::VarSubVar, sub, sup }) - .chain(Some(Constraint { kind: ConstraintKind::VarSubVar, sub: sup, sup: sub })) - } - ConstraintKind::VarEqReg => { - iter::once(Constraint { kind: ConstraintKind::VarSubReg, sub, sup }) - .chain(Some(Constraint { kind: ConstraintKind::RegSubVar, sub: sup, sup: sub })) - } - ConstraintKind::RegEqReg => { - iter::once(Constraint { kind: ConstraintKind::RegSubReg, sub, sup }) - .chain(Some(Constraint { kind: ConstraintKind::RegSubReg, sub: sup, sup: sub })) - } + ConstraintKind::VarEqVar => iter::once(Constraint { + kind: ConstraintKind::VarSubVar, + sub, + sup, + visible_for_leak_check, + }) + .chain(Some(Constraint { + kind: ConstraintKind::VarSubVar, + sub: sup, + sup: sub, + visible_for_leak_check, + })), + ConstraintKind::VarEqReg => iter::once(Constraint { + kind: ConstraintKind::VarSubReg, + sub, + sup, + visible_for_leak_check, + }) + .chain(Some(Constraint { + kind: ConstraintKind::RegSubVar, + sub: sup, + sup: sub, + visible_for_leak_check, + })), + ConstraintKind::RegEqReg => iter::once(Constraint { + kind: ConstraintKind::RegSubReg, + sub, + sup, + visible_for_leak_check, + }) + .chain(Some(Constraint { + kind: ConstraintKind::RegSubReg, + sub: sup, + sup: sub, + visible_for_leak_check, + })), } } } @@ -457,6 +482,7 @@ pub(super) fn make_eqregion( origin: SubregionOrigin<'tcx>, a: Region<'tcx>, b: Region<'tcx>, + visible_for_leak_check: ty::VisibleForLeakCheck, ) { if a != b { // FIXME: We could only emit constraints if `unify_var_{var, value}` fails when @@ -467,7 +493,12 @@ pub(super) fn make_eqregion( } (ReVar(a_vid), ReVar(b_vid), _, _) => { self.add_constraint( - Constraint { kind: ConstraintKind::VarEqVar, sub: a, sup: b }, + Constraint { + kind: ConstraintKind::VarEqVar, + sub: a, + sup: b, + visible_for_leak_check, + }, origin, ); debug!("make_eqregion: unifying {:?} with {:?}", a_vid, b_vid); @@ -479,12 +510,22 @@ pub(super) fn make_eqregion( if reg.is_static() { // all regions are subregions of static, so don't go bidirectional here self.add_constraint( - Constraint { kind: ConstraintKind::RegSubVar, sub: reg, sup: var }, + Constraint { + kind: ConstraintKind::RegSubVar, + sub: reg, + sup: var, + visible_for_leak_check, + }, origin, ); } else { self.add_constraint( - Constraint { kind: ConstraintKind::VarEqReg, sub: var, sup: reg }, + Constraint { + kind: ConstraintKind::VarEqReg, + sub: var, + sup: reg, + visible_for_leak_check, + }, origin, ); } @@ -500,13 +541,23 @@ pub(super) fn make_eqregion( (ReStatic, _, st, reg) | (_, ReStatic, reg, st) => { // all regions are subregions of static, so don't go bidirectional here self.add_constraint( - Constraint { kind: ConstraintKind::RegSubReg, sub: st, sup: reg }, + Constraint { + kind: ConstraintKind::RegSubReg, + sub: st, + sup: reg, + visible_for_leak_check, + }, origin, ); } _ => { self.add_constraint( - Constraint { kind: ConstraintKind::RegEqReg, sub: a, sup: b }, + Constraint { + kind: ConstraintKind::RegEqReg, + sub: a, + sup: b, + visible_for_leak_check, + }, origin, ); } @@ -520,6 +571,7 @@ pub(super) fn make_subregion( origin: SubregionOrigin<'tcx>, sub: Region<'tcx>, sup: Region<'tcx>, + visible_for_leak_check: ty::VisibleForLeakCheck, ) { // cannot add constraints once regions are resolved debug!("origin = {:#?}", origin); @@ -534,19 +586,33 @@ pub(super) fn make_subregion( (ReVar(sub_id), ReVar(sup_id)) => { if sub_id != sup_id { self.add_constraint( - Constraint { kind: ConstraintKind::VarSubVar, sub, sup }, + Constraint { + kind: ConstraintKind::VarSubVar, + sub, + sup, + visible_for_leak_check, + }, origin, ); } } - (_, ReVar(_)) => self - .add_constraint(Constraint { kind: ConstraintKind::RegSubVar, sub, sup }, origin), - (ReVar(_), _) => self - .add_constraint(Constraint { kind: ConstraintKind::VarSubReg, sub, sup }, origin), + (_, ReVar(_)) => self.add_constraint( + Constraint { kind: ConstraintKind::RegSubVar, sub, sup, visible_for_leak_check }, + origin, + ), + (ReVar(_), _) => self.add_constraint( + Constraint { kind: ConstraintKind::VarSubReg, sub, sup, visible_for_leak_check }, + origin, + ), _ => { if sub != sup { self.add_constraint( - Constraint { kind: ConstraintKind::RegSubReg, sub, sup }, + Constraint { + kind: ConstraintKind::RegSubReg, + sub, + sup, + visible_for_leak_check, + }, origin, ) } @@ -655,8 +721,12 @@ fn combine_vars( let new_r = ty::Region::new_var(tcx, c); for old_r in [a, b] { match t { - Glb => self.make_subregion(origin.clone(), new_r, old_r), - Lub => self.make_subregion(origin.clone(), old_r, new_r), + Glb => { + self.make_subregion(origin.clone(), new_r, old_r, ty::VisibleForLeakCheck::Yes) + } + Lub => { + self.make_subregion(origin.clone(), old_r, new_r, ty::VisibleForLeakCheck::Yes) + } } } debug!("combine_vars() c={:?}", c); diff --git a/compiler/rustc_infer/src/infer/relate/type_relating.rs b/compiler/rustc_infer/src/infer/relate/type_relating.rs index 408e2a055f1e..595392fcfb52 100644 --- a/compiler/rustc_infer/src/infer/relate/type_relating.rs +++ b/compiler/rustc_infer/src/infer/relate/type_relating.rs @@ -223,26 +223,29 @@ fn regions( match self.ambient_variance { // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a) ty::Covariant => { - self.infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .make_subregion(origin, b, a); + self.infcx.inner.borrow_mut().unwrap_region_constraints().make_subregion( + origin, + b, + a, + ty::VisibleForLeakCheck::Yes, + ); } // Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b) ty::Contravariant => { - self.infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .make_subregion(origin, a, b); + self.infcx.inner.borrow_mut().unwrap_region_constraints().make_subregion( + origin, + a, + b, + ty::VisibleForLeakCheck::Yes, + ); } ty::Invariant => { - self.infcx - .inner - .borrow_mut() - .unwrap_region_constraints() - .make_eqregion(origin, a, b); + self.infcx.inner.borrow_mut().unwrap_region_constraints().make_eqregion( + origin, + a, + b, + ty::VisibleForLeakCheck::Yes, + ); } ty::Bivariant => { unreachable!("Expected bivariance to be handled in relate_with_variance") diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 033e3e36b024..f6b0b89874d2 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -135,7 +135,9 @@ pub fn is_proven(&self) -> bool { } } -pub type QueryRegionConstraint<'tcx> = (ty::RegionConstraint<'tcx>, ConstraintCategory<'tcx>); +// FIXME: Convert this into a struct +pub type QueryRegionConstraint<'tcx> = + (ty::RegionConstraint<'tcx>, ConstraintCategory<'tcx>, ty::VisibleForLeakCheck); #[derive(Default)] pub struct CanonicalParamEnvCache<'tcx> { diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 914fb4314715..837b3cf8c770 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -64,7 +64,7 @@ )] use rustc_type_ir::inherent; pub use rustc_type_ir::relate::VarianceDiagInfo; -pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind}; +pub use rustc_type_ir::solve::{CandidatePreferenceMode, SizedTraitKind, VisibleForLeakCheck}; pub use rustc_type_ir::*; #[allow(hidden_glob_reexports, unused_imports)] use rustc_type_ir::{InferCtxtLike, Interner}; diff --git a/compiler/rustc_next_trait_solver/src/canonical/mod.rs b/compiler/rustc_next_trait_solver/src/canonical/mod.rs index b4a2eab2e838..7ecb7466d623 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/mod.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/mod.rs @@ -25,7 +25,7 @@ use crate::resolve::eager_resolve_vars; use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, Goal, - NestedNormalizationGoals, QueryInput, Response, inspect, + NestedNormalizationGoals, QueryInput, Response, VisibleForLeakCheck, inspect, }; pub mod canonicalizer; @@ -99,6 +99,7 @@ pub(super) fn instantiate_and_apply_query_response( param_env: I::ParamEnv, original_values: &[I::GenericArg], response: CanonicalResponse, + visible_for_leak_check: VisibleForLeakCheck, span: I::Span, ) -> (NestedNormalizationGoals, Certainty) where @@ -116,7 +117,11 @@ pub(super) fn instantiate_and_apply_query_response( let ExternalConstraintsData { region_constraints, opaque_types, normalization_nested_goals } = &*external_constraints; - register_region_constraints(delegate, region_constraints, span); + register_region_constraints( + delegate, + region_constraints.iter().map(|(c, vis)| (*c, vis.and(visible_for_leak_check))), + span, + ); register_new_opaque_types(delegate, opaque_types, span); (normalization_nested_goals.clone(), certainty) @@ -262,21 +267,21 @@ fn unify_query_var_values( fn register_region_constraints( delegate: &D, - constraints: &[ty::RegionConstraint], + constraints: impl IntoIterator, VisibleForLeakCheck)>, span: I::Span, ) where D: SolverDelegate, I: Interner, { - for &constraint in constraints { + for (constraint, vis) in constraints { match constraint { ty::RegionConstraint::Outlives(ty::OutlivesPredicate(lhs, rhs)) => match lhs.kind() { - ty::GenericArgKind::Lifetime(lhs) => delegate.sub_regions(rhs, lhs, span), + ty::GenericArgKind::Lifetime(lhs) => delegate.sub_regions(rhs, lhs, vis, span), ty::GenericArgKind::Type(lhs) => delegate.register_ty_outlives(lhs, rhs, span), ty::GenericArgKind::Const(_) => panic!("const outlives: {lhs:?}: {rhs:?}"), }, ty::RegionConstraint::Eq(ty::RegionEqPredicate(lhs, rhs)) => { - delegate.equate_regions(lhs, rhs, span) + delegate.equate_regions(lhs, rhs, vis, span) } } } diff --git a/compiler/rustc_next_trait_solver/src/delegate.rs b/compiler/rustc_next_trait_solver/src/delegate.rs index 7cf4e8a9238a..541276f5925d 100644 --- a/compiler/rustc_next_trait_solver/src/delegate.rs +++ b/compiler/rustc_next_trait_solver/src/delegate.rs @@ -1,6 +1,6 @@ use std::ops::Deref; -use rustc_type_ir::solve::{Certainty, Goal, NoSolution}; +use rustc_type_ir::solve::{Certainty, Goal, NoSolution, VisibleForLeakCheck}; use rustc_type_ir::{self as ty, InferCtxtLike, Interner, TypeFoldable}; pub trait SolverDelegate: Deref + Sized { @@ -45,7 +45,9 @@ fn well_formed_goals( term: ::Term, ) -> Option::Predicate>>>; - fn make_deduplicated_region_constraints(&self) -> Vec>; + fn make_deduplicated_region_constraints( + &self, + ) -> Vec<(ty::RegionConstraint, VisibleForLeakCheck)>; fn instantiate_canonical( &self, diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 278e1f7c0794..9e4c5e0f5ec5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -30,7 +30,8 @@ use crate::solve::{ CanonicalInput, CanonicalResponse, Certainty, ExternalConstraintsData, FIXPOINT_STEP_LIMIT, Goal, GoalEvaluation, GoalSource, GoalStalledOn, HasChanged, MaybeCause, - NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, Response, inspect, + NestedNormalizationGoals, NoSolution, QueryInput, QueryResult, Response, VisibleForLeakCheck, + inspect, }; mod probe; @@ -484,11 +485,29 @@ pub(super) fn evaluate_goal_raw( let has_changed = if !has_only_region_constraints(response) { HasChanged::Yes } else { HasChanged::No }; + // FIXME: We should revisit and consider removing this after + // *assumptions on binders* is available, like once we had done in the + // stabilization of `-Znext-solver=coherence`(#121848). + // We ignore constraints from the nested goals in leak check. This is to match + // with the old solver's behavior, which has separated evaluation and fulfillment, + // and the former doesn't consider outlives obligations from the later. + let vis = match goal.predicate.kind().skip_binder() { + ty::PredicateKind::Clause(_) + | ty::PredicateKind::DynCompatible(_) + | ty::PredicateKind::Subtype(_) + | ty::PredicateKind::Coerce(_) + | ty::PredicateKind::ConstEquate(_, _) + | ty::PredicateKind::Ambiguous + | ty::PredicateKind::NormalizesTo(_) => VisibleForLeakCheck::No, + ty::PredicateKind::AliasRelate(_, _, _) => VisibleForLeakCheck::Yes, + }; + let (normalization_nested_goals, certainty) = instantiate_and_apply_query_response( self.delegate, goal.param_env, &orig_values, response, + vis, self.origin_span, ); @@ -1100,9 +1119,14 @@ pub(super) fn register_ty_outlives(&self, ty: I::Ty, lt: I::Region) { self.delegate.register_ty_outlives(ty, lt, self.origin_span); } - pub(super) fn register_region_outlives(&self, a: I::Region, b: I::Region) { + pub(super) fn register_region_outlives( + &self, + a: I::Region, + b: I::Region, + vis: VisibleForLeakCheck, + ) { // `'a: 'b` ==> `'b <= 'a` - self.delegate.sub_regions(b, a, self.origin_span); + self.delegate.sub_regions(b, a, vis, self.origin_span); } /// Computes the list of goals required for `arg` to be well-formed @@ -1303,7 +1327,7 @@ pub(in crate::solve) fn evaluate_added_goals_and_make_canonical_response( let mut unique = HashSet::default(); external_constraints .region_constraints - .retain(|outlives| !outlives.is_trivial() && unique.insert(*outlives)); + .retain(|(outlives, _)| !outlives.is_trivial() && unique.insert(*outlives)); let canonical = canonicalize_response( self.delegate, @@ -1533,6 +1557,7 @@ pub(super) fn evaluate_root_goal_for_proof_tree, goal.param_env, &proof_tree.orig_values, response, + VisibleForLeakCheck::Yes, origin_span, ); diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index 1df5a80cf29a..6f05df707ad8 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -101,7 +101,7 @@ fn compute_region_outlives_goal( goal: Goal>, ) -> QueryResult { let ty::OutlivesPredicate(a, b) = goal.predicate; - self.register_region_outlives(a, b); + self.register_region_outlives(a, b, VisibleForLeakCheck::Yes); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 05ecc4725a7b..c61702a10f6e 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -1,6 +1,7 @@ +use std::collections::hash_map::Entry; use std::ops::Deref; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::FxHashMap; use rustc_hir::LangItem; use rustc_hir::def_id::{CRATE_DEF_ID, DefId}; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; @@ -112,6 +113,7 @@ fn compute_goal_fast_path( SubregionOrigin::RelateRegionParamBound(span, None), outlives.1, outlives.0, + ty::VisibleForLeakCheck::Yes, ); Some(Certainty::Yes) } @@ -204,7 +206,9 @@ fn well_formed_goals( .map(|obligations| obligations.into_iter().map(|obligation| obligation.as_goal()).collect()) } - fn make_deduplicated_region_constraints(&self) -> Vec> { + fn make_deduplicated_region_constraints( + &self, + ) -> Vec<(ty::RegionConstraint<'tcx>, ty::VisibleForLeakCheck)> { // 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.0.inner.borrow().region_obligations().to_owned(); @@ -217,13 +221,23 @@ fn make_deduplicated_region_constraints(&self) -> Vec ) }); - let mut seen = FxHashSet::default(); - region_constraints - .constraints - .into_iter() - .filter(|&(outlives, _)| seen.insert(outlives)) - .map(|(outlives, _)| outlives) - .collect() + let mut seen = FxHashMap::default(); + let mut constraints = vec![]; + for (outlives, _, vis) in region_constraints.constraints { + match seen.entry(outlives) { + Entry::Occupied(occupied) => { + let idx = occupied.get(); + let (_, prev_vis): &mut (_, ty::VisibleForLeakCheck) = + constraints.get_mut(*idx).unwrap(); + *prev_vis = (*prev_vis).or(vis); + } + Entry::Vacant(vacant) => { + vacant.insert(constraints.len()); + constraints.push((outlives, vis)); + } + } + } + constraints } fn instantiate_canonical( diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index f28e6f32b5f8..ef99b7772d6b 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -738,7 +738,7 @@ fn evaluate_nested_obligations( ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(binder)) => { let binder = bound_predicate.rebind(binder); selcx.infcx.enter_forall(binder, |pred| { - selcx.infcx.register_region_outlives_constraint(pred, &dummy_cause); + selcx.infcx.register_region_outlives_constraint(pred, ty::VisibleForLeakCheck::Yes,&dummy_cause); }); } ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(binder)) => { diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 2992e396c1b9..0b1d4a8453d0 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -484,7 +484,11 @@ fn process_obligation( ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(data)) => { if infcx.considering_regions { - infcx.register_region_outlives_constraint(data, &obligation.cause); + infcx.register_region_outlives_constraint( + data, + ty::VisibleForLeakCheck::Yes, + &obligation.cause, + ); } ProcessResult::Changed(Default::default()) diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 8bbdc9d76c51..8be26fed0ca4 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -83,13 +83,13 @@ fn implied_outlives_bounds<'a, 'tcx>( // outlives bound required proving some higher-ranked coroutine obl. let QueryRegionConstraints { constraints, assumptions: _ } = constraints; let cause = ObligationCause::misc(span, body_id); - for &(constraint, _) in &constraints { + for &(constraint, _, vis) in &constraints { match constraint { ty::RegionConstraint::Outlives(predicate) => { - infcx.register_outlives_constraint(predicate, &cause) + infcx.register_outlives_constraint(predicate, vis, &cause) } ty::RegionConstraint::Eq(predicate) => { - infcx.register_region_eq_constraint(predicate, &cause) + infcx.register_region_eq_constraint(predicate, vis, &cause) } } } diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 0dd4ea823c94..83a77f17b28c 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -80,7 +80,7 @@ fn compute_assumptions<'tcx>( tcx.mk_outlives_from_iter( constraints .into_iter() - .flat_map(|(constraint, _)| constraint.iter_outlives()) + .flat_map(|(constraint, _, _)| constraint.iter_outlives()) // FIXME(higher_ranked_auto): We probably should deeply resolve these before // filtering out infers which only correspond to unconstrained infer regions // which we can sometimes get. diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 905b005cd48f..2ecc4ebec150 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -8,6 +8,7 @@ use crate::inherent::*; use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; +use crate::solve::VisibleForLeakCheck; use crate::{self as ty, Interner, TyVid}; /// The current typing mode of an inference context. We unfortunately have some @@ -323,6 +324,7 @@ fn sub_regions( &self, sub: ::Region, sup: ::Region, + vis: VisibleForLeakCheck, span: ::Span, ); @@ -330,6 +332,7 @@ fn equate_regions( &self, a: ::Region, b: ::Region, + vis: VisibleForLeakCheck, span: ::Span, ); diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs index 9064f13eb45e..857738d207b4 100644 --- a/compiler/rustc_type_ir/src/macros.rs +++ b/compiler/rustc_type_ir/src/macros.rs @@ -58,6 +58,7 @@ fn visit_with>( crate::solve::BuiltinImplSource, crate::solve::Certainty, crate::solve::GoalSource, + crate::solve::VisibleForLeakCheck, rustc_ast_ir::Mutability, // tidy-alphabetical-end } diff --git a/compiler/rustc_type_ir/src/relate/solver_relating.rs b/compiler/rustc_type_ir/src/relate/solver_relating.rs index 82ee4f75fcb0..a643d22c1764 100644 --- a/compiler/rustc_type_ir/src/relate/solver_relating.rs +++ b/compiler/rustc_type_ir/src/relate/solver_relating.rs @@ -4,7 +4,7 @@ use crate::data_structures::DelayedSet; use crate::relate::combine::combine_ty_args; pub use crate::relate::*; -use crate::solve::Goal; +use crate::solve::{Goal, VisibleForLeakCheck}; use crate::{self as ty, InferCtxtLike, Interner}; pub trait RelateExt: InferCtxtLike { @@ -256,10 +256,10 @@ fn tys(&mut self, a: I::Ty, b: I::Ty) -> RelateResult { fn regions(&mut self, a: I::Region, b: I::Region) -> RelateResult { match self.ambient_variance { // Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a) - ty::Covariant => self.infcx.sub_regions(b, a, self.span), + ty::Covariant => self.infcx.sub_regions(b, a, VisibleForLeakCheck::Yes, self.span), // Suptype(&'a u8, &'b u8) => Outlives('b: 'a) => SubRegion('a, 'b) - ty::Contravariant => self.infcx.sub_regions(a, b, self.span), - ty::Invariant => self.infcx.equate_regions(a, b, self.span), + ty::Contravariant => self.infcx.sub_regions(a, b, VisibleForLeakCheck::Yes, self.span), + ty::Invariant => self.infcx.equate_regions(a, b, VisibleForLeakCheck::Yes, self.span), ty::Bivariant => { unreachable!("Expected bivariance to be handled in relate_with_variance") } diff --git a/compiler/rustc_type_ir/src/solve/mod.rs b/compiler/rustc_type_ir/src/solve/mod.rs index 0328a819d9b0..b32bbefb01a9 100644 --- a/compiler/rustc_type_ir/src/solve/mod.rs +++ b/compiler/rustc_type_ir/src/solve/mod.rs @@ -250,7 +250,7 @@ impl Eq for Response {} #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] pub struct ExternalConstraintsData { - pub region_constraints: Vec>, + pub region_constraints: Vec<(ty::RegionConstraint, VisibleForLeakCheck)>, pub opaque_types: Vec<(ty::OpaqueTypeKey, I::Ty)>, pub normalization_nested_goals: NestedNormalizationGoals, } @@ -265,6 +265,47 @@ pub fn is_empty(&self) -> bool { } } +/// Whether the given region constraint should be considered/ignored for +/// leak check. In most part of the compiler, this should be `Yes`, except +/// for applying constraints from the nested goals in next-solver. +/// `Unreachable` is used in places in which leak check isn't done, e.g. +/// borrowck. +#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug)] +#[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] +pub enum VisibleForLeakCheck { + Yes, + No, + Unreachable, +} + +impl VisibleForLeakCheck { + pub fn and(self, other: VisibleForLeakCheck) -> VisibleForLeakCheck { + match (self, other) { + // Make sure that we never overwrite that constraints shouldn't + // be encountered by the leak checked + (VisibleForLeakCheck::Unreachable, _) | (_, VisibleForLeakCheck::Unreachable) => { + VisibleForLeakCheck::Unreachable + } + (VisibleForLeakCheck::No, _) | (_, VisibleForLeakCheck::No) => VisibleForLeakCheck::No, + (VisibleForLeakCheck::Yes, VisibleForLeakCheck::Yes) => VisibleForLeakCheck::Yes, + } + } + + pub fn or(self, other: VisibleForLeakCheck) -> VisibleForLeakCheck { + match (self, other) { + // Make sure that we never overwrite that constraints shouldn't + // be encountered by the leak checked + (VisibleForLeakCheck::Unreachable, _) | (_, VisibleForLeakCheck::Unreachable) => { + VisibleForLeakCheck::Unreachable + } + (VisibleForLeakCheck::Yes, _) | (_, VisibleForLeakCheck::Yes) => { + VisibleForLeakCheck::Yes + } + (VisibleForLeakCheck::No, VisibleForLeakCheck::No) => VisibleForLeakCheck::No, + } + } +} + #[derive_where(Clone, Hash, PartialEq, Debug, Default; I: Interner)] #[derive(TypeVisitable_Generic, GenericTypeVisitable, TypeFoldable_Generic)] #[cfg_attr(feature = "nightly", derive(HashStable_NoContext))] diff --git a/tests/crashes/140577.rs b/tests/crashes/140577.rs deleted file mode 100644 index 21e6b1e1522f..000000000000 --- a/tests/crashes/140577.rs +++ /dev/null @@ -1,32 +0,0 @@ -//@ known-bug: #140577 -//@ compile-flags: -Znext-solver=globally -//@ edition:2021 - -use std::future::Future; -use std::pin::Pin; -trait Acquire { - type Connection; -} -impl Acquire for &'static () { - type Connection = (); -} -fn b() -> impl Future + Send { - let x: Pin + Send>> = todo!(); - x -} -fn main() { - async { - b::<&()>().await; - } - .aa(); -} - -impl Filter for F where F: Send {} - -trait Filter { - fn aa(self) - where - Self: Sized, - { - } -} diff --git a/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr b/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr index ab51e2bdae77..27418eb05dc7 100644 --- a/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr +++ b/tests/ui/generic-associated-types/must-prove-where-clauses-on-norm.next.stderr @@ -2,12 +2,10 @@ error[E0308]: mismatched types --> $DIR/must-prove-where-clauses-on-norm.rs:23:61 | LL | let func: for<'a, 'b> fn((), &'b str) -> &'static str = foo::<()>; - | ------------------------------------------- ^^^^^^^^^ one type is more general than the other - | | - | expected due to this + | ^^^^^^^^^ one type is more general than the other | - = note: expected fn pointer `for<'b> fn((), &'b _) -> &'static _` - found fn item `for<'b> fn(<() as Trait>::Assoc<'_, 'b>, &'b _) -> &_ {foo::<'_, ()>}` + = note: expected fn pointer `for<'b> fn((), &'b _) -> &_` + found fn pointer `for<'b> fn((), &'b _) -> &_` error: aborting due to 1 previous error diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr index ddfc94da1354..dcf0ed093199 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.next.stderr @@ -1,14 +1,8 @@ -error[E0271]: type mismatch resolving `>::Assoc == usize` - --> $DIR/candidate-from-env-universe-err-project.rs:38:24 +error: higher-ranked subtype error + --> $DIR/candidate-from-env-universe-err-project.rs:38:5 | LL | projection_bound::(); - | ^ types differ - | -note: required by a bound in `projection_bound` - --> $DIR/candidate-from-env-universe-err-project.rs:19:42 - | -LL | fn projection_bound Trait<'a, Assoc = usize>>() {} - | ^^^^^^^^^^^^^ required by this bound in `projection_bound` + | ^^^^^^^^^^^^^^^^^^^^^ error: higher-ranked subtype error --> $DIR/candidate-from-env-universe-err-project.rs:52:30 @@ -26,4 +20,3 @@ LL | let _higher_ranked_norm: for<'a> fn(>::Assoc) = |_| (); error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0271`. diff --git a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs index dd6da62a4727..2dce218f5b83 100644 --- a/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs +++ b/tests/ui/higher-ranked/leak-check/candidate-from-env-universe-err-project.rs @@ -36,7 +36,7 @@ fn function2>() { // does not use the leak check when trying the where-bound, causing us // to prefer it over the impl, resulting in a placeholder error. projection_bound::(); - //[next]~^ ERROR type mismatch resolving `>::Assoc == usize` + //[next]~^ ERROR higher-ranked subtype error //[current]~^^ ERROR mismatched types } diff --git a/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-1.rs b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-1.rs new file mode 100644 index 000000000000..e4368faa8fc1 --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-1.rs @@ -0,0 +1,45 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ edition:2021 + +// Regression test for . +// +// This previously caused an ICE due to a non–well-formed opaque type +// in a coroutine witness failing the leak check in the next-solver. +// +// In `TypingMode::Analysis`, the problematic type is hidden behind a +// stalled coroutine candidate. However, in later passes (e.g. MIR +// validation), we eagerly normalize it. The candidate that was +// previously accepted as a solution then fails the leak check, resulting +// in broken MIR and ultimately an ICE. + +use std::future::Future; +use std::pin::Pin; +trait Acquire { + type Connection; +} +impl Acquire for &'static () { + type Connection = (); +} +fn b() -> impl Future + Send { + let x: Pin + Send>> = todo!(); + x +} +fn main() { + async { + b::<&()>().await; + } + .aa(); +} + +impl Filter for F where F: Send {} + +trait Filter { + fn aa(self) + where + Self: Sized, + { + } +} diff --git a/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-2.rs b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-2.rs new file mode 100644 index 000000000000..13a76db73e6c --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-2.rs @@ -0,0 +1,50 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ edition: 2021 + +// Regression test for . +// +// This previously caused an ICE due to a non–well-formed opaque type +// in a coroutine witness failing the leak check in the next-solver. +// +// In `TypingMode::Analysis`, the problematic type is hidden behind a +// stalled coroutine candidate. However, in later passes (e.g. MIR +// validation), we eagerly normalize it. The candidate that was +// previously accepted as a solution then fails the leak check, resulting +// in broken MIR and ultimately an ICE. + +use std::future::Future; + +trait Access { + // has to have an associated type, but can be anything + type Reader; + + fn read(&self) -> impl Future + Send { + async { loop {} } + } +} + +trait AccessDyn: Sync {} +impl Access for dyn AccessDyn { + type Reader = (); +} + +trait Stream { + fn poll_next(s: &'static dyn AccessDyn); +} + +// has to be a function in a trait impl, can't be a normal impl block or standalone fn +impl Stream for () { + fn poll_next(s: &'static dyn AccessDyn) { + // new async block is important + is_dyn_send(&async { + s.read().await; + }); + } +} + +fn is_dyn_send(_: &dyn Send) {} + +fn main() {} diff --git a/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-3.rs b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-3.rs new file mode 100644 index 000000000000..13bf5a4fbe00 --- /dev/null +++ b/tests/ui/traits/next-solver/non-wf-candidate-behind-stalled-coroutine-3.rs @@ -0,0 +1,36 @@ +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver +//@ edition:2021 + +// Regression test for . +// +// This previously caused an ICE due to a non–well-formed opaque type +// in a coroutine witness failing the leak check in the next-solver. +// +// In `TypingMode::Analysis`, the problematic type is hidden behind a +// stalled coroutine candidate. However, in later passes (e.g. MIR +// validation), we eagerly normalize it. The candidate that was +// previously accepted as a solution then fails the leak check, resulting +// in broken MIR and ultimately an ICE. + +trait Trait { + type Assoc; +} +impl Trait for &'static u32 { + type Assoc = (); +} +struct W(T::Assoc); + +fn prove_send_and_hide(x: T) -> impl Send { x } +fn as_dyn_send(_: &dyn Send) {} +pub fn main() { + // Checking whether the cast to the trait object is correct + // during MIR validation uses `TypingMode::PostAnalysis` and + // therefore looks into the opaque. + as_dyn_send(&async move { + let opaque_ty = prove_send_and_hide(W::<&'static u32>(())); + std::future::ready(opaque_ty).await; + }); +} diff --git a/tests/ui/traits/vtable/lack-of-implied-bounds-for-opaque-types-unsound.rs b/tests/ui/traits/vtable/lack-of-implied-bounds-for-opaque-types-unsound.rs new file mode 100644 index 000000000000..b02996605b57 --- /dev/null +++ b/tests/ui/traits/vtable/lack-of-implied-bounds-for-opaque-types-unsound.rs @@ -0,0 +1,48 @@ +//@ run-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +// Regression test for . + +#![allow(warnings)] + +trait Trait { + type Assoc; +} +impl<'a, 'b: 'a> Trait for Inv<'a, 'b> { + type Assoc = (); +} + +trait ReqWf {} +impl ReqWf for T where T::Assoc: Sized {} +struct Inv<'a, 'b: 'a>(Option<*mut &'a &'b ()>); +fn mk_opaque<'a, 'b>(x: &'a &'b u32) -> impl ReqWf + use<'a, 'b> { + Inv::<'a, 'b>(None) +} + +trait Bound {} +impl Bound for F where F: FnOnce(T) -> R {} +trait ImpossiblePredicates { + fn call_me(&self) + where + F: for<'a, 'b> Bound<&'a &'b u32>, + { + println!("method body"); + } +} +impl ImpossiblePredicates for () {} +fn mk_trait_object(_: F) -> Box> { + Box::new(()) +} +pub fn main() { + let obj = mk_trait_object(mk_opaque); + // This previously caused a segfault: the where-bounds of + // `ImpossiblePredicate::call_me` did not hold due to missing implied bounds + // for the fully normalized opaque type of `obj` in `fn impossible_predicates`. + // As a result, the method's vtable ended up empty. + // + // However, earlier compilation passes did not report an error because the + // opaque type had not yet been fully normalized. + obj.call_me(); +} From 52b3f048cd3f63aa448124776c7554d126f5af36 Mon Sep 17 00:00:00 2001 From: WhySoBad <49595640+WhySoBad@users.noreply.github.com> Date: Fri, 1 May 2026 22:29:07 +0200 Subject: [PATCH 6/8] feat: map `WSAESHUTDOWN` to `BrokenPipe` --- library/std/src/sys/io/error/windows.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/library/std/src/sys/io/error/windows.rs b/library/std/src/sys/io/error/windows.rs index c093443f3033..5eb9dfe06762 100644 --- a/library/std/src/sys/io/error/windows.rs +++ b/library/std/src/sys/io/error/windows.rs @@ -81,6 +81,10 @@ pub fn decode_error_kind(errno: i32) -> io::ErrorKind { c::WSAENETDOWN => NetworkDown, c::WSAENETUNREACH => NetworkUnreachable, c::WSAEDQUOT => QuotaExceeded, + // Not a prefect mapping but this error is only returned when writing to + // the closed end of a socket. On Unix targets EPIPE is returned in those + // cases. + c::WSAESHUTDOWN => BrokenPipe, _ => Uncategorized, } From 3fe9b2ecd37f71f7dd11182288bfad8077cd4e7f Mon Sep 17 00:00:00 2001 From: WhySoBad <49595640+WhySoBad@users.noreply.github.com> Date: Fri, 1 May 2026 22:48:22 +0200 Subject: [PATCH 7/8] fix: update comment --- library/std/src/sys/io/error/windows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/io/error/windows.rs b/library/std/src/sys/io/error/windows.rs index 5eb9dfe06762..a4b9a4009843 100644 --- a/library/std/src/sys/io/error/windows.rs +++ b/library/std/src/sys/io/error/windows.rs @@ -82,8 +82,8 @@ pub fn decode_error_kind(errno: i32) -> io::ErrorKind { c::WSAENETUNREACH => NetworkUnreachable, c::WSAEDQUOT => QuotaExceeded, // Not a prefect mapping but this error is only returned when writing to - // the closed end of a socket. On Unix targets EPIPE is returned in those - // cases. + // a socket after shutting down the write-end. On Unix targets, EPIPE is + // returned in those cases. c::WSAESHUTDOWN => BrokenPipe, _ => Uncategorized, From e6c358bf66e17a40ff453e523bfc863b4fb3d587 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 1 May 2026 16:19:50 -0700 Subject: [PATCH 8/8] Typo fix: s/prefect/perfect/ --- library/std/src/sys/io/error/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/io/error/windows.rs b/library/std/src/sys/io/error/windows.rs index a4b9a4009843..3c2f41a90781 100644 --- a/library/std/src/sys/io/error/windows.rs +++ b/library/std/src/sys/io/error/windows.rs @@ -81,7 +81,7 @@ pub fn decode_error_kind(errno: i32) -> io::ErrorKind { c::WSAENETDOWN => NetworkDown, c::WSAENETUNREACH => NetworkUnreachable, c::WSAEDQUOT => QuotaExceeded, - // Not a prefect mapping but this error is only returned when writing to + // Not a perfect mapping but this error is only returned when writing to // a socket after shutting down the write-end. On Unix targets, EPIPE is // returned in those cases. c::WSAESHUTDOWN => BrokenPipe,