about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2022-05-10 14:19:19 +0000
committerOli Scherer <git-spam-no-reply9815368754983@oli-obk.de>2022-05-13 10:09:11 +0000
commit253408b4090bc15b88bb5faecaf1e9765be80587 (patch)
tree5244b56a59a36d6c692d1eff1972dbd09e625dad
parentf001f9301c889101d8a71358b64b96e9707c832b (diff)
downloadrust-253408b4090bc15b88bb5faecaf1e9765be80587.tar.gz
rust-253408b4090bc15b88bb5faecaf1e9765be80587.zip
Check that closures satisfy their where bounds
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs24
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/closures.rs2
-rw-r--r--src/test/ui/const-generics/generic_const_exprs/closures.stderr25
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr18
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-59311.rs2
-rw-r--r--src/test/ui/higher-rank-trait-bounds/issue-59311.stderr13
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53092.rs14
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-53092.stderr19
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60564-working.rs24
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60564.rs7
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60564.stderr121
-rw-r--r--src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs18
-rw-r--r--src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr19
-rw-r--r--src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs23
-rw-r--r--src/test/ui/type-alias-impl-trait/wf_check_closures.rs17
-rw-r--r--src/test/ui/type-alias-impl-trait/wf_check_closures.stderr19
16 files changed, 343 insertions, 22 deletions
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index de0ade64247..ca40c3452e2 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -575,7 +575,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     // generators don't take arguments.
                 }
 
-                ty::Closure(_, substs) => {
+                ty::Closure(did, substs) => {
                     // Only check the upvar types for WF, not the rest
                     // of the types within. This is needed because we
                     // capture the signature and it may not be WF
@@ -596,18 +596,26 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
                     // probably always be WF, because it should be
                     // shorthand for something like `where(T: 'a) {
                     // fn(&'a T) }`, as discussed in #25860.
-                    //
-                    // Note that we are also skipping the generic
-                    // types. This is consistent with the `outlives`
-                    // code, but anyway doesn't matter: within the fn
+                    walker.skip_current_subtree(); // subtree handled below
+                    // FIXME(eddyb) add the type to `walker` instead of recursing.
+                    self.compute(substs.as_closure().tupled_upvars_ty().into());
+                    // Note that we cannot skip the generic types
+                    // types. Normally, within the fn
                     // body where they are created, the generics will
                     // always be WF, and outside of that fn body we
                     // are not directly inspecting closure types
                     // anyway, except via auto trait matching (which
                     // only inspects the upvar types).
-                    walker.skip_current_subtree(); // subtree handled below
-                    // FIXME(eddyb) add the type to `walker` instead of recursing.
-                    self.compute(substs.as_closure().tupled_upvars_ty().into());
+                    // But when a closure is part of a type-alias-impl-trait
+                    // then the function that created the defining site may
+                    // have had more bounds available than the type alias
+                    // specifies. This may cause us to have a closure in the
+                    // hidden type that is not actually well formed and
+                    // can cause compiler crashes when the user abuses unsafe
+                    // code to procure such a closure.
+                    // See src/test/ui/type-alias-impl-trait/wf_check_closures.rs
+                    let obligations = self.nominal_obligations(did, substs);
+                    self.out.extend(obligations);
                 }
 
                 ty::FnPtr(_) => {
diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.rs b/src/test/ui/const-generics/generic_const_exprs/closures.rs
index 847843fe1a6..1ea310d063b 100644
--- a/src/test/ui/const-generics/generic_const_exprs/closures.rs
+++ b/src/test/ui/const-generics/generic_const_exprs/closures.rs
@@ -1,6 +1,6 @@
 #![feature(generic_const_exprs)]
 #![allow(incomplete_features)]
 fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
-//~^ ERROR overly complex generic constant
+//~^ ERROR cycle detected when building an abstract representation
 
 fn main() {}
diff --git a/src/test/ui/const-generics/generic_const_exprs/closures.stderr b/src/test/ui/const-generics/generic_const_exprs/closures.stderr
index 18010413b93..a15dd2016e9 100644
--- a/src/test/ui/const-generics/generic_const_exprs/closures.stderr
+++ b/src/test/ui/const-generics/generic_const_exprs/closures.stderr
@@ -1,13 +1,26 @@
-error: overly complex generic constant
+error[E0391]: cycle detected when building an abstract representation for test::{constant#0}
   --> $DIR/closures.rs:3:35
    |
 LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
-   |                                   ^^^^-------^^
-   |                                       |
-   |                                       borrowing is not supported in generic constants
+   |                                   ^^^^^^^^^^^^^
    |
-   = help: consider moving this anonymous constant into a `const` function
-   = note: this operation may be supported in the future
+note: ...which requires building THIR for `test::{constant#0}`...
+  --> $DIR/closures.rs:3:35
+   |
+LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
+   |                                   ^^^^^^^^^^^^^
+note: ...which requires type-checking `test::{constant#0}`...
+  --> $DIR/closures.rs:3:35
+   |
+LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
+   |                                   ^^^^^^^^^^^^^
+   = note: ...which again requires building an abstract representation for test::{constant#0}, completing the cycle
+note: cycle used when checking that `test` is well-formed
+  --> $DIR/closures.rs:3:1
+   |
+LL | fn test<const N: usize>() -> [u8; N + (|| 42)()] {}
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0391`.
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr
new file mode 100644
index 00000000000..15e83ab5a34
--- /dev/null
+++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.nll.stderr
@@ -0,0 +1,18 @@
+error: higher-ranked lifetime error
+  --> $DIR/issue-59311.rs:17:5
+   |
+LL |     v.t(|| {});
+   |     ^^^^^^^^^^
+   |
+   = note: could not prove [closure@$DIR/issue-59311.rs:17:9: 17:14] well-formed
+
+error: higher-ranked lifetime error
+  --> $DIR/issue-59311.rs:17:9
+   |
+LL |     v.t(|| {});
+   |         ^^^^^
+   |
+   = note: could not prove for<'a> &'a V: 'static
+
+error: aborting due to 2 previous errors
+
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.rs b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs
index d617571753c..69708577285 100644
--- a/src/test/ui/higher-rank-trait-bounds/issue-59311.rs
+++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.rs
@@ -14,7 +14,7 @@ pub fn crash<V>(v: &V)
 where
     for<'a> &'a V: T + 'static,
 {
-    v.t(|| {}); //~ ERROR: higher-ranked lifetime error
+    v.t(|| {}); //~ ERROR: `&'a V` does not fulfill the required lifetime
 }
 
 fn main() {}
diff --git a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
index c16c8206153..3dd05bba5c0 100644
--- a/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
+++ b/src/test/ui/higher-rank-trait-bounds/issue-59311.stderr
@@ -1,10 +1,15 @@
-error: higher-ranked lifetime error
-  --> $DIR/issue-59311.rs:17:9
+error[E0477]: the type `&'a V` does not fulfill the required lifetime
+  --> $DIR/issue-59311.rs:17:5
    |
 LL |     v.t(|| {});
-   |         ^^^^^
+   |     ^^^^^^^^^^
    |
-   = note: could not prove for<'a> &'a V: 'static
+note: type must satisfy the static lifetime as required by this binding
+  --> $DIR/issue-59311.rs:15:24
+   |
+LL |     for<'a> &'a V: T + 'static,
+   |                        ^^^^^^^
 
 error: aborting due to previous error
 
+For more information about this error, try `rustc --explain E0477`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-53092.rs b/src/test/ui/type-alias-impl-trait/issue-53092.rs
new file mode 100644
index 00000000000..45792ba97a7
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-53092.rs
@@ -0,0 +1,14 @@
+#![feature(type_alias_impl_trait)]
+#![allow(dead_code)]
+
+type Bug<T, U> = impl Fn(T) -> U + Copy;
+
+const CONST_BUG: Bug<u8, ()> = unsafe { std::mem::transmute(|_: u8| ()) };
+
+fn make_bug<T, U: From<T>>() -> Bug<T, U> {
+    |x| x.into() //~ ERROR the trait bound `U: From<T>` is not satisfied
+}
+
+fn main() {
+    CONST_BUG(0);
+}
diff --git a/src/test/ui/type-alias-impl-trait/issue-53092.stderr b/src/test/ui/type-alias-impl-trait/issue-53092.stderr
new file mode 100644
index 00000000000..2d423a0c0df
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-53092.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `U: From<T>` is not satisfied
+  --> $DIR/issue-53092.rs:9:5
+   |
+LL |     |x| x.into()
+   |     ^^^^^^^^^^^^ the trait `From<T>` is not implemented for `U`
+   |
+note: required by a bound in `make_bug`
+  --> $DIR/issue-53092.rs:8:19
+   |
+LL | fn make_bug<T, U: From<T>>() -> Bug<T, U> {
+   |                   ^^^^^^^ required by this bound in `make_bug`
+help: consider restricting type parameter `U`
+   |
+LL | type Bug<T, U: std::convert::From<T>> = impl Fn(T) -> U + Copy;
+   |              +++++++++++++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-60564-working.rs b/src/test/ui/type-alias-impl-trait/issue-60564-working.rs
new file mode 100644
index 00000000000..38accc8241c
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/issue-60564-working.rs
@@ -0,0 +1,24 @@
+#![feature(type_alias_impl_trait)]
+
+// check-pass
+
+trait IterBits {
+    type BitsIter: Iterator<Item = u8>;
+    fn iter_bits(self, n: u8) -> Self::BitsIter;
+}
+
+impl<T: Copy, E> IterBits for T
+where
+    T: std::ops::Shr<Output = T>
+        + std::ops::BitAnd<T, Output = T>
+        + std::convert::From<u8>
+        + std::convert::TryInto<u8, Error = E>,
+    E: std::fmt::Debug,
+{
+    type BitsIter = impl std::iter::Iterator<Item = u8>;
+    fn iter_bits(self, n: u8) -> Self::BitsIter {
+        (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.rs b/src/test/ui/type-alias-impl-trait/issue-60564.rs
index 0aeebae639e..48d8dff2b93 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60564.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs
@@ -20,6 +20,13 @@ where
         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
         //~^ ERROR non-defining opaque type use in defining scope
         //~| ERROR type mismatch resolving
+        //~| ERROR type mismatch resolving `<T as TryInto<u8>>::Error == E`
+        //~| ERROR no implementation for `T >> T`
+        //~| ERROR no implementation for `T & T`
+        //~| ERROR the trait bound `T: From<u8>`
+        //~| ERROR the trait bound `T: Copy` is not satisfied
+        //~| ERROR `E` doesn't implement `Debug`
+        //~| ERROR the trait bound `u8: From<T>` is not satisfied
     }
 }
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-60564.stderr b/src/test/ui/type-alias-impl-trait/issue-60564.stderr
index 9cb07cbbb44..4ef53973a7c 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60564.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-60564.stderr
@@ -11,6 +11,122 @@ LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from
            found type parameter `I`
    = 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]>`
 
+error[E0271]: type mismatch resolving `<T as TryInto<u8>>::Error == E`
+  --> $DIR/issue-60564.rs:20:9
+   |
+LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
+   |                      - this type parameter
+...
+LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `E`, found enum `Infallible`
+   |
+   = note: expected type parameter `E`
+                        found enum `Infallible`
+note: required by a bound in `<T as IterBits>`
+  --> $DIR/issue-60564.rs:15:37
+   |
+LL |         + std::convert::TryInto<u8, Error = E>,
+   |                                     ^^^^^^^^^ required by this bound in `<T as IterBits>`
+
+error[E0277]: no implementation for `T >> T`
+  --> $DIR/issue-60564.rs:20:9
+   |
+LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T >> T`
+   |
+note: required by a bound in `<T as IterBits>`
+  --> $DIR/issue-60564.rs:12:8
+   |
+LL |     T: std::ops::Shr<Output = T>
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
+help: consider restricting type parameter `T`
+   |
+LL | type IterBitsIter<T: std::ops::Shr, E, I> = impl std::iter::Iterator<Item = I>;
+   |                    +++++++++++++++
+
+error[E0277]: no implementation for `T & T`
+  --> $DIR/issue-60564.rs:20:9
+   |
+LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T & T`
+   |
+note: required by a bound in `<T as IterBits>`
+  --> $DIR/issue-60564.rs:13:11
+   |
+LL |         + std::ops::BitAnd<T, Output = T>
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
+help: consider restricting type parameter `T`
+   |
+LL | type IterBitsIter<T: std::ops::BitAnd, E, I> = impl std::iter::Iterator<Item = I>;
+   |                    ++++++++++++++++++
+
+error[E0277]: the trait bound `T: From<u8>` is not satisfied
+  --> $DIR/issue-60564.rs:20:9
+   |
+LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<u8>` is not implemented for `T`
+   |
+note: required by a bound in `<T as IterBits>`
+  --> $DIR/issue-60564.rs:14:11
+   |
+LL |         + std::convert::From<u8>
+   |           ^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
+help: consider restricting type parameter `T`
+   |
+LL | type IterBitsIter<T: std::convert::From<u8>, E, I> = impl std::iter::Iterator<Item = I>;
+   |                    ++++++++++++++++++++++++
+
+error[E0277]: the trait bound `T: Copy` is not satisfied
+  --> $DIR/issue-60564.rs:20:9
+   |
+LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |
+note: required by a bound in `<T as IterBits>`
+  --> $DIR/issue-60564.rs:10:9
+   |
+LL | impl<T: Copy, E> IterBits for T
+   |         ^^^^ required by this bound in `<T as IterBits>`
+help: consider restricting type parameter `T`
+   |
+LL | type IterBitsIter<T: std::marker::Copy, E, I> = impl std::iter::Iterator<Item = I>;
+   |                    +++++++++++++++++++
+
+error[E0277]: `E` doesn't implement `Debug`
+  --> $DIR/issue-60564.rs:20:9
+   |
+LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `E` cannot be formatted using `{:?}` because it doesn't implement `Debug`
+   |
+note: required by a bound in `<T as IterBits>`
+  --> $DIR/issue-60564.rs:16:8
+   |
+LL |     E: std::fmt::Debug,
+   |        ^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
+help: consider restricting type parameter `E`
+   |
+LL | type IterBitsIter<T, E: std::fmt::Debug, I> = impl std::iter::Iterator<Item = I>;
+   |                       +++++++++++++++++
+
+error[E0277]: the trait bound `u8: From<T>` is not satisfied
+  --> $DIR/issue-60564.rs:20:9
+   |
+LL |         (0u8..n).rev().map(move |shift| ((self >> T::from(shift)) & T::from(1)).try_into().unwrap())
+   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<T>` is not implemented for `u8`
+   |
+   = note: required because of the requirements on the impl of `Into<u8>` for `T`
+   = note: required because of the requirements on the impl of `TryFrom<T>` for `u8`
+   = note: required because of the requirements on the impl of `TryInto<u8>` for `T`
+note: required by a bound in `<T as IterBits>`
+  --> $DIR/issue-60564.rs:15:11
+   |
+LL |         + std::convert::TryInto<u8, Error = E>,
+   |           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `<T as IterBits>`
+help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
+   |
+LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I> where u8: From<T>;
+   |                                                                 +++++++++++++++++
+
 error: non-defining opaque type use in defining scope
   --> $DIR/issue-60564.rs:20:9
    |
@@ -23,6 +139,7 @@ note: used non-generic type `u8` for generic parameter
 LL | type IterBitsIter<T, E, I> = impl std::iter::Iterator<Item = I>;
    |                         ^
 
-error: aborting due to 2 previous errors
+error: aborting due to 9 previous errors
 
-For more information about this error, try `rustc --explain E0271`.
+Some errors have detailed explanations: E0271, E0277.
+For more information about an error, try `rustc --explain E0271`.
diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs
new file mode 100644
index 00000000000..449e9fbd0d8
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.rs
@@ -0,0 +1,18 @@
+#![feature(type_alias_impl_trait)]
+
+trait Bar {
+    fn bar(&self);
+}
+
+type FooFn<B> = impl FnOnce(B);
+
+fn foo<B: Bar>() -> FooFn<B> {
+    fn mop<B: Bar>(bar: B) { bar.bar() }
+    mop // NOTE: no function pointer, but function zst item
+    //~^ ERROR the trait bound `B: Bar` is not satisfied
+}
+
+fn main() {
+    let boom: FooFn<u32> = unsafe { core::mem::zeroed() };
+    boom(42);
+}
diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr
new file mode 100644
index 00000000000..e0005489d1e
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/wf-check-fn-def.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `B: Bar` is not satisfied
+  --> $DIR/wf-check-fn-def.rs:11:5
+   |
+LL |     mop // NOTE: no function pointer, but function zst item
+   |     ^^^ the trait `Bar` is not implemented for `B`
+   |
+note: required by a bound in `mop`
+  --> $DIR/wf-check-fn-def.rs:10:15
+   |
+LL |     fn mop<B: Bar>(bar: B) { bar.bar() }
+   |               ^^^ required by this bound in `mop`
+help: consider restricting type parameter `B`
+   |
+LL | type FooFn<B: Bar> = impl FnOnce(B);
+   |             +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs b/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs
new file mode 100644
index 00000000000..3b8470e4ae6
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/wf-check-fn-ptrs.rs
@@ -0,0 +1,23 @@
+#![feature(type_alias_impl_trait)]
+
+// build-pass
+
+trait Bar {
+    fn bar(&self);
+}
+
+type FooFn<B> = impl FnOnce(B);
+
+fn foo<B: Bar>() -> FooFn<B> {
+    fn mop<B: Bar>(bar: B) { bar.bar() }
+    mop as fn(B)
+    // function pointers don't have any obligations on them,
+    // thus the above compiles. It's obviously unsound to just
+    // procure a `FooFn` from the ether without making sure that
+    // the pointer is actually legal for all `B`
+}
+
+fn main() {
+    let boom: FooFn<u32> = unsafe { core::mem::zeroed() };
+    boom(42);
+}
diff --git a/src/test/ui/type-alias-impl-trait/wf_check_closures.rs b/src/test/ui/type-alias-impl-trait/wf_check_closures.rs
new file mode 100644
index 00000000000..2c70696ffcf
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/wf_check_closures.rs
@@ -0,0 +1,17 @@
+#![feature(type_alias_impl_trait)]
+
+trait Bar {
+    fn bar(&self);
+}
+
+type FooFn<B> = impl FnOnce();
+
+fn foo<B: Bar>(bar: B) -> FooFn<B> {
+    move || { bar.bar() }
+    //~^ ERROR the trait bound `B: Bar` is not satisfied
+}
+
+fn main() {
+    let boom: FooFn<u32> = unsafe { core::mem::zeroed() };
+    boom();
+}
diff --git a/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr b/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr
new file mode 100644
index 00000000000..58ae8617b9b
--- /dev/null
+++ b/src/test/ui/type-alias-impl-trait/wf_check_closures.stderr
@@ -0,0 +1,19 @@
+error[E0277]: the trait bound `B: Bar` is not satisfied
+  --> $DIR/wf_check_closures.rs:10:5
+   |
+LL |     move || { bar.bar() }
+   |     ^^^^^^^^^^^^^^^^^^^^^ the trait `Bar` is not implemented for `B`
+   |
+note: required by a bound in `foo`
+  --> $DIR/wf_check_closures.rs:9:11
+   |
+LL | fn foo<B: Bar>(bar: B) -> FooFn<B> {
+   |           ^^^ required by this bound in `foo`
+help: consider restricting type parameter `B`
+   |
+LL | type FooFn<B: Bar> = impl FnOnce();
+   |             +++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.