diff --git a/compiler/rustc_hir/src/target.rs b/compiler/rustc_hir/src/target.rs
index b870e4c6ead..2774cc9c08e 100644
--- a/compiler/rustc_hir/src/target.rs
+++ b/compiler/rustc_hir/src/target.rs
@@ -9,6 +9,13 @@ use crate::{Item, ItemKind, TraitItem, TraitItemKind};
 
 use std::fmt::{self, Display};
 
+#[derive(Copy, Clone, PartialEq, Debug)]
+pub enum GenericParamKind {
+    Type,
+    Lifetime,
+    Const,
+}
+
 #[derive(Copy, Clone, PartialEq, Debug)]
 pub enum MethodKind {
     Trait { body: bool },
@@ -43,6 +50,7 @@ pub enum Target {
     ForeignFn,
     ForeignStatic,
     ForeignTy,
+    GenericParam(GenericParamKind),
 }
 
 impl Display for Target {
@@ -77,6 +85,11 @@ impl Display for Target {
                 Target::ForeignFn => "foreign function",
                 Target::ForeignStatic => "foreign static item",
                 Target::ForeignTy => "foreign type",
+                Target::GenericParam(kind) => match kind {
+                    GenericParamKind::Type => "type parameter",
+                    GenericParamKind::Lifetime => "lifetime parameter",
+                    GenericParamKind::Const => "const parameter",
+                },
             }
         )
     }
@@ -124,4 +137,14 @@ impl Target {
             hir::ForeignItemKind::Type => Target::ForeignTy,
         }
     }
+
+    pub fn from_generic_param(generic_param: &hir::GenericParam<'_>) -> Target {
+        match generic_param.kind {
+            hir::GenericParamKind::Type { .. } => Target::GenericParam(GenericParamKind::Type),
+            hir::GenericParamKind::Lifetime { .. } => {
+                Target::GenericParam(GenericParamKind::Lifetime)
+            }
+            hir::GenericParamKind::Const { .. } => Target::GenericParam(GenericParamKind::Const),
+        }
+    }
 }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 73fb28e5c9a..aeaa862f5fd 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -882,6 +882,18 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> {
         intravisit::walk_item(self, item)
     }
 
+    fn visit_generic_param(&mut self, generic_param: &'tcx hir::GenericParam<'tcx>) {
+        let target = Target::from_generic_param(generic_param);
+        self.check_attributes(
+            generic_param.hir_id,
+            generic_param.attrs,
+            &generic_param.span,
+            target,
+            None,
+        );
+        intravisit::walk_generic_param(self, generic_param)
+    }
+
     fn visit_trait_item(&mut self, trait_item: &'tcx TraitItem<'tcx>) {
         let target = Target::from_trait_item(trait_item);
         self.check_attributes(trait_item.hir_id, &trait_item.attrs, &trait_item.span, target, None);
diff --git a/src/test/ui/issues/issue-78957.rs b/src/test/ui/issues/issue-78957.rs
new file mode 100644
index 00000000000..263c69bbc0b
--- /dev/null
+++ b/src/test/ui/issues/issue-78957.rs
@@ -0,0 +1,30 @@
+#![deny(unused_attributes)]
+#![feature(min_const_generics)]
+
+use std::marker::PhantomData;
+
+pub struct Foo<#[inline] const N: usize>;
+//~^ ERROR attribute should be applied to function or closure
+pub struct Bar<#[cold] const N: usize>;
+//~^ ERROR attribute should be applied to a function
+//~| WARN this was previously accepted
+pub struct Baz<#[repr(C)] const N: usize>;
+//~^ ERROR attribute should be applied to a struct, enum, or union
+//
+pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>);
+//~^ ERROR attribute should be applied to function or closure
+pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>);
+//~^ ERROR attribute should be applied to a function
+//~| WARN this was previously accepted
+pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>);
+//~^ ERROR attribute should be applied to a struct, enum, or union
+//
+pub struct Foo3<#[inline] T>(PhantomData<T>);
+//~^ ERROR attribute should be applied to function or closure
+pub struct Bar3<#[cold] T>(PhantomData<T>);
+//~^ ERROR attribute should be applied to a function
+//~| WARN this was previously accepted
+pub struct Baz3<#[repr(C)] T>(PhantomData<T>);
+//~^ ERROR attribute should be applied to a struct, enum, or union
+
+fn main() {}
diff --git a/src/test/ui/issues/issue-78957.stderr b/src/test/ui/issues/issue-78957.stderr
new file mode 100644
index 00000000000..26437ee4bef
--- /dev/null
+++ b/src/test/ui/issues/issue-78957.stderr
@@ -0,0 +1,69 @@
+error[E0518]: attribute should be applied to function or closure
+  --> $DIR/issue-78957.rs:6:16
+   |
+LL | pub struct Foo<#[inline] const N: usize>;
+   |                ^^^^^^^^^       - not a function or closure
+
+error: attribute should be applied to a function
+  --> $DIR/issue-78957.rs:8:16
+   |
+LL | pub struct Bar<#[cold] const N: usize>;
+   |                ^^^^^^^       - not a function
+   |
+note: the lint level is defined here
+  --> $DIR/issue-78957.rs:1:9
+   |
+LL | #![deny(unused_attributes)]
+   |         ^^^^^^^^^^^^^^^^^
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+error[E0517]: attribute should be applied to a struct, enum, or union
+  --> $DIR/issue-78957.rs:11:23
+   |
+LL | pub struct Baz<#[repr(C)] const N: usize>;
+   |                       ^         - not a struct, enum, or union
+
+error[E0518]: attribute should be applied to function or closure
+  --> $DIR/issue-78957.rs:14:17
+   |
+LL | pub struct Foo2<#[inline] 'a>(PhantomData<&'a ()>);
+   |                 ^^^^^^^^^ -- not a function or closure
+
+error: attribute should be applied to a function
+  --> $DIR/issue-78957.rs:16:17
+   |
+LL | pub struct Bar2<#[cold] 'a>(PhantomData<&'a ()>);
+   |                 ^^^^^^^ -- not a function
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+error[E0517]: attribute should be applied to a struct, enum, or union
+  --> $DIR/issue-78957.rs:19:24
+   |
+LL | pub struct Baz2<#[repr(C)] 'a>(PhantomData<&'a ()>);
+   |                        ^   -- not a struct, enum, or union
+
+error[E0518]: attribute should be applied to function or closure
+  --> $DIR/issue-78957.rs:22:17
+   |
+LL | pub struct Foo3<#[inline] T>(PhantomData<T>);
+   |                 ^^^^^^^^^ - not a function or closure
+
+error: attribute should be applied to a function
+  --> $DIR/issue-78957.rs:24:17
+   |
+LL | pub struct Bar3<#[cold] T>(PhantomData<T>);
+   |                 ^^^^^^^ - not a function
+   |
+   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+
+error[E0517]: attribute should be applied to a struct, enum, or union
+  --> $DIR/issue-78957.rs:27:24
+   |
+LL | pub struct Baz3<#[repr(C)] T>(PhantomData<T>);
+   |                        ^   - not a struct, enum, or union
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0517, E0518.
+For more information about an error, try `rustc --explain E0517`.
diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs
index 9f4f0abf324..142efb3c6cd 100644
--- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs
+++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.rs
@@ -17,7 +17,9 @@ fn test() {}
 #[bench] // OK, shadowed
 fn bench() {}
 
-fn non_macro_expanded_location<#[repr(C)] T>() { //~ ERROR `repr` is ambiguous
+fn non_macro_expanded_location<#[repr(C)] T>() {
+    //~^ ERROR `repr` is ambiguous
+    //~| ERROR attribute should be applied to a struct, enum, or union
     match 0u8 {
         #[repr(C)] //~ ERROR `repr` is ambiguous
         _ => {}
diff --git a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr
index 23310f6c6f5..276ee1cfd35 100644
--- a/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr
+++ b/src/test/ui/proc-macro/ambiguous-builtin-attrs.stderr
@@ -1,5 +1,5 @@
 error[E0425]: cannot find value `NonExistent` in this scope
-  --> $DIR/ambiguous-builtin-attrs.rs:30:5
+  --> $DIR/ambiguous-builtin-attrs.rs:32:5
    |
 LL |     NonExistent;
    |     ^^^^^^^^^^^ not found in this scope
@@ -47,7 +47,7 @@ LL | use builtin_attrs::*;
    = help: use `crate::repr` to refer to this attribute macro unambiguously
 
 error[E0659]: `repr` is ambiguous (built-in attribute vs any other name)
-  --> $DIR/ambiguous-builtin-attrs.rs:22:11
+  --> $DIR/ambiguous-builtin-attrs.rs:24:11
    |
 LL |         #[repr(C)]
    |           ^^^^ ambiguous name
@@ -74,7 +74,13 @@ LL | use builtin_attrs::*;
    |     ^^^^^^^^^^^^^^^^
    = help: use `crate::feature` to refer to this attribute macro unambiguously
 
-error: aborting due to 6 previous errors
+error[E0517]: attribute should be applied to a struct, enum, or union
+  --> $DIR/ambiguous-builtin-attrs.rs:20:39
+   |
+LL | fn non_macro_expanded_location<#[repr(C)] T>() {
+   |                                       ^   - not a struct, enum, or union
 
-Some errors have detailed explanations: E0425, E0659.
+error: aborting due to 7 previous errors
+
+Some errors have detailed explanations: E0425, E0517, E0659.
 For more information about an error, try `rustc --explain E0425`.