about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
authorJana Dönszelmann <jana@donsz.nl>2025-03-08 18:58:05 +0100
committerJana Dönszelmann <jana@donsz.nl>2025-06-17 23:22:51 +0200
commit5ab5f8a24a99cdbb178c886487d4c1971b86a32b (patch)
treefbb303eab922913bf4e4c50dea1a2c2ca1a2aad9 /compiler
parent672452d573e3f499a8edc4308400a6d116974938 (diff)
downloadrust-5ab5f8a24a99cdbb178c886487d4c1971b86a32b.tar.gz
rust-5ab5f8a24a99cdbb178c886487d4c1971b86a32b.zip
make error codes reflect reality better
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_attr_parsing/messages.ftl4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/confusables.rs6
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/deprecation.rs100
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/inline.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/repr.rs1
-rw-r--r--compiler/rustc_attr_parsing/src/attributes/stability.rs4
-rw-r--r--compiler/rustc_attr_parsing/src/context.rs31
-rw-r--r--compiler/rustc_attr_parsing/src/session_diagnostics.rs49
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0534.md8
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0535.md9
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0539.md29
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0565.md7
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0805.md26
-rw-r--r--compiler/rustc_error_codes/src/lib.rs1
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs9
-rw-r--r--compiler/rustc_passes/src/check_attr.rs7
17 files changed, 195 insertions, 104 deletions
diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl
index 70de83f2f74..b9b386635f6 100644
--- a/compiler/rustc_attr_parsing/messages.ftl
+++ b/compiler/rustc_attr_parsing/messages.ftl
@@ -121,10 +121,6 @@ attr_parsing_unsupported_literal_cfg_boolean =
     literal in `cfg` predicate value must be a boolean
 attr_parsing_unsupported_literal_cfg_string =
     literal in `cfg` predicate value must be a string
-attr_parsing_unsupported_literal_deprecated_kv_pair =
-    item in `deprecated` must be a key/value pair
-attr_parsing_unsupported_literal_deprecated_string =
-    literal in `deprecated` value must be a string
 attr_parsing_unsupported_literal_generic =
     unsupported literal
 attr_parsing_unsupported_literal_suggestion =
diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
index f4505cbc0e1..c911908dfb3 100644
--- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs
@@ -30,12 +30,12 @@ impl<S: Stage> AttributeParser<S> for ConfusablesParser {
             for param in list.mixed() {
                 let span = param.span();
 
-                let Some(lit) = param.lit() else {
-                    cx.expected_string_literal(span);
+                let Some(lit) = param.lit().and_then(|i| i.value_str()) else {
+                    cx.expected_string_literal(span, param.lit());
                     continue;
                 };
 
-                this.confusables.push(lit.symbol);
+                this.confusables.push(lit);
             }
 
             this.first_span.get_or_insert(cx.attr_span);
diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
index 0983a153efa..702ad66f578 100644
--- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs
@@ -7,7 +7,6 @@ use super::{AttributeOrder, OnDuplicate, SingleAttributeParser};
 use crate::context::{AcceptContext, Stage};
 use crate::parser::ArgParser;
 use crate::session_diagnostics;
-use crate::session_diagnostics::UnsupportedLiteralReason;
 
 pub(crate) struct DeprecationParser;
 
@@ -26,13 +25,7 @@ fn get<S: Stage>(
         if let Some(value_str) = v.value_as_str() {
             Some(value_str)
         } else {
-            let lit = v.value_as_lit();
-            cx.emit_err(session_diagnostics::UnsupportedLiteral {
-                span: v.value_span,
-                reason: UnsupportedLiteralReason::DeprecatedString,
-                is_bytestr: lit.kind.is_bytestr(),
-                start_point_span: cx.sess().source_map().start_point(lit.span),
-            });
+            cx.expected_string_literal(v.value_span, Some(&v.value_as_lit()));
             None
         }
     } else {
@@ -60,57 +53,60 @@ impl<S: Stage> SingleAttributeParser<S> for DeprecationParser {
 
         let is_rustc = features.staged_api();
 
-        if let Some(value) = args.name_value()
-            && let Some(value_str) = value.value_as_str()
-        {
-            note = Some(value_str)
-        } else if let Some(list) = args.list() {
-            for param in list.mixed() {
-                let param_span = param.span();
-                let Some(param) = param.meta_item() else {
-                    cx.emit_err(session_diagnostics::UnsupportedLiteral {
-                        span: param_span,
-                        reason: UnsupportedLiteralReason::DeprecatedKvPair,
-                        is_bytestr: false,
-                        start_point_span: cx.sess().source_map().start_point(param_span),
-                    });
-                    return None;
-                };
+        match args {
+            ArgParser::NoArgs => {
+                // ok
+            }
+            ArgParser::List(list) => {
+                for param in list.mixed() {
+                    let Some(param) = param.meta_item() else {
+                        cx.unexpected_literal(param.span());
+                        return None;
+                    };
 
-                let ident_name = param.path().word_sym();
+                    let ident_name = param.path().word_sym();
 
-                match ident_name {
-                    Some(name @ sym::since) => {
-                        since = Some(get(cx, name, param_span, param.args(), &since)?);
-                    }
-                    Some(name @ sym::note) => {
-                        note = Some(get(cx, name, param_span, param.args(), &note)?);
-                    }
-                    Some(name @ sym::suggestion) => {
-                        if !features.deprecated_suggestion() {
-                            cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
-                                span: param_span,
-                                is_nightly: cx.sess().is_nightly_build(),
-                                details: (),
-                            });
+                    match ident_name {
+                        Some(name @ sym::since) => {
+                            since = Some(get(cx, name, param.span(), param.args(), &since)?);
+                        }
+                        Some(name @ sym::note) => {
+                            note = Some(get(cx, name, param.span(), param.args(), &note)?);
                         }
+                        Some(name @ sym::suggestion) => {
+                            if !features.deprecated_suggestion() {
+                                cx.emit_err(session_diagnostics::DeprecatedItemSuggestion {
+                                    span: param.span(),
+                                    is_nightly: cx.sess().is_nightly_build(),
+                                    details: (),
+                                });
+                            }
 
-                        suggestion = Some(get(cx, name, param_span, param.args(), &suggestion)?);
-                    }
-                    _ => {
-                        cx.unknown_key(
-                            param_span,
-                            param.path().to_string(),
-                            if features.deprecated_suggestion() {
-                                &["since", "note", "suggestion"]
-                            } else {
-                                &["since", "note"]
-                            },
-                        );
-                        return None;
+                            suggestion =
+                                Some(get(cx, name, param.span(), param.args(), &suggestion)?);
+                        }
+                        _ => {
+                            cx.unknown_key(
+                                param.span(),
+                                param.path().to_string(),
+                                if features.deprecated_suggestion() {
+                                    &["since", "note", "suggestion"]
+                                } else {
+                                    &["since", "note"]
+                                },
+                            );
+                            return None;
+                        }
                     }
                 }
             }
+            ArgParser::NameValue(v) => {
+                let Some(value) = v.value_as_str() else {
+                    cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
+                    return None;
+                };
+                note = Some(value);
+            }
         }
 
         let since = if let Some(since) = since {
diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs
index 75ae1d6a6c1..25efc3ae49b 100644
--- a/compiler/rustc_attr_parsing/src/attributes/inline.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs
@@ -73,7 +73,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
                 };
 
                 let Some(reason) = l.lit().and_then(|i| i.kind.str()) else {
-                    cx.expected_string_literal(l.span());
+                    cx.expected_string_literal(l.span(), l.lit());
                     return None;
                 };
 
@@ -81,7 +81,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcForceInlineParser {
             }
             ArgParser::NameValue(v) => {
                 let Some(reason) = v.value_as_str() else {
-                    cx.expected_string_literal(v.value_span);
+                    cx.expected_string_literal(v.value_span, Some(v.value_as_lit()));
                     return None;
                 };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
index 32a20d4c5b5..d4c846de56e 100644
--- a/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/lint_helpers.rs
@@ -1,4 +1,5 @@
 use rustc_attr_data_structures::AttributeKind;
+use rustc_feature::{AttributeTemplate, template};
 use rustc_span::{Symbol, sym};
 
 use crate::attributes::{AttributeOrder, OnDuplicate, SingleAttributeParser};
@@ -9,10 +10,9 @@ pub(crate) struct AsPtrParser;
 
 impl<S: Stage> SingleAttributeParser<S> for AsPtrParser {
     const PATH: &[Symbol] = &[sym::rustc_as_ptr];
-
     const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst;
-
     const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
+    const TEMPLATE: AttributeTemplate = template!(Word);
 
     fn convert(cx: &mut AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option<AttributeKind> {
         // FIXME: check that there's no args (this is currently checked elsewhere)
diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs
index 6fb618541e3..ae9e7871874 100644
--- a/compiler/rustc_attr_parsing/src/attributes/repr.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs
@@ -34,6 +34,7 @@ impl<S: Stage> CombineAttributeParser<S> for ReprParser {
         let mut reprs = Vec::new();
 
         let Some(list) = args.list() else {
+            cx.expected_list(cx.attr_span);
             return reprs;
         };
 
diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs
index 65de13972a0..6871ff4ec9f 100644
--- a/compiler/rustc_attr_parsing/src/attributes/stability.rs
+++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs
@@ -369,7 +369,9 @@ pub(crate) fn parse_unstability<S: Stage>(
             Some(sym::implied_by) => {
                 insert_value_into_option_or_error(cx, &param, &mut implied_by, word.unwrap())?
             }
-            Some(sym::old_name) => insert_value_into_option_or_error(cx, &param, &mut old_name)?,
+            Some(sym::old_name) => {
+                insert_value_into_option_or_error(cx, &param, &mut old_name, word.unwrap())?
+            }
             _ => {
                 cx.emit_err(session_diagnostics::UnknownMetaItem {
                     span: param.span(),
diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs
index d6dfa2c7477..51c1760da30 100644
--- a/compiler/rustc_attr_parsing/src/context.rs
+++ b/compiler/rustc_attr_parsing/src/context.rs
@@ -5,8 +5,7 @@ use std::ops::{Deref, DerefMut};
 use std::sync::LazyLock;
 
 use private::Sealed;
-use rustc_ast as ast;
-use rustc_ast::NodeId;
+use rustc_ast::{self as ast, MetaItemLit, NodeId};
 use rustc_attr_data_structures::AttributeKind;
 use rustc_attr_data_structures::lints::{AttributeLint, AttributeLintKind};
 use rustc_errors::{DiagCtxtHandle, Diagnostic};
@@ -200,13 +199,25 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
         self.emit_err(UnknownMetaItem { span, item: found, expected: options })
     }
 
-    pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed {
+    /// error that a string literal was expected.
+    /// You can optionally give the literal you did find (which you found not to be a string literal)
+    /// which can make better errors. For example, if the literal was a byte string it will suggest
+    /// removing the `b` prefix.
+    pub(crate) fn expected_string_literal(
+        &self,
+        span: Span,
+        actual_literal: Option<&MetaItemLit>,
+    ) -> ErrorGuaranteed {
         self.emit_err(AttributeParseError {
             span,
             attr_span: self.attr_span,
             template: self.template.clone(),
             attribute: self.attr_path.clone(),
-            reason: AttributeParseErrorReason::ExpectedStringLiteral,
+            reason: AttributeParseErrorReason::ExpectedStringLiteral {
+                byte_string: actual_literal.and_then(|i| {
+                    i.kind.is_bytestr().then(|| self.sess().source_map().start_point(i.span))
+                }),
+            },
         })
     }
 
@@ -243,6 +254,18 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
         })
     }
 
+    /// an error that should be emitted when a [`MetaItemOrLitParser`](crate::parser::MetaItemOrLitParser)
+    /// was expected *not* to be a literal, but instead a meta item.
+    pub(crate) fn unexpected_literal(&self, span: Span) -> ErrorGuaranteed {
+        self.emit_err(AttributeParseError {
+            span,
+            attr_span: self.attr_span,
+            template: self.template.clone(),
+            attribute: self.attr_path.clone(),
+            reason: AttributeParseErrorReason::UnexpectedLiteral,
+        })
+    }
+
     pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed {
         self.emit_err(AttributeParseError {
             span,
diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
index 3d865c1d14e..57ac92a0ca1 100644
--- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs
+++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs
@@ -16,8 +16,6 @@ pub(crate) enum UnsupportedLiteralReason {
     Generic,
     CfgString,
     CfgBoolean,
-    DeprecatedString,
-    DeprecatedKvPair,
 }
 
 #[derive(Diagnostic)]
@@ -190,6 +188,7 @@ pub(crate) struct InvalidReprHintNoValue {
 }
 
 /// Error code: E0565
+// FIXME(jdonszelmann): slowly phased out
 pub(crate) struct UnsupportedLiteral {
     pub span: Span,
     pub reason: UnsupportedLiteralReason,
@@ -212,12 +211,6 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for UnsupportedLiteral {
                 UnsupportedLiteralReason::CfgBoolean => {
                     fluent::attr_parsing_unsupported_literal_cfg_boolean
                 }
-                UnsupportedLiteralReason::DeprecatedString => {
-                    fluent::attr_parsing_unsupported_literal_deprecated_string
-                }
-                UnsupportedLiteralReason::DeprecatedKvPair => {
-                    fluent::attr_parsing_unsupported_literal_deprecated_kv_pair
-                }
             },
         );
         diag.span(self.span);
@@ -473,9 +466,10 @@ pub(crate) struct UnrecognizedReprHint {
 }
 
 pub(crate) enum AttributeParseErrorReason {
-    ExpectedStringLiteral,
+    ExpectedStringLiteral { byte_string: Option<Span> },
     ExpectedSingleArgument,
     ExpectedList,
+    UnexpectedLiteral,
     ExpectedNameValue(Option<Symbol>),
     DuplicateKey(Symbol),
     ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool },
@@ -497,27 +491,44 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
         diag.span(self.attr_span);
         diag.code(E0539);
         match self.reason {
-            AttributeParseErrorReason::ExpectedStringLiteral => {
-                diag.span_note(self.span, "expected a string literal here");
+            AttributeParseErrorReason::ExpectedStringLiteral { byte_string } => {
+                if let Some(start_point_span) = byte_string {
+                    diag.span_suggestion(
+                        start_point_span,
+                        fluent::attr_parsing_unsupported_literal_suggestion,
+                        "",
+                        Applicability::MaybeIncorrect,
+                    );
+                    diag.note("expected a normal string literal, not a byte string literal");
+
+                    return diag;
+                } else {
+                    diag.span_label(self.span, "expected a string literal here");
+                }
             }
             AttributeParseErrorReason::ExpectedSingleArgument => {
-                diag.span_note(self.span, "expected a single argument here");
+                diag.span_label(self.span, "expected a single argument here");
+                diag.code(E0805);
             }
             AttributeParseErrorReason::ExpectedList => {
-                diag.span_note(self.span, "expected this to be a list");
+                diag.span_label(self.span, "expected this to be a list");
             }
             AttributeParseErrorReason::DuplicateKey(key) => {
-                diag.span_note(self.span, format!("found `{key}` used as a key more than once"));
+                diag.span_label(self.span, format!("found `{key}` used as a key more than once"));
                 diag.code(E0538);
             }
+            AttributeParseErrorReason::UnexpectedLiteral => {
+                diag.span_label(self.span, format!("didn't expect a literal here"));
+                diag.code(E0565);
+            }
             AttributeParseErrorReason::ExpectedNameValue(None) => {
-                diag.span_note(
+                diag.span_label(
                     self.span,
                     format!("expected this to be of the form `{name} = \"...\"`"),
                 );
             }
             AttributeParseErrorReason::ExpectedNameValue(Some(name)) => {
-                diag.span_note(
+                diag.span_label(
                     self.span,
                     format!("expected this to be of the form `{name} = \"...\"`"),
                 );
@@ -527,13 +538,13 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                 match possibilities.as_slice() {
                     &[] => {}
                     &[x] => {
-                        diag.span_note(
+                        diag.span_label(
                             self.span,
                             format!("the only valid argument here is {quote}{x}{quote}"),
                         );
                     }
                     [first, second] => {
-                        diag.span_note(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"));
+                        diag.span_label(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}"));
                     }
                     [first @ .., second_to_last, last] => {
                         let mut res = String::new();
@@ -544,7 +555,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
                             "{quote}{second_to_last}{quote} or {quote}{last}{quote}"
                         ));
 
-                        diag.span_note(self.span, format!("valid arguments are {res}"));
+                        diag.span_label(self.span, format!("valid arguments are {res}"));
                     }
                 }
             }
diff --git a/compiler/rustc_error_codes/src/error_codes/E0534.md b/compiler/rustc_error_codes/src/error_codes/E0534.md
index 1ca9411b8d4..023c38c730c 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0534.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0534.md
@@ -1,8 +1,14 @@
+#### Note: this error code is no longer emitted by the compiler
+
+This is because it was too specific to the `inline` attribute.
+Similar diagnostics occur for other attributes too.
+The example here will now emit `E0805`
+
 The `inline` attribute was malformed.
 
 Erroneous code example:
 
-```compile_fail,E0534
+```compile_fail,E0805
 #[inline()] // error: expected one argument
 pub fn something() {}
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0535.md b/compiler/rustc_error_codes/src/error_codes/E0535.md
index 0cf3118b02c..93e2ba53826 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0535.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0535.md
@@ -1,8 +1,13 @@
-An unknown argument was given to the `inline` attribute.
+#### Note: this error code is no longer emitted by the compiler
+
+This is because it was too specific to the `inline` attribute.
+Similar diagnostics occur for other attributes too.
+The example here will now emit `E0539`
+
 
 Erroneous code example:
 
-```compile_fail,E0535
+```compile_fail,E0539
 #[inline(unknown)] // error: invalid argument
 pub fn something() {}
 
diff --git a/compiler/rustc_error_codes/src/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md
index 6b2e23ba2d8..c76b60ac108 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0539.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0539.md
@@ -24,8 +24,7 @@ struct Stable;
 const fn stable_fn() {}
 ```
 
-Meta items are the key-value pairs inside of an attribute.
-To fix these issues you need to give required key-value pairs.
+To fix the above example, you can write the following:
 
 ```
 #![feature(staged_api)]
@@ -49,3 +48,29 @@ struct Stable;
 #[rustc_const_stable(feature = "stable_fn", since = "1.39.0")] // ok!
 const fn stable_fn() {}
 ```
+
+Several causes of this are,
+an attribute may have expected you to give a list but you gave a
+`name = value` pair:
+
+```compile_fail,E0539
+// wrong, should be `#[repr(C)]`
+#[repr = "C"]
+struct Foo {}
+```
+
+Or a `name = value` pair, but you gave a list:
+
+```compile_fail,E0539
+// wrong, should be `note = "reason"`
+#[deprecated(since = "1.0.0", note("reason"))]
+struct Foo {}
+```
+
+Or it expected some specific word but you gave an unexpected one:
+
+```compile_fail,E0539
+// should be `always` or `never`
+#[inline(maybe_if_you_feel_like_it)]
+fn foo() {}
+```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0565.md b/compiler/rustc_error_codes/src/error_codes/E0565.md
index d5bba941c1d..34152eb7cfe 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0565.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0565.md
@@ -9,10 +9,9 @@ struct Repr {}
 fn main() {}
 ```
 
-Literals in attributes are new and largely unsupported in built-in attributes.
-Work to support literals where appropriate is ongoing. Try using an unquoted
-name instead:
-
+Not all attributes support literals in their input,
+and in some cases they expect an identifier instead.
+That would be the solution in the case of `repr`:
 ```
 #[repr(C)] // ok!
 struct Repr {}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0805.md b/compiler/rustc_error_codes/src/error_codes/E0805.md
new file mode 100644
index 00000000000..b1ed3a11d48
--- /dev/null
+++ b/compiler/rustc_error_codes/src/error_codes/E0805.md
@@ -0,0 +1,26 @@
+An attribute was given an invalid number of arguments
+
+Erroneous code example:
+
+```compile_fail,E0805
+#[inline()] // error! should either have a single argument, or no parentheses
+fn foo() {}
+
+#[inline(always, never)] // error! should have only one argument, not two
+fn bar() {}
+```
+
+To fix this, either give the right number of arguments the attribute needs.
+In the case of inline, this could be none at all:
+
+```
+#[inline]
+fn foo() {}
+```
+
+or only one:
+
+```
+#[inline(always)]
+fn foo() {}
+```
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index 2488d870899..6f5e4829802 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -547,6 +547,7 @@ E0801: 0801,
 E0802: 0802,
 E0803: 0803,
 E0804: 0804,
+E0805: 0805,
         );
     )
 }
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 2296ec10432..b3096e46b09 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -283,7 +283,14 @@ fn emit_malformed_attribute(
     template: AttributeTemplate,
 ) {
     // attrs with new parsers are locally validated so excluded here
-    if matches!(name, sym::inline | sym::rustc_force_inline | sym::rustc_confusables) {
+    if matches!(
+        name,
+        sym::inline
+            | sym::rustc_force_inline
+            | sym::rustc_confusables
+            | sym::repr
+            | sym::deprecated
+    ) {
         return;
     }
 
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index d543abb5411..5ce803aa1f8 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -728,13 +728,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                     }
                 }
             }
-            // FIXME(#80564): We permit struct fields, match arms and macro defs to have an
-            // `#[naked]` attribute with just a lint, because we previously
-            // erroneously allowed it and some crates used it accidentally, to be compatible
-            // with crates depending on them, we can't throw an error here.
-            Target::Field | Target::Arm | Target::MacroDef => {
-                self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "naked")
-            }
             _ => {
                 self.dcx().emit_err(errors::AttrShouldBeAppliedToFn {
                     attr_span: attr.span(),