diff --git a/compiler/rustc_type_ir/src/outlives.rs b/compiler/rustc_type_ir/src/outlives.rs index 2a1cbc3575d85..4aed89aeeeaaa 100644 --- a/compiler/rustc_type_ir/src/outlives.rs +++ b/compiler/rustc_type_ir/src/outlives.rs @@ -75,6 +75,7 @@ impl TypeVisitor for OutlivesCollector<'_, I> { if !self.visited.insert(ty) { return; } + // Descend through the types, looking for the various "base" // components and collecting them into `out`. This is not written // with `collect()` because of the need to sometimes skip subtrees @@ -82,25 +83,18 @@ impl TypeVisitor for OutlivesCollector<'_, I> { // projection). match ty.kind() { ty::FnDef(_, args) => { - // HACK(eddyb) ignore lifetimes found shallowly in `args`. - // This is inconsistent with `ty::Adt` (including all args) - // and with `ty::Closure` (ignoring all args other than - // upvars, of which a `ty::FnDef` doesn't have any), but - // consistent with previous (accidental) behavior. - // See https://github.com/rust-lang/rust/issues/70917 - // for further background and discussion. for child in args.iter() { - match child.kind() { - ty::GenericArgKind::Lifetime(_) => {} - ty::GenericArgKind::Type(_) | ty::GenericArgKind::Const(_) => { - child.visit_with(self); - } - } + child.visit_with(self); } } ty::Closure(_, args) => { + // FIXME: this is still impacted by #84366 args.as_closure().tupled_upvars_ty().visit_with(self); + // i think this works? but crossbeam wouldn't compile with it enabled and it didn't fix The Bug. + // for child in args.as_closure().args.iter().filter(|a| a.as_type().is_none()) { + // child.visit_with(self); + // } } ty::CoroutineClosure(_, args) => { diff --git a/tests/ui/function-pointer/the-pointerrrr-84366.rs b/tests/ui/function-pointer/the-pointerrrr-84366.rs new file mode 100644 index 0000000000000..0f36a2cda3179 --- /dev/null +++ b/tests/ui/function-pointer/the-pointerrrr-84366.rs @@ -0,0 +1,48 @@ +use std::fmt; + +trait Trait: 'static { + type Associated; +} + +impl R) + 'static> Trait for F { + type Associated = R; +} + +// NOTE: this is early-bound, see https://rustc-dev-guide.rust-lang.org/early-late-parameters.html#must-be-constrained-by-argument-types +fn early_bound_function<'evil_intimidating>() -> &'evil_intimidating str { "" } + +fn static_transfers_to_associated( + _: &T, + // it is assumed that the associated value is also static + x: T::Associated, +) -> Box +where + T::Associated: fmt::Display, +{ + Box::new(x) +} + +fn require_static(_: F) {} + +fn make_static_displayable<'temp>(not_static: &'temp str) -> Box { + require_static(early_bound_function); + static_transfers_to_associated(&early_bound_function, not_static) + //~^ ERROR borrowed data escapes outside of function [E0521] +} + +// FIXME: add a test for closures, those are currently broken +// fn make_static_displayable_closure<'temp>(not_static: &'temp str) -> Box { +// let closure = || -> &'temp str { "" }; +// require_static(closure); +// static_transfers_to_associated(&closure, not_static) +// // ERROR borrowed data escapes outside of function [E0521] +// } + +fn main() { + let d; + { + let x = "Hello World".to_string(); + d = make_static_displayable(&x); + } + println!("{}", d); +} diff --git a/tests/ui/function-pointer/the-pointerrrr-84366.stderr b/tests/ui/function-pointer/the-pointerrrr-84366.stderr new file mode 100644 index 0000000000000..0116772812fc5 --- /dev/null +++ b/tests/ui/function-pointer/the-pointerrrr-84366.stderr @@ -0,0 +1,17 @@ +error[E0521]: borrowed data escapes outside of function + --> $DIR/the-pointerrrr-84366.rs:29:5 + | +LL | fn make_static_displayable<'temp>(not_static: &'temp str) -> Box { + | ----- ---------- `not_static` is a reference that is only valid in the function body + | | + | lifetime `'temp` defined here +LL | require_static(early_bound_function); +LL | static_transfers_to_associated(&early_bound_function, not_static) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `not_static` escapes the function body here + | argument requires that `'temp` must outlive `'static` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0521`. diff --git a/tests/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs b/tests/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs index 1dbe4f35ca883..67a72435ba380 100644 --- a/tests/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs +++ b/tests/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs @@ -1,4 +1,4 @@ -//@ check-pass +// fn assert_static(_: T) {} @@ -8,6 +8,7 @@ fn capture_lifetime<'a: 'a>() {} fn test_lifetime<'a>() { assert_static(capture_lifetime::<'a>); + //~^ ERROR lifetime may not live long enough } fn main() {} diff --git a/tests/ui/lifetimes/issue-70917-lifetimes-in-fn-def.stderr b/tests/ui/lifetimes/issue-70917-lifetimes-in-fn-def.stderr new file mode 100644 index 0000000000000..97efdd35bea23 --- /dev/null +++ b/tests/ui/lifetimes/issue-70917-lifetimes-in-fn-def.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/issue-70917-lifetimes-in-fn-def.rs:10:5 + | +LL | fn test_lifetime<'a>() { + | -- lifetime `'a` defined here +LL | assert_static(capture_lifetime::<'a>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'a` must outlive `'static` + | + = note: requirement occurs because of the function item type defined by `capture_lifetime` + = note: the function `capture_lifetime` is invariant over the parameter `'a` + = help: see for more information about variance + +error: aborting due to 1 previous error +