about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-05-13 11:18:01 +0000
committerbors <bors@rust-lang.org>2022-05-13 11:18:01 +0000
commita7d6408b05912396618dfdcc9cc713d3ace2aa9a (patch)
treeb910c7ea0ec5136d8b763d77817aff710a4b0312
parent1c80ac003b59a2e708f127a721904e92ea51d0b9 (diff)
parent7a4ac84a902084e613f1668b9e08297f4901320a (diff)
downloadrust-a7d6408b05912396618dfdcc9cc713d3ace2aa9a.tar.gz
rust-a7d6408b05912396618dfdcc9cc713d3ace2aa9a.zip
Auto merge of #96899 - oli-obk:closure_wf_check_bounds, r=nikomatsakis
Check that closures satisfy their where bounds

fixes https://github.com/rust-lang/rust/issues/53092
fixes https://github.com/rust-lang/rust/issues/90409

based on https://github.com/rust-lang/rust/pull/96736
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs107
-rw-r--r--compiler/rustc_trait_selection/src/opaque_types.rs101
-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/generic_duplicate_param_use.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr18
-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.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-60564.stderr16
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr14
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs1
-rw-r--r--src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr14
-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
24 files changed, 325 insertions, 186 deletions
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index f3d37a6be7b..81073758791 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -1,11 +1,8 @@
-use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::vec_map::VecMap;
 use rustc_hir::def_id::DefId;
 use rustc_hir::OpaqueTyOrigin;
 use rustc_infer::infer::InferCtxt;
-use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, TyCtxt, TypeFoldable};
-use rustc_span::Span;
 use rustc_trait_selection::opaque_types::InferCtxtExt;
 
 use super::RegionInferenceContext;
@@ -107,21 +104,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
 
             let opaque_type_key =
                 OpaqueTypeKey { def_id: opaque_type_key.def_id, substs: universal_substs };
-            let remapped_type = infcx.infer_opaque_definition_from_instantiation(
+            let ty = infcx.infer_opaque_definition_from_instantiation(
                 opaque_type_key,
                 universal_concrete_type,
                 origin,
             );
-            let ty = if check_opaque_type_parameter_valid(
-                infcx.tcx,
-                opaque_type_key,
-                origin,
-                concrete_type.span,
-            ) {
-                remapped_type
-            } else {
-                infcx.tcx.ty_error()
-            };
             // Sometimes two opaque types are the same only after we remap the generic parameters
             // back to the opaque type definition. E.g. we may have `OpaqueType<X, Y>` mapped to `(X, Y)`
             // and `OpaqueType<Y, X>` mapped to `(Y, X)`, and those are the same, but we only know that
@@ -184,95 +171,3 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         })
     }
 }
-
-fn check_opaque_type_parameter_valid(
-    tcx: TyCtxt<'_>,
-    opaque_type_key: OpaqueTypeKey<'_>,
-    origin: OpaqueTyOrigin,
-    span: Span,
-) -> bool {
-    match origin {
-        // No need to check return position impl trait (RPIT)
-        // because for type and const parameters they are correct
-        // by construction: we convert
-        //
-        // fn foo<P0..Pn>() -> impl Trait
-        //
-        // into
-        //
-        // type Foo<P0...Pn>
-        // fn foo<P0..Pn>() -> Foo<P0...Pn>.
-        //
-        // For lifetime parameters we convert
-        //
-        // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
-        //
-        // into
-        //
-        // type foo::<'p0..'pn>::Foo<'q0..'qm>
-        // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
-        //
-        // which would error here on all of the `'static` args.
-        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
-        // Check these
-        OpaqueTyOrigin::TyAlias => {}
-    }
-    let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
-    let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
-    for (i, arg) in opaque_type_key.substs.iter().enumerate() {
-        let arg_is_param = match arg.unpack() {
-            GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
-            GenericArgKind::Lifetime(lt) if lt.is_static() => {
-                tcx.sess
-                    .struct_span_err(span, "non-defining opaque type use in defining scope")
-                    .span_label(
-                        tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
-                        "cannot use static lifetime; use a bound lifetime \
-                                    instead or remove the lifetime parameter from the \
-                                    opaque type",
-                    )
-                    .emit();
-                return false;
-            }
-            GenericArgKind::Lifetime(lt) => {
-                matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
-            }
-            GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)),
-        };
-
-        if arg_is_param {
-            seen_params.entry(arg).or_default().push(i);
-        } else {
-            // Prevent `fn foo() -> Foo<u32>` from being defining.
-            let opaque_param = opaque_generics.param_at(i, tcx);
-            tcx.sess
-                .struct_span_err(span, "non-defining opaque type use in defining scope")
-                .span_note(
-                    tcx.def_span(opaque_param.def_id),
-                    &format!(
-                        "used non-generic {} `{}` for generic parameter",
-                        opaque_param.kind.descr(),
-                        arg,
-                    ),
-                )
-                .emit();
-            return false;
-        }
-    }
-
-    for (_, indices) in seen_params {
-        if indices.len() > 1 {
-            let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
-            let spans: Vec<_> = indices
-                .into_iter()
-                .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
-                .collect();
-            tcx.sess
-                .struct_span_err(span, "non-defining opaque type use in defining scope")
-                .span_note(spans, &format!("{} used multiple times", descr))
-                .emit();
-            return false;
-        }
-    }
-    true
-}
diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs
index 74f5185d672..238c6d99990 100644
--- a/compiler/rustc_trait_selection/src/opaque_types.rs
+++ b/compiler/rustc_trait_selection/src/opaque_types.rs
@@ -82,6 +82,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
         ));
         debug!(?definition_ty);
 
+        if !check_opaque_type_parameter_valid(
+            self.tcx,
+            opaque_type_key,
+            origin,
+            instantiated_ty.span,
+        ) {
+            return self.tcx.ty_error();
+        }
+
         // Only check this for TAIT. RPIT already supports `src/test/ui/impl-trait/nested-return-type2.rs`
         // on stable and we'd break that.
         if let OpaqueTyOrigin::TyAlias = origin {
@@ -148,6 +157,98 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
     }
 }
 
+fn check_opaque_type_parameter_valid(
+    tcx: TyCtxt<'_>,
+    opaque_type_key: OpaqueTypeKey<'_>,
+    origin: OpaqueTyOrigin,
+    span: Span,
+) -> bool {
+    match origin {
+        // No need to check return position impl trait (RPIT)
+        // because for type and const parameters they are correct
+        // by construction: we convert
+        //
+        // fn foo<P0..Pn>() -> impl Trait
+        //
+        // into
+        //
+        // type Foo<P0...Pn>
+        // fn foo<P0..Pn>() -> Foo<P0...Pn>.
+        //
+        // For lifetime parameters we convert
+        //
+        // fn foo<'l0..'ln>() -> impl Trait<'l0..'lm>
+        //
+        // into
+        //
+        // type foo::<'p0..'pn>::Foo<'q0..'qm>
+        // fn foo<l0..'ln>() -> foo::<'static..'static>::Foo<'l0..'lm>.
+        //
+        // which would error here on all of the `'static` args.
+        OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return true,
+        // Check these
+        OpaqueTyOrigin::TyAlias => {}
+    }
+    let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
+    let mut seen_params: FxHashMap<_, Vec<_>> = FxHashMap::default();
+    for (i, arg) in opaque_type_key.substs.iter().enumerate() {
+        let arg_is_param = match arg.unpack() {
+            GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)),
+            GenericArgKind::Lifetime(lt) if lt.is_static() => {
+                tcx.sess
+                    .struct_span_err(span, "non-defining opaque type use in defining scope")
+                    .span_label(
+                        tcx.def_span(opaque_generics.param_at(i, tcx).def_id),
+                        "cannot use static lifetime; use a bound lifetime \
+                                    instead or remove the lifetime parameter from the \
+                                    opaque type",
+                    )
+                    .emit();
+                return false;
+            }
+            GenericArgKind::Lifetime(lt) => {
+                matches!(*lt, ty::ReEarlyBound(_) | ty::ReFree(_))
+            }
+            GenericArgKind::Const(ct) => matches!(ct.val(), ty::ConstKind::Param(_)),
+        };
+
+        if arg_is_param {
+            seen_params.entry(arg).or_default().push(i);
+        } else {
+            // Prevent `fn foo() -> Foo<u32>` from being defining.
+            let opaque_param = opaque_generics.param_at(i, tcx);
+            tcx.sess
+                .struct_span_err(span, "non-defining opaque type use in defining scope")
+                .span_note(
+                    tcx.def_span(opaque_param.def_id),
+                    &format!(
+                        "used non-generic {} `{}` for generic parameter",
+                        opaque_param.kind.descr(),
+                        arg,
+                    ),
+                )
+                .emit();
+            return false;
+        }
+    }
+
+    for (_, indices) in seen_params {
+        if indices.len() > 1 {
+            let descr = opaque_generics.param_at(indices[0], tcx).kind.descr();
+            let spans: Vec<_> = indices
+                .into_iter()
+                .map(|i| tcx.def_span(opaque_generics.param_at(i, tcx).def_id))
+                .collect();
+            tcx.sess
+                .struct_span_err(span, "non-defining opaque type use in defining scope")
+                .span_note(spans, &format!("{} used multiple times", descr))
+                .emit();
+            return false;
+        }
+    }
+    true
+}
+
 struct ReverseMapper<'tcx> {
     tcx: TyCtxt<'tcx>,
 
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/generic_duplicate_param_use.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs
index cf46add124c..093c1c23186 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.rs
@@ -15,7 +15,6 @@ type TwoConsts<const X: usize, const Y: usize> = impl Debug;
 fn one_ty<T: Debug>(t: T) -> TwoTys<T, T> {
     t
     //~^ ERROR non-defining opaque type use in defining scope
-    //~| ERROR `U` doesn't implement `Debug`
 }
 
 fn one_lifetime<'a>(t: &'a u32) -> TwoLifetimes<'a, 'a> {
diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr
index d661196e1bf..b2edcc5526a 100644
--- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr
+++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use.stderr
@@ -1,14 +1,3 @@
-error[E0277]: `U` doesn't implement `Debug`
-  --> $DIR/generic_duplicate_param_use.rs:16:5
-   |
-LL |     t
-   |     ^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug`
-   |
-help: consider restricting type parameter `U`
-   |
-LL | type TwoTys<T, U: std::fmt::Debug> = impl Debug;
-   |                 +++++++++++++++++
-
 error: non-defining opaque type use in defining scope
   --> $DIR/generic_duplicate_param_use.rs:16:5
    |
@@ -22,7 +11,7 @@ LL | type TwoTys<T, U> = impl Debug;
    |             ^  ^
 
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use.rs:22:5
+  --> $DIR/generic_duplicate_param_use.rs:21:5
    |
 LL |     t
    |     ^
@@ -34,7 +23,7 @@ LL | type TwoLifetimes<'a, 'b> = impl Debug;
    |                   ^^  ^^
 
 error: non-defining opaque type use in defining scope
-  --> $DIR/generic_duplicate_param_use.rs:27:5
+  --> $DIR/generic_duplicate_param_use.rs:26:5
    |
 LL |     t
    |     ^
@@ -45,6 +34,5 @@ note: constant used multiple times
 LL | type TwoConsts<const X: usize, const Y: usize> = impl Debug;
    |                ^^^^^^^^^^^^^^  ^^^^^^^^^^^^^^
 
-error: aborting due to 4 previous errors
+error: aborting due to 3 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
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..4fc7679311a 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60564.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-60564.rs
@@ -19,7 +19,6 @@ where
     fn iter_bits(self, n: u8) -> Self::BitsIter {
         (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
     }
 }
 
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..bbc93657be3 100644
--- a/src/test/ui/type-alias-impl-trait/issue-60564.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-60564.stderr
@@ -1,16 +1,3 @@
-error[E0271]: type mismatch resolving `<[closure@$DIR/issue-60564.rs:20:28: 20:100] as FnOnce<(u8,)>>::Output == I`
-  --> $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 `u8`, found type parameter `I`
-   |
-   = note:        expected type `u8`
-           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: non-defining opaque type use in defining scope
   --> $DIR/issue-60564.rs:20:9
    |
@@ -23,6 +10,5 @@ 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 previous error
 
-For more information about this error, try `rustc --explain E0271`.
diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs
index bffff8787e4..b50462bf237 100644
--- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.rs
@@ -8,7 +8,6 @@ type Alias<'a, U> = impl Trait<U>;
 
 fn f<'a>() -> Alias<'a, ()> {}
 //~^ ERROR non-defining opaque type use in defining scope
-//~| ERROR the trait bound `(): Trait<U>` is not satisfied
 
 fn main() {}
 
diff --git a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr
index b79d638ad99..8059621b61a 100644
--- a/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-68368-non-defining-use.stderr
@@ -1,14 +1,3 @@
-error[E0277]: the trait bound `(): Trait<U>` is not satisfied
-  --> $DIR/issue-68368-non-defining-use.rs:9:29
-   |
-LL | fn f<'a>() -> Alias<'a, ()> {}
-   |                             ^^ the trait `Trait<U>` is not implemented for `()`
-   |
-help: consider introducing a `where` bound, but there might be an alternative better way to express this requirement
-   |
-LL | type Alias<'a, U> = impl Trait<U> where (): Trait<U>;
-   |                                   ++++++++++++++++++
-
 error: non-defining opaque type use in defining scope
   --> $DIR/issue-68368-non-defining-use.rs:9:29
    |
@@ -21,6 +10,5 @@ note: used non-generic type `()` for generic parameter
 LL | type Alias<'a, U> = impl Trait<U>;
    |                ^
 
-error: aborting due to 2 previous errors
+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-69136-inner-lifetime-resolve-error.rs b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs
index b0de8bf6aa4..428454bc048 100644
--- a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs
+++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.rs
@@ -19,6 +19,5 @@ type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
 
 fn my_fun() -> Return<()> {}
 //~^ ERROR non-defining opaque type use in defining scope
-//~| ERROR non-defining opaque type use in defining scope
 
 fn main() {}
diff --git a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr
index d038fbbe1b4..7b50c8af26e 100644
--- a/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr
+++ b/src/test/ui/type-alias-impl-trait/issue-69136-inner-lifetime-resolve-error.stderr
@@ -26,18 +26,6 @@ note: used non-generic type `()` for generic parameter
 LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
    |             ^
 
-error: non-defining opaque type use in defining scope
-  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:20:27
-   |
-LL | fn my_fun() -> Return<()> {}
-   |                           ^^
-   |
-note: used non-generic type `()` for generic parameter
-  --> $DIR/issue-69136-inner-lifetime-resolve-error.rs:17:13
-   |
-LL | type Return<A> = impl WithAssoc<A, AssocType = impl SomeTrait + 'a>;
-   |             ^
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0261`.
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`.