Skip to content

Commit 253408b

Browse files
committed
Check that closures satisfy their where bounds
1 parent f001f93 commit 253408b

File tree

16 files changed

+343
-22
lines changed

16 files changed

+343
-22
lines changed

compiler/rustc_trait_selection/src/traits/wf.rs

+16-8
Original file line numberDiff line numberDiff line change
@@ -575,7 +575,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
575575
// generators don't take arguments.
576576
}
577577

578-
ty::Closure(_, substs) => {
578+
ty::Closure(did, substs) => {
579579
// Only check the upvar types for WF, not the rest
580580
// of the types within. This is needed because we
581581
// capture the signature and it may not be WF
@@ -596,18 +596,26 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
596596
// probably always be WF, because it should be
597597
// shorthand for something like `where(T: 'a) {
598598
// fn(&'a T) }`, as discussed in #25860.
599-
//
600-
// Note that we are also skipping the generic
601-
// types. This is consistent with the `outlives`
602-
// code, but anyway doesn't matter: within the fn
599+
walker.skip_current_subtree(); // subtree handled below
600+
// FIXME(eddyb) add the type to `walker` instead of recursing.
601+
self.compute(substs.as_closure().tupled_upvars_ty().into());
602+
// Note that we cannot skip the generic types
603+
// types. Normally, within the fn
603604
// body where they are created, the generics will
604605
// always be WF, and outside of that fn body we
605606
// are not directly inspecting closure types
606607
// anyway, except via auto trait matching (which
607608
// only inspects the upvar types).
608-
walker.skip_current_subtree(); // subtree handled below
609-
// FIXME(eddyb) add the type to `walker` instead of recursing.
610-
self.compute(substs.as_closure().tupled_upvars_ty().into());
609+
// But when a closure is part of a type-alias-impl-trait
610+
// then the function that created the defining site may
611+
// have had more bounds available than the type alias
612+
// specifies. This may cause us to have a closure in the
613+
// hidden type that is not actually well formed and
614+
// can cause compiler crashes when the user abuses unsafe
615+
// code to procure such a closure.
616+
// See src/test/ui/type-alias-impl-trait/wf_check_closures.rs
617+
let obligations = self.nominal_obligations(did, substs);
618+
self.out.extend(obligations);
611619
}
612620

613621
ty::FnPtr(_) => {
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![feature(generic_const_exprs)]
22
#![allow(incomplete_features)]
33
fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
4-
//~^ ERROR overly complex generic constant
4+
//~^ ERROR cycle detected when building an abstract representation
55

66
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,26 @@
1-
error: overly complex generic constant
1+
error[E0391]: cycle detected when building an abstract representation for test::{constant#0}
22
--> $DIR/closures.rs:3:35
33
|
44
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
5-
| ^^^^-------^^
6-
| |
7-
| borrowing is not supported in generic constants
5+
| ^^^^^^^^^^^^^
86
|
9-
= help: consider moving this anonymous constant into a `const` function
10-
= note: this operation may be supported in the future
7+
note: ...which requires building THIR for `test::{constant#0}`...
8+
--> $DIR/closures.rs:3:35
9+
|
10+
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
11+
| ^^^^^^^^^^^^^
12+
note: ...which requires type-checking `test::{constant#0}`...
13+
--> $DIR/closures.rs:3:35
14+
|
15+
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
16+
| ^^^^^^^^^^^^^
17+
= note: ...which again requires building an abstract representation for test::{constant#0}, completing the cycle
18+
note: cycle used when checking that `test` is well-formed
19+
--> $DIR/closures.rs:3:1
20+
|
21+
LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
22+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1123

1224
error: aborting due to previous error
1325

26+
For more information about this error, try `rustc --explain E0391`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
error: higher-ranked lifetime error
2+
--> $DIR/issue-59311.rs:17:5
3+
|
4+
LL | v.t(|| {});
5+
| ^^^^^^^^^^
6+
|
7+
= note: could not prove [closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed
8+
9+
error: higher-ranked lifetime error
10+
--> $DIR/issue-59311.rs:17:9
11+
|
12+
LL | v.t(|| {});
13+
| ^^^^^
14+
|
15+
= note: could not prove for<'a> &'a V: 'static
16+
17+
error: aborting due to 2 previous errors
18+

src/test/ui/higher-rank-trait-bounds/issue-59311.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub fn crash<V>(v: &V)
1414
where
1515
for<'a> &'a V: T + 'static,
1616
{
17-
v.t(|| {}); //~ ERROR: higher-ranked lifetime error
17+
v.t(|| {}); //~ ERROR: `&'a V` does not fulfill the required lifetime
1818
}
1919

2020
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1-
error: higher-ranked lifetime error
2-
--> $DIR/issue-59311.rs:17:9
1+
error[E0477]: the type `&'a V` does not fulfill the required lifetime
2+
--> $DIR/issue-59311.rs:17:5
33
|
44
LL | v.t(|| {});
5-
| ^^^^^
5+
| ^^^^^^^^^^
66
|
7-
= note: could not prove for<'a> &'a V: 'static
7+
note: type must satisfy the static lifetime as required by this binding
8+
--> $DIR/issue-59311.rs:15:24
9+
|
10+
LL | for<'a> &'a V: T + 'static,
11+
| ^^^^^^^
812

913
error: aborting due to previous error
1014

15+
For more information about this error, try `rustc --explain E0477`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
#![feature(type_alias_impl_trait)]
2+
#![allow(dead_code)]
3+
4+
type Bug<T, U> = impl Fn(T) -> U + Copy;
5+
6+
const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
7+
8+
fn make_bug<T, U: From<T>>() -> Bug<T, U> {
9+
|x| x.into() //~ ERROR the trait bound `U: From<T>` is not satisfied
10+
}
11+
12+
fn main() {
13+
CONST_BUG(0);
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0277]: the trait bound `U: From<T>` is not satisfied
2+
--> $DIR/issue-53092.rs:9:5
3+
|
4+
LL | |x| x.into()
5+
| ^^^^^^^^^^^^ the trait `From<T>` is not implemented for `U`
6+
|
7+
note: required by a bound in `make_bug`
8+
--> $DIR/issue-53092.rs:8:19
9+
|
10+
LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> {
11+
| ^^^^^^^ required by this bound in `make_bug`
12+
help: consider restricting type parameter `U`
13+
|
14+
LL | type Bug<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy;
15+
| +++++++++++++++++++++++
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0277`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
// check-pass
4+
5+
trait IterBits {
6+
type BitsIter: Iterator<Item = u8>;
7+
fn iter_bits(self, n: u8) -> Self::BitsIter;
8+
}
9+
10+
impl<T: Copy, E> IterBits for T
11+
where
12+
T: std::ops::Shr<Output = T>
13+
+ std::ops::BitAnd<T, Output = T>
14+
+ std::convert::From<u8>
15+
+ std::convert::TryInto<u8, Error = E>,
16+
E: std::fmt::Debug,
17+
{
18+
type BitsIter = impl std::iter::Iterator<Item = u8>;
19+
fn iter_bits(self, n: u8) -> Self::BitsIter {
20+
(0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
21+
}
22+
}
23+
24+
fn main() {}

src/test/ui/type-alias-impl-trait/issue-60564.rs

+7
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,13 @@ where
2020
(0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
2121
//~^ ERROR non-defining opaque type use in defining scope
2222
//~| ERROR type mismatch resolving
23+
//~| ERROR type mismatch resolving `<T as TryInto<u8>>::Error == E`
24+
//~| ERROR no implementation for `T >> T`
25+
//~| ERROR no implementation for `T & T`
26+
//~| ERROR the trait bound `T: From<u8>`
27+
//~| ERROR the trait bound `T: Copy` is not satisfied
28+
//~| ERROR `E` doesn't implement `Debug`
29+
//~| ERROR the trait bound `u8: From<T>` is not satisfied
2330
}
2431
}
2532

src/test/ui/type-alias-impl-trait/issue-60564.stderr

+119-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,122 @@ LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from
1111
found type parameter `I`
1212
= note: required because of the requirements on the impl of `Iterator` for `Map<Rev<std::ops::Range<u8>>, [closure@$DIR/issue-60564.rs:20:28: 20:100]>`
1313

14+
error[E0271]: type mismatch resolving `<T as TryInto<u8>>::Error == E`
15+
--> $DIR/issue-60564.rs:20:9
16+
|
17+
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
18+
| - this type parameter
19+
...
20+
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
21+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `E`, found enum `Infallible`
22+
|
23+
= note: expected type parameter `E`
24+
found enum `Infallible`
25+
note: required by a bound in `<T as IterBits>`
26+
--> $DIR/issue-60564.rs:15:37
27+
|
28+
LL | + std::convert::TryInto<u8, Error = E>,
29+
| ^^^^^^^^^ required by this bound in `<T as IterBits>`
30+
31+
error[E0277]: no implementation for `T >> T`
32+
--> $DIR/issue-60564.rs:20:9
33+
|
34+
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
35+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T >> T`
36+
|
37+
note: required by a bound in `<T as IterBits>`
38+
--> $DIR/issue-60564.rs:12:8
39+
|
40+
LL | T: std::ops::Shr<Output = T>
41+
| ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
42+
help: consider restricting type parameter `T`
43+
|
44+
LL | type IterBitsIter<T: std::ops::Shr, E, I> = impl std::iter::Iterator<Item = I>;
45+
| +++++++++++++++
46+
47+
error[E0277]: no implementation for `T & T`
48+
--> $DIR/issue-60564.rs:20:9
49+
|
50+
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
51+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T & T`
52+
|
53+
note: required by a bound in `<T as IterBits>`
54+
--> $DIR/issue-60564.rs:13:11
55+
|
56+
LL | + std::ops::BitAnd<T, Output = T>
57+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
58+
help: consider restricting type parameter `T`
59+
|
60+
LL | type IterBitsIter<T: std::ops::BitAnd, E, I> = impl std::iter::Iterator<Item = I>;
61+
| ++++++++++++++++++
62+
63+
error[E0277]: the trait bound `T: From<u8>` is not satisfied
64+
--> $DIR/issue-60564.rs:20:9
65+
|
66+
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
67+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<u8>` is not implemented for `T`
68+
|
69+
note: required by a bound in `<T as IterBits>`
70+
--> $DIR/issue-60564.rs:14:11
71+
|
72+
LL | + std::convert::From<u8>
73+
| ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
74+
help: consider restricting type parameter `T`
75+
|
76+
LL | type IterBitsIter<T: std::convert::From<u8>, E, I> = impl std::iter::Iterator<Item = I>;
77+
| ++++++++++++++++++++++++
78+
79+
error[E0277]: the trait bound `T: Copy` is not satisfied
80+
--> $DIR/issue-60564.rs:20:9
81+
|
82+
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
83+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
84+
|
85+
note: required by a bound in `<T as IterBits>`
86+
--> $DIR/issue-60564.rs:10:9
87+
|
88+
LL | impl<T: Copy, E> IterBits for T
89+
| ^^^^ required by this bound in `<T as IterBits>`
90+
help: consider restricting type parameter `T`
91+
|
92+
LL | type IterBitsIter<T: std::marker::Copy, E, I> = impl std::iter::Iterator<Item = I>;
93+
| +++++++++++++++++++
94+
95+
error[E0277]: `E` doesn't implement `Debug`
96+
--> $DIR/issue-60564.rs:20:9
97+
|
98+
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
99+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `E` cannot be formatted using `{:?}` because it doesn't implement `Debug`
100+
|
101+
note: required by a bound in `<T as IterBits>`
102+
--> $DIR/issue-60564.rs:16:8
103+
|
104+
LL | E: std::fmt::Debug,
105+
| ^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
106+
help: consider restricting type parameter `E`
107+
|
108+
LL | type IterBitsIter<T, E: std::fmt::Debug, I> = impl std::iter::Iterator<Item = I>;
109+
| +++++++++++++++++
110+
111+
error[E0277]: the trait bound `u8: From<T>` is not satisfied
112+
--> $DIR/issue-60564.rs:20:9
113+
|
114+
LL | (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
115+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u8`
116+
|
117+
= note: required because of the requirements on the impl of `Into<u8>` for `T`
118+
= note: required because of the requirements on the impl of `TryFrom<T>` for `u8`
119+
= note: required because of the requirements on the impl of `TryInto<u8>` for `T`
120+
note: required by a bound in `<T as IterBits>`
121+
--> $DIR/issue-60564.rs:15:11
122+
|
123+
LL | + std::convert::TryInto<u8, Error = E>,
124+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
125+
help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
126+
|
127+
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I> where u8: From<T>;
128+
| +++++++++++++++++
129+
14130
error: non-defining opaque type use in defining scope
15131
--> $DIR/issue-60564.rs:20:9
16132
|
@@ -23,6 +139,7 @@ note: used non-generic type `u8` for generic parameter
23139
LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
24140
| ^
25141

26-
error: aborting due to 2 previous errors
142+
error: aborting due to 9 previous errors
27143

28-
For more information about this error, try `rustc --explain E0271`.
144+
Some errors have detailed explanations: E0271, E0277.
145+
For more information about an error, try `rustc --explain E0271`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#![feature(type_alias_impl_trait)]
2+
3+
trait Bar {
4+
fn bar(&self);
5+
}
6+
7+
type FooFn<B> = impl FnOnce(B);
8+
9+
fn foo<B: Bar>() -> FooFn<B> {
10+
fn mop<B: Bar>(bar: B) { bar.bar() }
11+
mop // NOTE: no function pointer, but function zst item
12+
//~^ ERROR the trait bound `B: Bar` is not satisfied
13+
}
14+
15+
fn main() {
16+
let boom: FooFn<u32> = unsafe { core::mem::zeroed() };
17+
boom(42);
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
error[E0277]: the trait bound `B: Bar` is not satisfied
2+
--> $DIR/wf-check-fn-def.rs:11:5
3+
|
4+
LL | mop // NOTE: no function pointer, but function zst item
5+
| ^^^ the trait `Bar` is not implemented for `B`
6+
|
7+
note: required by a bound in `mop`
8+
--> $DIR/wf-check-fn-def.rs:10:15
9+
|
10+
LL | fn mop<B: Bar>(bar: B) { bar.bar() }
11+
| ^^^ required by this bound in `mop`
12+
help: consider restricting type parameter `B`
13+
|
14+
LL | type FooFn<B: Bar> = impl FnOnce(B);
15+
| +++++
16+
17+
error: aborting due to previous error
18+
19+
For more information about this error, try `rustc --explain E0277`.

0 commit comments

Comments
 (0)