Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 7 additions & 13 deletions compiler/rustc_type_ir/src/outlives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,32 +75,26 @@ impl<I: Interner> TypeVisitor<I> 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
// in the `subtys` iterator (e.g., when encountering a
// 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) => {
Expand Down
48 changes: 48 additions & 0 deletions tests/ui/function-pointer/the-pointerrrr-84366.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
use std::fmt;

trait Trait: 'static {
type Associated;
}

impl<R, F: (Fn() -> 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: Trait + 'static>(
_: &T,
// it is assumed that the associated value is also static
x: T::Associated,
) -> Box<dyn fmt::Display + 'static>
where
T::Associated: fmt::Display,
{
Box::new(x)
}

fn require_static<F: 'static>(_: F) {}

fn make_static_displayable<'temp>(not_static: &'temp str) -> Box<dyn fmt::Display> {
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<dyn fmt::Display> {
// 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);
}
17 changes: 17 additions & 0 deletions tests/ui/function-pointer/the-pointerrrr-84366.stderr
Original file line number Diff line number Diff line change
@@ -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<dyn fmt::Display> {
| ----- ---------- `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`.
3 changes: 2 additions & 1 deletion tests/ui/lifetimes/issue-70917-lifetimes-in-fn-def.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//@ check-pass
//

fn assert_static<T: 'static>(_: T) {}

Expand All @@ -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() {}
14 changes: 14 additions & 0 deletions tests/ui/lifetimes/issue-70917-lifetimes-in-fn-def.stderr
Original file line number Diff line number Diff line change
@@ -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 <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance

error: aborting due to 1 previous error

Loading