From dd557d8c3720c82c488d6e2af3b7e19025f2473a Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Jun 2024 12:04:59 -0400 Subject: [PATCH 1/2] Add a test demonstrating that RPITITs cant use precise capturing --- .../ui/impl-trait/precise-capturing/rpitit.rs | 21 ++++++++++ .../precise-capturing/rpitit.stderr | 42 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 tests/ui/impl-trait/precise-capturing/rpitit.rs create mode 100644 tests/ui/impl-trait/precise-capturing/rpitit.stderr diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.rs b/tests/ui/impl-trait/precise-capturing/rpitit.rs new file mode 100644 index 0000000000000..4eb053573e1f2 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit.rs @@ -0,0 +1,21 @@ +//@ known-bug: unknown + +// RPITITs don't have variances in their GATs, so they always relate invariantly +// and act as if they capture all their args. +// To fix this soundly, we need to make sure that all the trait header args +// remain captured, since they affect trait selection. + +#![feature(precise_capturing)] + +trait Foo<'a> { + fn hello() -> impl PartialEq + use; +} + +fn test<'a, 'b, T: for<'r> Foo<'r>>() { + PartialEq::eq( + &>::hello(), + &>::hello(), + ); +} + +fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.stderr b/tests/ui/impl-trait/precise-capturing/rpitit.stderr new file mode 100644 index 0000000000000..202eeb39385da --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/rpitit.stderr @@ -0,0 +1,42 @@ +error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list + --> $DIR/rpitit.rs:11:19 + | +LL | trait Foo<'a> { + | -- this lifetime parameter is captured +LL | fn hello() -> impl PartialEq + use; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime captured due to being mentioned in the bounds of the `impl Trait` + +error: lifetime may not live long enough + --> $DIR/rpitit.rs:15:5 + | +LL | fn test<'a, 'b, T: for<'r> Foo<'r>>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | / PartialEq::eq( +LL | | &>::hello(), +LL | | &>::hello(), +LL | | ); + | |_____^ argument requires that `'a` must outlive `'b` + | + = help: consider adding the following bound: `'a: 'b` + +error: lifetime may not live long enough + --> $DIR/rpitit.rs:15:5 + | +LL | fn test<'a, 'b, T: for<'r> Foo<'r>>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | / PartialEq::eq( +LL | | &>::hello(), +LL | | &>::hello(), +LL | | ); + | |_____^ argument requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + +help: `'a` and `'b` must be the same: replace one with the other + +error: aborting due to 3 previous errors + From 6521c3971d0818ab37f27f36f2eb99de420c780f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 20 Jun 2024 12:17:42 -0400 Subject: [PATCH 2/2] Deny use<> for RPITITs --- compiler/rustc_ast_lowering/messages.ftl | 3 ++ compiler/rustc_ast_lowering/src/errors.rs | 8 +++++ compiler/rustc_ast_lowering/src/lib.rs | 20 +++++++++++ .../forgot-to-capture-type.rs | 1 + .../forgot-to-capture-type.stderr | 10 +++++- .../precise-capturing/redundant.normal.stderr | 20 +++++++++++ .../precise-capturing/redundant.rpitit.stderr | 18 ++++++++++ .../impl-trait/precise-capturing/redundant.rs | 13 ++++--- .../precise-capturing/redundant.stderr | 36 ------------------- .../precise-capturing/rpitit.stderr | 10 +++++- .../precise-capturing/self-capture.rs | 3 +- .../precise-capturing/self-capture.stderr | 10 ++++++ 12 files changed, 107 insertions(+), 45 deletions(-) create mode 100644 tests/ui/impl-trait/precise-capturing/redundant.normal.stderr create mode 100644 tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr delete mode 100644 tests/ui/impl-trait/precise-capturing/redundant.stderr create mode 100644 tests/ui/impl-trait/precise-capturing/self-capture.stderr diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl index 7d81e45d314d8..57b9d904dc2f9 100644 --- a/compiler/rustc_ast_lowering/messages.ftl +++ b/compiler/rustc_ast_lowering/messages.ftl @@ -130,6 +130,9 @@ ast_lowering_never_pattern_with_guard = ast_lowering_no_precise_captures_on_apit = `use<...>` precise capturing syntax not allowed in argument-position `impl Trait` +ast_lowering_no_precise_captures_on_rpitit = `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + .note = currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + ast_lowering_previously_used_here = previously used here ast_lowering_register1 = register `{$reg1_name}` diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs index 02744d16b422f..3d4b6a1f033fb 100644 --- a/compiler/rustc_ast_lowering/src/errors.rs +++ b/compiler/rustc_ast_lowering/src/errors.rs @@ -424,6 +424,14 @@ pub(crate) struct NoPreciseCapturesOnApit { pub span: Span, } +#[derive(Diagnostic)] +#[diag(ast_lowering_no_precise_captures_on_rpitit)] +#[note] +pub(crate) struct NoPreciseCapturesOnRpitit { + #[primary_span] + pub span: Span, +} + #[derive(Diagnostic)] #[diag(ast_lowering_yield_in_closure)] pub(crate) struct YieldInClosure { diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index da8682d3d095d..0a06304fcecfa 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -1594,6 +1594,26 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; debug!(?captured_lifetimes_to_duplicate); + match fn_kind { + // Deny `use<>` on RPITIT in trait/trait-impl for now. + Some(FnDeclKind::Trait | FnDeclKind::Impl) => { + if let Some(span) = bounds.iter().find_map(|bound| match *bound { + ast::GenericBound::Use(_, span) => Some(span), + _ => None, + }) { + self.tcx.dcx().emit_err(errors::NoPreciseCapturesOnRpitit { span }); + } + } + None + | Some( + FnDeclKind::Fn + | FnDeclKind::Inherent + | FnDeclKind::ExternFn + | FnDeclKind::Closure + | FnDeclKind::Pointer, + ) => {} + } + self.lower_opaque_inner( opaque_ty_node_id, origin, diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs index 0801498578398..0028a45cbf3f2 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.rs @@ -6,6 +6,7 @@ fn type_param() -> impl Sized + use<> {} trait Foo { fn bar() -> impl Sized + use<>; //~^ ERROR `impl Trait` must mention the `Self` type of the trait + //~| ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr index 93b44a0c18c27..89bd4df443106 100644 --- a/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr +++ b/tests/ui/impl-trait/precise-capturing/forgot-to-capture-type.stderr @@ -1,3 +1,11 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/forgot-to-capture-type.rs:7:30 + | +LL | fn bar() -> impl Sized + use<>; + | ^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + error: `impl Trait` must mention all type parameters in scope in `use<...>` --> $DIR/forgot-to-capture-type.rs:3:23 | @@ -18,5 +26,5 @@ LL | fn bar() -> impl Sized + use<>; | = note: currently, all type parameters are required to be mentioned in the precise captures list -error: aborting due to 2 previous errors +error: aborting due to 3 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr b/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr new file mode 100644 index 0000000000000..44bc9f7daad8d --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/redundant.normal.stderr @@ -0,0 +1,20 @@ +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:7:19 + | +LL | fn hello<'a>() -> impl Sized + use<'a> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax + | + = note: `#[warn(impl_trait_redundant_captures)]` on by default + +warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant + --> $DIR/redundant.rs:12:27 + | +LL | fn inherent(&self) -> impl Sized + use<'_> {} + | ^^^^^^^^^^^^^------- + | | + | help: remove the `use<...>` syntax + +warning: 2 warnings emitted + diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr b/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr new file mode 100644 index 0000000000000..9aa73353126cd --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/redundant.rpitit.stderr @@ -0,0 +1,18 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/redundant.rs:18:35 + | +LL | fn in_trait() -> impl Sized + use<'a, Self>; + | ^^^^^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/redundant.rs:23:35 + | +LL | fn in_trait() -> impl Sized + use<'a> {} + | ^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + +error: aborting due to 2 previous errors + diff --git a/tests/ui/impl-trait/precise-capturing/redundant.rs b/tests/ui/impl-trait/precise-capturing/redundant.rs index 99c128fdc4823..ef4f05bd7e458 100644 --- a/tests/ui/impl-trait/precise-capturing/redundant.rs +++ b/tests/ui/impl-trait/precise-capturing/redundant.rs @@ -1,24 +1,27 @@ //@ compile-flags: -Zunstable-options --edition=2024 -//@ check-pass +//@ revisions: normal rpitit +//@[normal] check-pass #![feature(precise_capturing)] fn hello<'a>() -> impl Sized + use<'a> {} -//~^ WARN all possible in-scope parameters are already captured +//[normal]~^ WARN all possible in-scope parameters are already captured struct Inherent; impl Inherent { fn inherent(&self) -> impl Sized + use<'_> {} - //~^ WARN all possible in-scope parameters are already captured + //[normal]~^ WARN all possible in-scope parameters are already captured } +#[cfg(rpitit)] trait Test<'a> { fn in_trait() -> impl Sized + use<'a, Self>; - //~^ WARN all possible in-scope parameters are already captured + //[rpitit]~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } +#[cfg(rpitit)] impl<'a> Test<'a> for () { fn in_trait() -> impl Sized + use<'a> {} - //~^ WARN all possible in-scope parameters are already captured + //[rpitit]~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/redundant.stderr b/tests/ui/impl-trait/precise-capturing/redundant.stderr deleted file mode 100644 index 274d9d2375f7d..0000000000000 --- a/tests/ui/impl-trait/precise-capturing/redundant.stderr +++ /dev/null @@ -1,36 +0,0 @@ -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:6:19 - | -LL | fn hello<'a>() -> impl Sized + use<'a> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax - | - = note: `#[warn(impl_trait_redundant_captures)]` on by default - -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:11:27 - | -LL | fn inherent(&self) -> impl Sized + use<'_> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax - -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:16:22 - | -LL | fn in_trait() -> impl Sized + use<'a, Self>; - | ^^^^^^^^^^^^^------------- - | | - | help: remove the `use<...>` syntax - -warning: all possible in-scope parameters are already captured, so `use<...>` syntax is redundant - --> $DIR/redundant.rs:20:22 - | -LL | fn in_trait() -> impl Sized + use<'a> {} - | ^^^^^^^^^^^^^------- - | | - | help: remove the `use<...>` syntax - -warning: 4 warnings emitted - diff --git a/tests/ui/impl-trait/precise-capturing/rpitit.stderr b/tests/ui/impl-trait/precise-capturing/rpitit.stderr index 202eeb39385da..45eceef2f494b 100644 --- a/tests/ui/impl-trait/precise-capturing/rpitit.stderr +++ b/tests/ui/impl-trait/precise-capturing/rpitit.stderr @@ -1,3 +1,11 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/rpitit.rs:11:36 + | +LL | fn hello() -> impl PartialEq + use; + | ^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + error: `impl Trait` captures lifetime parameter, but it is not mentioned in `use<...>` precise captures list --> $DIR/rpitit.rs:11:19 | @@ -38,5 +46,5 @@ LL | | ); help: `'a` and `'b` must be the same: replace one with the other -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.rs b/tests/ui/impl-trait/precise-capturing/self-capture.rs index e0a4a8b658c5c..07bb417f9f7f1 100644 --- a/tests/ui/impl-trait/precise-capturing/self-capture.rs +++ b/tests/ui/impl-trait/precise-capturing/self-capture.rs @@ -1,9 +1,8 @@ -//@ check-pass - #![feature(precise_capturing)] trait Foo { fn bar<'a>() -> impl Sized + use; + //~^ ERROR `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits } fn main() {} diff --git a/tests/ui/impl-trait/precise-capturing/self-capture.stderr b/tests/ui/impl-trait/precise-capturing/self-capture.stderr new file mode 100644 index 0000000000000..351de86dd5fa6 --- /dev/null +++ b/tests/ui/impl-trait/precise-capturing/self-capture.stderr @@ -0,0 +1,10 @@ +error: `use<...>` precise capturing syntax is currently not allowed in return-position `impl Trait` in traits + --> $DIR/self-capture.rs:4:34 + | +LL | fn bar<'a>() -> impl Sized + use; + | ^^^^^^^^^ + | + = note: currently, return-position `impl Trait` in traits and trait implementations capture all lifetimes in scope + +error: aborting due to 1 previous error +