about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0091.md6
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl11
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs77
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs64
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs24
-rw-r--r--tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr6
-rw-r--r--tests/ui/const-generics/issue-46511.stderr4
-rw-r--r--tests/ui/const-generics/issues/issue-67375.min.stderr6
-rw-r--r--tests/ui/const-generics/issues/issue-67945-1.min.stderr6
-rw-r--r--tests/ui/const-generics/issues/issue-67945-3.min.stderr6
-rw-r--r--tests/ui/const-generics/issues/issue-67945-4.min.stderr6
-rw-r--r--tests/ui/const-generics/unused-type-param-suggestion.rs27
-rw-r--r--tests/ui/const-generics/unused-type-param-suggestion.stderr56
-rw-r--r--tests/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr6
-rw-r--r--tests/ui/enum/issue-67945-1.stderr6
-rw-r--r--tests/ui/enum/issue-67945-2.stderr6
-rw-r--r--tests/ui/error-codes/E0091.stderr10
-rw-r--r--tests/ui/error-codes/E0392.stderr6
-rw-r--r--tests/ui/inner-static-type-parameter.stderr6
-rw-r--r--tests/ui/issues/issue-17904-2.stderr4
-rw-r--r--tests/ui/issues/issue-17994.rs2
-rw-r--r--tests/ui/issues/issue-17994.stderr4
-rw-r--r--tests/ui/issues/issue-20413.stderr6
-rw-r--r--tests/ui/issues/issue-30236.rs2
-rw-r--r--tests/ui/issues/issue-30236.stderr5
-rw-r--r--tests/ui/issues/issue-31910.stderr4
-rw-r--r--tests/ui/issues/issue-34373.stderr6
-rw-r--r--tests/ui/issues/issue-36299.stderr10
-rw-r--r--tests/ui/issues/issue-37534.stderr4
-rw-r--r--tests/ui/lang-items/lang-item-generic-requirements.stderr12
-rw-r--r--tests/ui/lazy-type-alias/unused-generic-parameters.rs22
-rw-r--r--tests/ui/lazy-type-alias/unused-generic-parameters.stderr28
-rw-r--r--tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr8
-rw-r--r--tests/ui/parser/item-free-type-bounds-semantic-fail.rs4
-rw-r--r--tests/ui/parser/item-free-type-bounds-semantic-fail.stderr10
-rw-r--r--tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr4
-rw-r--r--tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr4
-rw-r--r--tests/ui/self/self_type_keyword.stderr4
-rw-r--r--tests/ui/tag-type-args.stderr6
-rw-r--r--tests/ui/variance/variance-regions-unused-direct.stderr8
-rw-r--r--tests/ui/variance/variance-regions-unused-indirect.stderr8
-rw-r--r--tests/ui/variance/variance-unused-region-param.stderr8
-rw-r--r--tests/ui/variance/variance-unused-type-param.stderr30
43 files changed, 371 insertions, 171 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0091.md b/compiler/rustc_error_codes/src/error_codes/E0091.md
index 03cb3280371..3bf4e907ecb 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0091.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0091.md
@@ -1,11 +1,11 @@
-An unnecessary type or const parameter was given in a type alias.
+An unnecessary type parameter was given in a type alias.
 
 Erroneous code example:
 
 ```compile_fail,E0091
-type Foo<T> = u32; // error: type parameter `T` is unused
+type Foo<T> = u32; // error: type parameter `T` is never used
 // or:
-type Foo<A,B> = Box<A>; // error: type parameter `B` is unused
+type Foo<A, B> = Box<A>; // error: type parameter `B` is never used
 ```
 
 Please check you didn't write too many parameters. Example:
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 432c9c12cbf..54d0fb6ffab 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -434,6 +434,17 @@ hir_analysis_unused_associated_type_bounds =
     .note = this associated type has a `where Self: Sized` bound. Thus, while the associated type can be specified, it cannot be used in any way, because trait objects are not `Sized`.
     .suggestion = remove this bound
 
+hir_analysis_unused_generic_parameter =
+    {$param_def_kind} `{$param_name}` is never used
+    .label = unused {$param_def_kind}
+    .const_param_help = if you intended `{$param_name}` to be a const parameter, use `const {$param_name}: /* Type */` instead
+hir_analysis_unused_generic_parameter_adt_help =
+    consider removing `{$param_name}`, referring to it in a field, or using a marker such as `{$phantom_data}`
+hir_analysis_unused_generic_parameter_adt_no_phantom_data_help =
+    consider removing `{$param_name}` or referring to it in a field
+hir_analysis_unused_generic_parameter_ty_alias_help =
+    consider removing `{$param_name}` or referring to it in the body of the type alias
+
 hir_analysis_value_of_associated_struct_already_specified =
     the value of the associated type `{$item_name}` in trait `{$def_path}` is already specified
     .label = re-bound here
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 2fe3499e8e6..50809a571b8 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -31,6 +31,7 @@ use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt as _};
 use rustc_type_ir::fold::TypeFoldable;
 
+use std::cell::LazyCell;
 use std::ops::ControlFlow;
 
 pub fn check_abi(tcx: TyCtxt<'_>, hir_id: hir::HirId, span: Span, abi: Abi) {
@@ -520,9 +521,7 @@ pub(crate) fn check_item_type(tcx: TyCtxt<'_>, def_id: LocalDefId) {
             }
         }
         DefKind::TyAlias => {
-            let pty_ty = tcx.type_of(def_id).instantiate_identity();
-            let generics = tcx.generics_of(def_id);
-            check_type_params_are_used(tcx, generics, pty_ty);
+            check_type_alias_type_params_are_used(tcx, def_id);
         }
         DefKind::ForeignMod => {
             let it = tcx.hir().expect_item(def_id);
@@ -1269,28 +1268,51 @@ fn detect_discriminant_duplicate<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
     }
 }
 
-pub(super) fn check_type_params_are_used<'tcx>(
-    tcx: TyCtxt<'tcx>,
-    generics: &ty::Generics,
-    ty: Ty<'tcx>,
-) {
-    debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty);
-
-    assert_eq!(generics.parent, None);
+fn check_type_alias_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {
+    if tcx.type_alias_is_lazy(def_id) {
+        // Since we compute the variances for lazy type aliases and already reject bivariant
+        // parameters as unused, we can and should skip this check for lazy type aliases.
+        return;
+    }
 
+    let generics = tcx.generics_of(def_id);
     if generics.own_counts().types == 0 {
         return;
     }
 
-    let mut params_used = BitSet::new_empty(generics.params.len());
-
+    let ty = tcx.type_of(def_id).instantiate_identity();
     if ty.references_error() {
-        // If there is already another error, do not emit
-        // an error for not using a type parameter.
+        // If there is already another error, do not emit an error for not using a type parameter.
         assert!(tcx.dcx().has_errors().is_some());
         return;
     }
 
+    // Lazily calculated because it is only needed in case of an error.
+    let bounded_params = LazyCell::new(|| {
+        tcx.explicit_predicates_of(def_id)
+            .predicates
+            .iter()
+            .filter_map(|(predicate, span)| {
+                let bounded_ty = match predicate.kind().skip_binder() {
+                    ty::ClauseKind::Trait(pred) => pred.trait_ref.self_ty(),
+                    ty::ClauseKind::TypeOutlives(pred) => pred.0,
+                    _ => return None,
+                };
+                if let ty::Param(param) = bounded_ty.kind() {
+                    Some((param.index, span))
+                } else {
+                    None
+                }
+            })
+            // FIXME: This assumes that elaborated `Sized` bounds come first (which does hold at the
+            // time of writing). This is a bit fragile since we later use the span to detect elaborated
+            // `Sized` bounds. If they came last for example, this would break `Trait + /*elab*/Sized`
+            // since it would overwrite the span of the user-written bound. This could be fixed by
+            // folding the spans with `Span::to` which requires a bit of effort I think.
+            .collect::<FxHashMap<_, _>>()
+    });
+
+    let mut params_used = BitSet::new_empty(generics.params.len());
     for leaf in ty.walk() {
         if let GenericArgKind::Type(leaf_ty) = leaf.unpack()
             && let ty::Param(param) = leaf_ty.kind()
@@ -1305,15 +1327,24 @@ pub(super) fn check_type_params_are_used<'tcx>(
             && let ty::GenericParamDefKind::Type { .. } = param.kind
         {
             let span = tcx.def_span(param.def_id);
-            struct_span_code_err!(
-                tcx.dcx(),
+            let param_name = Ident::new(param.name, span);
+
+            // The corresponding predicates are post-`Sized`-elaboration. Therefore we
+            // * check for emptiness to detect lone user-written `?Sized` bounds
+            // * compare the param span to the pred span to detect lone user-written `Sized` bounds
+            let has_explicit_bounds = bounded_params.is_empty()
+                || (*bounded_params).get(&param.index).is_some_and(|&&pred_sp| pred_sp != span);
+            let const_param_help = (!has_explicit_bounds).then_some(());
+
+            let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
                 span,
-                E0091,
-                "type parameter `{}` is unused",
-                param.name,
-            )
-            .with_span_label(span, "unused type parameter")
-            .emit();
+                param_name,
+                param_def_kind: tcx.def_descr(param.def_id),
+                help: errors::UnusedGenericParameterHelp::TyAlias { param_name },
+                const_param_help,
+            });
+            diag.code(E0091);
+            diag.emit();
         }
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index b9c9eec2813..07f798dcbda 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1,11 +1,10 @@
 use crate::autoderef::Autoderef;
 use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
+use crate::errors;
 
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
-use rustc_errors::{
-    codes::*, pluralize, struct_span_code_err, Applicability, DiagnosticBuilder, ErrorGuaranteed,
-};
+use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, ErrorGuaranteed};
 use rustc_hir as hir;
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::lang_items::LangItem;
@@ -21,7 +20,7 @@ use rustc_middle::ty::{
 };
 use rustc_middle::ty::{GenericArgKind, GenericArgs};
 use rustc_session::parse::feature_err;
-use rustc_span::symbol::{sym, Ident, Symbol};
+use rustc_span::symbol::{sym, Ident};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
 use rustc_trait_selection::regions::InferCtxtRegionExt;
@@ -1869,7 +1868,7 @@ fn check_variances_for_type_defn<'tcx>(
             hir::ParamName::Error => {}
             _ => {
                 let has_explicit_bounds = explicitly_bounded_params.contains(&parameter);
-                report_bivariance(tcx, hir_param, has_explicit_bounds);
+                report_bivariance(tcx, hir_param, has_explicit_bounds, item.kind);
             }
         }
     }
@@ -1879,30 +1878,38 @@ fn report_bivariance(
     tcx: TyCtxt<'_>,
     param: &rustc_hir::GenericParam<'_>,
     has_explicit_bounds: bool,
+    item_kind: ItemKind<'_>,
 ) -> ErrorGuaranteed {
-    let span = param.span;
-    let param_name = param.name.ident().name;
-    let mut err = error_392(tcx, span, param_name);
-
-    let suggested_marker_id = tcx.lang_items().phantom_data();
-    // Help is available only in presence of lang items.
-    let msg = if let Some(def_id) = suggested_marker_id {
-        format!(
-            "consider removing `{}`, referring to it in a field, or using a marker such as `{}`",
-            param_name,
-            tcx.def_path_str(def_id),
-        )
-    } else {
-        format!("consider removing `{param_name}` or referring to it in a field")
+    let param_name = param.name.ident();
+
+    let help = match item_kind {
+        ItemKind::Enum(..) | ItemKind::Struct(..) | ItemKind::Union(..) => {
+            if let Some(def_id) = tcx.lang_items().phantom_data() {
+                errors::UnusedGenericParameterHelp::Adt {
+                    param_name,
+                    phantom_data: tcx.def_path_str(def_id),
+                }
+            } else {
+                errors::UnusedGenericParameterHelp::AdtNoPhantomData { param_name }
+            }
+        }
+        ItemKind::TyAlias(..) => errors::UnusedGenericParameterHelp::TyAlias { param_name },
+        item_kind => bug!("report_bivariance: unexpected item kind: {item_kind:?}"),
     };
-    err.help(msg);
 
-    if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds {
-        err.help(format!(
-            "if you intended `{param_name}` to be a const parameter, use `const {param_name}: usize` instead"
-        ));
-    }
-    err.emit()
+    let const_param_help =
+        matches!(param.kind, hir::GenericParamKind::Type { .. } if !has_explicit_bounds)
+            .then_some(());
+
+    let mut diag = tcx.dcx().create_err(errors::UnusedGenericParameter {
+        span: param.span,
+        param_name,
+        param_def_kind: tcx.def_descr(param.def_id.to_def_id()),
+        help,
+        const_param_help,
+    });
+    diag.code(E0392);
+    diag.emit()
 }
 
 impl<'tcx> WfCheckingCtxt<'_, 'tcx> {
@@ -1967,11 +1974,6 @@ fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), Error
     res
 }
 
-fn error_392(tcx: TyCtxt<'_>, span: Span, param_name: Symbol) -> DiagnosticBuilder<'_> {
-    struct_span_code_err!(tcx.dcx(), span, E0392, "parameter `{param_name}` is never used")
-        .with_span_label(span, "unused parameter")
-}
-
 pub fn provide(providers: &mut Providers) {
     *providers = Providers { check_mod_type_wf, check_well_formed, ..*providers };
 }
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index e5871276d64..4eba31e327f 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -1511,3 +1511,27 @@ pub struct NotSupportedDelegation<'a> {
     #[label]
     pub callee_span: Span,
 }
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_unused_generic_parameter)]
+pub(crate) struct UnusedGenericParameter {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub param_name: Ident,
+    pub param_def_kind: &'static str,
+    #[subdiagnostic]
+    pub help: UnusedGenericParameterHelp,
+    #[help(hir_analysis_const_param_help)]
+    pub const_param_help: Option<()>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum UnusedGenericParameterHelp {
+    #[help(hir_analysis_unused_generic_parameter_adt_help)]
+    Adt { param_name: Ident, phantom_data: String },
+    #[help(hir_analysis_unused_generic_parameter_adt_no_phantom_data_help)]
+    AdtNoPhantomData { param_name: Ident },
+    #[help(hir_analysis_unused_generic_parameter_ty_alias_help)]
+    TyAlias { param_name: Ident },
+}
diff --git a/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr b/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr
index a6b736261e0..6d8dd017734 100644
--- a/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr
+++ b/tests/ui/const-generics/generic_arg_infer/infer-arg-test.stderr
@@ -10,14 +10,14 @@ error: expected identifier, found reserved identifier `_`
 LL | fn bad_infer_fn<_>() {}
    |                 ^ expected identifier, found reserved identifier
 
-error[E0392]: parameter `_` is never used
+error[E0392]: type parameter `_` is never used
   --> $DIR/infer-arg-test.rs:7:17
    |
 LL | struct BadInfer<_>;
-   |                 ^ unused parameter
+   |                 ^ unused type parameter
    |
    = help: consider removing `_`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `_` to be a const parameter, use `const _: usize` instead
+   = help: if you intended `_` to be a const parameter, use `const _: /* Type */` instead
 
 error[E0107]: struct takes 2 generic arguments but 3 generic arguments were supplied
   --> $DIR/infer-arg-test.rs:18:10
diff --git a/tests/ui/const-generics/issue-46511.stderr b/tests/ui/const-generics/issue-46511.stderr
index d57295fa2fa..75d59ee40b3 100644
--- a/tests/ui/const-generics/issue-46511.stderr
+++ b/tests/ui/const-generics/issue-46511.stderr
@@ -7,11 +7,11 @@ LL |     _a: [u8; std::mem::size_of::<&'a mut u8>()]
    = note: lifetime parameters may not be used in const expressions
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
-error[E0392]: parameter `'a` is never used
+error[E0392]: lifetime parameter `'a` is never used
   --> $DIR/issue-46511.rs:3:12
    |
 LL | struct Foo<'a>
-   |            ^^ unused parameter
+   |            ^^ unused lifetime parameter
    |
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/const-generics/issues/issue-67375.min.stderr b/tests/ui/const-generics/issues/issue-67375.min.stderr
index 7671e3c4688..e871203ed9b 100644
--- a/tests/ui/const-generics/issues/issue-67375.min.stderr
+++ b/tests/ui/const-generics/issues/issue-67375.min.stderr
@@ -7,14 +7,14 @@ LL |     inner: [(); { [|_: &T| {}; 0].len() }],
    = note: type parameters may not be used in const expressions
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/issue-67375.rs:5:12
    |
 LL | struct Bug<T> {
-   |            ^ unused parameter
+   |            ^ unused type 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
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-67945-1.min.stderr b/tests/ui/const-generics/issues/issue-67945-1.min.stderr
index 1d071da903f..1de607644f5 100644
--- a/tests/ui/const-generics/issues/issue-67945-1.min.stderr
+++ b/tests/ui/const-generics/issues/issue-67945-1.min.stderr
@@ -16,14 +16,14 @@ LL |         let b = &*(&x as *const _ as *const S);
    = note: type parameters may not be used in const expressions
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
-error[E0392]: parameter `S` is never used
+error[E0392]: type parameter `S` is never used
   --> $DIR/issue-67945-1.rs:7:12
    |
 LL | struct Bug<S> {
-   |            ^ unused parameter
+   |            ^ unused type parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
+   = help: if you intended `S` to be a const parameter, use `const S: /* Type */` instead
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-67945-3.min.stderr b/tests/ui/const-generics/issues/issue-67945-3.min.stderr
index e34869c7938..0ccba18e953 100644
--- a/tests/ui/const-generics/issues/issue-67945-3.min.stderr
+++ b/tests/ui/const-generics/issues/issue-67945-3.min.stderr
@@ -7,14 +7,14 @@ LL |         let x: Option<S> = None;
    = note: type parameters may not be used in const expressions
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
-error[E0392]: parameter `S` is never used
+error[E0392]: type parameter `S` is never used
   --> $DIR/issue-67945-3.rs:9:12
    |
 LL | struct Bug<S> {
-   |            ^ unused parameter
+   |            ^ unused type parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
+   = help: if you intended `S` to be a const parameter, use `const S: /* Type */` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/issues/issue-67945-4.min.stderr b/tests/ui/const-generics/issues/issue-67945-4.min.stderr
index 280c6f4f2cd..83ae68e2dbf 100644
--- a/tests/ui/const-generics/issues/issue-67945-4.min.stderr
+++ b/tests/ui/const-generics/issues/issue-67945-4.min.stderr
@@ -7,14 +7,14 @@ LL |         let x: Option<Box<S>> = None;
    = note: type parameters may not be used in const expressions
    = help: add `#![feature(generic_const_exprs)]` to allow generic const expressions
 
-error[E0392]: parameter `S` is never used
+error[E0392]: type parameter `S` is never used
   --> $DIR/issue-67945-4.rs:8:12
    |
 LL | struct Bug<S> {
-   |            ^ unused parameter
+   |            ^ unused type parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
+   = help: if you intended `S` to be a const parameter, use `const S: /* Type */` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/const-generics/unused-type-param-suggestion.rs b/tests/ui/const-generics/unused-type-param-suggestion.rs
index 2251512c459..fb0ccb4fdcd 100644
--- a/tests/ui/const-generics/unused-type-param-suggestion.rs
+++ b/tests/ui/const-generics/unused-type-param-suggestion.rs
@@ -1,4 +1,27 @@
 #![crate_type="lib"]
 
-struct Example<N>;
-//~^ ERROR parameter
+struct S<N>;
+//~^ ERROR type parameter `N` is never used
+//~| HELP consider removing `N`
+//~| HELP if you intended `N` to be a const parameter
+
+// Ensure that we don't emit the const param suggestion here:
+struct T<N: Copy>;
+//~^ ERROR type parameter `N` is never used
+//~| HELP consider removing `N`
+
+type A<N> = ();
+//~^ ERROR type parameter `N` is never used
+//~| HELP consider removing `N`
+//~| HELP if you intended `N` to be a const parameter
+
+// Ensure that we don't emit the const param suggestion here:
+type B<N: Copy> = ();
+//~^ ERROR type parameter `N` is never used
+//~| HELP consider removing `N`
+type C<N: Sized> = ();
+//~^ ERROR type parameter `N` is never used
+//~| HELP consider removing `N`
+type D<N: ?Sized> = ();
+//~^ ERROR type parameter `N` is never used
+//~| HELP consider removing `N`
diff --git a/tests/ui/const-generics/unused-type-param-suggestion.stderr b/tests/ui/const-generics/unused-type-param-suggestion.stderr
index 6e985f56666..67b704d8bc7 100644
--- a/tests/ui/const-generics/unused-type-param-suggestion.stderr
+++ b/tests/ui/const-generics/unused-type-param-suggestion.stderr
@@ -1,12 +1,54 @@
-error[E0392]: parameter `N` is never used
-  --> $DIR/unused-type-param-suggestion.rs:3:16
+error[E0392]: type parameter `N` is never used
+  --> $DIR/unused-type-param-suggestion.rs:3:10
    |
-LL | struct Example<N>;
-   |                ^ unused parameter
+LL | struct S<N>;
+   |          ^ unused type parameter
    |
    = help: consider removing `N`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `N` to be a const parameter, use `const N: usize` instead
+   = help: if you intended `N` to be a const parameter, use `const N: /* Type */` instead
 
-error: aborting due to 1 previous error
+error[E0392]: type parameter `N` is never used
+  --> $DIR/unused-type-param-suggestion.rs:9:10
+   |
+LL | struct T<N: Copy>;
+   |          ^ unused type parameter
+   |
+   = help: consider removing `N`, referring to it in a field, or using a marker such as `PhantomData`
+
+error[E0091]: type parameter `N` is never used
+  --> $DIR/unused-type-param-suggestion.rs:13:8
+   |
+LL | type A<N> = ();
+   |        ^ unused type parameter
+   |
+   = help: consider removing `N` or referring to it in the body of the type alias
+   = help: if you intended `N` to be a const parameter, use `const N: /* Type */` instead
+
+error[E0091]: type parameter `N` is never used
+  --> $DIR/unused-type-param-suggestion.rs:19:8
+   |
+LL | type B<N: Copy> = ();
+   |        ^ unused type parameter
+   |
+   = help: consider removing `N` or referring to it in the body of the type alias
+
+error[E0091]: type parameter `N` is never used
+  --> $DIR/unused-type-param-suggestion.rs:22:8
+   |
+LL | type C<N: Sized> = ();
+   |        ^ unused type parameter
+   |
+   = help: consider removing `N` or referring to it in the body of the type alias
+
+error[E0091]: type parameter `N` is never used
+  --> $DIR/unused-type-param-suggestion.rs:25:8
+   |
+LL | type D<N: ?Sized> = ();
+   |        ^ unused type parameter
+   |
+   = help: consider removing `N` or referring to it in the body of the type alias
+
+error: aborting due to 6 previous errors
 
-For more information about this error, try `rustc --explain E0392`.
+Some errors have detailed explanations: E0091, E0392.
+For more information about an error, try `rustc --explain E0091`.
diff --git a/tests/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr b/tests/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr
index fac3ce07aeb..1341b03cb56 100644
--- a/tests/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr
+++ b/tests/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr
@@ -6,14 +6,14 @@ LL |     Some = std::mem::size_of::<T>(),
    |
    = note: type parameters may not be used in enum discriminant values
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/issue-70453-generics-in-discr-ice.rs:7:20
    |
 LL | enum MyWeirdOption<T> {
-   |                    ^ unused parameter
+   |                    ^ unused type 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
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/enum/issue-67945-1.stderr b/tests/ui/enum/issue-67945-1.stderr
index 878fa322f02..ce0ea777636 100644
--- a/tests/ui/enum/issue-67945-1.stderr
+++ b/tests/ui/enum/issue-67945-1.stderr
@@ -6,14 +6,14 @@ LL |         let x: S = 0;
    |
    = note: type parameters may not be used in enum discriminant values
 
-error[E0392]: parameter `S` is never used
+error[E0392]: type parameter `S` is never used
   --> $DIR/issue-67945-1.rs:1:10
    |
 LL | enum Bug<S> {
-   |          ^ unused parameter
+   |          ^ unused type parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
+   = help: if you intended `S` to be a const parameter, use `const S: /* Type */` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/enum/issue-67945-2.stderr b/tests/ui/enum/issue-67945-2.stderr
index f8ec12d470a..96bd08f841a 100644
--- a/tests/ui/enum/issue-67945-2.stderr
+++ b/tests/ui/enum/issue-67945-2.stderr
@@ -6,14 +6,14 @@ LL |     Var = type_ascribe!(0, S),
    |
    = note: type parameters may not be used in enum discriminant values
 
-error[E0392]: parameter `S` is never used
+error[E0392]: type parameter `S` is never used
   --> $DIR/issue-67945-2.rs:3:10
    |
 LL | enum Bug<S> {
-   |          ^ unused parameter
+   |          ^ unused type parameter
    |
    = help: consider removing `S`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `S` to be a const parameter, use `const S: usize` instead
+   = help: if you intended `S` to be a const parameter, use `const S: /* Type */` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/error-codes/E0091.stderr b/tests/ui/error-codes/E0091.stderr
index a596b75e481..c1427ec6686 100644
--- a/tests/ui/error-codes/E0091.stderr
+++ b/tests/ui/error-codes/E0091.stderr
@@ -1,14 +1,20 @@
-error[E0091]: type parameter `T` is unused
+error[E0091]: type parameter `T` is never used
   --> $DIR/E0091.rs:1:10
    |
 LL | type Foo<T> = u32;
    |          ^ unused type parameter
+   |
+   = help: consider removing `T` or referring to it in the body of the type alias
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
-error[E0091]: type parameter `B` is unused
+error[E0091]: type parameter `B` is never used
   --> $DIR/E0091.rs:2:14
    |
 LL | type Foo2<A, B> = Box<A>;
    |              ^ unused type parameter
+   |
+   = help: consider removing `B` or referring to it in the body of the type alias
+   = help: if you intended `B` to be a const parameter, use `const B: /* Type */` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/error-codes/E0392.stderr b/tests/ui/error-codes/E0392.stderr
index ecbfd5584d5..9971267e927 100644
--- a/tests/ui/error-codes/E0392.stderr
+++ b/tests/ui/error-codes/E0392.stderr
@@ -1,11 +1,11 @@
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/E0392.rs:1:10
    |
 LL | enum Foo<T> { Bar }
-   |          ^ unused parameter
+   |          ^ unused type 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
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/inner-static-type-parameter.stderr b/tests/ui/inner-static-type-parameter.stderr
index ff6558e494b..6c7f1ffbe16 100644
--- a/tests/ui/inner-static-type-parameter.stderr
+++ b/tests/ui/inner-static-type-parameter.stderr
@@ -6,14 +6,14 @@ LL | fn foo<T>() {
 LL |     static a: Bar<T> = Bar::What;
    |                   ^ use of generic parameter from outer item
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/inner-static-type-parameter.rs:3:10
    |
 LL | enum Bar<T> { What }
-   |          ^ unused parameter
+   |          ^ unused type 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
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-17904-2.stderr b/tests/ui/issues/issue-17904-2.stderr
index 102c8537f8e..9965106d140 100644
--- a/tests/ui/issues/issue-17904-2.stderr
+++ b/tests/ui/issues/issue-17904-2.stderr
@@ -1,8 +1,8 @@
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/issue-17904-2.rs:4:12
    |
 LL | struct Foo<T> where T: Copy;
-   |            ^ unused parameter
+   |            ^ unused type parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/issues/issue-17994.rs b/tests/ui/issues/issue-17994.rs
index 39b0a7ebe74..ab37a172eaa 100644
--- a/tests/ui/issues/issue-17994.rs
+++ b/tests/ui/issues/issue-17994.rs
@@ -1,3 +1,3 @@
 trait Tr {}
-type Huh<T> where T: Tr = isize; //~  ERROR type parameter `T` is unused
+type Huh<T> where T: Tr = isize; //~ ERROR type parameter `T` is never used
 fn main() {}
diff --git a/tests/ui/issues/issue-17994.stderr b/tests/ui/issues/issue-17994.stderr
index ba3def64dfb..f149e5d08fa 100644
--- a/tests/ui/issues/issue-17994.stderr
+++ b/tests/ui/issues/issue-17994.stderr
@@ -1,8 +1,10 @@
-error[E0091]: type parameter `T` is unused
+error[E0091]: type parameter `T` is never used
   --> $DIR/issue-17994.rs:2:10
    |
 LL | type Huh<T> where T: Tr = isize;
    |          ^ unused type parameter
+   |
+   = help: consider removing `T` or referring to it in the body of the type alias
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-20413.stderr b/tests/ui/issues/issue-20413.stderr
index 8793029dd22..5d442eb9898 100644
--- a/tests/ui/issues/issue-20413.stderr
+++ b/tests/ui/issues/issue-20413.stderr
@@ -1,11 +1,11 @@
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/issue-20413.rs:6:15
    |
 LL | struct NoData<T>;
-   |               ^ unused parameter
+   |               ^ unused type 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
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
 error[E0275]: overflow evaluating the requirement `NoData<NoData<NoData<NoData<NoData<NoData<NoData<...>>>>>>>: Foo`
   --> $DIR/issue-20413.rs:9:36
diff --git a/tests/ui/issues/issue-30236.rs b/tests/ui/issues/issue-30236.rs
index 9c2d855076d..08d08a54402 100644
--- a/tests/ui/issues/issue-30236.rs
+++ b/tests/ui/issues/issue-30236.rs
@@ -1,5 +1,5 @@
 type Foo<
-    Unused //~ ERROR type parameter `Unused` is unused
+    Unused //~ ERROR type parameter `Unused` is never used
     > = u8;
 
 fn main() {
diff --git a/tests/ui/issues/issue-30236.stderr b/tests/ui/issues/issue-30236.stderr
index 0f69f49f505..bfe374a653f 100644
--- a/tests/ui/issues/issue-30236.stderr
+++ b/tests/ui/issues/issue-30236.stderr
@@ -1,8 +1,11 @@
-error[E0091]: type parameter `Unused` is unused
+error[E0091]: type parameter `Unused` is never used
   --> $DIR/issue-30236.rs:2:5
    |
 LL |     Unused
    |     ^^^^^^ unused type parameter
+   |
+   = help: consider removing `Unused` or referring to it in the body of the type alias
+   = help: if you intended `Unused` to be a const parameter, use `const Unused: /* Type */` instead
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/issues/issue-31910.stderr b/tests/ui/issues/issue-31910.stderr
index 89a6d5574a1..ca2d2f619e6 100644
--- a/tests/ui/issues/issue-31910.stderr
+++ b/tests/ui/issues/issue-31910.stderr
@@ -4,11 +4,11 @@ error[E0308]: mismatched types
 LL |     X = Trait::Number,
    |         ^^^^^^^^^^^^^ expected `isize`, found `i32`
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/issue-31910.rs:1:11
    |
 LL | enum Enum<T: Trait> {
-   |           ^ unused parameter
+   |           ^ unused type parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/issues/issue-34373.stderr b/tests/ui/issues/issue-34373.stderr
index 1a1cfc925b7..13667cd920e 100644
--- a/tests/ui/issues/issue-34373.stderr
+++ b/tests/ui/issues/issue-34373.stderr
@@ -45,14 +45,14 @@ help: alternatively, consider constraining `foo` so it does not apply to trait o
 LL |     fn foo(_: T) where Self: Sized {}
    |                  +++++++++++++++++
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/issue-34373.rs:7:16
    |
 LL | pub struct Foo<T = Box<Trait<DefaultFoo>>>;
-   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^ unused parameter
+   |                ^^^^^^^^^^^^^^^^^^^^^^^^^^ unused type 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
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/issues/issue-36299.stderr b/tests/ui/issues/issue-36299.stderr
index dc24fb353f4..29e8d7ca59a 100644
--- a/tests/ui/issues/issue-36299.stderr
+++ b/tests/ui/issues/issue-36299.stderr
@@ -1,19 +1,19 @@
-error[E0392]: parameter `'a` is never used
+error[E0392]: lifetime parameter `'a` is never used
   --> $DIR/issue-36299.rs:1:12
    |
 LL | struct Foo<'a, A> {}
-   |            ^^ unused parameter
+   |            ^^ unused lifetime parameter
    |
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
-error[E0392]: parameter `A` is never used
+error[E0392]: type parameter `A` is never used
   --> $DIR/issue-36299.rs:1:16
    |
 LL | struct Foo<'a, A> {}
-   |                ^ unused parameter
+   |                ^ unused type parameter
    |
    = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `A` to be a const parameter, use `const A: usize` instead
+   = help: if you intended `A` to be a const parameter, use `const A: /* Type */` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/issues/issue-37534.stderr b/tests/ui/issues/issue-37534.stderr
index 03fea2c1648..a687e733d3d 100644
--- a/tests/ui/issues/issue-37534.stderr
+++ b/tests/ui/issues/issue-37534.stderr
@@ -15,11 +15,11 @@ warning: relaxing a default bound only does something for `?Sized`; all other tr
 LL | struct Foo<T: ?Hash> {}
    |               ^^^^^
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/issue-37534.rs:1:12
    |
 LL | struct Foo<T: ?Hash> {}
-   |            ^ unused parameter
+   |            ^ unused type parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/lang-items/lang-item-generic-requirements.stderr b/tests/ui/lang-items/lang-item-generic-requirements.stderr
index 8072e6797e4..30abdf84046 100644
--- a/tests/ui/lang-items/lang-item-generic-requirements.stderr
+++ b/tests/ui/lang-items/lang-item-generic-requirements.stderr
@@ -50,23 +50,23 @@ LL |
 LL | fn start(_: *const u8, _: isize, _: *const *const u8) -> isize {
    |         - this function has 0 generic arguments
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/lang-item-generic-requirements.rs:24:22
    |
 LL | struct MyPhantomData<T, U>;
-   |                      ^ unused parameter
+   |                      ^ unused type parameter
    |
    = help: consider removing `T` or referring to it in a field
-   = help: if you intended `T` to be a const parameter, use `const T: usize` instead
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
-error[E0392]: parameter `U` is never used
+error[E0392]: type parameter `U` is never used
   --> $DIR/lang-item-generic-requirements.rs:24:25
    |
 LL | struct MyPhantomData<T, U>;
-   |                         ^ unused parameter
+   |                         ^ unused type parameter
    |
    = help: consider removing `U` or referring to it in a field
-   = help: if you intended `U` to be a const parameter, use `const U: usize` instead
+   = help: if you intended `U` to be a const parameter, use `const U: /* Type */` instead
 
 error[E0369]: cannot add `{integer}` to `{integer}`
   --> $DIR/lang-item-generic-requirements.rs:44:7
diff --git a/tests/ui/lazy-type-alias/unused-generic-parameters.rs b/tests/ui/lazy-type-alias/unused-generic-parameters.rs
new file mode 100644
index 00000000000..9d02de7a721
--- /dev/null
+++ b/tests/ui/lazy-type-alias/unused-generic-parameters.rs
@@ -0,0 +1,22 @@
+// Check that we reject bivariant generic parameters as unused.
+// Furthermore, check that we only emit a single diagnostic for unused type parameters:
+// Previously, we would emit *two* errors, namely E0392 and E0091.
+
+#![feature(lazy_type_alias)]
+#![allow(incomplete_features)]
+
+type A<'a> = ();
+//~^ ERROR lifetime parameter `'a` is never used
+//~| HELP consider removing `'a`
+
+type B<T> = ();
+//~^ ERROR type parameter `T` is never used
+//~| HELP consider removing `T`
+//~| HELP if you intended `T` to be a const parameter
+
+// Check that we don't emit the const param help message here:
+type C<T: Copy> = ();
+//~^ ERROR type parameter `T` is never used
+//~| HELP consider removing `T`
+
+fn main() {}
diff --git a/tests/ui/lazy-type-alias/unused-generic-parameters.stderr b/tests/ui/lazy-type-alias/unused-generic-parameters.stderr
new file mode 100644
index 00000000000..484e21b0a03
--- /dev/null
+++ b/tests/ui/lazy-type-alias/unused-generic-parameters.stderr
@@ -0,0 +1,28 @@
+error[E0392]: lifetime parameter `'a` is never used
+  --> $DIR/unused-generic-parameters.rs:8:8
+   |
+LL | type A<'a> = ();
+   |        ^^ unused lifetime parameter
+   |
+   = help: consider removing `'a` or referring to it in the body of the type alias
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/unused-generic-parameters.rs:12:8
+   |
+LL | type B<T> = ();
+   |        ^ unused type parameter
+   |
+   = help: consider removing `T` or referring to it in the body of the type alias
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
+
+error[E0392]: type parameter `T` is never used
+  --> $DIR/unused-generic-parameters.rs:18:8
+   |
+LL | type C<T: Copy> = ();
+   |        ^ unused type parameter
+   |
+   = help: consider removing `T` or referring to it in the body of the type alias
+
+error: aborting due to 3 previous errors
+
+For more information about this error, try `rustc --explain E0392`.
diff --git a/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr b/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr
index ec4aea62391..534ba933ba5 100644
--- a/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr
+++ b/tests/ui/lifetimes/issue-64173-unused-lifetimes.stderr
@@ -13,19 +13,19 @@ error: generic `Self` types are currently not permitted in anonymous constants
 LL |     array: [(); size_of::<&Self>()],
    |                            ^^^^
 
-error[E0392]: parameter `'s` is never used
+error[E0392]: lifetime parameter `'s` is never used
   --> $DIR/issue-64173-unused-lifetimes.rs:3:12
    |
 LL | struct Foo<'s> {
-   |            ^^ unused parameter
+   |            ^^ unused lifetime parameter
    |
    = help: consider removing `'s`, referring to it in a field, or using a marker such as `PhantomData`
 
-error[E0392]: parameter `'a` is never used
+error[E0392]: lifetime parameter `'a` is never used
   --> $DIR/issue-64173-unused-lifetimes.rs:15:12
    |
 LL | struct Bar<'a> {
-   |            ^^ unused parameter
+   |            ^^ unused lifetime parameter
    |
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/parser/item-free-type-bounds-semantic-fail.rs b/tests/ui/parser/item-free-type-bounds-semantic-fail.rs
index 9db4111fbab..062b51e5978 100644
--- a/tests/ui/parser/item-free-type-bounds-semantic-fail.rs
+++ b/tests/ui/parser/item-free-type-bounds-semantic-fail.rs
@@ -13,8 +13,8 @@ fn semantics() {
     //~| ERROR free type alias without body
     type E<_T>: Ord = u8;
     //~^ ERROR bounds on `type`s in this context have no effect
-    //~| ERROR type parameter `_T` is unused
+    //~| ERROR type parameter `_T` is never used
     type F<_T>: Ord where 'static: 'static = u8;
     //~^ ERROR bounds on `type`s in this context have no effect
-    //~| ERROR type parameter `_T` is unused
+    //~| ERROR type parameter `_T` is never used
 }
diff --git a/tests/ui/parser/item-free-type-bounds-semantic-fail.stderr b/tests/ui/parser/item-free-type-bounds-semantic-fail.stderr
index 1b086512891..1077c103928 100644
--- a/tests/ui/parser/item-free-type-bounds-semantic-fail.stderr
+++ b/tests/ui/parser/item-free-type-bounds-semantic-fail.stderr
@@ -50,17 +50,23 @@ error: bounds on `type`s in this context have no effect
 LL |     type F<_T>: Ord where 'static: 'static = u8;
    |                 ^^^
 
-error[E0091]: type parameter `_T` is unused
+error[E0091]: type parameter `_T` is never used
   --> $DIR/item-free-type-bounds-semantic-fail.rs:14:12
    |
 LL |     type E<_T>: Ord = u8;
    |            ^^ unused type parameter
+   |
+   = help: consider removing `_T` or referring to it in the body of the type alias
+   = help: if you intended `_T` to be a const parameter, use `const _T: /* Type */` instead
 
-error[E0091]: type parameter `_T` is unused
+error[E0091]: type parameter `_T` is never used
   --> $DIR/item-free-type-bounds-semantic-fail.rs:17:12
    |
 LL |     type F<_T>: Ord where 'static: 'static = u8;
    |            ^^ unused type parameter
+   |
+   = help: consider removing `_T` or referring to it in the body of the type alias
+   = help: if you intended `_T` to be a const parameter, use `const _T: /* Type */` instead
 
 error: aborting due to 10 previous errors
 
diff --git a/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr
index 2ec2ca49b11..b15d2affeea 100644
--- a/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr
+++ b/tests/ui/regions/region-bounds-on-objects-and-type-parameters.stderr
@@ -21,11 +21,11 @@ note: but lifetime parameter must outlive the lifetime `'a` as defined here
 LL | struct Foo<'a,'b,'c> {
    |            ^^
 
-error[E0392]: parameter `'c` is never used
+error[E0392]: lifetime parameter `'c` is never used
   --> $DIR/region-bounds-on-objects-and-type-parameters.rs:11:18
    |
 LL | struct Foo<'a,'b,'c> {
-   |                  ^^ unused parameter
+   |                  ^^ unused lifetime parameter
    |
    = help: consider removing `'c`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
index d57f5702a63..92a9c347a07 100644
--- a/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
+++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/tilde-const-invalid-places.stderr
@@ -272,11 +272,11 @@ LL |     type Type<T: ~const Trait> = ();
    = help: add `#![feature(inherent_associated_types)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/tilde-const-invalid-places.rs:11:19
    |
 LL | struct UnitStruct<T: ~const Trait>;
-   |                   ^ unused parameter
+   |                   ^ unused type parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/self/self_type_keyword.stderr b/tests/ui/self/self_type_keyword.stderr
index fed853a7e1f..4909a9cdc7f 100644
--- a/tests/ui/self/self_type_keyword.stderr
+++ b/tests/ui/self/self_type_keyword.stderr
@@ -72,11 +72,11 @@ note: unit struct `foo::Self` exists but is inaccessible
 LL |   struct Self;
    |   ^^^^^^^^^^^^ not accessible
 
-error[E0392]: parameter `'Self` is never used
+error[E0392]: lifetime parameter `'Self` is never used
   --> $DIR/self_type_keyword.rs:6:12
    |
 LL | struct Bar<'Self>;
-   |            ^^^^^ unused parameter
+   |            ^^^^^ unused lifetime parameter
    |
    = help: consider removing `'Self`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/tag-type-args.stderr b/tests/ui/tag-type-args.stderr
index 80ffd3a2f05..a1136f61cc5 100644
--- a/tests/ui/tag-type-args.stderr
+++ b/tests/ui/tag-type-args.stderr
@@ -14,14 +14,14 @@ help: add missing generic argument
 LL | fn foo(c: Quux<T>) { assert!((false)); }
    |               +++
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/tag-type-args.rs:1:11
    |
 LL | enum Quux<T> { Bar }
-   |           ^ unused parameter
+   |           ^ unused type 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
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/variance/variance-regions-unused-direct.stderr b/tests/ui/variance/variance-regions-unused-direct.stderr
index 1a600f5b058..4dc2af6ce2c 100644
--- a/tests/ui/variance/variance-regions-unused-direct.stderr
+++ b/tests/ui/variance/variance-regions-unused-direct.stderr
@@ -1,16 +1,16 @@
-error[E0392]: parameter `'a` is never used
+error[E0392]: lifetime parameter `'a` is never used
   --> $DIR/variance-regions-unused-direct.rs:5:18
    |
 LL | struct Bivariant<'a>;
-   |                  ^^ unused parameter
+   |                  ^^ unused lifetime parameter
    |
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
-error[E0392]: parameter `'d` is never used
+error[E0392]: lifetime parameter `'d` is never used
   --> $DIR/variance-regions-unused-direct.rs:7:19
    |
 LL | struct Struct<'a, 'd> {
-   |                   ^^ unused parameter
+   |                   ^^ unused lifetime parameter
    |
    = help: consider removing `'d`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/variance/variance-regions-unused-indirect.stderr b/tests/ui/variance/variance-regions-unused-indirect.stderr
index 14fdd849294..ec4d480baab 100644
--- a/tests/ui/variance/variance-regions-unused-indirect.stderr
+++ b/tests/ui/variance/variance-regions-unused-indirect.stderr
@@ -21,19 +21,19 @@ LL | enum Bar<'a> {
 LL ~     Bar1(Box<Foo<'a>>)
    |
 
-error[E0392]: parameter `'a` is never used
+error[E0392]: lifetime parameter `'a` is never used
   --> $DIR/variance-regions-unused-indirect.rs:3:10
    |
 LL | enum Foo<'a> {
-   |          ^^ unused parameter
+   |          ^^ unused lifetime parameter
    |
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
-error[E0392]: parameter `'a` is never used
+error[E0392]: lifetime parameter `'a` is never used
   --> $DIR/variance-regions-unused-indirect.rs:8:10
    |
 LL | enum Bar<'a> {
-   |          ^^ unused parameter
+   |          ^^ unused lifetime parameter
    |
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/variance/variance-unused-region-param.stderr b/tests/ui/variance/variance-unused-region-param.stderr
index 7c7ec40ba35..b9c08bd43c4 100644
--- a/tests/ui/variance/variance-unused-region-param.stderr
+++ b/tests/ui/variance/variance-unused-region-param.stderr
@@ -1,16 +1,16 @@
-error[E0392]: parameter `'a` is never used
+error[E0392]: lifetime parameter `'a` is never used
   --> $DIR/variance-unused-region-param.rs:3:19
    |
 LL | struct SomeStruct<'a> { x: u32 }
-   |                   ^^ unused parameter
+   |                   ^^ unused lifetime parameter
    |
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
-error[E0392]: parameter `'a` is never used
+error[E0392]: lifetime parameter `'a` is never used
   --> $DIR/variance-unused-region-param.rs:4:15
    |
 LL | enum SomeEnum<'a> { Nothing }
-   |               ^^ unused parameter
+   |               ^^ unused lifetime parameter
    |
    = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
 
diff --git a/tests/ui/variance/variance-unused-type-param.stderr b/tests/ui/variance/variance-unused-type-param.stderr
index e612da118f0..3011b7bd18f 100644
--- a/tests/ui/variance/variance-unused-type-param.stderr
+++ b/tests/ui/variance/variance-unused-type-param.stderr
@@ -1,51 +1,51 @@
-error[E0392]: parameter `A` is never used
+error[E0392]: type parameter `A` is never used
   --> $DIR/variance-unused-type-param.rs:6:19
    |
 LL | struct SomeStruct<A> { x: u32 }
-   |                   ^ unused parameter
+   |                   ^ unused type parameter
    |
    = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `A` to be a const parameter, use `const A: usize` instead
+   = help: if you intended `A` to be a const parameter, use `const A: /* Type */` instead
 
-error[E0392]: parameter `A` is never used
+error[E0392]: type parameter `A` is never used
   --> $DIR/variance-unused-type-param.rs:9:15
    |
 LL | enum SomeEnum<A> { Nothing }
-   |               ^ unused parameter
+   |               ^ unused type parameter
    |
    = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData`
-   = help: if you intended `A` to be a const parameter, use `const A: usize` instead
+   = help: if you intended `A` to be a const parameter, use `const A: /* Type */` instead
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/variance-unused-type-param.rs:13:15
    |
 LL | enum ListCell<T> {
-   |               ^ unused parameter
+   |               ^ unused type 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
+   = help: if you intended `T` to be a const parameter, use `const T: /* Type */` instead
 
-error[E0392]: parameter `T` is never used
+error[E0392]: type parameter `T` is never used
   --> $DIR/variance-unused-type-param.rs:19:19
    |
 LL | struct WithBounds<T: Sized> {}
-   |                   ^ unused parameter
+   |                   ^ unused type 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
+error[E0392]: type parameter `T` is never used
   --> $DIR/variance-unused-type-param.rs:22:24
    |
 LL | struct WithWhereBounds<T> where T: Sized {}
-   |                        ^ unused parameter
+   |                        ^ unused type 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
+error[E0392]: type parameter `T` is never used
   --> $DIR/variance-unused-type-param.rs:25:27
    |
 LL | struct WithOutlivesBounds<T: 'static> {}
-   |                           ^ unused parameter
+   |                           ^ unused type parameter
    |
    = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`