Skip to content

Commit 0922f41

Browse files
committed
Use a 'static default for fn arguments and returns.
1 parent fdeb7f2 commit 0922f41

File tree

4 files changed

+85
-8
lines changed

4 files changed

+85
-8
lines changed

compiler/rustc_typeck/src/collect/object_lifetime_defaults.rs

+53-5
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,48 @@ impl<'a, 'tcx> Visitor<'tcx> for LifetimeContext<'a, 'tcx> {
345345
}
346346
}
347347

348+
fn visit_fn_decl(&mut self, fd: &'tcx hir::FnDecl<'tcx>) {
349+
let output = match fd.output {
350+
hir::FnRetTy::DefaultReturn(_) => None,
351+
hir::FnRetTy::Return(ref output) => {
352+
let parent = self.tcx.hir().get_parent_node(output.hir_id);
353+
let static_for_output = match self.tcx.hir().get(parent) {
354+
// `fn` definitions and methods.
355+
Node::Item(_) | Node::TraitItem(_) | Node::ImplItem(_) => true,
356+
357+
// Foreign functions, `fn(...) -> R` and `Trait(...) -> R` (both types and bounds).
358+
Node::ForeignItem(_) | Node::Ty(_) | Node::TraitRef(_) => true,
359+
360+
Node::TypeBinding(_) => matches!(
361+
self.tcx.hir().get(self.tcx.hir().get_parent_node(parent)),
362+
Node::TraitRef(_)
363+
),
364+
365+
// Everything else (only closures?) doesn't
366+
// actually enjoy elision in return types.
367+
_ => false,
368+
};
369+
Some((output, static_for_output))
370+
}
371+
};
372+
373+
// Lifetime elision prescribes a `'static` default lifetime.
374+
let scope = Scope::ObjectLifetimeDefault { lifetime: Some(Region::Static), s: self.scope };
375+
self.with(scope, |this| {
376+
for ty in fd.inputs {
377+
this.visit_ty(ty)
378+
}
379+
380+
if let Some((output, static_for_output)) = output && static_for_output {
381+
this.visit_ty(output)
382+
}
383+
});
384+
385+
if let Some((output, static_for_output)) = output && !static_for_output {
386+
self.visit_ty(output)
387+
}
388+
}
389+
348390
fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _: hir::HirId) {
349391
for (i, segment) in path.segments.iter().enumerate() {
350392
let depth = path.segments.len() - i - 1;
@@ -423,11 +465,17 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> {
423465
generic_args: &'tcx hir::GenericArgs<'tcx>,
424466
) {
425467
if generic_args.parenthesized {
426-
for input in generic_args.inputs() {
427-
self.visit_ty(input);
428-
}
429-
let output = generic_args.bindings[0].ty();
430-
self.visit_ty(output);
468+
// Lifetime elision rules require us to use a `'static` default lifetime.
469+
let scope =
470+
Scope::ObjectLifetimeDefault { lifetime: Some(Region::Static), s: self.scope };
471+
self.with(scope, |this| {
472+
for input in generic_args.inputs() {
473+
this.visit_ty(input);
474+
}
475+
476+
let output = generic_args.bindings[0].ty();
477+
this.visit_ty(output);
478+
});
431479
return;
432480
}
433481

src/test/ui/issues/issue-41139.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ fn main() {
88
// This isn't great. The issue here is that `dyn Trait` is not sized, so
99
// `dyn Fn() -> dyn Trait` is not well-formed.
1010
let t: &dyn Trait = &get_function()();
11-
//~^ ERROR expected function, found `&dyn Fn() -> dyn Trait`
11+
//~^ ERROR expected function, found `&dyn Fn() -> (dyn Trait + 'static)`
1212
}

src/test/ui/issues/issue-41139.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
error[E0618]: expected function, found `&dyn Fn() -> dyn Trait`
1+
error[E0618]: expected function, found `&dyn Fn() -> (dyn Trait + 'static)`
22
--> $DIR/issue-41139.rs:10:26
33
|
44
LL | fn get_function<'a>() -> &'a dyn Fn() -> dyn Trait {
5-
| -------------------------------------------------- `get_function` defined here returns `&dyn Fn() -> dyn Trait`
5+
| -------------------------------------------------- `get_function` defined here returns `&dyn Fn() -> (dyn Trait + 'static)`
66
...
77
LL | let t: &dyn Trait = &get_function()();
88
| ^^^^^^^^^^^^^^--

src/test/ui/object-lifetime/object-lifetime-default-default-to-static.rs

+29
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,34 @@ fn d(t: Box<dyn Test+'static>, mut ss: SomeStruct) {
3131
ss.u = t;
3232
}
3333

34+
// Check that closures obey the same rules.
35+
fn e() {
36+
let _ = |t: Box<dyn Test>, mut ss: SomeStruct| {
37+
ss.t = t;
38+
};
39+
let _ = |t: Box<dyn Test+'static>, mut ss: SomeStruct| {
40+
ss.t = t;
41+
};
42+
let _ = |t: Box<dyn Test>, mut ss: SomeStruct| {
43+
ss.u = t;
44+
};
45+
let _ = |t: Box<dyn Test+'static>, mut ss: SomeStruct| {
46+
ss.u = t;
47+
};
48+
}
49+
50+
// Check that bare fns and Fn trait obey the same rules.
51+
fn f() {
52+
let _: fn(Box<dyn Test>, SomeStruct) = a;
53+
let _: fn(Box<dyn Test + 'static>, SomeStruct) = a;
54+
let _: &dyn Fn(Box<dyn Test>, SomeStruct) = &a;
55+
let _: &dyn Fn(Box<dyn Test + 'static>, SomeStruct) = &a;
56+
}
57+
58+
// But closure return type does not need to.
59+
fn g<'a>(t: Box<dyn Test + 'a>) {
60+
let _ = || -> Box<dyn Test> { t };
61+
}
62+
3463
fn main() {
3564
}

0 commit comments

Comments
 (0)