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

Lines changed: 16 additions & 8 deletions
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(_) => {
Lines changed: 1 addition & 1 deletion
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() {}
Lines changed: 19 additions & 6 deletions
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`.
Lines changed: 18 additions & 0 deletions
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

Lines changed: 1 addition & 1 deletion
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() {}
Lines changed: 9 additions & 4 deletions
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`.
Lines changed: 14 additions & 0 deletions
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+
}
Lines changed: 19 additions & 0 deletions
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`.
Lines changed: 24 additions & 0 deletions
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

Lines changed: 7 additions & 0 deletions
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

0 commit comments

Comments
 (0)