diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index 0d2ae115cb0..00913a483db 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -241,9 +241,19 @@ fn compress(
     v: PreorderIndex,
 ) {
     assert!(is_processed(v, lastlinked));
-    let u = ancestor[v];
-    if is_processed(u, lastlinked) {
-        compress(ancestor, lastlinked, semi, label, u);
+    // Compute the processed list of ancestors
+    //
+    // We use a heap stack here to avoid recursing too deeply, exhausting the
+    // stack space.
+    let mut stack: smallvec::SmallVec<[_; 8]> = smallvec::smallvec![v];
+    let mut u = ancestor[v];
+    while is_processed(u, lastlinked) {
+        stack.push(u);
+        u = ancestor[u];
+    }
+
+    // Then in reverse order, popping the stack
+    for &[v, u] in stack.array_windows().rev() {
         if semi[label[u]] < semi[label[v]] {
             label[v] = label[u];
         }
diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
index bb9755e4f48..4981ab5152c 100644
--- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs
@@ -10,38 +10,11 @@ use rustc_middle::mir::*;
 /// At present, this is used as a very limited form of alias analysis. For example,
 /// `MaybeBorrowedLocals` is used to compute which locals are live during a yield expression for
 /// immovable generators.
-pub struct MaybeBorrowedLocals {
-    ignore_borrow_on_drop: bool,
-}
+pub struct MaybeBorrowedLocals;
 
 impl MaybeBorrowedLocals {
-    /// A dataflow analysis that records whether a pointer or reference exists that may alias the
-    /// given local.
-    pub fn all_borrows() -> Self {
-        MaybeBorrowedLocals { ignore_borrow_on_drop: false }
-    }
-}
-
-impl MaybeBorrowedLocals {
-    /// During dataflow analysis, ignore the borrow that may occur when a place is dropped.
-    ///
-    /// Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut self` as a
-    /// parameter. In the general case, a drop impl could launder that reference into the
-    /// surrounding environment through a raw pointer, thus creating a valid `*mut` pointing to the
-    /// dropped local. We are not yet willing to declare this particular case UB, so we must treat
-    /// all dropped locals as mutably borrowed for now. See discussion on [#61069].
-    ///
-    /// In some contexts, we know that this borrow will never occur. For example, during
-    /// const-eval, custom drop glue cannot be run. Code that calls this should document the
-    /// assumptions that justify ignoring `Drop` terminators in this way.
-    ///
-    /// [#61069]: https://github.com/rust-lang/rust/pull/61069
-    pub fn unsound_ignore_borrow_on_drop(self) -> Self {
-        MaybeBorrowedLocals { ignore_borrow_on_drop: true, ..self }
-    }
-
     fn transfer_function<'a, T>(&'a self, trans: &'a mut T) -> TransferFunction<'a, T> {
-        TransferFunction { trans, ignore_borrow_on_drop: self.ignore_borrow_on_drop }
+        TransferFunction { trans }
     }
 }
 
@@ -92,7 +65,6 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeBorrowedLocals {
 /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`.
 struct TransferFunction<'a, T> {
     trans: &'a mut T,
-    ignore_borrow_on_drop: bool,
 }
 
 impl<'tcx, T> Visitor<'tcx> for TransferFunction<'_, T>
@@ -146,10 +118,15 @@ where
         match terminator.kind {
             mir::TerminatorKind::Drop { place: dropped_place, .. }
             | mir::TerminatorKind::DropAndReplace { place: dropped_place, .. } => {
-                // See documentation for `unsound_ignore_borrow_on_drop` for an explanation.
-                if !self.ignore_borrow_on_drop {
-                    self.trans.gen(dropped_place.local);
-                }
+                // Drop terminators may call custom drop glue (`Drop::drop`), which takes `&mut
+                // self` as a parameter. In the general case, a drop impl could launder that
+                // reference into the surrounding environment through a raw pointer, thus creating
+                // a valid `*mut` pointing to the dropped local. We are not yet willing to declare
+                // this particular case UB, so we must treat all dropped locals as mutably borrowed
+                // for now. See discussion on [#61069].
+                //
+                // [#61069]: https://github.com/rust-lang/rust/pull/61069
+                self.trans.gen(dropped_place.local);
             }
 
             TerminatorKind::Abort
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 388bb7d3436..d9a66cace52 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -463,10 +463,8 @@ fn locals_live_across_suspend_points<'tcx>(
 
     // Calculate the MIR locals which have been previously
     // borrowed (even if they are still active).
-    let borrowed_locals_results = MaybeBorrowedLocals::all_borrows()
-        .into_engine(tcx, body_ref)
-        .pass_name("generator")
-        .iterate_to_fixpoint();
+    let borrowed_locals_results =
+        MaybeBorrowedLocals.into_engine(tcx, body_ref).pass_name("generator").iterate_to_fixpoint();
 
     let mut borrowed_locals_cursor =
         rustc_mir_dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results);
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 8d4b97571a6..47b1ee04e77 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -8,7 +8,7 @@
 
 use rustc_middle::traits::ChalkRustInterner as RustInterner;
 use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef};
-use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt, TypeFoldable};
+use rustc_middle::ty::{self, AssocItemContainer, AssocKind, Ty, TyCtxt, TypeFoldable};
 
 use rustc_ast::ast;
 use rustc_attr as attr;
@@ -482,21 +482,11 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
                 .iter()
                 .map(|(bound, _)| bound.subst(self.interner.tcx, &bound_vars))
                 .map(|bound| {
-                    bound.fold_with(&mut ty::fold::BottomUpFolder {
+                    bound.fold_with(&mut ReplaceOpaqueTyFolder {
                         tcx: self.interner.tcx,
-                        ty_op: |ty| {
-                            if let ty::Opaque(def_id, substs) = *ty.kind() {
-                                if def_id == opaque_ty_id.0 && substs == identity_substs {
-                                    return self.interner.tcx.mk_ty(ty::Bound(
-                                        ty::INNERMOST,
-                                        ty::BoundTy::from(ty::BoundVar::from_u32(0)),
-                                    ));
-                                }
-                            }
-                            ty
-                        },
-                        lt_op: |lt| lt,
-                        ct_op: |ct| ct,
+                        opaque_ty_id,
+                        identity_substs,
+                        binder_index: ty::INNERMOST,
                     })
                 })
                 .filter_map(|bound| {
@@ -739,3 +729,38 @@ fn binders_for<'tcx>(
         }),
     )
 }
+
+struct ReplaceOpaqueTyFolder<'tcx> {
+    tcx: TyCtxt<'tcx>,
+    opaque_ty_id: chalk_ir::OpaqueTyId<RustInterner<'tcx>>,
+    identity_substs: SubstsRef<'tcx>,
+    binder_index: ty::DebruijnIndex,
+}
+
+impl<'tcx> ty::TypeFolder<'tcx> for ReplaceOpaqueTyFolder<'tcx> {
+    fn tcx<'b>(&'b self) -> TyCtxt<'tcx> {
+        self.tcx
+    }
+
+    fn fold_binder<T: TypeFoldable<'tcx>>(
+        &mut self,
+        t: ty::Binder<'tcx, T>,
+    ) -> ty::Binder<'tcx, T> {
+        self.binder_index.shift_in(1);
+        let t = t.super_fold_with(self);
+        self.binder_index.shift_out(1);
+        t
+    }
+
+    fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
+        if let ty::Opaque(def_id, substs) = *ty.kind() {
+            if def_id == self.opaque_ty_id.0 && substs == self.identity_substs {
+                return self.tcx.mk_ty(ty::Bound(
+                    self.binder_index,
+                    ty::BoundTy::from(ty::BoundVar::from_u32(0)),
+                ));
+            }
+        }
+        ty
+    }
+}
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 2cd179526bf..e3c865ce9e6 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -323,7 +323,10 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
             ty::Closure(def_id, substs) => {
                 chalk_ir::TyKind::Closure(chalk_ir::ClosureId(def_id), substs.lower_into(interner))
             }
-            ty::Generator(_def_id, _substs, _) => unimplemented!(),
+            ty::Generator(def_id, substs, _) => chalk_ir::TyKind::Generator(
+                chalk_ir::GeneratorId(def_id),
+                substs.lower_into(interner),
+            ),
             ty::GeneratorWitness(_) => unimplemented!(),
             ty::Never => chalk_ir::TyKind::Never,
             ty::Tuple(types) => {
diff --git a/compiler/rustc_typeck/src/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs
index b16bf33f06a..a06b37627e3 100644
--- a/compiler/rustc_typeck/src/astconv/generics.rs
+++ b/compiler/rustc_typeck/src/astconv/generics.rs
@@ -512,62 +512,70 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             explicit_late_bound == ExplicitLateBound::Yes,
         );
 
-        let mut check_types_and_consts =
-            |expected_min, expected_max, provided, params_offset, args_offset| {
-                debug!(
-                    ?expected_min,
-                    ?expected_max,
-                    ?provided,
-                    ?params_offset,
-                    ?args_offset,
-                    "check_types_and_consts"
+        let mut check_types_and_consts = |expected_min,
+                                          expected_max,
+                                          expected_max_with_synth,
+                                          provided,
+                                          params_offset,
+                                          args_offset| {
+            debug!(
+                ?expected_min,
+                ?expected_max,
+                ?provided,
+                ?params_offset,
+                ?args_offset,
+                "check_types_and_consts"
+            );
+            if (expected_min..=expected_max).contains(&provided) {
+                return true;
+            }
+
+            let num_default_params = expected_max - expected_min;
+
+            let gen_args_info = if provided > expected_max {
+                invalid_args.extend(
+                    gen_args.args[args_offset + expected_max..args_offset + provided]
+                        .iter()
+                        .map(|arg| arg.span()),
                 );
-                if (expected_min..=expected_max).contains(&provided) {
-                    return true;
+                let num_redundant_args = provided - expected_max;
+
+                // Provide extra note if synthetic arguments like `impl Trait` are specified.
+                let synth_provided = provided <= expected_max_with_synth;
+
+                GenericArgsInfo::ExcessTypesOrConsts {
+                    num_redundant_args,
+                    num_default_params,
+                    args_offset,
+                    synth_provided,
                 }
+            } else {
+                let num_missing_args = expected_max - provided;
 
-                let num_default_params = expected_max - expected_min;
-
-                let gen_args_info = if provided > expected_max {
-                    invalid_args.extend(
-                        gen_args.args[args_offset + expected_max..args_offset + provided]
-                            .iter()
-                            .map(|arg| arg.span()),
-                    );
-                    let num_redundant_args = provided - expected_max;
-
-                    GenericArgsInfo::ExcessTypesOrConsts {
-                        num_redundant_args,
-                        num_default_params,
-                        args_offset,
-                    }
-                } else {
-                    let num_missing_args = expected_max - provided;
-
-                    GenericArgsInfo::MissingTypesOrConsts {
-                        num_missing_args,
-                        num_default_params,
-                        args_offset,
-                    }
-                };
-
-                debug!(?gen_args_info);
-
-                WrongNumberOfGenericArgs::new(
-                    tcx,
-                    gen_args_info,
-                    seg,
-                    gen_params,
-                    params_offset,
-                    gen_args,
-                    def_id,
-                )
-                .diagnostic()
-                .emit_unless(gen_args.has_err());
-
-                false
+                GenericArgsInfo::MissingTypesOrConsts {
+                    num_missing_args,
+                    num_default_params,
+                    args_offset,
+                }
             };
 
+            debug!(?gen_args_info);
+
+            WrongNumberOfGenericArgs::new(
+                tcx,
+                gen_args_info,
+                seg,
+                gen_params,
+                params_offset,
+                gen_args,
+                def_id,
+            )
+            .diagnostic()
+            .emit_unless(gen_args.has_err());
+
+            false
+        };
+
         let args_correct = {
             let expected_min = if infer_args {
                 0
@@ -582,6 +590,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             check_types_and_consts(
                 expected_min,
                 param_counts.consts + named_type_param_count,
+                param_counts.consts + named_type_param_count + synth_type_param_count,
                 gen_args.num_generic_params(),
                 param_counts.lifetimes + has_self as usize,
                 gen_args.num_lifetime_params(),
diff --git a/compiler/rustc_typeck/src/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs
index 4ab654560ea..a42ed9eab64 100644
--- a/compiler/rustc_typeck/src/check/wfcheck.rs
+++ b/compiler/rustc_typeck/src/check/wfcheck.rs
@@ -31,6 +31,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode,
 
 use std::convert::TryInto;
 use std::iter;
+use std::lazy::Lazy;
 use std::ops::ControlFlow;
 
 /// Helper type of a temporary returned by `.for_item(...)`.
@@ -1720,8 +1721,29 @@ fn check_variances_for_type_defn<'tcx>(
 
     identify_constrained_generic_params(tcx, ty_predicates, None, &mut constrained_parameters);
 
+    // Lazily calculated because it is only needed in case of an error.
+    let explicitly_bounded_params = Lazy::new(|| {
+        let icx = crate::collect::ItemCtxt::new(tcx, item.def_id.to_def_id());
+        hir_generics
+            .where_clause
+            .predicates
+            .iter()
+            .filter_map(|predicate| match predicate {
+                hir::WherePredicate::BoundPredicate(predicate) => {
+                    match icx.to_ty(predicate.bounded_ty).kind() {
+                        ty::Param(data) => Some(Parameter(data.index)),
+                        _ => None,
+                    }
+                }
+                _ => None,
+            })
+            .collect::<FxHashSet<_>>()
+    });
+
     for (index, _) in variances.iter().enumerate() {
-        if constrained_parameters.contains(&Parameter(index as u32)) {
+        let parameter = Parameter(index as u32);
+
+        if constrained_parameters.contains(&parameter) {
             continue;
         }
 
@@ -1730,13 +1752,19 @@ fn check_variances_for_type_defn<'tcx>(
         match param.name {
             hir::ParamName::Error => {}
             _ => {
-                report_bivariance(tcx, param);
+                let has_explicit_bounds =
+                    !param.bounds.is_empty() || explicitly_bounded_params.contains(&parameter);
+                report_bivariance(tcx, param, has_explicit_bounds);
             }
         }
     }
 }
 
-fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) -> ErrorReported {
+fn report_bivariance(
+    tcx: TyCtxt<'_>,
+    param: &rustc_hir::GenericParam<'_>,
+    has_explicit_bounds: bool,
+) -> ErrorReported {
     let span = param.span;
     let param_name = param.name.ident().name;
     let mut err = error_392(tcx, span, param_name);
@@ -1754,7 +1782,7 @@ fn report_bivariance(tcx: TyCtxt<'_>, param: &rustc_hir::GenericParam<'_>) -> Er
     };
     err.help(&msg);
 
-    if matches!(param.kind, rustc_hir::GenericParamKind::Type { .. }) {
+    if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds {
         err.help(&format!(
             "if you intended `{0}` to be a const parameter, use `const {0}: usize` instead",
             param_name
diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs
index 40904c1dfd6..f0289fd505a 100644
--- a/compiler/rustc_typeck/src/lib.rs
+++ b/compiler/rustc_typeck/src/lib.rs
@@ -68,6 +68,7 @@ This API is completely unstable and subject to change.
 #![feature(slice_partition_dedup)]
 #![feature(control_flow_enum)]
 #![feature(hash_drain_filter)]
+#![feature(once_cell)]
 #![recursion_limit = "256"]
 #![allow(rustc::potential_query_instability)]
 
diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
index b763b51dd01..62f89a2e6cf 100644
--- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs
@@ -84,6 +84,9 @@ pub enum GenericArgsInfo {
         // us infer the position of type and const generic arguments
         // in the angle brackets
         args_offset: usize,
+
+        // if synthetic type arguments (e.g. `impl Trait`) are specified
+        synth_provided: bool,
     },
 }
 
@@ -254,6 +257,13 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
         }
     }
 
+    fn is_synth_provided(&self) -> bool {
+        match self.gen_args_info {
+            ExcessTypesOrConsts { synth_provided, .. } => synth_provided,
+            _ => false,
+        }
+    }
+
     // Helper function to choose a quantifier word for the number of expected arguments
     // and to give a bound for the number of expected arguments
     fn get_quantifier_and_bound(&self) -> (&'static str, usize) {
@@ -780,6 +790,15 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
 
         err.span_note(spans, &msg);
     }
+
+    /// Add note if `impl Trait` is explicitly specified.
+    fn note_synth_provided(&self, err: &mut Diagnostic) {
+        if !self.is_synth_provided() {
+            return;
+        }
+
+        err.note("`impl Trait` cannot be explicitly specified as a generic argument");
+    }
 }
 
 impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> {
@@ -797,6 +816,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for WrongNumberOfGenericArgs<'_, 'tcx> {
         self.notify(&mut err);
         self.suggest(&mut err);
         self.show_definition(&mut err);
+        self.note_synth_provided(&mut err);
 
         err
     }
diff --git a/src/test/ui/chalkify/bugs/async.rs b/src/test/ui/chalkify/bugs/async.rs
new file mode 100644
index 00000000000..58fc93064ed
--- /dev/null
+++ b/src/test/ui/chalkify/bugs/async.rs
@@ -0,0 +1,9 @@
+// check-fail
+// known-bug
+// compile-flags: -Z chalk --edition=2021
+
+fn main() -> () {}
+
+async fn foo(x: u32) -> u32 {
+    x
+}
diff --git a/src/test/ui/chalkify/bugs/async.stderr b/src/test/ui/chalkify/bugs/async.stderr
new file mode 100644
index 00000000000..7a86561bcb9
--- /dev/null
+++ b/src/test/ui/chalkify/bugs/async.stderr
@@ -0,0 +1,39 @@
+error[E0277]: the trait bound `[static generator@$DIR/async.rs:7:29: 9:2]: Generator<ResumeTy>` is not satisfied
+  --> $DIR/async.rs:7:29
+   |
+LL |   async fn foo(x: u32) -> u32 {
+   |  _____________________________^
+LL | |     x
+LL | | }
+   | |_^ the trait `Generator<ResumeTy>` is not implemented for `[static generator@$DIR/async.rs:7:29: 9:2]`
+   |
+note: required by a bound in `from_generator`
+  --> $SRC_DIR/core/src/future/mod.rs:LL:COL
+   |
+LL |     T: Generator<ResumeTy, Yield = ()>,
+   |        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `from_generator`
+
+error[E0280]: the requirement `<[static generator@$DIR/async.rs:7:29: 9:2] as Generator<ResumeTy>>::Yield == ()` is not satisfied
+  --> $DIR/async.rs:7:29
+   |
+LL |   async fn foo(x: u32) -> u32 {
+   |  _____________________________^
+LL | |     x
+LL | | }
+   | |_^
+   |
+note: required by a bound in `from_generator`
+  --> $SRC_DIR/core/src/future/mod.rs:LL:COL
+   |
+LL |     T: Generator<ResumeTy, Yield = ()>,
+   |                            ^^^^^^^^^^ required by this bound in `from_generator`
+
+error[E0280]: the requirement `<impl Future<Output = [async output]> as Future>::Output == u32` is not satisfied
+  --> $DIR/async.rs:7:25
+   |
+LL | async fn foo(x: u32) -> u32 {
+   |                         ^^^
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
index 3add0429d2d..2ae7745c725 100644
--- a/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
+++ b/src/test/ui/impl-trait/explicit-generic-args-with-impl-trait/explicit-generic-args-for-impl.stderr
@@ -11,6 +11,7 @@ note: function defined here, with 1 generic parameter: `T`
    |
 LL | fn foo<T: ?Sized>(_f: impl AsRef<T>) {}
    |    ^^^ -
+   = note: `impl Trait` cannot be explicitly specified as a generic argument
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-17904-2.stderr b/src/test/ui/issues/issue-17904-2.stderr
index 259e029113d..62b7b79538c 100644
--- a/src/test/ui/issues/issue-17904-2.stderr
+++ b/src/test/ui/issues/issue-17904-2.stderr
@@ -5,7 +5,6 @@ LL | struct Foo<T> where T: Copy;
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr
index 82bb51028c9..895479986f1 100644
--- a/src/test/ui/issues/issue-37534.stderr
+++ b/src/test/ui/issues/issue-37534.stderr
@@ -22,7 +22,6 @@ LL | struct Foo<T: ?Hash> { }
    |            ^ unused parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
 error: aborting due to 2 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/variance/variance-unused-type-param.rs b/src/test/ui/variance/variance-unused-type-param.rs
index 1e0e403ebce..d1114064364 100644
--- a/src/test/ui/variance/variance-unused-type-param.rs
+++ b/src/test/ui/variance/variance-unused-type-param.rs
@@ -16,4 +16,13 @@ enum ListCell<T> {
     Nil
 }
 
+struct WithBounds<T: Sized> {}
+//~^ ERROR parameter `T` is never used
+
+struct WithWhereBounds<T> where T: Sized {}
+//~^ ERROR parameter `T` is never used
+
+struct WithOutlivesBounds<T: 'static> {}
+//~^ ERROR parameter `T` is never used
+
 fn main() {}
diff --git a/src/test/ui/variance/variance-unused-type-param.stderr b/src/test/ui/variance/variance-unused-type-param.stderr
index 270233c0c97..e612da118f0 100644
--- a/src/test/ui/variance/variance-unused-type-param.stderr
+++ b/src/test/ui/variance/variance-unused-type-param.stderr
@@ -25,6 +25,30 @@ LL | enum ListCell<T> {
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
    = help: if you intended `T` to be a const parameter, use `const T: usize` instead
 
-error: aborting due to 3 previous errors
+error[E0392]: parameter `T` is never used
+  --> $DIR/variance-unused-type-param.rs:19:19
+   |
+LL | struct WithBounds<T: Sized> {}
+   |                   ^ unused parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: parameter `T` is never used
+  --> $DIR/variance-unused-type-param.rs:22:24
+   |
+LL | struct WithWhereBounds<T> where T: Sized {}
+   |                        ^ unused parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0392]: parameter `T` is never used
+  --> $DIR/variance-unused-type-param.rs:25:27
+   |
+LL | struct WithOutlivesBounds<T: 'static> {}
+   |                           ^ unused parameter
+   |
+   = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
+
+error: aborting due to 6 previous errors
 
 For more information about this error, try `rustc --explain E0392`.
diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs
index 2a23d72edc0..f6be550283a 100644
--- a/src/tools/tidy/src/error_codes_check.rs
+++ b/src/tools/tidy/src/error_codes_check.rs
@@ -10,8 +10,8 @@ use regex::Regex;
 
 // A few of those error codes can't be tested but all the others can and *should* be tested!
 const EXEMPTED_FROM_TEST: &[&str] = &[
-    "E0279", "E0280", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514", "E0519",
-    "E0523", "E0554", "E0640", "E0717", "E0729",
+    "E0279", "E0313", "E0377", "E0461", "E0462", "E0465", "E0476", "E0514", "E0519", "E0523",
+    "E0554", "E0640", "E0717", "E0729",
 ];
 
 // Some error codes don't have any tests apparently...