diff options
| author | Matthew Jasper <mjjasper1@gmail.com> | 2025-04-10 10:57:55 +0000 |
|---|---|---|
| committer | Matthew Jasper <mjjasper1@gmail.com> | 2025-04-14 10:00:28 +0000 |
| commit | 2d5e80b8cb89e9d809e569426d948e4f1fa6002d (patch) | |
| tree | 225c4df46a01ed2d5ebf8dcd6f721955190c1c57 | |
| parent | f836ae4e663b6e8938096b8559e094d18361be55 (diff) | |
| download | rust-2d5e80b8cb89e9d809e569426d948e4f1fa6002d.tar.gz rust-2d5e80b8cb89e9d809e569426d948e4f1fa6002d.zip | |
Handle regions equivalent to 'static in non_local_bounds
`non_local_bounds` would only find non local bounds that strictly bound a given region, but it's possible that a local region is equated to 'static when showing a type referencing a locally bound lifetime, such as `dyn Any + 'a` in the tests added, is well-formed. In this case we should return 'static.
7 files changed, 185 insertions, 15 deletions
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index eaac633b512..aad10e3d6dc 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -133,7 +133,8 @@ impl UniversalRegionRelations<'_> { assert!(self.universal_regions.is_universal_region(fr0)); let mut external_parents = vec![]; - let mut queue = vec![fr0]; + + let mut queue = vec![relation.minimal_scc_representative(fr0)]; // Keep expanding `fr` into its parents until we reach // non-local regions. diff --git a/compiler/rustc_data_structures/src/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs index 33ac279f3e0..31abea93819 100644 --- a/compiler/rustc_data_structures/src/transitive_relation.rs +++ b/compiler/rustc_data_structures/src/transitive_relation.rs @@ -354,6 +354,20 @@ impl<T: Eq + Hash + Copy> TransitiveRelation<T> { .collect() } + /// Given an element A, elements B with the lowest index such that `A R B` + /// and `B R A`, or `A` if no such element exists. + pub fn minimal_scc_representative(&self, a: T) -> T { + match self.index(a) { + Some(a_i) => self.with_closure(|closure| { + closure + .iter(a_i.0) + .find(|i| closure.contains(*i, a_i.0)) + .map_or(a, |i| self.elements[i]) + }), + None => a, + } + } + fn with_closure<OP, R>(&self, op: OP) -> R where OP: FnOnce(&BitMatrix<usize, usize>) -> R, diff --git a/tests/crashes/122704.rs b/tests/crashes/122704.rs deleted file mode 100644 index d6c07be8318..00000000000 --- a/tests/crashes/122704.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ known-bug: #122704 -use std::any::Any; - -pub struct Foo { - bar: Box<dyn for<'a> Fn(&'a usize) -> Box<dyn Any + 'a>>, -} - -impl Foo { - pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) { - self.bar = Box::new(|baz| Box::new(f(baz))); - } -} - -fn main() {} diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs new file mode 100644 index 00000000000..4fdf5470fea --- /dev/null +++ b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.rs @@ -0,0 +1,22 @@ +// Regression test for #122704 +use std::any::Any; + +pub struct Foo { + bar: Box<dyn for<'a> Fn(&'a usize) -> Box<dyn Any + 'a>>, +} + +impl Foo { + pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) { + self.bar = Box::new(|baz| Box::new(f(baz))); + //~^ ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough + //~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough + //~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough + //~| ERROR the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough + //~| ERROR the parameter type `I` may not live long enough + //~| ERROR the parameter type `I` may not live long enough + //~| ERROR the parameter type `I` may not live long enough + //~| ERROR `f` does not live long enough + } +} + +fn main() {} diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr new file mode 100644 index 00000000000..df86ce79f09 --- /dev/null +++ b/tests/ui/borrowck/unconstrained-closure-lifetime-generic.stderr @@ -0,0 +1,119 @@ +error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:9 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^ + | | + | the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime... + | ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) { + | +++++++++ + +error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:9 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^ + | | + | the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime... + | ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) { + | +++++++++ + +error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:20 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^ + | | + | the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime... + | ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) { + | +++++++++ + +error[E0310]: the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:20 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | the parameter type `impl for<'a> Fn(&'a usize) -> Box<I>` must be valid for the static lifetime... + | ...so that the type `impl for<'a> Fn(&'a usize) -> Box<I>` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I> + 'static) { + | +++++++++ + +error[E0310]: the parameter type `I` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:35 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^^^^^^^^^ + | | + | the parameter type `I` must be valid for the static lifetime... + | ...so that the type `I` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | pub fn ack<I: 'static>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) { + | +++++++++ + +error[E0310]: the parameter type `I` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:35 + | +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^^^^^^^^^ + | | + | the parameter type `I` must be valid for the static lifetime... + | ...so that the type `I` will meet its required lifetime bounds + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider adding an explicit lifetime bound + | +LL | pub fn ack<I: 'static>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) { + | +++++++++ + +error[E0311]: the parameter type `I` may not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:35 + | +LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) { + | --------- the parameter type `I` must be valid for the anonymous lifetime defined here... +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | ^^^^^^^^^^^^^^^^ ...so that the type `I` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | pub fn ack<'a, I: 'a>(&'a mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) { + | +++ ++++ ++ + +error[E0597]: `f` does not live long enough + --> $DIR/unconstrained-closure-lifetime-generic.rs:10:44 + | +LL | pub fn ack<I>(&mut self, f: impl for<'a> Fn(&'a usize) -> Box<I>) { + | - binding `f` declared here +LL | self.bar = Box::new(|baz| Box::new(f(baz))); + | -------- ----- ^ borrowed value does not live long enough + | | | + | | value captured here + | coercion requires that `f` is borrowed for `'static` +... +LL | } + | - `f` dropped here while still borrowed + | + = note: due to object lifetime defaults, `Box<dyn for<'a> Fn(&'a usize) -> Box<(dyn Any + 'a)>>` actually means `Box<(dyn for<'a> Fn(&'a usize) -> Box<(dyn Any + 'a)> + 'static)>` + +error: aborting due to 8 previous errors + +Some errors have detailed explanations: E0310, E0311, E0597. +For more information about an error, try `rustc --explain E0310`. diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs new file mode 100644 index 00000000000..3eee98d9bdb --- /dev/null +++ b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.rs @@ -0,0 +1,11 @@ +// Regression test for #139004 +use std::any::Any; + +type B = Box<dyn for<'a> Fn(&(dyn Any + 'a)) -> Box<dyn Any + 'a>>; + +fn foo<E>() -> B { + Box::new(|e| Box::new(e.is::<E>())) + //~^ ERROR the parameter type `E` may not live long enough +} + +fn main() {} diff --git a/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr new file mode 100644 index 00000000000..c9d5f78828d --- /dev/null +++ b/tests/ui/borrowck/unconstrained-closure-lifetime-trait-object.stderr @@ -0,0 +1,17 @@ +error[E0310]: the parameter type `E` may not live long enough + --> $DIR/unconstrained-closure-lifetime-trait-object.rs:7:29 + | +LL | Box::new(|e| Box::new(e.is::<E>())) + | ^^ + | | + | the parameter type `E` must be valid for the static lifetime... + | ...so that the type `E` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound + | +LL | fn foo<E: 'static>() -> B { + | +++++++++ + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0310`. |
