Skip to content

Commit 67efbeb

Browse files
committed
Enforce Sized return types on Fn* bounds
In a `fn() -> Out` bound, enforce `Out: Sized` to avoid unsoundness. Fix rust-lang#82633.
1 parent 16143d1 commit 67efbeb

File tree

3 files changed

+195
-0
lines changed

3 files changed

+195
-0
lines changed

compiler/rustc_trait_selection/src/traits/select/confirmation.rs

+24
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,30 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
529529
obligation.predicate.to_poly_trait_ref(),
530530
trait_ref,
531531
)?);
532+
533+
let lang_items = self.tcx().lang_items();
534+
if [lang_items.fn_once_trait(), lang_items.fn_trait(), lang_items.fn_mut_trait()]
535+
.contains(&Some(obligation.predicate.def_id()))
536+
{
537+
// Do not allow `foo::<fn() -> A>();` for `A: !Sized` (#82633)
538+
let fn_sig = obligation.predicate.self_ty().skip_binder().fn_sig(self.tcx());
539+
let ty = fn_sig.output().skip_binder();
540+
let trait_ref = ty::TraitRef {
541+
def_id: lang_items.sized_trait().unwrap(),
542+
substs: self.tcx().mk_substs_trait(ty, &[]),
543+
};
544+
if !matches!(ty.kind(), ty::Projection(_) | ty::Opaque(..)) {
545+
let pred = crate::traits::util::predicate_for_trait_ref(
546+
self.tcx(),
547+
obligation.cause.clone(),
548+
obligation.param_env,
549+
trait_ref,
550+
obligation.recursion_depth,
551+
);
552+
obligations.push(pred);
553+
}
554+
}
555+
532556
Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested: obligations })
533557
}
534558

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#![feature(unboxed_closures)]
2+
3+
trait A {
4+
fn a() where Self: Sized;
5+
}
6+
7+
mod a {
8+
use A;
9+
10+
pub fn foo<F: FnOnce<()>>() where F::Output: A {
11+
F::Output::a()
12+
}
13+
14+
pub fn bar<F: FnOnce() -> R, R: ?Sized>() {}
15+
16+
pub fn baz<F: FnOnce<()>>() where F::Output: A, F::Output: Sized {
17+
F::Output::a()
18+
}
19+
}
20+
21+
mod b {
22+
use A;
23+
24+
pub fn foo<F: Fn<()>>() where F::Output: A {
25+
F::Output::a()
26+
}
27+
28+
pub fn bar<F: Fn() -> R, R: ?Sized>() {}
29+
30+
pub fn baz<F: Fn<()>>() where F::Output: A, F::Output: Sized {
31+
F::Output::a()
32+
}
33+
}
34+
35+
mod c {
36+
use A;
37+
38+
pub fn foo<F: FnMut<()>>() where F::Output: A {
39+
F::Output::a()
40+
}
41+
42+
pub fn bar<F: FnMut() -> R, R: ?Sized>() {}
43+
44+
pub fn baz<F: FnMut<()>>() where F::Output: A, F::Output: Sized {
45+
F::Output::a()
46+
}
47+
}
48+
49+
impl A for Box<dyn A> {
50+
fn a() {}
51+
}
52+
53+
fn main() {
54+
a::foo::<fn() -> dyn A>(); //~ERROR E0277
55+
a::bar::<fn() -> dyn A, _>(); //~ERROR E0277
56+
a::baz::<fn() -> dyn A>(); //~ERROR E0277
57+
a::foo::<fn() -> Box<dyn A>>(); // ok
58+
a::bar::<fn() -> Box<dyn A>, _>(); // ok
59+
a::baz::<fn() -> Box<dyn A>>(); // ok
60+
b::foo::<fn() -> dyn A>(); //~ERROR E0277
61+
b::bar::<fn() -> dyn A, _>(); //~ERROR E0277
62+
b::baz::<fn() -> dyn A>(); //~ERROR E0277
63+
b::foo::<fn() -> Box<dyn A>>(); // ok
64+
b::bar::<fn() -> Box<dyn A>, _>(); // ok
65+
b::baz::<fn() -> Box<dyn A>>(); // ok
66+
c::foo::<fn() -> dyn A>(); //~ERROR E0277
67+
c::bar::<fn() -> dyn A, _>(); //~ERROR E0277
68+
c::baz::<fn() -> dyn A>(); //~ERROR E0277
69+
c::foo::<fn() -> Box<dyn A>>(); // ok
70+
c::bar::<fn() -> Box<dyn A>, _>(); // ok
71+
c::baz::<fn() -> Box<dyn A>>(); // ok
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
2+
--> $DIR/closure-return-type-must-be-sized.rs:54:5
3+
|
4+
LL | a::foo::<fn() -> dyn A>();
5+
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
6+
|
7+
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
8+
9+
error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
10+
--> $DIR/closure-return-type-must-be-sized.rs:55:5
11+
|
12+
LL | pub fn bar<F: FnOnce() -> R, R: ?Sized>() {}
13+
| ------------- required by this bound in `a::bar`
14+
...
15+
LL | a::bar::<fn() -> dyn A, _>();
16+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
17+
|
18+
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
19+
20+
error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
21+
--> $DIR/closure-return-type-must-be-sized.rs:56:5
22+
|
23+
LL | pub fn baz<F: FnOnce<()>>() where F::Output: A, F::Output: Sized {
24+
| ----- required by this bound in `a::baz`
25+
...
26+
LL | a::baz::<fn() -> dyn A>();
27+
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
28+
|
29+
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
30+
31+
error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
32+
--> $DIR/closure-return-type-must-be-sized.rs:60:5
33+
|
34+
LL | pub fn foo<F: Fn<()>>() where F::Output: A {
35+
| ------ required by this bound in `b::foo`
36+
...
37+
LL | b::foo::<fn() -> dyn A>();
38+
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
39+
|
40+
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
41+
42+
error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
43+
--> $DIR/closure-return-type-must-be-sized.rs:61:5
44+
|
45+
LL | pub fn bar<F: Fn() -> R, R: ?Sized>() {}
46+
| --------- required by this bound in `b::bar`
47+
...
48+
LL | b::bar::<fn() -> dyn A, _>();
49+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
50+
|
51+
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
52+
53+
error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
54+
--> $DIR/closure-return-type-must-be-sized.rs:62:5
55+
|
56+
LL | pub fn baz<F: Fn<()>>() where F::Output: A, F::Output: Sized {
57+
| ----- required by this bound in `b::baz`
58+
...
59+
LL | b::baz::<fn() -> dyn A>();
60+
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
61+
|
62+
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
63+
64+
error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
65+
--> $DIR/closure-return-type-must-be-sized.rs:66:5
66+
|
67+
LL | pub fn foo<F: FnMut<()>>() where F::Output: A {
68+
| --------- required by this bound in `c::foo`
69+
...
70+
LL | c::foo::<fn() -> dyn A>();
71+
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
72+
|
73+
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
74+
75+
error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
76+
--> $DIR/closure-return-type-must-be-sized.rs:67:5
77+
|
78+
LL | pub fn bar<F: FnMut() -> R, R: ?Sized>() {}
79+
| ------------ required by this bound in `c::bar`
80+
...
81+
LL | c::bar::<fn() -> dyn A, _>();
82+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
83+
|
84+
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
85+
86+
error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at compilation time
87+
--> $DIR/closure-return-type-must-be-sized.rs:68:5
88+
|
89+
LL | pub fn baz<F: FnMut<()>>() where F::Output: A, F::Output: Sized {
90+
| ----- required by this bound in `c::baz`
91+
...
92+
LL | c::baz::<fn() -> dyn A>();
93+
| ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
94+
|
95+
= help: the trait `Sized` is not implemented for `(dyn A + 'static)`
96+
97+
error: aborting due to 9 previous errors
98+
99+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)