From aac585d3a682e8856dbc89ea7a978c3408968780 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 16:02:11 +0100 Subject: [PATCH 01/26] create variant for inline --- compiler/rustc_attr_data_structures/src/attributes.rs | 3 ++- compiler/rustc_attr_parsing/src/attributes/inline.rs | 1 + compiler/rustc_attr_parsing/src/attributes/mod.rs | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 compiler/rustc_attr_parsing/src/attributes/inline.rs diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9ac8de0227d79..61eab1550e4f4 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -8,7 +8,7 @@ use thin_vec::ThinVec; use crate::{DefaultBodyStability, PartialConstStability, PrintAttribute, RustcVersion, Stability}; -#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Copy, Clone, PartialEq, Encodable, Decodable, Debug, HashStable_Generic, PrintAttribute)] pub enum InlineAttr { None, Hint, @@ -186,6 +186,7 @@ pub enum AttributeKind { span: Span, comment: Symbol, }, + Inline(InlineAttr), MacroTransparency(Transparency), Repr(ThinVec<(ReprAttr, Span)>), Stability { diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs new file mode 100644 index 0000000000000..8b137891791fe --- /dev/null +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -0,0 +1 @@ + diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 6ecd6b4d7dbb7..8a7152fa72f6b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -27,6 +27,7 @@ pub(crate) mod allow_unstable; pub(crate) mod cfg; pub(crate) mod confusables; pub(crate) mod deprecation; +pub(crate) mod inline; pub(crate) mod repr; pub(crate) mod stability; pub(crate) mod transparency; From ccd995b5a9a2364f2e093eada0b9baca2db95648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 16:29:04 +0100 Subject: [PATCH 02/26] install a blank parser --- .../rustc_attr_parsing/src/attributes/inline.rs | 16 ++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 2 ++ 2 files changed, 18 insertions(+) diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 8b137891791fe..51b1b0a9c3e16 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -1 +1,17 @@ +use rustc_span::sym; +use crate::attributes::SingleAttributeParser; + +pub(crate) struct InlineParser; + +impl SingleAttributeParser for InlineParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::inline]; + + fn on_duplicate(cx: &super::AcceptContext<'_>, first_span: rustc_span::Span) { + todo!() + } + + fn convert(cx: &super::AcceptContext<'_>, args: &crate::parser::ArgParser<'_>) -> Option { + todo!() + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 0e6b0bab082e9..2048a5e34b418 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -15,6 +15,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; +use crate::attributes::inline::InlineParser; use crate::attributes::repr::ReprParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, @@ -77,6 +78,7 @@ attribute_groups!( // tidy-alphabetical-start Single, Single, + Single, Single, // tidy-alphabetical-end ]; From f439e02643be308cae59bdcef9e91ae6ed9eb742 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 16:34:10 +0100 Subject: [PATCH 03/26] introduce reject duplicate strategy --- compiler/rustc_attr_parsing/src/attributes/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 8a7152fa72f6b..becd8b2dbc0d3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -75,6 +75,8 @@ pub(crate) trait AttributeParser: Default + 'static { pub(crate) trait SingleAttributeParser: 'static { const PATH: &'static [rustc_span::Symbol]; + const REJECT_DUPLICATE_STRATEGY: RejectDuplicateStrategy = RejectDuplicateStrategy::ErrorAfterFirst; + /// Caled when a duplicate attribute is found. /// /// `first_span` is the span of the first occurrence of this attribute. @@ -110,6 +112,10 @@ impl AttributeParser for Single { } } +pub(crate) enum RejectDuplicateStrategy { + ErrorAfterFirst, +} + type ConvertFn = fn(ThinVec) -> AttributeKind; /// Alternative to [`AttributeParser`] that automatically handles state management. From 2b4c12ba5642555885bfdcb5d248cedd6ec84b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 16:43:42 +0100 Subject: [PATCH 04/26] default error on single attribute parsers --- compiler/rustc_attr_parsing/src/attributes/mod.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index becd8b2dbc0d3..41ad9d1c6161b 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -17,11 +17,12 @@ use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; use crate::context::{AcceptContext, FinalizeContext}; use crate::parser::ArgParser; +use crate::session_diagnostics::UnusedMultiple; pub(crate) mod allow_unstable; pub(crate) mod cfg; @@ -81,7 +82,13 @@ pub(crate) trait SingleAttributeParser: 'static { /// /// `first_span` is the span of the first occurrence of this attribute. // FIXME(jdonszelmann): default error - fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span); + fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) { + cx.emit_err(UnusedMultiple { + this: cx.attr_span, + other: first_span, + name: Symbol::intern(&Self::PATH.into_iter().map(|i| i.to_string()).collect::>().join("..")), + }); + } /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option; From 694a777ec890665158e83e334bed5c5d4dc01c51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 16:53:00 +0100 Subject: [PATCH 05/26] start using the first rejection strategy --- compiler/rustc_attr_parsing/src/attributes/mod.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 41ad9d1c6161b..49fe2a8470437 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -104,9 +104,13 @@ impl Default for Single { impl AttributeParser for Single { const ATTRIBUTES: AcceptMapping = &[(T::PATH, |group: &mut Single, cx, args| { - if let Some((_, s)) = group.1 { - T::on_duplicate(cx, s); - return; + match T::REJECT_DUPLICATE_STRATEGY { + RejectDuplicateStrategy::ErrorAfterFirst => { + if let Some((_, s)) = group.1 { + T::on_duplicate(cx, s); + return; + } + }, } if let Some(pa) = T::convert(cx, args) { From 4234d2d992214586abe0b11ccd143c62987adde8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 16:55:17 +0100 Subject: [PATCH 06/26] rename --- compiler/rustc_attr_parsing/src/attributes/mod.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 49fe2a8470437..bda11fd0ccb69 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -76,7 +76,7 @@ pub(crate) trait AttributeParser: Default + 'static { pub(crate) trait SingleAttributeParser: 'static { const PATH: &'static [rustc_span::Symbol]; - const REJECT_DUPLICATE_STRATEGY: RejectDuplicateStrategy = RejectDuplicateStrategy::ErrorAfterFirst; + const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; /// Caled when a duplicate attribute is found. /// @@ -104,8 +104,8 @@ impl Default for Single { impl AttributeParser for Single { const ATTRIBUTES: AcceptMapping = &[(T::PATH, |group: &mut Single, cx, args| { - match T::REJECT_DUPLICATE_STRATEGY { - RejectDuplicateStrategy::ErrorAfterFirst => { + match T::ON_DUPLICATE_STRATEGY { + AttributeDuplicates::ErrorFollowing => { if let Some((_, s)) = group.1 { T::on_duplicate(cx, s); return; @@ -123,8 +123,8 @@ impl AttributeParser for Single { } } -pub(crate) enum RejectDuplicateStrategy { - ErrorAfterFirst, +pub(crate) enum AttributeDuplicates { + ErrorFollowing, } type ConvertFn = fn(ThinVec) -> AttributeKind; From cb31ca69e8cd961a8f734619a815d462821e4d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 17:12:23 +0100 Subject: [PATCH 07/26] add future warn preceding strategy --- .../src/attributes/deprecation.rs | 6 +-- .../src/attributes/inline.rs | 4 +- .../rustc_attr_parsing/src/attributes/mod.rs | 49 ++++++++++++++----- .../src/attributes/stability.rs | 2 +- .../src/attributes/transparency.rs | 6 +-- 5 files changed, 45 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 7d1417446b21d..c84d8608544c0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -48,11 +48,11 @@ fn get( impl SingleAttributeParser for DeprecationParser { const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; - fn on_duplicate(cx: &AcceptContext<'_>, first_span: rustc_span::Span) { + fn on_duplicate(cx: &AcceptContext<'_>, used: Span, unused: Span) { // FIXME(jdonszelmann): merge with errors from check_attrs.rs cx.emit_err(session_diagnostics::UnusedMultiple { - this: cx.attr_span, - other: first_span, + this: used, + other: unused, name: sym::deprecated, }); } diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 51b1b0a9c3e16..c62d1966ec7d3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -1,4 +1,4 @@ -use rustc_span::sym; +use rustc_span::{sym, Span}; use crate::attributes::SingleAttributeParser; @@ -7,7 +7,7 @@ pub(crate) struct InlineParser; impl SingleAttributeParser for InlineParser { const PATH: &'static [rustc_span::Symbol] = &[sym::inline]; - fn on_duplicate(cx: &super::AcceptContext<'_>, first_span: rustc_span::Span) { + fn on_duplicate(cx: &super::AcceptContext<'_>, used: Span, unused: Span) { todo!() } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index bda11fd0ccb69..c1cd941a02702 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -80,12 +80,14 @@ pub(crate) trait SingleAttributeParser: 'static { /// Caled when a duplicate attribute is found. /// - /// `first_span` is the span of the first occurrence of this attribute. + /// - `unused` is the span of the attribute that was unused or bad because of some + /// duplicate reason (see [`AttributeDuplicates`]) + /// - `used` is the span of the attribute that was used in favor of the unused attribute // FIXME(jdonszelmann): default error - fn on_duplicate(cx: &AcceptContext<'_>, first_span: Span) { + fn on_duplicate(cx: &AcceptContext<'_>, used: Span, unused: Span) { cx.emit_err(UnusedMultiple { - this: cx.attr_span, - other: first_span, + this: used, + other: unused, name: Symbol::intern(&Self::PATH.into_iter().map(|i| i.to_string()).collect::>().join("..")), }); } @@ -104,16 +106,24 @@ impl Default for Single { impl AttributeParser for Single { const ATTRIBUTES: AcceptMapping = &[(T::PATH, |group: &mut Single, cx, args| { - match T::ON_DUPLICATE_STRATEGY { - AttributeDuplicates::ErrorFollowing => { - if let Some((_, s)) = group.1 { - T::on_duplicate(cx, s); - return; - } - }, - } - if let Some(pa) = T::convert(cx, args) { + match T::ON_DUPLICATE_STRATEGY { + // keep the first and error + AttributeDuplicates::ErrorFollowing => { + if let Some((_, unused)) = group.1 { + T::on_duplicate(cx,cx.attr_span, unused); + return; + } + }, + // keep the new one and warn about the previous, + // then replace + AttributeDuplicates::FutureWarnPreceding => { + if let Some((_, used)) = group.1 { + T::on_duplicate(cx, used, cx.attr_span); + } + }, + } + group.1 = Some((pa, cx.attr_span)); } })]; @@ -124,7 +134,20 @@ impl AttributeParser for Single { } pub(crate) enum AttributeDuplicates { + /// Duplicates after the first attribute will be an error. + /// + /// This should be used where duplicates would be ignored, but carry extra + /// meaning that could cause confusion. For example, `#[stable(since="1.0")] + /// #[stable(since="2.0")]`, which version should be used for `stable`? ErrorFollowing, + + /// Duplicates preceding the last instance of the attribute will be a + /// warning, with a note that this will be an error in the future. + /// + /// This is the same as `FutureWarnFollowing`, except the last attribute is + /// the one that is "used". Ideally these can eventually migrate to + /// `ErrorPreceding`. + FutureWarnPreceding, } type ConvertFn = fn(ThinVec) -> AttributeKind; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 6d76456e83c80..5d972eccb8dfa 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -124,7 +124,7 @@ impl SingleAttributeParser for ConstStabilityIndirectParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_const_stable_indirect]; // ignore - fn on_duplicate(_cx: &AcceptContext<'_>, _first_span: Span) {} + fn on_duplicate(_cx: &AcceptContext<'_>, _used: Span, _unused: Span) {} fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option { Some(AttributeKind::ConstStabilityIndirect) diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index ad83a1f7af80c..56584fbaab490 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,5 +1,5 @@ use rustc_attr_data_structures::AttributeKind; -use rustc_span::hygiene::Transparency; +use rustc_span::{hygiene::Transparency, Span}; use rustc_span::sym; use super::{AcceptContext, SingleAttributeParser}; @@ -13,8 +13,8 @@ pub(crate) struct TransparencyParser; impl SingleAttributeParser for TransparencyParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_transparency]; - fn on_duplicate(cx: &crate::context::AcceptContext<'_>, first_span: rustc_span::Span) { - cx.dcx().span_err(vec![first_span, cx.attr_span], "multiple macro transparency attributes"); + fn on_duplicate(cx: &crate::context::AcceptContext<'_>, used: Span, unused: Span) { + cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); } fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { From b2c718211ff30fa7535022b0789bece034bfb9ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 17:18:13 +0100 Subject: [PATCH 08/26] remove default --- compiler/rustc_attr_parsing/src/attributes/deprecation.rs | 3 ++- compiler/rustc_attr_parsing/src/attributes/mod.rs | 2 +- compiler/rustc_attr_parsing/src/attributes/stability.rs | 3 ++- compiler/rustc_attr_parsing/src/attributes/transparency.rs | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index c84d8608544c0..c912fd985cb74 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -2,7 +2,7 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol, sym}; -use super::SingleAttributeParser; +use super::{AttributeDuplicates, SingleAttributeParser}; use super::util::parse_version; use crate::context::AcceptContext; use crate::parser::ArgParser; @@ -47,6 +47,7 @@ fn get( impl SingleAttributeParser for DeprecationParser { const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; + const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; fn on_duplicate(cx: &AcceptContext<'_>, used: Span, unused: Span) { // FIXME(jdonszelmann): merge with errors from check_attrs.rs diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index c1cd941a02702..a6c093309870f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -76,7 +76,7 @@ pub(crate) trait AttributeParser: Default + 'static { pub(crate) trait SingleAttributeParser: 'static { const PATH: &'static [rustc_span::Symbol]; - const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; + const ON_DUPLICATE_STRATEGY: AttributeDuplicates; /// Caled when a duplicate attribute is found. /// diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 5d972eccb8dfa..a07f342a2e299 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -8,7 +8,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_span::{Span, Symbol, kw, sym}; use super::util::parse_version; -use super::{AcceptMapping, AttributeParser, SingleAttributeParser}; +use super::{AcceptMapping, AttributeDuplicates, AttributeParser, SingleAttributeParser}; use crate::context::{AcceptContext, FinalizeContext}; use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -122,6 +122,7 @@ pub(crate) struct ConstStabilityIndirectParser; // FIXME(jdonszelmann): single word attribute group when we have these impl SingleAttributeParser for ConstStabilityIndirectParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_const_stable_indirect]; + const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; // ignore fn on_duplicate(_cx: &AcceptContext<'_>, _used: Span, _unused: Span) {} diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 56584fbaab490..480629c565869 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -2,7 +2,7 @@ use rustc_attr_data_structures::AttributeKind; use rustc_span::{hygiene::Transparency, Span}; use rustc_span::sym; -use super::{AcceptContext, SingleAttributeParser}; +use super::{AcceptContext, AttributeDuplicates, SingleAttributeParser}; use crate::parser::ArgParser; pub(crate) struct TransparencyParser; @@ -12,6 +12,7 @@ pub(crate) struct TransparencyParser; #[allow(rustc::diagnostic_outside_of_impl)] impl SingleAttributeParser for TransparencyParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_transparency]; + const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; fn on_duplicate(cx: &crate::context::AcceptContext<'_>, used: Span, unused: Span) { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); From 248ab8feef647647ff5decbd8fb418f187fcba3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 17:28:14 +0100 Subject: [PATCH 09/26] new on duplicate enum --- .../rustc_attr_parsing/src/attributes/mod.rs | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index a6c093309870f..8e59d0e27f8f4 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -133,6 +133,43 @@ impl AttributeParser for Single { } } +pub(crate) enum OnDuplicate { + /// Give a default warning + Warn, + + /// Give a default error + Error, + + /// Ignore duplicates + Ignore, + + /// Custom function called when a duplicate attribute is found. + /// + /// - `unused` is the span of the attribute that was unused or bad because of some + /// duplicate reason (see [`AttributeDuplicates`]) + /// - `used` is the span of the attribute that was used in favor of the unused attribute + Custom(fn (cx: &AcceptContext<'_>, used: Span, unused: Span)) +} + +impl OnDuplicate { + fn exec(&self, cx: &AcceptContext<'_>, used: Span, unused: Span) { + match self { + OnDuplicate::Warn => { + todo!() + }, + OnDuplicate::Error => { + cx.emit_err(UnusedMultiple { + this: used, + other: unused, + name: Symbol::intern(&P::PATH.into_iter().map(|i| i.to_string()).collect::>().join("..")), + }); + }, + OnDuplicate::Ignore => {} + OnDuplicate::Custom(f) => f(cx, used, unused), + } + } +} + pub(crate) enum AttributeDuplicates { /// Duplicates after the first attribute will be an error. /// From 68976b275695a81b1b416426d8a75d0b4de252b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 17:36:34 +0100 Subject: [PATCH 10/26] use OnDuplicate for all existing single parsers --- .../src/attributes/deprecation.rs | 12 ++---------- .../rustc_attr_parsing/src/attributes/mod.rs | 19 +++---------------- .../src/attributes/stability.rs | 7 +++---- .../src/attributes/transparency.rs | 7 +++---- 4 files changed, 11 insertions(+), 34 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index c912fd985cb74..26e4c23aa790a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -2,7 +2,7 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol, sym}; -use super::{AttributeDuplicates, SingleAttributeParser}; +use super::{AttributeDuplicates, OnDuplicate, SingleAttributeParser}; use super::util::parse_version; use crate::context::AcceptContext; use crate::parser::ArgParser; @@ -48,15 +48,7 @@ fn get( impl SingleAttributeParser for DeprecationParser { const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; - - fn on_duplicate(cx: &AcceptContext<'_>, used: Span, unused: Span) { - // FIXME(jdonszelmann): merge with errors from check_attrs.rs - cx.emit_err(session_diagnostics::UnusedMultiple { - this: used, - other: unused, - name: sym::deprecated, - }); - } + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { let features = cx.features(); diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 8e59d0e27f8f4..30b8557bb0a28 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -77,20 +77,7 @@ pub(crate) trait SingleAttributeParser: 'static { const PATH: &'static [rustc_span::Symbol]; const ON_DUPLICATE_STRATEGY: AttributeDuplicates; - - /// Caled when a duplicate attribute is found. - /// - /// - `unused` is the span of the attribute that was unused or bad because of some - /// duplicate reason (see [`AttributeDuplicates`]) - /// - `used` is the span of the attribute that was used in favor of the unused attribute - // FIXME(jdonszelmann): default error - fn on_duplicate(cx: &AcceptContext<'_>, used: Span, unused: Span) { - cx.emit_err(UnusedMultiple { - this: used, - other: unused, - name: Symbol::intern(&Self::PATH.into_iter().map(|i| i.to_string()).collect::>().join("..")), - }); - } + const ON_DUPLICATE: OnDuplicate; /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option; @@ -111,7 +98,7 @@ impl AttributeParser for Single { // keep the first and error AttributeDuplicates::ErrorFollowing => { if let Some((_, unused)) = group.1 { - T::on_duplicate(cx,cx.attr_span, unused); + T::ON_DUPLICATE.exec::(cx, cx.attr_span, unused); return; } }, @@ -119,7 +106,7 @@ impl AttributeParser for Single { // then replace AttributeDuplicates::FutureWarnPreceding => { if let Some((_, used)) = group.1 { - T::on_duplicate(cx, used, cx.attr_span); + T::ON_DUPLICATE.exec::(cx, used, cx.attr_span); } }, } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index a07f342a2e299..b3b39c85f3e19 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -8,7 +8,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_span::{Span, Symbol, kw, sym}; use super::util::parse_version; -use super::{AcceptMapping, AttributeDuplicates, AttributeParser, SingleAttributeParser}; +use super::{AcceptMapping, AttributeDuplicates, AttributeParser, OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, FinalizeContext}; use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -123,13 +123,12 @@ pub(crate) struct ConstStabilityIndirectParser; impl SingleAttributeParser for ConstStabilityIndirectParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_const_stable_indirect]; const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; - - // ignore - fn on_duplicate(_cx: &AcceptContext<'_>, _used: Span, _unused: Span) {} + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option { Some(AttributeKind::ConstStabilityIndirect) } + } #[derive(Default)] diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 480629c565869..3365bbcbddf2f 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -2,7 +2,7 @@ use rustc_attr_data_structures::AttributeKind; use rustc_span::{hygiene::Transparency, Span}; use rustc_span::sym; -use super::{AcceptContext, AttributeDuplicates, SingleAttributeParser}; +use super::{AcceptContext, AttributeDuplicates, OnDuplicate, SingleAttributeParser}; use crate::parser::ArgParser; pub(crate) struct TransparencyParser; @@ -13,10 +13,9 @@ pub(crate) struct TransparencyParser; impl SingleAttributeParser for TransparencyParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_transparency]; const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; - - fn on_duplicate(cx: &crate::context::AcceptContext<'_>, used: Span, unused: Span) { + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Custom(|cx, used, unused| { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); - } + }); fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { match args.name_value().and_then(|nv| nv.value_as_str()) { From 828ebdbb0abf091ba10fca6488252ae49e65ed4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 17:44:24 +0100 Subject: [PATCH 11/26] convert DUPLICATE_STRATEGY into attribute order --- .../src/attributes/deprecation.rs | 4 +- .../rustc_attr_parsing/src/attributes/mod.rs | 41 ++++++++++--------- .../src/attributes/stability.rs | 4 +- .../src/attributes/transparency.rs | 4 +- 4 files changed, 28 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 26e4c23aa790a..3fe6add8ca0a3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -2,7 +2,7 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol, sym}; -use super::{AttributeDuplicates, OnDuplicate, SingleAttributeParser}; +use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; use super::util::parse_version; use crate::context::AcceptContext; use crate::parser::ArgParser; @@ -47,7 +47,7 @@ fn get( impl SingleAttributeParser for DeprecationParser { const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; - const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 30b8557bb0a28..e1181f63956fa 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -76,7 +76,7 @@ pub(crate) trait AttributeParser: Default + 'static { pub(crate) trait SingleAttributeParser: 'static { const PATH: &'static [rustc_span::Symbol]; - const ON_DUPLICATE_STRATEGY: AttributeDuplicates; + const ATTRIBUTE_ORDER: AttributeOrder; const ON_DUPLICATE: OnDuplicate; /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] @@ -94,9 +94,9 @@ impl Default for Single { impl AttributeParser for Single { const ATTRIBUTES: AcceptMapping = &[(T::PATH, |group: &mut Single, cx, args| { if let Some(pa) = T::convert(cx, args) { - match T::ON_DUPLICATE_STRATEGY { - // keep the first and error - AttributeDuplicates::ErrorFollowing => { + match T::ATTRIBUTE_ORDER { + // keep the first and report immediately. ignore this attribute + AttributeOrder::KeepFirst => { if let Some((_, unused)) = group.1 { T::ON_DUPLICATE.exec::(cx, cx.attr_span, unused); return; @@ -104,7 +104,7 @@ impl AttributeParser for Single { }, // keep the new one and warn about the previous, // then replace - AttributeDuplicates::FutureWarnPreceding => { + AttributeOrder::KeepLast => { if let Some((_, used)) = group.1 { T::ON_DUPLICATE.exec::(cx, used, cx.attr_span); } @@ -124,10 +124,17 @@ pub(crate) enum OnDuplicate { /// Give a default warning Warn, + /// Duplicates will be a warning, with a note that this will be an error in the future. + FutureWarn, + /// Give a default error Error, /// Ignore duplicates + /// + /// This should be used where duplicates would be ignored, but carry extra + /// meaning that could cause confusion. For example, `#[stable(since="1.0")] + /// #[stable(since="2.0")]`, which version should be used for `stable`? Ignore, /// Custom function called when a duplicate attribute is found. @@ -144,6 +151,9 @@ impl OnDuplicate { OnDuplicate::Warn => { todo!() }, + OnDuplicate::FutureWarn => { + todo!() + }, OnDuplicate::Error => { cx.emit_err(UnusedMultiple { this: used, @@ -157,21 +167,14 @@ impl OnDuplicate { } } -pub(crate) enum AttributeDuplicates { - /// Duplicates after the first attribute will be an error. - /// - /// This should be used where duplicates would be ignored, but carry extra - /// meaning that could cause confusion. For example, `#[stable(since="1.0")] - /// #[stable(since="2.0")]`, which version should be used for `stable`? - ErrorFollowing, +pub(crate) enum AttributeOrder { + /// The first attribute is kept, and any duplicates after that are + /// handled according to the [duplicate strategy](SingleAttributeParser::ON_DUPLICATE) + KeepFirst, - /// Duplicates preceding the last instance of the attribute will be a - /// warning, with a note that this will be an error in the future. - /// - /// This is the same as `FutureWarnFollowing`, except the last attribute is - /// the one that is "used". Ideally these can eventually migrate to - /// `ErrorPreceding`. - FutureWarnPreceding, + /// The last attribute is kept, and any duplicates already seen earlier are + /// handled according to the [duplicate strategy](SingleAttributeParser::ON_DUPLICATE) + KeepLast, } type ConvertFn = fn(ThinVec) -> AttributeKind; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b3b39c85f3e19..b700b4804c0b2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -8,7 +8,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_span::{Span, Symbol, kw, sym}; use super::util::parse_version; -use super::{AcceptMapping, AttributeDuplicates, AttributeParser, OnDuplicate, SingleAttributeParser}; +use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; use crate::context::{AcceptContext, FinalizeContext}; use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -122,7 +122,7 @@ pub(crate) struct ConstStabilityIndirectParser; // FIXME(jdonszelmann): single word attribute group when we have these impl SingleAttributeParser for ConstStabilityIndirectParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_const_stable_indirect]; - const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option { diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 3365bbcbddf2f..6e9610becbfbe 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -2,7 +2,7 @@ use rustc_attr_data_structures::AttributeKind; use rustc_span::{hygiene::Transparency, Span}; use rustc_span::sym; -use super::{AcceptContext, AttributeDuplicates, OnDuplicate, SingleAttributeParser}; +use super::{AcceptContext, AttributeOrder, OnDuplicate, SingleAttributeParser}; use crate::parser::ArgParser; pub(crate) struct TransparencyParser; @@ -12,7 +12,7 @@ pub(crate) struct TransparencyParser; #[allow(rustc::diagnostic_outside_of_impl)] impl SingleAttributeParser for TransparencyParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_transparency]; - const ON_DUPLICATE_STRATEGY: AttributeDuplicates = AttributeDuplicates::ErrorFollowing; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Custom(|cx, used, unused| { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); }); From 29c3315346f74b8b5ea11a73782f15f103e01387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 17:59:14 +0100 Subject: [PATCH 12/26] implement inline parser --- .../src/attributes/inline.rs | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index c62d1966ec7d3..c4b2b15cb02e8 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -1,17 +1,41 @@ -use rustc_span::{sym, Span}; +use rustc_attr_data_structures::{AttributeKind, InlineAttr}; +use rustc_errors::{struct_span_code_err, E0534, E0535}; +use rustc_span::sym; -use crate::attributes::SingleAttributeParser; +use crate::{attributes::SingleAttributeParser, parser::ArgParser}; + +use super::{AcceptContext, AttributeOrder, OnDuplicate}; pub(crate) struct InlineParser; impl SingleAttributeParser for InlineParser { const PATH: &'static [rustc_span::Symbol] = &[sym::inline]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::FutureWarn; - fn on_duplicate(cx: &super::AcceptContext<'_>, used: Span, unused: Span) { - todo!() - } + fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { + match args { + ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint)), + ArgParser::List(list) => { + let Some(l) = list.single() else { + struct_span_code_err!(cx.dcx(), cx.attr_span, E0534, "expected one argument").emit(); + return None; + }; - fn convert(cx: &super::AcceptContext<'_>, args: &crate::parser::ArgParser<'_>) -> Option { - todo!() + match l.lit().and_then(|i| i.value_str()) { + Some(sym::always) => Some(AttributeKind::Inline(InlineAttr::Always)), + Some(sym::never) => Some(AttributeKind::Inline(InlineAttr::Never)), + _ => { + struct_span_code_err!(cx.dcx(), l.span(), E0535, "invalid argument") + .with_help("valid inline arguments are `always` and `never`") + .emit(); + return None + } + } + }, + ArgParser::NameValue(_) => { + todo!() + }, + } } } From 0cb28912ddfe22654fee56e952449aa339ed37c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 18:00:10 +0100 Subject: [PATCH 13/26] rename future error --- compiler/rustc_attr_parsing/src/attributes/inline.rs | 2 +- compiler/rustc_attr_parsing/src/attributes/mod.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index c4b2b15cb02e8..f53cc0d891858 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -11,7 +11,7 @@ pub(crate) struct InlineParser; impl SingleAttributeParser for InlineParser { const PATH: &'static [rustc_span::Symbol] = &[sym::inline]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::FutureWarn; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { match args { diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index e1181f63956fa..e94cdd6af00d2 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -125,7 +125,7 @@ pub(crate) enum OnDuplicate { Warn, /// Duplicates will be a warning, with a note that this will be an error in the future. - FutureWarn, + WarnButFutureError, /// Give a default error Error, @@ -151,7 +151,7 @@ impl OnDuplicate { OnDuplicate::Warn => { todo!() }, - OnDuplicate::FutureWarn => { + OnDuplicate::WarnButFutureError => { todo!() }, OnDuplicate::Error => { From 336587cd6a06c595a742d739ca109ed8faa91ecd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20D=C3=B6nszelmann?= Date: Thu, 6 Feb 2025 18:38:41 +0100 Subject: [PATCH 14/26] convert entire codebase to parsed inline attrs --- .../src/attributes.rs | 2 +- .../src/attributes/inline.rs | 14 +++-- .../rustc_attr_parsing/src/attributes/mod.rs | 4 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 48 +---------------- compiler/rustc_passes/src/check_attr.rs | 51 ++++++++++--------- .../clippy_lints/src/attrs/inline_always.rs | 25 ++++----- .../src/inline_fn_without_body.rs | 14 ++--- .../clippy/clippy_lints/src/missing_inline.rs | 6 +-- .../clippy_lints/src/pass_by_ref_or_value.rs | 15 +++--- 9 files changed, 67 insertions(+), 112 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 61eab1550e4f4..9649571733fc7 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -186,7 +186,7 @@ pub enum AttributeKind { span: Span, comment: Symbol, }, - Inline(InlineAttr), + Inline(InlineAttr, Span), MacroTransparency(Transparency), Repr(ThinVec<(ReprAttr, Span)>), Stability { diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index f53cc0d891858..dd963d85b74c1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -15,16 +15,16 @@ impl SingleAttributeParser for InlineParser { fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { match args { - ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint)), + ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)), ArgParser::List(list) => { let Some(l) = list.single() else { struct_span_code_err!(cx.dcx(), cx.attr_span, E0534, "expected one argument").emit(); return None; }; - match l.lit().and_then(|i| i.value_str()) { - Some(sym::always) => Some(AttributeKind::Inline(InlineAttr::Always)), - Some(sym::never) => Some(AttributeKind::Inline(InlineAttr::Never)), + match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) { + Some(sym::always) => Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span)), + Some(sym::never) => Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span)), _ => { struct_span_code_err!(cx.dcx(), l.span(), E0535, "invalid argument") .with_help("valid inline arguments are `always` and `never`") @@ -34,8 +34,12 @@ impl SingleAttributeParser for InlineParser { } }, ArgParser::NameValue(_) => { - todo!() + // silently ignored, we warn somewhere else. + // FIXME(jdonszelmann): that warning *should* go here. + None }, } } } + + diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index e94cdd6af00d2..5462fa11a4299 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -149,10 +149,10 @@ impl OnDuplicate { fn exec(&self, cx: &AcceptContext<'_>, used: Span, unused: Span) { match self { OnDuplicate::Warn => { - todo!() + // todo!() }, OnDuplicate::WarnButFutureError => { - todo!() + // todo!() }, OnDuplicate::Error => { cx.emit_err(UnusedMultiple { diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 673740b4aab9f..eed306a01bbbd 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -6,7 +6,7 @@ use rustc_ast::expand::autodiff_attrs::{ }; use rustc_ast::{MetaItem, MetaItemInner, attr}; use rustc_attr_parsing::ReprAttr::ReprAlign; -use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_attr_parsing::{find_attr, AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; @@ -25,7 +25,6 @@ use rustc_session::parse::feature_err; use rustc_session::{Session, lint}; use rustc_span::{Ident, Span, sym}; use rustc_target::spec::SanitizerSet; -use tracing::debug; use crate::errors; use crate::target_features::{check_target_feature_trait_unsafe, from_target_feature_attr}; @@ -519,50 +518,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); - codegen_fn_attrs.inline = attrs.iter().fold(InlineAttr::None, |ia, attr| { - if !attr.has_name(sym::inline) { - return ia; - } - - if attr.is_word() { - return InlineAttr::Hint; - } - let Some(ref items) = attr.meta_item_list() else { - return ia; - }; - inline_span = Some(attr.span()); - - let [item] = &items[..] else { - struct_span_code_err!(tcx.dcx(), attr.span(), E0534, "expected one argument").emit(); - return InlineAttr::None; - }; - - if item.has_name(sym::always) { - InlineAttr::Always - } else if item.has_name(sym::never) { - InlineAttr::Never - } else { - struct_span_code_err!(tcx.dcx(), items[0].span(), E0535, "invalid argument") - .with_help("valid inline arguments are `always` and `never`") - .emit(); - - InlineAttr::None - } - }); - codegen_fn_attrs.inline = attrs.iter().fold(codegen_fn_attrs.inline, |ia, attr| { - if !attr.has_name(sym::rustc_force_inline) || !tcx.features().rustc_attrs() { - return ia; - } - - if attr.is_word() { - InlineAttr::Force { attr_span: attr.span(), reason: None } - } else if let Some(val) = attr.value_str() { - InlineAttr::Force { attr_span: attr.span(), reason: Some(val) } - } else { - debug!("`rustc_force_inline` not checked by attribute validation"); - ia - } - }); + codegen_fn_attrs.inline = find_attr!(attrs, AttributeKind::Inline(i, _) => *i).unwrap_or(InlineAttr::None); // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself, // but not for the code generation backend because at that point the naked function will just be diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 5ada289cc2090..61d0419624c5b 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -123,6 +123,9 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Stability { span, .. } | AttributeKind::ConstStability { span, .. }, ) => self.check_stability_promotable(*span, target), + Attribute::Parsed(AttributeKind::Inline(_, attr_span)) => { + self.check_inline(hir_id, *attr_span, span, target) + } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self .check_allow_internal_unstable( hir_id, @@ -139,7 +142,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> { [sym::diagnostic, sym::on_unimplemented, ..] => { self.check_diagnostic_on_unimplemented(attr.span(), hir_id, target) } - [sym::inline, ..] => self.check_inline(hir_id, attr, span, target), [sym::coverage, ..] => self.check_coverage(attr, span, target), [sym::optimize, ..] => self.check_optimize(hir_id, attr, span, target), [sym::no_sanitize, ..] => { @@ -347,11 +349,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.check_rustc_force_inline(hir_id, attrs, span, target); } - fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr: &Attribute, sym: &str) { + fn inline_attr_str_error_with_macro_def(&self, hir_id: HirId, attr_span: Span, sym: &str) { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::IgnoredAttrWithMacro { sym }, ); } @@ -411,7 +413,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { } /// Checks if an `#[inline]` is applied to a function or a closure. - fn check_inline(&self, hir_id: HirId, attr: &Attribute, span: Span, target: Target) { + fn check_inline(&self, hir_id: HirId, attr_span: Span, defn_span: Span, target: Target) { match target { Target::Fn | Target::Closure @@ -420,7 +422,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::IgnoredInlineAttrFnProto, ) } @@ -431,17 +433,17 @@ impl<'tcx> CheckAttrVisitor<'tcx> { Target::AssocConst => self.tcx.emit_node_span_lint( UNUSED_ATTRIBUTES, hir_id, - attr.span(), + attr_span, errors::IgnoredInlineAttrConstants, ), // FIXME(#80564): Same for fields, arms, and macro defs Target::Field | Target::Arm | Target::MacroDef => { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "inline") + self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "inline") } _ => { self.dcx().emit_err(errors::InlineNotFnOrClosure { - attr_span: attr.span(), - defn_span: span, + attr_span, + defn_span, }); } } @@ -636,7 +638,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "naked") + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "naked") } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { @@ -714,7 +716,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // with crates depending on them, we can't throw an error here. Target::Field | Target::Arm | Target::MacroDef => { for attr in attrs { - self.inline_attr_str_error_with_macro_def(hir_id, attr, "track_caller"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "track_caller"); } } _ => { @@ -757,7 +759,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "non_exhaustive"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "non_exhaustive"); } _ => { self.dcx().emit_err(errors::NonExhaustiveWrongLocation { @@ -777,7 +779,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "marker"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "marker"); } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToTrait { @@ -831,7 +833,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "target_feature"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "target_feature"); } _ => { self.dcx().emit_err(errors::AttrShouldBeAppliedToFn { @@ -1541,7 +1543,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "cold"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "cold"); } _ => { // FIXME: #[cold] was previously allowed on non-functions and some crates used @@ -1583,7 +1585,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "link_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_name"); } _ => { // FIXME: #[cold] was previously allowed on non-functions/statics and some crates @@ -1617,7 +1619,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "no_link"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_link"); } _ => { self.dcx().emit_err(errors::NoLink { attr_span: attr.span(), span }); @@ -1639,7 +1641,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "export_name"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "export_name"); } _ => { self.dcx().emit_err(errors::ExportName { attr_span: attr.span(), span }); @@ -1813,7 +1815,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "link_section"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "link_section"); } _ => { // FIXME: #[link_section] was previously allowed on non-functions/statics and some @@ -1838,7 +1840,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "no_mangle"); + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "no_mangle"); } // FIXME: #[no_mangle] was previously allowed on non-functions/statics, this should be an error // The error should specify that the item that is wrong is specifically a *foreign* fn/static @@ -2186,7 +2188,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // 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, "allow_internal_unstable") + self.inline_attr_str_error_with_macro_def(hir_id, attr.span(), "allow_internal_unstable") } _ => { self.tcx @@ -2768,10 +2770,8 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) { let attrs = tcx.hir().attrs(item.hir_id()); - for attr in attrs { - if attr.has_name(sym::inline) { - tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span: attr.span() }); - } + if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(_, span) => *span) { + tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span }); } } @@ -2791,6 +2791,7 @@ pub(crate) fn provide(providers: &mut Providers) { *providers = Providers { check_mod_attrs, ..*providers }; } +// FIXME(jdonszelmann): remove, check during parsing fn check_duplicates( tcx: TyCtxt<'_>, attr: &Attribute, diff --git a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs index cb63fadb4e21c..141ba7b0636a5 100644 --- a/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs +++ b/src/tools/clippy/clippy_lints/src/attrs/inline_always.rs @@ -1,29 +1,22 @@ use super::INLINE_ALWAYS; -use super::utils::is_word; use clippy_utils::diagnostics::span_lint; +use rustc_attr_parsing::{find_attr, AttributeKind, InlineAttr}; use rustc_hir::Attribute; use rustc_lint::LateContext; use rustc_span::symbol::Symbol; -use rustc_span::{Span, sym}; +use rustc_span::Span; pub(super) fn check(cx: &LateContext<'_>, span: Span, name: Symbol, attrs: &[Attribute]) { if span.from_expansion() { return; } - for attr in attrs { - if let Some(values) = attr.meta_item_list() { - if values.len() != 1 || !attr.has_name(sym::inline) { - continue; - } - if is_word(&values[0], sym::always) { - span_lint( - cx, - INLINE_ALWAYS, - attr.span(), - format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), - ); - } - } + if let Some(span) = find_attr!(attrs, AttributeKind::Inline(InlineAttr::Always, span) => *span) { + span_lint( + cx, + INLINE_ALWAYS, + span, + format!("you have declared `#[inline(always)]` on `{name}`. This is usually a bad idea"), + ); } } diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs index 9b4a3b3f9c84c..b8be9a807f565 100644 --- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs +++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs @@ -1,10 +1,10 @@ use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sugg::DiagExt; +use rustc_attr_parsing::{find_attr, AttributeKind}; use rustc_errors::Applicability; use rustc_hir::{TraitFn, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::declare_lint_pass; -use rustc_span::sym; declare_clippy_lint! { /// ### What it does @@ -32,20 +32,20 @@ declare_lint_pass!(InlineFnWithoutBody => [INLINE_FN_WITHOUT_BODY]); impl<'tcx> LateLintPass<'tcx> for InlineFnWithoutBody { fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if let TraitItemKind::Fn(_, TraitFn::Required(_)) = item.kind - && let Some(attr) = cx + && let Some(attr_span) = find_attr!(cx .tcx .hir() - .attrs(item.hir_id()) - .iter() - .find(|a| a.has_name(sym::inline)) + .attrs(item.hir_id()), + AttributeKind::Inline(_, span) => *span + ) { span_lint_and_then( cx, INLINE_FN_WITHOUT_BODY, - attr.span(), + attr_span, format!("use of `#[inline]` on trait method `{}` which has no body", item.ident), |diag| { - diag.suggest_remove_item(cx, attr.span(), "remove", Applicability::MachineApplicable); + diag.suggest_remove_item(cx, attr_span, "remove", Applicability::MachineApplicable); }, ); } diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs index 3cf1a80607e8b..a14070488ab3d 100644 --- a/src/tools/clippy/clippy_lints/src/missing_inline.rs +++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs @@ -1,10 +1,11 @@ use clippy_utils::diagnostics::span_lint; +use rustc_attr_parsing::{find_attr, AttributeKind}; use rustc_hir as hir; use rustc_hir::Attribute; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::AssocItemContainer; use rustc_session::declare_lint_pass; -use rustc_span::{Span, sym}; +use rustc_span::Span; declare_clippy_lint! { /// ### What it does @@ -64,8 +65,7 @@ declare_clippy_lint! { } fn check_missing_inline_attrs(cx: &LateContext<'_>, attrs: &[Attribute], sp: Span, desc: &'static str) { - let has_inline = attrs.iter().any(|a| a.has_name(sym::inline)); - if !has_inline { + if !find_attr!(attrs, AttributeKind::Inline(..)) { span_lint( cx, MISSING_INLINE_IN_PUBLIC_ITEMS, diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 73c31b83b51f6..c86ca6cf93ebd 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -5,8 +5,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::{for_each_top_level_late_bound_region, is_copy}; use clippy_utils::{is_self, is_self_ty}; +use rustc_attr_parsing::{find_attr, AttributeKind, InlineAttr}; use core::ops::ControlFlow; -use rustc_ast::attr; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; @@ -281,13 +281,14 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { return; } let attrs = cx.tcx.hir().attrs(hir_id); + if find_attr!(attrs, AttributeKind::Inline(InlineAttr::Always, _)) { + return; + } + for a in attrs { - if let Some(meta_items) = a.meta_item_list() { - if a.has_name(sym::proc_macro_derive) - || (a.has_name(sym::inline) && attr::list_contains_name(&meta_items, sym::always)) - { - return; - } + // FIXME(jdonszelmann): make part of the find_attr above + if a.has_name(sym::proc_macro_derive) { + return; } } }, From cfbcc72f7284658f9de09ac553449312a754e2fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 12 Feb 2025 13:59:08 +0100 Subject: [PATCH 15/26] make lints possible in attr lowering fix --- compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 15 ++++++------ compiler/rustc_ast_lowering/src/item.rs | 16 ++++++------- compiler/rustc_ast_lowering/src/lib.rs | 10 ++++---- compiler/rustc_ast_lowering/src/pat.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 23 ++++++++++++++++--- .../src/deriving/generic/mod.rs | 2 +- compiler/rustc_lint/src/nonstandard_style.rs | 2 +- compiler/rustc_resolve/src/def_collector.rs | 1 + 9 files changed, 46 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 1d9ca6bb9c8cb..0500da38286d2 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -108,7 +108,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs, l.span); + self.lower_attrs(hir_id, &l.attrs, l.span, l.id); self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index efbd1711daa92..e20cc1951d836 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -77,7 +77,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.attrs.insert( ex.hir_id.local_id, &*self.arena.alloc_from_iter( - self.lower_attrs_vec(&e.attrs, e.span) + self.lower_attrs_vec(&e.attrs, e.span, e.id) .into_iter() .chain(old_attrs.iter().cloned()), ), @@ -97,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span); + self.lower_attrs(expr_hir_id, &e.attrs, e.span, e.id); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -669,7 +669,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span); + self.lower_attrs(hir_id, &arm.attrs, arm.span, arm.id); let is_never_pattern = pat.is_never_pattern(); let body = if let Some(body) = &arm.body && !is_never_pattern @@ -839,6 +839,7 @@ impl<'hir> LoweringContext<'_, 'hir> { span: unstable_span, }], span, + DUMMY_NODE_ID ); } } @@ -1673,7 +1674,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, f.id); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1936,7 +1937,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs, e.span); + self.lower_attrs(expr.hir_id, &e.attrs, e.span, e.id); expr } @@ -1993,7 +1994,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let val_ident = Ident::with_dummy_span(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let val_expr = self.expr_ident(span, val_ident, val_pat_nid); - self.lower_attrs(val_expr.hir_id, &attrs, span); + self.lower_attrs(val_expr.hir_id, &attrs, span, sub_expr.node_id()); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr) }; @@ -2024,7 +2025,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ret_expr = self.checked_return(Some(from_residual_expr)); self.arena.alloc(self.expr(try_span, ret_expr)) }; - self.lower_attrs(ret_expr.hir_id, &attrs, ret_expr.span); + self.lower_attrs(ret_expr.hir_id, &attrs, span, sub_expr.node_id()); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a4fc4b3e3a121..b5d7dfa4dd9e8 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -94,7 +94,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP); + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP, c.id); hir::OwnerNode::Crate(module) }) } @@ -158,7 +158,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut ident = i.ident; let vis_span = self.lower_span(i.vis.span); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, i.id); let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind); let item = hir::Item { owner_id: hir_id.expect_owner(), @@ -621,7 +621,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, i.id); let item = hir::ForeignItem { owner_id, ident: self.lower_ident(i.ident), @@ -679,7 +679,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> { let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span); + self.lower_attrs(hir_id, &v.attrs, v.span, v.id); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -741,7 +741,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FieldDef<'hir> { let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, f.id); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -760,7 +760,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, i.id); let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { @@ -896,7 +896,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, i.id); let (generics, kind) = match &i.kind { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( @@ -1057,7 +1057,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span); + self.lower_attrs(hir_id, ¶m.attrs, param.span, param.id); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1c69937eed07a..1e2b3600260ef 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -866,11 +866,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: HirId, attrs: &[Attribute], target_span: Span, + target_node_id: NodeId, ) -> &'hir [hir::Attribute] { if attrs.is_empty() { &[] } else { - let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span)); + let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), target_node_id); debug_assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(lowered_attrs); @@ -890,9 +891,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span) -> Vec { - self.attribute_parser - .parse_attribute_list(attrs, target_span, OmitDoc::Lower, |s| self.lower_span(s)) + fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span, target_node_id: NodeId) -> Vec { + self.attribute_parser.parse_attribute_list(attrs, target_span, target_node_id, OmitDoc::Lower, |s| self.lower_span(s)) } fn alias_attrs(&mut self, id: HirId, target_id: HirId) { @@ -1816,7 +1816,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span()); + self.lower_attrs(hir_id, ¶m.attrs, param.span(), param.id); hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 2dcfe7c745da5..ba4ebdf4aeb67 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -93,7 +93,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span); + self.lower_attrs(hir_id, &f.attrs, f.span, f.id); hir::PatField { hir_id, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 2048a5e34b418..8caebf3ee4ac5 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -3,11 +3,12 @@ use std::collections::BTreeMap; use std::ops::Deref; use std::sync::LazyLock; -use rustc_ast::{self as ast, DelimArgs}; +use rustc_ast::{self as ast, node_id, DelimArgs}; use rustc_attr_data_structures::AttributeKind; use rustc_errors::{DiagCtxtHandle, Diagnostic}; use rustc_feature::Features; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId}; +use rustc_session::lint::{BuiltinLintDiag, Lint}; use rustc_session::Session; use rustc_span::symbol::kw; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -23,6 +24,7 @@ use crate::attributes::stability::{ use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single}; use crate::parser::{ArgParser, MetaItemParser}; +use rustc_ast::NodeId; macro_rules! attribute_groups { ( @@ -101,6 +103,17 @@ impl<'a> AcceptContext<'a> { self.dcx().emit_err(diag) } } + + pub(crate) fn emit_lint(&self, lint: &'static Lint, span: Span, diagnostic: BuiltinLintDiag) { + if !self.limit_diagnostics { + self.sess().psess.buffer_lint( + lint, + span, + self.target_node_id, + diagnostic, + ); + } + } } impl<'a> Deref for AcceptContext<'a> { @@ -120,6 +133,8 @@ pub(crate) struct FinalizeContext<'a> { pub(crate) cx: &'a AttributeParser<'a>, /// The span of the syntactical component this attribute was applied to pub(crate) target_span: Span, + /// The node id (in the ast) of the syntactical component this attribute was applied to + pub(crate) target_node_id: NodeId, } impl<'a> Deref for FinalizeContext<'a> { @@ -171,6 +186,7 @@ impl<'sess> AttributeParser<'sess> { attrs: &[ast::Attribute], sym: Symbol, target_span: Span, + target_node_id: NodeId, limit_diagnostics: bool, ) -> Option { let mut parsed = Self { @@ -180,7 +196,7 @@ impl<'sess> AttributeParser<'sess> { parse_only: Some(sym), limit_diagnostics, } - .parse_attribute_list(attrs, target_span, OmitDoc::Skip, std::convert::identity); + .parse_attribute_list(attrs, target_span, target_node_id, OmitDoc::Skip, std::convert::identity); assert!(parsed.len() <= 1); @@ -211,13 +227,14 @@ impl<'sess> AttributeParser<'sess> { &'a self, attrs: &'a [ast::Attribute], target_span: Span, + target_node_id: NodeId, omit_doc: OmitDoc, lower_span: impl Copy + Fn(Span) -> Span, ) -> Vec { let mut attributes = Vec::new(); - let group_cx = FinalizeContext { cx: self, target_span }; + let group_cx = FinalizeContext { cx: self, target_span, target_node_id }; for attr in attrs { // if we're only looking for a single attribute, diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 6b59ac2582755..3e943181f8f96 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -482,7 +482,7 @@ impl<'a> TraitDef<'a> { match item { Annotatable::Item(item) => { let is_packed = matches!( - AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, true), + AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, true), Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..))) ); diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 49f9ad39780a3..3010f71a5ebed 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -163,7 +163,7 @@ impl NonCamelCaseTypes { impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = matches!( - AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, true), + AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id, true), Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC) ); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 75972a71c8e57..d9140f7425844 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -145,6 +145,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { let attrs = parser.parse_attribute_list( &i.attrs, i.span, + i.id, OmitDoc::Skip, std::convert::identity, ); From c06e77b68faa4780c9f8fff87bc6c0f28ba25e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 12 Feb 2025 15:04:26 +0100 Subject: [PATCH 16/26] depend more on attr_data_structures and move find_attr! there --- Cargo.lock | 6 ++- .../rustc_attr_data_structures/src/lib.rs | 44 +++++++++++++++++++ compiler/rustc_attr_parsing/Cargo.toml | 1 + compiler/rustc_attr_parsing/src/lib.rs | 43 +----------------- compiler/rustc_hir_pretty/Cargo.toml | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_middle/Cargo.toml | 3 +- .../src/middle/codegen_fn_attrs.rs | 2 +- compiler/rustc_middle/src/middle/stability.rs | 2 +- compiler/rustc_middle/src/mir/mono.rs | 2 +- compiler/rustc_middle/src/query/erase.rs | 14 +++--- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/ty/instance.rs | 2 +- compiler/rustc_middle/src/ty/mod.rs | 5 ++- compiler/rustc_middle/src/ty/parameterized.rs | 8 ++-- 15 files changed, 73 insertions(+), 65 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb4cf235c6f49..7f53ef1d5705f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3286,6 +3286,7 @@ dependencies = [ "rustc_hir", "rustc_lexer", "rustc_macros", + "rustc_middle", "rustc_serialize", "rustc_session", "rustc_span", @@ -3741,7 +3742,7 @@ dependencies = [ "rustc_abi", "rustc_ast", "rustc_ast_pretty", - "rustc_attr_parsing", + "rustc_attr_data_structures", "rustc_hir", "rustc_span", ] @@ -4008,7 +4009,8 @@ dependencies = [ "rustc_apfloat", "rustc_arena", "rustc_ast", - "rustc_attr_parsing", + "rustc_ast_ir", + "rustc_attr_data_structures", "rustc_data_structures", "rustc_error_messages", "rustc_errors", diff --git a/compiler/rustc_attr_data_structures/src/lib.rs b/compiler/rustc_attr_data_structures/src/lib.rs index e4bb459e6df5a..f4986d1d1872a 100644 --- a/compiler/rustc_attr_data_structures/src/lib.rs +++ b/compiler/rustc_attr_data_structures/src/lib.rs @@ -149,3 +149,47 @@ print_tup!(A B C D E F G H); print_skip!(Span, ()); print_disp!(Symbol, u16, bool, NonZero); print_debug!(UintTy, IntTy, Align, AttrStyle, CommentKind, Transparency); + +/// Finds attributes in sequences of attributes by pattern matching. +/// +/// A little like `matches` but for attributes. +/// +/// ```rust,ignore (illustrative) +/// // finds the repr attribute +/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) { +/// +/// } +/// +/// // checks if one has matched +/// if find_attr!(attrs, AttributeKind::Repr(_)) { +/// +/// } +/// ``` +/// +/// Often this requires you to first end up with a list of attributes. +/// A common way to get those is through `tcx.get_all_attrs(did)` +#[macro_export] +macro_rules! find_attr { + ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{ + $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some() + }}; + + ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ + fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator) {} + check_attribute_iterator(&$attributes_list); + + let find_attribute = |iter| { + for i in $attributes_list { + match i { + rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { + return Some($e); + } + _ => {} + } + } + + None + }; + find_attribute($attributes_list) + }}; +} diff --git a/compiler/rustc_attr_parsing/Cargo.toml b/compiler/rustc_attr_parsing/Cargo.toml index c335eeb5f7120..6b4ce957630ff 100644 --- a/compiler/rustc_attr_parsing/Cargo.toml +++ b/compiler/rustc_attr_parsing/Cargo.toml @@ -16,6 +16,7 @@ rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_hir = { path = "../rustc_hir" } rustc_lexer = { path = "../rustc_lexer" } rustc_macros = { path = "../rustc_macros" } +rustc_middle = { path = "../rustc_middle" } rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 9841166b37dbd..61706ee27b13d 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -92,50 +92,9 @@ mod session_diagnostics; pub use attributes::cfg::*; pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version}; pub use context::{AttributeParser, OmitDoc}; +#[macro_use] pub use rustc_attr_data_structures::*; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } -/// Finds attributes in sequences of attributes by pattern matching. -/// -/// A little like `matches` but for attributes. -/// -/// ```rust,ignore (illustrative) -/// // finds the repr attribute -/// if let Some(r) = find_attr!(attrs, AttributeKind::Repr(r) => r) { -/// -/// } -/// -/// // checks if one has matched -/// if find_attr!(attrs, AttributeKind::Repr(_)) { -/// -/// } -/// ``` -/// -/// Often this requires you to first end up with a list of attributes. -/// A common way to get those is through `tcx.get_all_attrs(did)` -#[macro_export] -macro_rules! find_attr { - ($attributes_list: expr, $pattern: pat $(if $guard: expr)?) => {{ - $crate::find_attr!($attributes_list, $pattern $(if $guard)? => ()).is_some() - }}; - - ($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{ - fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator) {} - check_attribute_iterator(&$attributes_list); - - let find_attribute = |iter| { - for i in $attributes_list { - match i { - rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => { - return Some($e); - } - _ => {} - } - } - None - }; - find_attribute($attributes_list) - }}; -} diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml index 86989d1e55b4d..91da8cb3fc5fb 100644 --- a/compiler/rustc_hir_pretty/Cargo.toml +++ b/compiler/rustc_hir_pretty/Cargo.toml @@ -8,7 +8,7 @@ edition = "2024" rustc_abi = { path = "../rustc_abi" } rustc_ast = { path = "../rustc_ast" } rustc_ast_pretty = { path = "../rustc_ast_pretty" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_hir = { path = "../rustc_hir" } rustc_span = { path = "../rustc_span" } # tidy-alphabetical-end diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 5c7426d76b31c..80fba97542d8c 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -16,7 +16,7 @@ use rustc_ast_pretty::pp::Breaks::{Consistent, Inconsistent}; use rustc_ast_pretty::pp::{self, Breaks}; use rustc_ast_pretty::pprust::state::MacHeader; use rustc_ast_pretty::pprust::{Comments, PrintState}; -use rustc_attr_parsing::{AttributeKind, PrintAttribute}; +use rustc_attr_data_structures::{AttributeKind, PrintAttribute}; use rustc_hir::{ BindingMode, ByRef, ConstArgKind, GenericArg, GenericBound, GenericParam, GenericParamKind, HirId, ImplicitSelfKind, LifetimeParamKind, Node, PatKind, PreciseCapturingArg, RangeEnd, Term, diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index aebd2181f31e1..43c1af642dd56 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -14,7 +14,8 @@ rustc_abi = { path = "../rustc_abi" } rustc_apfloat = "0.2.0" rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } -rustc_attr_parsing = { path = "../rustc_attr_parsing" } +rustc_ast_ir = { path = "../rustc_ast_ir" } +rustc_attr_data_structures = { path = "../rustc_attr_data_structures" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_messages = { path = "../rustc_error_messages" } # Used for intra-doc links rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 311bc60c3cd39..a94ead161c379 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -1,6 +1,6 @@ use rustc_abi::Align; use rustc_ast::expand::autodiff_attrs::AutoDiffAttrs; -use rustc_attr_parsing::{InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_attr_data_structures::{InlineAttr, InstructionSetAttr, OptimizeAttr}; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_span::Symbol; use rustc_target::spec::SanitizerSet; diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs index 2260cad41b97c..ec128c8c47863 100644 --- a/compiler/rustc_middle/src/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -4,7 +4,7 @@ use std::num::NonZero; use rustc_ast::NodeId; -use rustc_attr_parsing::{ +use rustc_attr_data_structures::{ self as attr, ConstStability, DefaultBodyStability, DeprecatedSince, Deprecation, Stability, }; use rustc_data_structures::unord::UnordMap; diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 58d5c94d03326..897119c071223 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -2,7 +2,7 @@ use std::fmt; use std::hash::Hash; use rustc_ast::expand::autodiff_attrs::AutoDiffItem; -use rustc_attr_parsing::InlineAttr; +use rustc_attr_data_structures::InlineAttr; use rustc_data_structures::base_n::{BaseNString, CASE_INSENSITIVE, ToBaseN}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxIndexMap; diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index cbd60920bc572..2abb2d2d8e5d0 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -231,9 +231,9 @@ trivial! { bool, Option<(rustc_span::def_id::DefId, rustc_session::config::EntryFnType)>, Option, - Option, - Option, - Option, + Option, + Option, + Option, Option, Option, Option, @@ -256,10 +256,10 @@ trivial! { Result, rustc_abi::ReprOptions, rustc_ast::expand::allocator::AllocatorKind, - rustc_attr_parsing::ConstStability, - rustc_attr_parsing::DefaultBodyStability, - rustc_attr_parsing::Deprecation, - rustc_attr_parsing::Stability, + rustc_attr_data_structures::ConstStability, + rustc_attr_data_structures::DefaultBodyStability, + rustc_attr_data_structures::Deprecation, + rustc_attr_data_structures::Stability, rustc_data_structures::svh::Svh, rustc_errors::ErrorGuaranteed, rustc_hir::Constness, diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 7c4ea06a7461a..aff0584f4d5a0 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -41,7 +41,7 @@ use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::Spanned; use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_target::spec::PanicStrategy; -use {rustc_abi as abi, rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_abi as abi, rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir}; use crate::infer::canonical::{self, Canonical}; use crate::lint::LintExpectation; diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index e9c19331e4a0b..20bd4d54d1d08 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -202,7 +202,7 @@ impl<'tcx> Instance<'tcx> { if !tcx.sess.opts.share_generics() // However, if the def_id is marked inline(never), then it's fine to just reuse the // upstream monomorphization. - && tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr_parsing::InlineAttr::Never + && tcx.codegen_fn_attrs(self.def_id()).inline != rustc_attr_data_structures::InlineAttr::Never { return None; } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index eb70a35d3708c..670d2e5647f4c 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -27,7 +27,8 @@ pub use intrinsic::IntrinsicDef; use rustc_abi::{Align, FieldIdx, Integer, IntegerType, ReprFlags, ReprOptions, VariantIdx}; use rustc_ast::expand::StrippedCfgItem; use rustc_ast::node_id::NodeMap; -use rustc_attr_parsing::AttributeKind; +pub use rustc_ast_ir::{Movability, Mutability, try_visit}; +use rustc_attr_data_structures::AttributeKind; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -51,7 +52,7 @@ pub use rustc_type_ir::relate::VarianceDiagInfo; pub use rustc_type_ir::*; use tracing::{debug, instrument}; pub use vtable::*; -use {rustc_ast as ast, rustc_attr_parsing as attr, rustc_hir as hir}; +use {rustc_ast as ast, rustc_attr_data_structures as attr, rustc_hir as hir}; pub use self::closure::{ BorrowKind, CAPTURE_STRUCT_LOCAL, CaptureInfo, CapturedPlace, ClosureTypeInfo, diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 8eaf0a58f7086..71fc38cb7edb4 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -80,10 +80,10 @@ trivially_parameterized_over_tcx! { rustc_ast::Attribute, rustc_ast::DelimArgs, rustc_ast::expand::StrippedCfgItem, - rustc_attr_parsing::ConstStability, - rustc_attr_parsing::DefaultBodyStability, - rustc_attr_parsing::Deprecation, - rustc_attr_parsing::Stability, + rustc_attr_data_structures::ConstStability, + rustc_attr_data_structures::DefaultBodyStability, + rustc_attr_data_structures::Deprecation, + rustc_attr_data_structures::Stability, rustc_hir::Constness, rustc_hir::Defaultness, rustc_hir::Safety, From 721a706ef4e79ebe587426b38e76d9a1c4fc5490 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 28 Feb 2025 13:01:11 +0100 Subject: [PATCH 17/26] implement duplicate attr lints --- compiler/rustc_ast_lowering/src/block.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 15 +- compiler/rustc_ast_lowering/src/item.rs | 16 +- compiler/rustc_ast_lowering/src/lib.rs | 22 +- compiler/rustc_ast_lowering/src/pat.rs | 2 +- compiler/rustc_attr_parsing/messages.ftl | 10 + .../src/attributes/allow_unstable.rs | 34 +-- .../src/attributes/confusables.rs | 8 +- .../src/attributes/deprecation.rs | 14 +- .../src/attributes/inline.rs | 34 +-- .../rustc_attr_parsing/src/attributes/mod.rs | 132 +++++----- .../rustc_attr_parsing/src/attributes/repr.rs | 21 +- .../src/attributes/stability.rs | 43 ++-- .../src/attributes/transparency.rs | 9 +- compiler/rustc_attr_parsing/src/context.rs | 243 +++++++++++++----- compiler/rustc_attr_parsing/src/lib.rs | 5 +- compiler/rustc_attr_parsing/src/parser.rs | 14 +- .../src/session_diagnostics.rs | 13 +- .../src/deriving/generic/mod.rs | 2 +- .../rustc_codegen_ssa/src/codegen_attrs.rs | 5 +- compiler/rustc_lint/src/nonstandard_style.rs | 2 +- compiler/rustc_passes/src/check_attr.rs | 14 +- compiler/rustc_resolve/src/def_collector.rs | 2 +- 23 files changed, 411 insertions(+), 251 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/block.rs b/compiler/rustc_ast_lowering/src/block.rs index 0500da38286d2..1d9ca6bb9c8cb 100644 --- a/compiler/rustc_ast_lowering/src/block.rs +++ b/compiler/rustc_ast_lowering/src/block.rs @@ -108,7 +108,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }; let span = self.lower_span(l.span); let source = hir::LocalSource::Normal; - self.lower_attrs(hir_id, &l.attrs, l.span, l.id); + self.lower_attrs(hir_id, &l.attrs, l.span); self.arena.alloc(hir::LetStmt { hir_id, ty, pat, init, els, span, source }) } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e20cc1951d836..c1c4b6be5d7a5 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -77,7 +77,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.attrs.insert( ex.hir_id.local_id, &*self.arena.alloc_from_iter( - self.lower_attrs_vec(&e.attrs, e.span, e.id) + self.lower_attrs_vec(&e.attrs, e.span, ex.hir_id) .into_iter() .chain(old_attrs.iter().cloned()), ), @@ -97,7 +97,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } let expr_hir_id = self.lower_node_id(e.id); - self.lower_attrs(expr_hir_id, &e.attrs, e.span, e.id); + self.lower_attrs(expr_hir_id, &e.attrs, e.span); let kind = match &e.kind { ExprKind::Array(exprs) => hir::ExprKind::Array(self.lower_exprs(exprs)), @@ -669,7 +669,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let guard = arm.guard.as_ref().map(|cond| self.lower_expr(cond)); let hir_id = self.next_id(); let span = self.lower_span(arm.span); - self.lower_attrs(hir_id, &arm.attrs, arm.span, arm.id); + self.lower_attrs(hir_id, &arm.attrs, arm.span); let is_never_pattern = pat.is_never_pattern(); let body = if let Some(body) = &arm.body && !is_never_pattern @@ -839,7 +839,6 @@ impl<'hir> LoweringContext<'_, 'hir> { span: unstable_span, }], span, - DUMMY_NODE_ID ); } } @@ -1674,7 +1673,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, f.id); + self.lower_attrs(hir_id, &f.attrs, f.span); hir::ExprField { hir_id, ident: self.lower_ident(f.ident), @@ -1937,7 +1936,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // // Also, add the attributes to the outer returned expr node. let expr = self.expr_drop_temps_mut(for_span, match_expr); - self.lower_attrs(expr.hir_id, &e.attrs, e.span, e.id); + self.lower_attrs(expr.hir_id, &e.attrs, e.span); expr } @@ -1994,7 +1993,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let val_ident = Ident::with_dummy_span(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let val_expr = self.expr_ident(span, val_ident, val_pat_nid); - self.lower_attrs(val_expr.hir_id, &attrs, span, sub_expr.node_id()); + self.lower_attrs(val_expr.hir_id, &attrs, span); let continue_pat = self.pat_cf_continue(unstable_span, val_pat); self.arm(continue_pat, val_expr) }; @@ -2025,7 +2024,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let ret_expr = self.checked_return(Some(from_residual_expr)); self.arena.alloc(self.expr(try_span, ret_expr)) }; - self.lower_attrs(ret_expr.hir_id, &attrs, span, sub_expr.node_id()); + self.lower_attrs(ret_expr.hir_id, &attrs, span); let break_pat = self.pat_cf_break(try_span, residual_local); self.arm(break_pat, ret_expr) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index b5d7dfa4dd9e8..a4fc4b3e3a121 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -94,7 +94,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { self.with_lctx(CRATE_NODE_ID, |lctx| { let module = lctx.lower_mod(&c.items, &c.spans); // FIXME(jdonszelman): is dummy span ever a problem here? - lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP, c.id); + lctx.lower_attrs(hir::CRATE_HIR_ID, &c.attrs, DUMMY_SP); hir::OwnerNode::Crate(module) }) } @@ -158,7 +158,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let mut ident = i.ident; let vis_span = self.lower_span(i.vis.span); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, i.id); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let kind = self.lower_item_kind(i.span, i.id, hir_id, &mut ident, attrs, vis_span, &i.kind); let item = hir::Item { owner_id: hir_id.expect_owner(), @@ -621,7 +621,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_foreign_item(&mut self, i: &ForeignItem) -> &'hir hir::ForeignItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); let owner_id = hir_id.expect_owner(); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, i.id); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let item = hir::ForeignItem { owner_id, ident: self.lower_ident(i.ident), @@ -679,7 +679,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_variant(&mut self, v: &Variant) -> hir::Variant<'hir> { let hir_id = self.lower_node_id(v.id); - self.lower_attrs(hir_id, &v.attrs, v.span, v.id); + self.lower_attrs(hir_id, &v.attrs, v.span); hir::Variant { hir_id, def_id: self.local_def_id(v.id), @@ -741,7 +741,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::FieldDef<'hir> { let ty = self.lower_ty(&f.ty, ImplTraitContext::Disallowed(ImplTraitPosition::FieldTy)); let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, f.id); + self.lower_attrs(hir_id, &f.attrs, f.span); hir::FieldDef { span: self.lower_span(f.span), hir_id, @@ -760,7 +760,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_trait_item(&mut self, i: &AssocItem) -> &'hir hir::TraitItem<'hir> { let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, i.id); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let trait_item_def_id = hir_id.expect_owner(); let (generics, kind, has_default) = match &i.kind { @@ -896,7 +896,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let has_value = true; let (defaultness, _) = self.lower_defaultness(i.kind.defaultness(), has_value); let hir_id = hir::HirId::make_owner(self.current_hir_id_owner.def_id); - let attrs = self.lower_attrs(hir_id, &i.attrs, i.span, i.id); + let attrs = self.lower_attrs(hir_id, &i.attrs, i.span); let (generics, kind) = match &i.kind { AssocItemKind::Const(box ConstItem { generics, ty, expr, .. }) => self.lower_generics( @@ -1057,7 +1057,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_param(&mut self, param: &Param) -> hir::Param<'hir> { let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span, param.id); + self.lower_attrs(hir_id, ¶m.attrs, param.span); hir::Param { hir_id, pat: self.lower_pat(¶m.pat), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1e2b3600260ef..597c20e7c3fab 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -187,7 +187,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // interact with `gen`/`async gen` blocks allow_async_iterator: [sym::gen_future, sym::async_iterator].into(), - attribute_parser: AttributeParser::new(tcx.sess, tcx.features(), registered_tools), + attribute_parser: AttributeParser::new(tcx, tcx.features(), registered_tools), } } @@ -866,12 +866,11 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: HirId, attrs: &[Attribute], target_span: Span, - target_node_id: NodeId, ) -> &'hir [hir::Attribute] { if attrs.is_empty() { &[] } else { - let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), target_node_id); + let lowered_attrs = self.lower_attrs_vec(attrs, self.lower_span(target_span), id); debug_assert_eq!(id.owner, self.current_hir_id_owner); let ret = self.arena.alloc_from_iter(lowered_attrs); @@ -891,8 +890,19 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } - fn lower_attrs_vec(&self, attrs: &[Attribute], target_span: Span, target_node_id: NodeId) -> Vec { - self.attribute_parser.parse_attribute_list(attrs, target_span, target_node_id, OmitDoc::Lower, |s| self.lower_span(s)) + fn lower_attrs_vec( + &self, + attrs: &[Attribute], + target_span: Span, + target_hir_id: HirId, + ) -> Vec { + self.attribute_parser.parse_attribute_list( + attrs, + target_span, + target_hir_id, + OmitDoc::Lower, + |s| self.lower_span(s), + ) } fn alias_attrs(&mut self, id: HirId, target_id: HirId) { @@ -1816,7 +1826,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let (name, kind) = self.lower_generic_param_kind(param, source); let hir_id = self.lower_node_id(param.id); - self.lower_attrs(hir_id, ¶m.attrs, param.span(), param.id); + self.lower_attrs(hir_id, ¶m.attrs, param.span()); hir::GenericParam { hir_id, def_id: self.local_def_id(param.id), diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index ba4ebdf4aeb67..2dcfe7c745da5 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -93,7 +93,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let fs = self.arena.alloc_from_iter(fields.iter().map(|f| { let hir_id = self.lower_node_id(f.id); - self.lower_attrs(hir_id, &f.attrs, f.span, f.id); + self.lower_attrs(hir_id, &f.attrs, f.span); hir::PatField { hir_id, diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 45174c9582d33..573854afa746c 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -131,7 +131,17 @@ attr_parsing_unsupported_literal_generic = attr_parsing_unsupported_literal_suggestion = consider removing the prefix +attr_parsing_unused_duplicate = + unused attribute + .suggestion = remove this attribute + .note = attribute also specified here + .warn = {-attr_parsing_previously_accepted} + + attr_parsing_unused_multiple = multiple `{$name}` attributes .suggestion = remove this attribute .note = attribute also specified here + +-attr_parsing_perviously_accepted = + this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index d37ede86cfd2a..ef0aa734df4c6 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -4,41 +4,43 @@ use rustc_attr_data_structures::AttributeKind; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; -use crate::context::AcceptContext; +use crate::context::{AcceptContext, Stage}; use crate::parser::ArgParser; use crate::session_diagnostics; pub(crate) struct AllowInternalUnstableParser; -impl CombineAttributeParser for AllowInternalUnstableParser { +impl CombineAttributeParser for AllowInternalUnstableParser { const PATH: &'static [rustc_span::Symbol] = &[sym::allow_internal_unstable]; type Item = (Symbol, Span); const CONVERT: ConvertFn = AttributeKind::AllowInternalUnstable; - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator + 'a { - parse_unstable(cx, args, Self::PATH[0]).into_iter().zip(iter::repeat(cx.attr_span)) + fn extend<'c>( + cx: &'c AcceptContext<'c, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator { + parse_unstable(cx, args, >::PATH[0]) + .into_iter() + .zip(iter::repeat(cx.attr_span)) } } pub(crate) struct AllowConstFnUnstableParser; -impl CombineAttributeParser for AllowConstFnUnstableParser { +impl CombineAttributeParser for AllowConstFnUnstableParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_allow_const_fn_unstable]; type Item = Symbol; const CONVERT: ConvertFn = AttributeKind::AllowConstFnUnstable; - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator + 'a { - parse_unstable(cx, args, Self::PATH[0]) + fn extend<'c>( + cx: &'c AcceptContext<'c, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator + 'c { + parse_unstable(cx, args, >::PATH[0]) } } -fn parse_unstable<'a>( - cx: &AcceptContext<'_>, - args: &'a ArgParser<'a>, +fn parse_unstable( + cx: &AcceptContext<'_, '_, S>, + args: &ArgParser<'_>, symbol: Symbol, ) -> impl IntoIterator { let mut res = Vec::new(); diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 6cff952fcf229..afd3c012f05ad 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -3,7 +3,7 @@ use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; use super::{AcceptMapping, AttributeParser}; -use crate::context::FinalizeContext; +use crate::context::{FinalizeContext, Stage}; use crate::session_diagnostics; #[derive(Default)] @@ -12,8 +12,8 @@ pub(crate) struct ConfusablesParser { first_span: Option, } -impl AttributeParser for ConfusablesParser { - const ATTRIBUTES: AcceptMapping = &[(&[sym::rustc_confusables], |this, cx, args| { +impl AttributeParser for ConfusablesParser { + const ATTRIBUTES: AcceptMapping = &[(&[sym::rustc_confusables], |this, cx, args| { let Some(list) = args.list() else { // FIXME(jdonszelmann): error when not a list? Bring validation code here. // NOTE: currently subsequent attributes are silently ignored using @@ -45,7 +45,7 @@ impl AttributeParser for ConfusablesParser { this.first_span.get_or_insert(cx.attr_span); })]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.confusables.is_empty() { return None; } diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 3fe6add8ca0a3..71916e2b432e0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -2,17 +2,17 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol, sym}; -use super::{AttributeOrder, OnDuplicate, SingleAttributeParser}; use super::util::parse_version; -use crate::context::AcceptContext; +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; -fn get( - cx: &AcceptContext<'_>, +fn get( + cx: &AcceptContext<'_, '_, S>, ident: Ident, param_span: Span, arg: &ArgParser<'_>, @@ -45,12 +45,12 @@ fn get( } } -impl SingleAttributeParser for DeprecationParser { +impl SingleAttributeParser for DeprecationParser { const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { let features = cx.features(); let mut since = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index dd963d85b74c1..2d78547deaf3d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -1,45 +1,49 @@ use rustc_attr_data_structures::{AttributeKind, InlineAttr}; -use rustc_errors::{struct_span_code_err, E0534, E0535}; +use rustc_errors::{E0534, E0535, struct_span_code_err}; use rustc_span::sym; -use crate::{attributes::SingleAttributeParser, parser::ArgParser}; - use super::{AcceptContext, AttributeOrder, OnDuplicate}; +use crate::attributes::SingleAttributeParser; +use crate::context::Stage; +use crate::parser::ArgParser; pub(crate) struct InlineParser; -impl SingleAttributeParser for InlineParser { +impl SingleAttributeParser for InlineParser { const PATH: &'static [rustc_span::Symbol] = &[sym::inline]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { match args { ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)), ArgParser::List(list) => { - let Some(l) = list.single() else { - struct_span_code_err!(cx.dcx(), cx.attr_span, E0534, "expected one argument").emit(); + let Some(l) = list.single() else { + struct_span_code_err!(cx.dcx(), cx.attr_span, E0534, "expected one argument") + .emit(); return None; }; match l.meta_item().and_then(|i| i.word_without_args().map(|i| i.name)) { - Some(sym::always) => Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span)), - Some(sym::never) => Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span)), + Some(sym::always) => { + Some(AttributeKind::Inline(InlineAttr::Always, cx.attr_span)) + } + Some(sym::never) => { + Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span)) + } _ => { struct_span_code_err!(cx.dcx(), l.span(), E0535, "invalid argument") .with_help("valid inline arguments are `always` and `never`") .emit(); - return None + return None; } } - }, + } ArgParser::NameValue(_) => { // silently ignored, we warn somewhere else. // FIXME(jdonszelmann): that warning *should* go here. None - }, + } } } } - - diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 5462fa11a4299..0a5ae4768da41 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -17,12 +17,13 @@ use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; +use rustc_session::lint::builtin::UNUSED_ATTRIBUTES; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; -use crate::context::{AcceptContext, FinalizeContext}; +use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::ArgParser; -use crate::session_diagnostics::UnusedMultiple; +use crate::session_diagnostics::{self, UnusedMultiple}; pub(crate) mod allow_unstable; pub(crate) mod cfg; @@ -34,8 +35,8 @@ pub(crate) mod stability; pub(crate) mod transparency; pub(crate) mod util; -type AcceptFn = fn(&mut T, &AcceptContext<'_>, &ArgParser<'_>); -type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AcceptFn)]; +type AcceptFn = for<'sess> fn(&mut T, &AcceptContext<'_, 'sess, S>, &ArgParser<'_>); +type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AcceptFn)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. /// @@ -53,15 +54,15 @@ type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AcceptFn)]; /// whether it has seen the attribute it has been looking for. /// /// The state machine is automatically reset to parse attributes on the next item. -pub(crate) trait AttributeParser: Default + 'static { +pub(crate) trait AttributeParser: Default + 'static { /// The symbols for the attributes that this parser is interested in. /// /// If an attribute has this symbol, the `accept` function will be called on it. - const ATTRIBUTES: AcceptMapping; + const ATTRIBUTES: AcceptMapping; /// The parser has gotten a chance to accept the attributes on an item, /// here it can produce an attribute. - fn finalize(self, cx: &FinalizeContext<'_>) -> Option; + fn finalize(self, cx: &FinalizeContext<'_, '_, S>) -> Option; } /// Alternative to [`AttributeParser`] that automatically handles state management. @@ -73,54 +74,58 @@ pub(crate) trait AttributeParser: Default + 'static { /// /// [`SingleAttributeParser`] can only convert attributes one-to-one, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. -pub(crate) trait SingleAttributeParser: 'static { +pub(crate) trait SingleAttributeParser: 'static { const PATH: &'static [rustc_span::Symbol]; const ATTRIBUTE_ORDER: AttributeOrder; - const ON_DUPLICATE: OnDuplicate; + const ON_DUPLICATE: OnDuplicate; /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option; + fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option; } -pub(crate) struct Single(PhantomData, Option<(AttributeKind, Span)>); +pub(crate) struct Single, S: Stage>( + PhantomData<(S, T)>, + Option<(AttributeKind, Span)>, +); -impl Default for Single { +impl, S: Stage> Default for Single { fn default() -> Self { Self(Default::default(), Default::default()) } } -impl AttributeParser for Single { - const ATTRIBUTES: AcceptMapping = &[(T::PATH, |group: &mut Single, cx, args| { - if let Some(pa) = T::convert(cx, args) { - match T::ATTRIBUTE_ORDER { - // keep the first and report immediately. ignore this attribute - AttributeOrder::KeepFirst => { - if let Some((_, unused)) = group.1 { - T::ON_DUPLICATE.exec::(cx, cx.attr_span, unused); - return; +impl, S: Stage> AttributeParser for Single { + const ATTRIBUTES: AcceptMapping = + &[(T::PATH, |group: &mut Single, cx, args| { + if let Some(pa) = T::convert(cx, args) { + match T::ATTRIBUTE_ORDER { + // keep the first and report immediately. ignore this attribute + AttributeOrder::KeepFirst => { + if let Some((_, unused)) = group.1 { + T::ON_DUPLICATE.exec::(cx, cx.attr_span, unused); + return; + } } - }, - // keep the new one and warn about the previous, - // then replace - AttributeOrder::KeepLast => { - if let Some((_, used)) = group.1 { - T::ON_DUPLICATE.exec::(cx, used, cx.attr_span); + // keep the new one and warn about the previous, + // then replace + AttributeOrder::KeepLast => { + if let Some((_, used)) = group.1 { + T::ON_DUPLICATE.exec::(cx, used, cx.attr_span); + } } - }, - } + } - group.1 = Some((pa, cx.attr_span)); - } - })]; + group.1 = Some((pa, cx.attr_span)); + } + })]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { Some(self.1?.0) } } -pub(crate) enum OnDuplicate { +pub(crate) enum OnDuplicate { /// Give a default warning Warn, @@ -142,25 +147,36 @@ pub(crate) enum OnDuplicate { /// - `unused` is the span of the attribute that was unused or bad because of some /// duplicate reason (see [`AttributeDuplicates`]) /// - `used` is the span of the attribute that was used in favor of the unused attribute - Custom(fn (cx: &AcceptContext<'_>, used: Span, unused: Span)) + Custom(fn(cx: &AcceptContext<'_, '_, S>, used: Span, unused: Span)), } -impl OnDuplicate { - fn exec(&self, cx: &AcceptContext<'_>, used: Span, unused: Span) { +impl OnDuplicate { + fn exec>( + &self, + cx: &AcceptContext<'_, '_, S>, + used: Span, + unused: Span, + ) { match self { - OnDuplicate::Warn => { - // todo!() - }, - OnDuplicate::WarnButFutureError => { - // todo!() - }, + OnDuplicate::Warn => cx.emit_lint( + UNUSED_ATTRIBUTES, + unused, + session_diagnostics::UnusedDuplicate { this: unused, other: used, warning: false }, + ), + OnDuplicate::WarnButFutureError => cx.emit_lint( + UNUSED_ATTRIBUTES, + unused, + session_diagnostics::UnusedDuplicate { this: unused, other: used, warning: true }, + ), OnDuplicate::Error => { cx.emit_err(UnusedMultiple { this: used, other: unused, - name: Symbol::intern(&P::PATH.into_iter().map(|i| i.to_string()).collect::>().join("..")), + name: Symbol::intern( + &P::PATH.into_iter().map(|i| i.to_string()).collect::>().join(".."), + ), }); - }, + } OnDuplicate::Ignore => {} OnDuplicate::Custom(f) => f(cx, used, unused), } @@ -186,35 +202,35 @@ type ConvertFn = fn(ThinVec) -> AttributeKind; /// /// [`CombineAttributeParser`] can only convert a single kind of attribute, and cannot combine multiple /// attributes together like is necessary for `#[stable()]` and `#[unstable()]` for example. -pub(crate) trait CombineAttributeParser: 'static { +pub(crate) trait CombineAttributeParser: 'static { const PATH: &'static [rustc_span::Symbol]; type Item; const CONVERT: ConvertFn; /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator + 'a; + fn extend<'c>( + cx: &'c AcceptContext<'c, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator + 'c; } -pub(crate) struct Combine( - PhantomData, - ThinVec<::Item>, +pub(crate) struct Combine, S: Stage>( + PhantomData<(S, T)>, + ThinVec<>::Item>, ); -impl Default for Combine { +impl, S: Stage> Default for Combine { fn default() -> Self { Self(Default::default(), Default::default()) } } -impl AttributeParser for Combine { - const ATTRIBUTES: AcceptMapping = - &[(T::PATH, |group: &mut Combine, cx, args| group.1.extend(T::extend(cx, args)))]; +impl, S: Stage> AttributeParser for Combine { + const ATTRIBUTES: AcceptMapping = + &[(T::PATH, |group: &mut Combine, cx, args| group.1.extend(T::extend(cx, args)))]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) } } } diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 26ca637faec68..de77fea06c61c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -4,7 +4,7 @@ use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; -use crate::context::AcceptContext; +use crate::context::{AcceptContext, Stage}; use crate::parser::{ArgParser, MetaItemListParser, MetaItemParser}; use crate::session_diagnostics; use crate::session_diagnostics::IncorrectReprFormatGenericCause; @@ -19,15 +19,15 @@ use crate::session_diagnostics::IncorrectReprFormatGenericCause; // FIXME(jdonszelmann): is a vec the right representation here even? isn't it just a struct? pub(crate) struct ReprParser; -impl CombineAttributeParser for ReprParser { +impl CombineAttributeParser for ReprParser { type Item = (ReprAttr, Span); const PATH: &'static [rustc_span::Symbol] = &[sym::repr]; const CONVERT: ConvertFn = AttributeKind::Repr; - fn extend<'a>( - cx: &'a AcceptContext<'a>, - args: &'a ArgParser<'a>, - ) -> impl IntoIterator + 'a { + fn extend<'c>( + cx: &'c AcceptContext<'c, '_, S>, + args: &'c ArgParser<'_>, + ) -> impl IntoIterator + 'c { let mut reprs = Vec::new(); let Some(list) = args.list() else { @@ -91,7 +91,10 @@ fn int_type_of_word(s: Symbol) -> Option { } } -fn parse_repr(cx: &AcceptContext<'_>, param: &MetaItemParser<'_>) -> Option { +fn parse_repr( + cx: &AcceptContext<'_, '_, S>, + param: &MetaItemParser<'_>, +) -> Option { use ReprAttr::*; // FIXME(jdonszelmann): invert the parsing here to match on the word first and then the @@ -163,8 +166,8 @@ enum AlignKind { Align, } -fn parse_repr_align( - cx: &AcceptContext<'_>, +fn parse_repr_align( + cx: &AcceptContext<'_, '_, S>, list: &MetaItemListParser<'_>, param_span: Span, align_kind: AlignKind, diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index b700b4804c0b2..00b9e23d3a733 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -9,7 +9,7 @@ use rustc_span::{Span, Symbol, kw, sym}; use super::util::parse_version; use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; -use crate::context::{AcceptContext, FinalizeContext}; +use crate::context::{AcceptContext, FinalizeContext, Stage}; use crate::parser::{ArgParser, MetaItemParser}; use crate::session_diagnostics::{self, UnsupportedLiteralReason}; @@ -31,7 +31,7 @@ pub(crate) struct StabilityParser { impl StabilityParser { /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate. - fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { + fn check_duplicate(&self, cx: &AcceptContext<'_, '_, S>) -> bool { if let Some((_, _)) = self.stability { cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); true @@ -41,8 +41,8 @@ impl StabilityParser { } } -impl AttributeParser for StabilityParser { - const ATTRIBUTES: AcceptMapping = &[ +impl AttributeParser for StabilityParser { + const ATTRIBUTES: AcceptMapping = &[ (&[sym::stable], |this, cx, args| { reject_outside_std!(cx); if !this.check_duplicate(cx) @@ -69,7 +69,7 @@ impl AttributeParser for StabilityParser { }), ]; - fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option { + fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option { if let Some(atum) = self.allowed_through_unstable_modules { if let Some(( Stability { @@ -99,8 +99,8 @@ pub(crate) struct BodyStabilityParser { stability: Option<(DefaultBodyStability, Span)>, } -impl AttributeParser for BodyStabilityParser { - const ATTRIBUTES: AcceptMapping = +impl AttributeParser for BodyStabilityParser { + const ATTRIBUTES: AcceptMapping = &[(&[sym::rustc_default_body_unstable], |this, cx, args| { reject_outside_std!(cx); if this.stability.is_some() { @@ -111,7 +111,7 @@ impl AttributeParser for BodyStabilityParser { } })]; - fn finalize(self, _cx: &FinalizeContext<'_>) -> Option { + fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { let (stability, span) = self.stability?; Some(AttributeKind::BodyStability { stability, span }) @@ -120,15 +120,14 @@ impl AttributeParser for BodyStabilityParser { pub(crate) struct ConstStabilityIndirectParser; // FIXME(jdonszelmann): single word attribute group when we have these -impl SingleAttributeParser for ConstStabilityIndirectParser { +impl SingleAttributeParser for ConstStabilityIndirectParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_const_stable_indirect]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; - fn convert(_cx: &AcceptContext<'_>, _args: &ArgParser<'_>) -> Option { + fn convert(_cx: &AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { Some(AttributeKind::ConstStabilityIndirect) } - } #[derive(Default)] @@ -139,7 +138,7 @@ pub(crate) struct ConstStabilityParser { impl ConstStabilityParser { /// Checks, and emits an error when a stability (or unstability) was already set, which would be a duplicate. - fn check_duplicate(&self, cx: &AcceptContext<'_>) -> bool { + fn check_duplicate(&self, cx: &AcceptContext<'_, '_, S>) -> bool { if let Some((_, _)) = self.stability { cx.emit_err(session_diagnostics::MultipleStabilityLevels { span: cx.attr_span }); true @@ -149,8 +148,8 @@ impl ConstStabilityParser { } } -impl AttributeParser for ConstStabilityParser { - const ATTRIBUTES: AcceptMapping = &[ +impl AttributeParser for ConstStabilityParser { + const ATTRIBUTES: AcceptMapping = &[ (&[sym::rustc_const_stable], |this, cx, args| { reject_outside_std!(cx); @@ -180,7 +179,7 @@ impl AttributeParser for ConstStabilityParser { }), ]; - fn finalize(mut self, cx: &FinalizeContext<'_>) -> Option { + fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option { if self.promotable { if let Some((ref mut stab, _)) = self.stability { stab.promotable = true; @@ -200,8 +199,8 @@ impl AttributeParser for ConstStabilityParser { /// /// Emits an error when either the option was already Some, or the arguments weren't of form /// `name = value` -fn insert_value_into_option_or_error( - cx: &AcceptContext<'_>, +fn insert_value_into_option_or_error( + cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser<'_>, item: &mut Option, ) -> Option<()> { @@ -227,8 +226,8 @@ fn insert_value_into_option_or_error( /// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and /// its stability information. -pub(crate) fn parse_stability( - cx: &AcceptContext<'_>, +pub(crate) fn parse_stability( + cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; @@ -293,8 +292,8 @@ pub(crate) fn parse_stability( // Read the content of a `unstable`/`rustc_const_unstable`/`rustc_default_body_unstable` /// attribute, and return the feature name and its stability information. -pub(crate) fn parse_unstability( - cx: &AcceptContext<'_>, +pub(crate) fn parse_unstability( + cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>, ) -> Option<(Symbol, StabilityLevel)> { let mut feature = None; diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 6e9610becbfbe..f3d4327d897ed 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,8 +1,9 @@ use rustc_attr_data_structures::AttributeKind; -use rustc_span::{hygiene::Transparency, Span}; +use rustc_span::hygiene::Transparency; use rustc_span::sym; use super::{AcceptContext, AttributeOrder, OnDuplicate, SingleAttributeParser}; +use crate::context::Stage; use crate::parser::ArgParser; pub(crate) struct TransparencyParser; @@ -10,14 +11,14 @@ pub(crate) struct TransparencyParser; // FIXME(jdonszelmann): make these proper diagnostics #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] -impl SingleAttributeParser for TransparencyParser { +impl SingleAttributeParser for TransparencyParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_transparency]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; - const ON_DUPLICATE: OnDuplicate = OnDuplicate::Custom(|cx, used, unused| { + const ON_DUPLICATE: OnDuplicate = OnDuplicate::Custom(|cx, used, unused| { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); }); - fn convert(cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option { + fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { match args.name_value().and_then(|nv| nv.value_as_str()) { Some(sym::transparent) => Some(Transparency::Transparent), Some(sym::semitransparent) => Some(Transparency::SemiTransparent), diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 8caebf3ee4ac5..0fae63a076386 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -3,13 +3,15 @@ use std::collections::BTreeMap; use std::ops::Deref; use std::sync::LazyLock; -use rustc_ast::{self as ast, node_id, DelimArgs}; +use private::Sealed; +use rustc_ast::{self as ast, DelimArgs, NodeId}; use rustc_attr_data_structures::AttributeKind; -use rustc_errors::{DiagCtxtHandle, Diagnostic}; +use rustc_errors::{DiagCtxtHandle, Diagnostic, LintDiagnostic}; use rustc_feature::Features; -use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId}; -use rustc_session::lint::{BuiltinLintDiag, Lint}; +use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId}; +use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_session::lint::Lint; use rustc_span::symbol::kw; use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; @@ -24,18 +26,41 @@ use crate::attributes::stability::{ use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single}; use crate::parser::{ArgParser, MetaItemParser}; -use rustc_ast::NodeId; + +macro_rules! group_type { + ($stage: ty) => { + LazyLock<( + BTreeMap<&'static [Symbol], Vec Fn(&AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>>, + Vec) -> Option>> + )> + }; +} macro_rules! attribute_groups { ( pub(crate) static $name: ident = [$($names: ty),* $(,)?]; ) => { - pub(crate) static $name: LazyLock<( - BTreeMap<&'static [Symbol], Vec, &ArgParser<'_>) + Send + Sync>>>, - Vec) -> Option>> - )> = LazyLock::new(|| { - let mut accepts = BTreeMap::<_, Vec, &ArgParser<'_>) + Send + Sync>>>::new(); - let mut finalizes = Vec::) -> Option>>::new(); + mod early { + use super::*; + type Combine = super::Combine; + type Single = super::Single; + + attribute_groups!(@[Early] pub(crate) static $name = [$($names),*];); + } + mod late { + use super::*; + type Combine = super::Combine; + type Single = super::Single; + + attribute_groups!(@[Late] pub(crate) static $name = [$($names),*];); + } + }; + ( + @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?]; + ) => { + pub(crate) static $name: group_type!($ty) = LazyLock::new(|| { + let mut accepts = BTreeMap::<_, Vec Fn(&AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>>::new(); + let mut finalizes = Vec::) -> Option>>::new(); $( { thread_local! { @@ -61,7 +86,6 @@ macro_rules! attribute_groups { }); }; } - attribute_groups!( pub(crate) static ATTRIBUTE_MAPPING = [ // tidy-alphabetical-start @@ -86,38 +110,114 @@ attribute_groups!( ]; ); +mod private { + pub trait Sealed {} + impl Sealed for super::Early {} + impl Sealed for super::Late {} +} + +// allow because it's a sealed trait +#[allow(private_interfaces)] +pub trait Stage: Sized + 'static + Sealed { + type Id: Copy; + type Sess<'sess>; + fn parsers() -> &'static group_type!(Self); + + fn sess<'short, 'sess: 'short>(s: &Self::Sess<'sess>) -> &'short Session; + fn emit_err<'sess>( + sess: &Self::Sess<'sess>, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed; + fn emit_lint<'sess>( + _sess: &Self::Sess<'sess>, + _lint: &'static Lint, + _id: Self::Id, + _span: Span, + _diag: impl for<'x> LintDiagnostic<'x, ()>, + ) { + } +} + +// allow because it's a sealed trait +#[allow(private_interfaces)] +impl Stage for Early { + type Id = NodeId; + type Sess<'sess> = &'sess Session; + + fn parsers() -> &'static group_type!(Self) { + &early::ATTRIBUTE_MAPPING + } + fn sess<'short, 'sess: 'short>(s: &Self::Sess<'sess>) -> &'short Session { + s + } + fn emit_err<'sess>( + sess: &Self::Sess<'sess>, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed { + sess.dcx().create_err(diag).delay_as_bug() + } +} + +// allow because it's a sealed trait +#[allow(private_interfaces)] +impl Stage for Late { + type Id = HirId; + type Sess<'sess> = TyCtxt<'sess>; + + fn parsers() -> &'static group_type!(Self) { + &late::ATTRIBUTE_MAPPING + } + fn sess<'short, 'sess: 'short>(tcx: &Self::Sess<'sess>) -> &'short Session { + &tcx.sess + } + fn emit_err<'sess>( + tcx: &Self::Sess<'sess>, + diag: impl for<'x> Diagnostic<'x>, + ) -> ErrorGuaranteed { + tcx.dcx().emit_err(diag) + } + fn emit_lint<'sess>( + tcx: &TyCtxt<'sess>, + lint: &'static Lint, + hir_id: HirId, + span: Span, + diag: impl for<'x> LintDiagnostic<'x, ()>, + ) { + tcx.emit_node_span_lint(lint, hir_id, span, diag); + } +} + +/// used when parsing attributes for miscelaneous things *before* ast lowering +pub struct Early; +/// used when parsing attributes during ast lowering +pub struct Late; + /// Context given to every attribute parser when accepting /// /// Gives [`AttributeParser`]s enough information to create errors, for example. -pub(crate) struct AcceptContext<'a> { - pub(crate) group_cx: &'a FinalizeContext<'a>, +pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { + pub(crate) group_cx: &'f FinalizeContext<'f, 'sess, S>, /// The span of the attribute currently being parsed pub(crate) attr_span: Span, } -impl<'a> AcceptContext<'a> { - pub(crate) fn emit_err(&self, diag: impl Diagnostic<'a>) -> ErrorGuaranteed { - if self.limit_diagnostics { - self.dcx().create_err(diag).delay_as_bug() - } else { - self.dcx().emit_err(diag) - } +impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { + pub(crate) fn emit_err(&self, diag: impl for<'x> Diagnostic<'x>) -> ErrorGuaranteed { + S::emit_err(&self.sess, diag) } - pub(crate) fn emit_lint(&self, lint: &'static Lint, span: Span, diagnostic: BuiltinLintDiag) { - if !self.limit_diagnostics { - self.sess().psess.buffer_lint( - lint, - span, - self.target_node_id, - diagnostic, - ); - } + pub(crate) fn emit_lint( + &self, + lint: &'static Lint, + span: Span, + diag: impl for<'x> LintDiagnostic<'x, ()>, + ) { + S::emit_lint(&self.sess, lint, self.target_id, span, diag); } } -impl<'a> Deref for AcceptContext<'a> { - type Target = FinalizeContext<'a>; +impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { + type Target = FinalizeContext<'f, 'sess, S>; fn deref(&self) -> &Self::Target { &self.group_cx @@ -127,21 +227,21 @@ impl<'a> Deref for AcceptContext<'a> { /// Context given to every attribute parser during finalization. /// /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create errors, for example. -pub(crate) struct FinalizeContext<'a> { +pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> { /// The parse context, gives access to the session and the /// diagnostics context. - pub(crate) cx: &'a AttributeParser<'a>, + pub(crate) cx: &'p AttributeParser<'sess, S>, /// The span of the syntactical component this attribute was applied to pub(crate) target_span: Span, - /// The node id (in the ast) of the syntactical component this attribute was applied to - pub(crate) target_node_id: NodeId, + /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to + pub(crate) target_id: S::Id, } -impl<'a> Deref for FinalizeContext<'a> { - type Target = AttributeParser<'a>; +impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> { + type Target = AttributeParser<'sess, S>; fn deref(&self) -> &Self::Target { - &self.cx + self.cx } } @@ -153,24 +253,20 @@ pub enum OmitDoc { /// Context created once, for example as part of the ast lowering /// context, through which all attributes can be lowered. -pub struct AttributeParser<'sess> { +pub struct AttributeParser<'sess, S: Stage = Late> { #[expect(dead_code)] // FIXME(jdonszelmann): needed later to verify we parsed all attributes tools: Vec, - sess: &'sess Session, features: Option<&'sess Features>, + sess: S::Sess<'sess>, /// *only* parse attributes with this symbol. /// /// Used in cases where we want the lowering infrastructure for /// parse just a single attribute. parse_only: Option, - - /// Can be used to instruct parsers to reduce the number of diagnostics it emits. - /// Useful when using `parse_limited` and you know the attr will be reparsed later. - pub(crate) limit_diagnostics: bool, } -impl<'sess> AttributeParser<'sess> { +impl<'sess> AttributeParser<'sess, Early> { /// This method allows you to parse attributes *before* you have access to features or tools. /// One example where this is necessary, is to parse `feature` attributes themselves for /// example. @@ -181,34 +277,45 @@ impl<'sess> AttributeParser<'sess> { /// /// To make sure use is limited, supply a `Symbol` you'd like to parse. Only attributes with /// that symbol are picked out of the list of instructions and parsed. Those are returned. + /// + /// No diagnostics will be emitted when parsing limited. Lints are not emitted at all, while + /// errors will be emitted as a delayed bugs. in other words, we *expect* attributes parsed + /// with `parse_limited` to be reparsed later during ast lowering where we *do* emit the errors pub fn parse_limited( sess: &'sess Session, attrs: &[ast::Attribute], sym: Symbol, target_span: Span, target_node_id: NodeId, - limit_diagnostics: bool, ) -> Option { - let mut parsed = Self { - sess, - features: None, - tools: Vec::new(), - parse_only: Some(sym), - limit_diagnostics, - } - .parse_attribute_list(attrs, target_span, target_node_id, OmitDoc::Skip, std::convert::identity); + let mut parsed = Self { features: None, tools: Vec::new(), parse_only: Some(sym), sess } + .parse_attribute_list( + attrs, + target_span, + target_node_id, + OmitDoc::Skip, + std::convert::identity, + ); assert!(parsed.len() <= 1); parsed.pop() } - pub fn new(sess: &'sess Session, features: &'sess Features, tools: Vec) -> Self { - Self { sess, features: Some(features), tools, parse_only: None, limit_diagnostics: false } + pub fn new_early(sess: &'sess Session, features: &'sess Features, tools: Vec) -> Self { + Self { features: Some(features), tools, parse_only: None, sess } + } +} + +impl<'sess> AttributeParser<'sess, Late> { + pub fn new(tcx: TyCtxt<'sess>, features: &'sess Features, tools: Vec) -> Self { + Self { features: Some(features), tools, parse_only: None, sess: tcx } } +} +impl<'sess, S: Stage> AttributeParser<'sess, S> { pub(crate) fn sess(&self) -> &'sess Session { - self.sess + S::sess(&self.sess) } pub(crate) fn features(&self) -> &'sess Features { @@ -216,25 +323,25 @@ impl<'sess> AttributeParser<'sess> { } pub(crate) fn dcx(&self) -> DiagCtxtHandle<'sess> { - self.sess.dcx() + self.sess().dcx() } /// Parse a list of attributes. /// /// `target_span` is the span of the thing this list of attributes is applied to, /// and when `omit_doc` is set, doc attributes are filtered out. - pub fn parse_attribute_list<'a>( - &'a self, - attrs: &'a [ast::Attribute], + pub fn parse_attribute_list( + &self, + attrs: &[ast::Attribute], target_span: Span, - target_node_id: NodeId, + target_id: S::Id, omit_doc: OmitDoc, lower_span: impl Copy + Fn(Span) -> Span, ) -> Vec { let mut attributes = Vec::new(); - let group_cx = FinalizeContext { cx: self, target_span, target_node_id }; + let group_cx = FinalizeContext { cx: self, target_span, target_id }; for attr in attrs { // if we're only looking for a single attribute, @@ -283,14 +390,14 @@ impl<'sess> AttributeParser<'sess> { let (path, args) = parser.deconstruct(); let parts = path.segments().map(|i| i.name).collect::>(); - if let Some(accepts) = ATTRIBUTE_MAPPING.0.get(parts.as_slice()) { + if let Some(accepts) = S::parsers().0.get(parts.as_slice()) { for f in accepts { - let cx = AcceptContext { + let cx: AcceptContext<'_, 'sess, S> = AcceptContext { group_cx: &group_cx, attr_span: lower_span(attr.span), }; - f(&cx, &args) + f(&cx, args) } } else { // if we're here, we must be compiling a tool attribute... Or someone forgot to @@ -321,7 +428,7 @@ impl<'sess> AttributeParser<'sess> { } let mut parsed_attributes = Vec::new(); - for f in &ATTRIBUTE_MAPPING.1 { + for f in &S::parsers().1 { if let Some(attr) = f(&group_cx) { parsed_attributes.push(Attribute::Parsed(attr)); } diff --git a/compiler/rustc_attr_parsing/src/lib.rs b/compiler/rustc_attr_parsing/src/lib.rs index 61706ee27b13d..a72f5c94a92fb 100644 --- a/compiler/rustc_attr_parsing/src/lib.rs +++ b/compiler/rustc_attr_parsing/src/lib.rs @@ -91,10 +91,7 @@ mod session_diagnostics; pub use attributes::cfg::*; pub use attributes::util::{find_crate_name, is_builtin_attr, parse_version}; -pub use context::{AttributeParser, OmitDoc}; -#[macro_use] +pub use context::{AttributeParser, Early, Late, OmitDoc}; pub use rustc_attr_data_structures::*; rustc_fluent_macro::fluent_messages! { "../messages.ftl" } - - diff --git a/compiler/rustc_attr_parsing/src/parser.rs b/compiler/rustc_attr_parsing/src/parser.rs index b6d66af4466e2..f30d58e0fc2cf 100644 --- a/compiler/rustc_attr_parsing/src/parser.rs +++ b/compiler/rustc_attr_parsing/src/parser.rs @@ -116,7 +116,7 @@ impl<'a> ArgParser<'a> { } } - pub fn from_attr_args(value: &'a AttrArgs, dcx: DiagCtxtHandle<'a>) -> Self { + pub fn from_attr_args<'sess>(value: &'a AttrArgs, dcx: DiagCtxtHandle<'sess>) -> Self { match value { AttrArgs::Empty => Self::NoArgs, AttrArgs::Delimited(args) if args.delim == Delimiter::Parenthesis => { @@ -236,7 +236,7 @@ impl<'a> Debug for MetaItemParser<'a> { impl<'a> MetaItemParser<'a> { /// Create a new parser from a [`NormalAttr`], which is stored inside of any /// [`ast::Attribute`](rustc_ast::Attribute) - pub fn from_attr(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'a>) -> Self { + pub fn from_attr<'sess>(attr: &'a NormalAttr, dcx: DiagCtxtHandle<'sess>) -> Self { Self { path: PathParser::Ast(&attr.item.path), args: ArgParser::from_attr_args(&attr.item.args, dcx), @@ -364,13 +364,13 @@ fn expr_to_lit(dcx: DiagCtxtHandle<'_>, expr: &Expr, span: Span) -> MetaItemLit } } -struct MetaItemListParserContext<'a> { +struct MetaItemListParserContext<'a, 'sess> { // the tokens inside the delimiters, so `#[some::attr(a b c)]` would have `a b c` inside inside_delimiters: Peekable>, - dcx: DiagCtxtHandle<'a>, + dcx: DiagCtxtHandle<'sess>, } -impl<'a> MetaItemListParserContext<'a> { +impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> { fn done(&mut self) -> bool { self.inside_delimiters.peek().is_none() } @@ -582,11 +582,11 @@ pub struct MetaItemListParser<'a> { } impl<'a> MetaItemListParser<'a> { - fn new(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'a>) -> MetaItemListParser<'a> { + fn new<'sess>(delim: &'a DelimArgs, dcx: DiagCtxtHandle<'sess>) -> Self { MetaItemListParser::new_tts(delim.tokens.iter(), delim.dspan.entire(), dcx) } - fn new_tts(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'a>) -> Self { + fn new_tts<'sess>(tts: TokenStreamIter<'a>, span: Span, dcx: DiagCtxtHandle<'sess>) -> Self { MetaItemListParserContext { inside_delimiters: tts.peekable(), dcx }.parse(span) } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 9d34b807ac2fe..c185ec8a1079a 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -3,7 +3,7 @@ use std::num::IntErrorKind; use rustc_ast as ast; use rustc_errors::codes::*; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; -use rustc_macros::{Diagnostic, Subdiagnostic}; +use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; use crate::fluent_generated as fluent; @@ -451,6 +451,17 @@ pub(crate) struct UnusedMultiple { pub name: Symbol, } +#[derive(LintDiagnostic)] +#[diag(attr_parsing_unused_multiple)] +pub(crate) struct UnusedDuplicate { + #[suggestion(code = "", applicability = "machine-applicable")] + pub this: Span, + #[note] + pub other: Span, + #[warning] + pub warning: bool, +} + #[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 3e943181f8f96..7bc9dc913bb63 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -482,7 +482,7 @@ impl<'a> TraitDef<'a> { match item { Annotatable::Item(item) => { let is_packed = matches!( - AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id, true), + AttributeParser::parse_limited(cx.sess, &item.attrs, sym::repr, item.span, item.id), Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(x, _)| matches!(x, ReprPacked(..))) ); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index eed306a01bbbd..2b2dc9b4e73f9 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -6,7 +6,7 @@ use rustc_ast::expand::autodiff_attrs::{ }; use rustc_ast::{MetaItem, MetaItemInner, attr}; use rustc_attr_parsing::ReprAttr::ReprAlign; -use rustc_attr_parsing::{find_attr, AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr}; +use rustc_attr_parsing::{AttributeKind, InlineAttr, InstructionSetAttr, OptimizeAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::codes::*; use rustc_errors::{DiagMessage, SubdiagMessage, struct_span_code_err}; @@ -518,7 +518,8 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); - codegen_fn_attrs.inline = find_attr!(attrs, AttributeKind::Inline(i, _) => *i).unwrap_or(InlineAttr::None); + codegen_fn_attrs.inline = + find_attr!(attrs, AttributeKind::Inline(i, _) => *i).unwrap_or(InlineAttr::None); // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself, // but not for the code generation backend because at that point the naked function will just be diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index 3010f71a5ebed..1df8fd8286675 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -163,7 +163,7 @@ impl NonCamelCaseTypes { impl EarlyLintPass for NonCamelCaseTypes { fn check_item(&mut self, cx: &EarlyContext<'_>, it: &ast::Item) { let has_repr_c = matches!( - AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id, true), + AttributeParser::parse_limited(cx.sess(), &it.attrs, sym::repr, it.span, it.id), Some(Attribute::Parsed(AttributeKind::Repr(r))) if r.iter().any(|(r, _)| r == &ReprAttr::ReprC) ); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 61d0419624c5b..389406f226ed9 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -441,10 +441,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { self.inline_attr_str_error_with_macro_def(hir_id, attr_span, "inline") } _ => { - self.dcx().emit_err(errors::InlineNotFnOrClosure { - attr_span, - defn_span, - }); + self.dcx().emit_err(errors::InlineNotFnOrClosure { attr_span, defn_span }); } } } @@ -2187,9 +2184,12 @@ impl<'tcx> CheckAttrVisitor<'tcx> { // `#[allow_internal_unstable]` 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(), "allow_internal_unstable") - } + Target::Field | Target::Arm | Target::MacroDef => self + .inline_attr_str_error_with_macro_def( + hir_id, + attr.span(), + "allow_internal_unstable", + ), _ => { self.tcx .dcx() diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index d9140f7425844..b1a74bebf5f20 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -137,7 +137,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // FIXME(jdonszelmann) make one of these in the resolver? // FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can. // Does that prevents errors from happening? maybe - let parser = AttributeParser::new( + let parser = AttributeParser::new_early( &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), From 5768ea52bae4768585e5d81d8abeba9ea94984a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Sun, 2 Mar 2025 09:59:28 +0100 Subject: [PATCH 18/26] edit mailmap --- .mailmap | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.mailmap b/.mailmap index eb6a9fcabca99..527e00516d4f8 100644 --- a/.mailmap +++ b/.mailmap @@ -276,7 +276,7 @@ Jacob Greenfield Jacob Pratt Jacob Pratt Jake Goulding -Jake Goulding +Jake Goulding Jake Goulding Jake Vossen Jakob Degen @@ -292,6 +292,9 @@ James Hinshelwood James Miller James Perry James Sanderson +Jana Dönszelmann +Jana Dönszelmann +Jana Dönszelmann Jan-Erik Rediger Jaro Fietz Jason Fager From 6d300045d450793b6db11f919dce9f9156446b53 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 3 Mar 2025 16:44:59 +0100 Subject: [PATCH 19/26] hopefully implement lints during attr parsing rm print --- compiler/rustc_ast_lowering/src/expr.rs | 7 +- compiler/rustc_ast_lowering/src/item.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 37 ++++++-- .../src/attributes/allow_unstable.rs | 4 +- .../rustc_attr_parsing/src/attributes/mod.rs | 6 +- .../rustc_attr_parsing/src/attributes/repr.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 91 ++++++++++++------- compiler/rustc_errors/src/lib.rs | 34 +++++++ compiler/rustc_interface/src/passes.rs | 7 ++ compiler/rustc_resolve/src/def_collector.rs | 2 +- 10 files changed, 139 insertions(+), 53 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index c1c4b6be5d7a5..727cda61b56b0 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -74,12 +74,13 @@ impl<'hir> LoweringContext<'_, 'hir> { // Merge attributes into the inner expression. if !e.attrs.is_empty() { let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); + let new_attrs = self.lower_attrs_vec(&e.attrs, e.span, ex.hir_id) + .into_iter() + .chain(old_attrs.iter().cloned()); self.attrs.insert( ex.hir_id.local_id, &*self.arena.alloc_from_iter( - self.lower_attrs_vec(&e.attrs, e.span, ex.hir_id) - .into_iter() - .chain(old_attrs.iter().cloned()), + new_attrs, ), ); } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index a4fc4b3e3a121..6b129bb030ffa 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -58,7 +58,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { &mut self, owner: NodeId, f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, - ) { + ) { let mut lctx = LoweringContext::new(self.tcx, self.resolver); lctx.with_hir_id_owner(owner, |lctx| f(lctx)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 597c20e7c3fab..8b3619acc128f 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -52,7 +52,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::TaggedRef; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{ self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, ParamName, TraitCandidate, }; @@ -196,6 +196,22 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } } +struct SpanLowerer { + is_incremental: bool, + defid: LocalDefId, +} + +impl SpanLowerer { + fn lower(&self, span: Span) -> Span { + if self.is_incremental { + span.with_parent(Some(self.defid)) + } else { + // Do not make spans relative when not using incremental compilation. + span + } + } +} + #[extension(trait ResolverAstLoweringExt)] impl ResolverAstLowering { fn legacy_const_generic_args(&self, expr: &Expr) -> Option> { @@ -739,15 +755,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { }) } + fn span_lowerer(&self) -> SpanLowerer { + SpanLowerer { + is_incremental: self.tcx.sess.opts.incremental.is_some(), + defid: self.current_hir_id_owner.def_id, + } + } + /// Intercept all spans entering HIR. /// Mark a span as relative to the current owning item. fn lower_span(&self, span: Span) -> Span { - if self.tcx.sess.opts.incremental.is_some() { - span.with_parent(Some(self.current_hir_id_owner.def_id)) - } else { - // Do not make spans relative when not using incremental compilation. - span - } + self.span_lowerer().lower(span) } fn lower_ident(&self, ident: Ident) -> Ident { @@ -891,17 +909,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { } fn lower_attrs_vec( - &self, + &mut self, attrs: &[Attribute], target_span: Span, target_hir_id: HirId, ) -> Vec { + let l = self.span_lowerer(); self.attribute_parser.parse_attribute_list( attrs, target_span, target_hir_id, OmitDoc::Lower, - |s| self.lower_span(s), + |s| l.lower(s), ) } diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index ef0aa734df4c6..647ebd21b47c3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -15,7 +15,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser { const CONVERT: ConvertFn = AttributeKind::AllowInternalUnstable; fn extend<'c>( - cx: &'c AcceptContext<'c, '_, S>, + cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser<'_>, ) -> impl IntoIterator { parse_unstable(cx, args, >::PATH[0]) @@ -31,7 +31,7 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { const CONVERT: ConvertFn = AttributeKind::AllowConstFnUnstable; fn extend<'c>( - cx: &'c AcceptContext<'c, '_, S>, + cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser<'_>, ) -> impl IntoIterator + 'c { parse_unstable(cx, args, >::PATH[0]) diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 0a5ae4768da41..d1790a46c397c 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -35,7 +35,7 @@ pub(crate) mod stability; pub(crate) mod transparency; pub(crate) mod util; -type AcceptFn = for<'sess> fn(&mut T, &AcceptContext<'_, 'sess, S>, &ArgParser<'_>); +type AcceptFn = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>); type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AcceptFn)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. @@ -153,7 +153,7 @@ pub(crate) enum OnDuplicate { impl OnDuplicate { fn exec>( &self, - cx: &AcceptContext<'_, '_, S>, + cx: &mut AcceptContext<'_, '_, S>, used: Span, unused: Span, ) { @@ -210,7 +210,7 @@ pub(crate) trait CombineAttributeParser: 'static { /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] fn extend<'c>( - cx: &'c AcceptContext<'c, '_, S>, + cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser<'_>, ) -> impl IntoIterator + 'c; } diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index de77fea06c61c..1ee4359dcdac1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -25,7 +25,7 @@ impl CombineAttributeParser for ReprParser { const CONVERT: ConvertFn = AttributeKind::Repr; fn extend<'c>( - cx: &'c AcceptContext<'c, '_, S>, + cx: &'c mut AcceptContext<'_, '_, S>, args: &'c ArgParser<'_>, ) -> impl IntoIterator + 'c { let mut reprs = Vec::new(); diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 0fae63a076386..ed563816baabf 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -1,11 +1,12 @@ use std::cell::RefCell; use std::collections::BTreeMap; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; use std::sync::LazyLock; use private::Sealed; use rustc_ast::{self as ast, DelimArgs, NodeId}; use rustc_attr_data_structures::AttributeKind; +use rustc_data_structures::sync::DynSend; use rustc_errors::{DiagCtxtHandle, Diagnostic, LintDiagnostic}; use rustc_feature::Features; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId}; @@ -30,8 +31,8 @@ use crate::parser::{ArgParser, MetaItemParser}; macro_rules! group_type { ($stage: ty) => { LazyLock<( - BTreeMap<&'static [Symbol], Vec Fn(&AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>>, - Vec) -> Option>> + BTreeMap<&'static [Symbol], Vec Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>>, + Vec) -> Option>> )> }; } @@ -59,8 +60,8 @@ macro_rules! attribute_groups { @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?]; ) => { pub(crate) static $name: group_type!($ty) = LazyLock::new(|| { - let mut accepts = BTreeMap::<_, Vec Fn(&AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>>::new(); - let mut finalizes = Vec::) -> Option>>::new(); + let mut accepts = BTreeMap::<_, Vec Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>>::new(); + let mut finalizes = Vec::) -> Option>>::new(); $( { thread_local! { @@ -128,14 +129,14 @@ pub trait Stage: Sized + 'static + Sealed { sess: &Self::Sess<'sess>, diag: impl for<'x> Diagnostic<'x>, ) -> ErrorGuaranteed; - fn emit_lint<'sess>( - _sess: &Self::Sess<'sess>, - _lint: &'static Lint, - _id: Self::Id, - _span: Span, - _diag: impl for<'x> LintDiagnostic<'x, ()>, - ) { - } + + fn emit_lint( + dcx: DiagCtxtHandle<'_>, + lint: &'static Lint, + id: Self::Id, + span: Span, + diag: impl DynSend + for<'x> LintDiagnostic<'x, ()> + 'static, + ); } // allow because it's a sealed trait @@ -156,6 +157,17 @@ impl Stage for Early { ) -> ErrorGuaranteed { sess.dcx().create_err(diag).delay_as_bug() } + + fn emit_lint( + _dcx: DiagCtxtHandle<'_>, + _lint: &'static Lint, + _id: Self::Id, + _span: Span, + _diag: impl DynSend + for<'x> LintDiagnostic<'x, ()> + 'static, + ) { + // FIXME(jdonszelmann): currently not a thing (yet) + panic!("lints during ast attr parsing not yet implemented"); + } } // allow because it's a sealed trait @@ -176,14 +188,18 @@ impl Stage for Late { ) -> ErrorGuaranteed { tcx.dcx().emit_err(diag) } - fn emit_lint<'sess>( - tcx: &TyCtxt<'sess>, + + fn emit_lint( + dcx: DiagCtxtHandle<'_>, lint: &'static Lint, - hir_id: HirId, + id: Self::Id, span: Span, - diag: impl for<'x> LintDiagnostic<'x, ()>, + diag: impl DynSend + for<'x> LintDiagnostic<'x, ()> + 'static, ) { - tcx.emit_node_span_lint(lint, hir_id, span, diag); + println!("stashing lint"); + dcx.delay_lint_during_ast_lowering((lint, id, span, Box::new(|x| { + diag.decorate_lint(x) + }))); } } @@ -196,7 +212,7 @@ pub struct Late; /// /// Gives [`AttributeParser`]s enough information to create errors, for example. pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { - pub(crate) group_cx: &'f FinalizeContext<'f, 'sess, S>, + pub(crate) group_cx: FinalizeContext<'f, 'sess, S>, /// The span of the attribute currently being parsed pub(crate) attr_span: Span, } @@ -207,12 +223,12 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { } pub(crate) fn emit_lint( - &self, + & self, lint: &'static Lint, span: Span, - diag: impl for<'x> LintDiagnostic<'x, ()>, + diag: impl DynSend + for<'x> LintDiagnostic<'x, ()> + 'static, ) { - S::emit_lint(&self.sess, lint, self.target_id, span, diag); + S::emit_lint(self.dcx(), lint, self.target_id, span, diag) } } @@ -224,13 +240,19 @@ impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { } } +impl<'f, 'sess, S: Stage> DerefMut for AcceptContext<'f, 'sess, S> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.group_cx + } +} + /// Context given to every attribute parser during finalization. /// /// Gives [`AttributeParser`](crate::attributes::AttributeParser)s enough information to create errors, for example. pub(crate) struct FinalizeContext<'p, 'sess, S: Stage> { /// The parse context, gives access to the session and the /// diagnostics context. - pub(crate) cx: &'p AttributeParser<'sess, S>, + pub(crate) cx: &'p mut AttributeParser<'sess, S>, /// The span of the syntactical component this attribute was applied to pub(crate) target_span: Span, /// The id ([`NodeId`] if `S` is `Early`, [`HirId`] if `S` is `Late`) of the syntactical component this attribute was applied to @@ -245,6 +267,12 @@ impl<'p, 'sess: 'p, S: Stage> Deref for FinalizeContext<'p, 'sess, S> { } } +impl<'p, 'sess: 'p, S: Stage> DerefMut for FinalizeContext<'p, 'sess, S> { + fn deref_mut(&mut self) -> &mut Self::Target { + self.cx + } +} + #[derive(PartialEq, Clone, Copy, Debug)] pub enum OmitDoc { Lower, @@ -288,15 +316,14 @@ impl<'sess> AttributeParser<'sess, Early> { target_span: Span, target_node_id: NodeId, ) -> Option { - let mut parsed = Self { features: None, tools: Vec::new(), parse_only: Some(sym), sess } - .parse_attribute_list( + let mut p = Self { features: None, tools: Vec::new(), parse_only: Some(sym), sess }; + let mut parsed = p.parse_attribute_list( attrs, target_span, target_node_id, OmitDoc::Skip, std::convert::identity, ); - assert!(parsed.len() <= 1); parsed.pop() @@ -331,7 +358,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { /// `target_span` is the span of the thing this list of attributes is applied to, /// and when `omit_doc` is set, doc attributes are filtered out. pub fn parse_attribute_list( - &self, + &mut self, attrs: &[ast::Attribute], target_span: Span, target_id: S::Id, @@ -341,8 +368,6 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { ) -> Vec { let mut attributes = Vec::new(); - let group_cx = FinalizeContext { cx: self, target_span, target_id }; - for attr in attrs { // if we're only looking for a single attribute, // skip all the ones we don't care about @@ -392,12 +417,12 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { if let Some(accepts) = S::parsers().0.get(parts.as_slice()) { for f in accepts { - let cx: AcceptContext<'_, 'sess, S> = AcceptContext { - group_cx: &group_cx, + let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { + group_cx: FinalizeContext { cx: self, target_span, target_id }, attr_span: lower_span(attr.span), }; - f(&cx, args) + f(&mut cx, args) } } else { // if we're here, we must be compiling a tool attribute... Or someone forgot to @@ -429,7 +454,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { let mut parsed_attributes = Vec::new(); for f in &S::parsers().1 { - if let Some(attr) = f(&group_cx) { + if let Some(attr) = f(&mut FinalizeContext { cx: self, target_span, target_id }) { parsed_attributes.push(Attribute::Parsed(attr)); } } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index f2b133f56773b..67a29edd6609e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -53,6 +53,8 @@ pub use diagnostic_impls::{ DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, IndicateAnonymousLifetime, SingleLabelManySpans, }; +use rustc_lint_defs::Lint; +use rustc_hir::HirId; pub use emitter::ColorConfig; use emitter::{DynEmitter, Emitter, is_case_difference, is_different}; use rustc_data_structures::AtomicRef; @@ -536,6 +538,13 @@ impl<'a> std::ops::Deref for DiagCtxtHandle<'a> { } } +pub type HirDelayedLint = ( + &'static Lint, + HirId, + Span, + Box FnOnce(&'b mut Diag<'a, ()>) + 'static> +); + /// This inner struct exists to keep it all behind a single lock; /// this is done to prevent possible deadlocks in a multi-threaded compiler, /// as well as inconsistent state observation. @@ -552,6 +561,11 @@ struct DiagCtxtInner { /// The delayed bugs and their error guarantees. delayed_bugs: Vec<(DelayedDiagInner, ErrorGuaranteed)>, + /// *specifically* for lints emitted during ast lowering. + /// At this point we can't get the lint level yet (doing so will cause really weird bugs). + /// So, by stuffing lints in here they can be emitted when hir is built. + hir_delayed_lints: Vec, + /// The error count shown to the user at the end. deduplicated_err_count: usize, /// The warning count shown to the user at the end. @@ -770,6 +784,18 @@ impl DiagCtxt { inner.emitter = new_emitter; } + /// You can't emit lints during ast lowering, + /// since you'd need to find the lint level of hir nodes you're currently working on lowering. + /// + /// This stashes them and emits them during the late lint pass. + /// + /// Lints stashed at other stages of the compiler will be ignored. + /// Instead, in all other stages after hir lowering you should be able to + /// use `TyCtx::{emit}_node_span_lint(...)`. + pub fn delay_lint_during_ast_lowering(&self, lint: HirDelayedLint) { + self.inner.borrow_mut().hir_delayed_lints.push(lint); + } + pub fn set_emitter(&self, emitter: Box) { self.inner.borrow_mut().emitter = emitter; } @@ -829,6 +855,7 @@ impl DiagCtxt { future_breakage_diagnostics, fulfilled_expectations, ice_file: _, + hir_delayed_lints, } = inner.deref_mut(); // For the `Vec`s and `HashMap`s, we overwrite with an empty container to free the @@ -847,6 +874,7 @@ impl DiagCtxt { *stashed_diagnostics = Default::default(); *future_breakage_diagnostics = Default::default(); *fulfilled_expectations = Default::default(); + *hir_delayed_lints = Default::default(); } pub fn handle<'a>(&'a self) -> DiagCtxtHandle<'a> { @@ -992,6 +1020,11 @@ impl<'a> DiagCtxtHandle<'a> { self.inner.borrow_mut().emit_stashed_diagnostics() } + /// Emit all lints that were delayed while building the hir. + pub fn steal_hir_delayed_lints(&self) -> Vec { + std::mem::take(&mut self.inner.borrow_mut().hir_delayed_lints) + } + /// This excludes delayed bugs. #[inline] pub fn err_count(&self) -> usize { @@ -1480,6 +1513,7 @@ impl DiagCtxtInner { future_breakage_diagnostics: Vec::new(), fulfilled_expectations: Default::default(), ice_file: None, + hir_delayed_lints: Vec::new(), } } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 553215ca0af02..fb2342fe22f87 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -882,6 +882,13 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { CStore::from_tcx(tcx).report_unused_deps(tcx); }, + { + // emit lints that couldnt be emitted during hir building because + // the lint level couldn't be determined + for (lint, hir_id, span, decorate) in tcx.dcx().steal_hir_delayed_lints() { + tcx.node_span_lint(lint, hir_id, span, decorate); + } + }, { tcx.par_hir_for_each_module(|module| { tcx.ensure_ok().check_mod_loops(module); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index b1a74bebf5f20..483471eaf409d 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -137,7 +137,7 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> { // FIXME(jdonszelmann) make one of these in the resolver? // FIXME(jdonszelmann) don't care about tools here maybe? Just parse what we can. // Does that prevents errors from happening? maybe - let parser = AttributeParser::new_early( + let mut parser = AttributeParser::new_early( &self.resolver.tcx.sess, self.resolver.tcx.features(), Vec::new(), From 5542dba88a0f07212e6e15a251d4971526297cdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 3 Mar 2025 17:14:11 +0100 Subject: [PATCH 20/26] convert rustc_force_inline --- .../src/attributes.rs | 1 + .../src/attributes/inline.rs | 39 +++++++++++++++++++ compiler/rustc_attr_parsing/src/context.rs | 3 +- compiler/rustc_passes/src/check_attr.rs | 21 +++++----- 4 files changed, 53 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_attr_data_structures/src/attributes.rs b/compiler/rustc_attr_data_structures/src/attributes.rs index 9649571733fc7..f32f5594a4c72 100644 --- a/compiler/rustc_attr_data_structures/src/attributes.rs +++ b/compiler/rustc_attr_data_structures/src/attributes.rs @@ -189,6 +189,7 @@ pub enum AttributeKind { Inline(InlineAttr, Span), MacroTransparency(Transparency), Repr(ThinVec<(ReprAttr, Span)>), + RustcForceInline(Span, Option), Stability { stability: Stability, /// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 2d78547deaf3d..eea08ae4a49db 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -1,3 +1,7 @@ +// FIXME(jdonszelmann): merge these two parsers and error when both attributes are present here. +// note: need to model better how duplicate attr errors work when not using +// SingleAttributeParser which is what we have two of here. + use rustc_attr_data_structures::{AttributeKind, InlineAttr}; use rustc_errors::{E0534, E0535, struct_span_code_err}; use rustc_span::sym; @@ -6,6 +10,7 @@ use super::{AcceptContext, AttributeOrder, OnDuplicate}; use crate::attributes::SingleAttributeParser; use crate::context::Stage; use crate::parser::ArgParser; +use crate::session_diagnostics::IncorrectMetaItem; pub(crate) struct InlineParser; @@ -47,3 +52,37 @@ impl SingleAttributeParser for InlineParser { } } } + +pub(crate) struct RustcForceInlineParser; + +impl SingleAttributeParser for RustcForceInlineParser { + const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_force_inline]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; + const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + + fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { + let reason = match args { + ArgParser::NoArgs => None, + ArgParser::List(list) => { + cx.emit_err(IncorrectMetaItem { + span: list.span, + suggestion: None, + }); + return None + } + ArgParser::NameValue(v) => { + let Some(str) = v.value_as_str() else { + cx.emit_err(IncorrectMetaItem { + span: v.value_span, + suggestion: None, + }); + return None; + }; + + Some(str) + } + }; + + Some(AttributeKind::Inline(InlineAttr::Force { attr_span: cx.attr_span, reason }, cx.attr_span)) + } +} diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index ed563816baabf..c3e5dba1b600c 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -19,7 +19,7 @@ use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span, Symbol, sym}; use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInternalUnstableParser}; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::deprecation::DeprecationParser; -use crate::attributes::inline::InlineParser; +use crate::attributes::inline::{InlineParser, RustcForceInlineParser}; use crate::attributes::repr::ReprParser; use crate::attributes::stability::{ BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser, @@ -106,6 +106,7 @@ attribute_groups!( Single, Single, Single, + Single, Single, // tidy-alphabetical-end ]; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 389406f226ed9..e53ee3bfcb154 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; -use rustc_attr_parsing::{AttributeKind, ReprAttr, find_attr}; +use rustc_attr_parsing::{find_attr, AttributeKind, InlineAttr, ReprAttr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; @@ -123,7 +123,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Stability { span, .. } | AttributeKind::ConstStability { span, .. }, ) => self.check_stability_promotable(*span, target), - Attribute::Parsed(AttributeKind::Inline(_, attr_span)) => { + Attribute::Parsed(AttributeKind::Inline(i, attr_span)) => { self.check_inline(hir_id, *attr_span, span, target) } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self @@ -2548,8 +2548,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { span: Span, target: Target, ) { - let force_inline_attr = attrs.iter().find(|attr| attr.has_name(sym::rustc_force_inline)); - match (target, force_inline_attr) { + match (target, find_attr!(attrs, AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span)) { (Target::Closure, None) => { let is_coro = matches!( self.tcx.hir().expect_expr(hir_id).kind, @@ -2561,20 +2560,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ); let parent_did = self.tcx.hir_get_parent_item(hir_id).to_def_id(); let parent_span = self.tcx.def_span(parent_did); - let parent_force_inline_attr = - self.tcx.get_attr(parent_did, sym::rustc_force_inline); - if let Some(attr) = parent_force_inline_attr + + if let Some(attr_span) = find_attr!( + self.tcx.get_all_attrs(parent_did), + AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span + ) && is_coro { self.dcx().emit_err(errors::RustcForceInlineCoro { - attr_span: attr.span(), + attr_span, span: parent_span, }); } } (Target::Fn, _) => (), - (_, Some(attr)) => { - self.dcx().emit_err(errors::RustcForceInline { attr_span: attr.span(), span }); + (_, Some(attr_span)) => { + self.dcx().emit_err(errors::RustcForceInline { attr_span, span }); } (_, None) => (), } From 2d0754a18922c7816e45c9c236164b205a4627cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Mon, 3 Mar 2025 17:45:14 +0100 Subject: [PATCH 21/26] add error message for unused duplicate --- compiler/rustc_attr_parsing/messages.ftl | 13 ++++++------- .../rustc_attr_parsing/src/session_diagnostics.rs | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 573854afa746c..a5b1c291c03a7 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -131,13 +131,6 @@ attr_parsing_unsupported_literal_generic = attr_parsing_unsupported_literal_suggestion = consider removing the prefix -attr_parsing_unused_duplicate = - unused attribute - .suggestion = remove this attribute - .note = attribute also specified here - .warn = {-attr_parsing_previously_accepted} - - attr_parsing_unused_multiple = multiple `{$name}` attributes .suggestion = remove this attribute @@ -145,3 +138,9 @@ attr_parsing_unused_multiple = -attr_parsing_perviously_accepted = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +attr_parsing_unused_duplicate = + unused attribute + .suggestion = remove this attribute + .note = attribute also specified here + .warn = {-passes_previously_accepted} diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index c185ec8a1079a..8698cf0e5839e 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -452,7 +452,7 @@ pub(crate) struct UnusedMultiple { } #[derive(LintDiagnostic)] -#[diag(attr_parsing_unused_multiple)] +#[diag(attr_parsing_unused_duplicate)] pub(crate) struct UnusedDuplicate { #[suggestion(code = "", applicability = "machine-applicable")] pub this: Span, From 8a64946e425c6ef5a01bb2e0e24cc70ac541e022 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 4 Mar 2025 14:17:06 +0100 Subject: [PATCH 22/26] fix most bugs in inline attribute parsing --- .../src/attributes/inline.rs | 24 +++- .../rustc_codegen_ssa/src/codegen_attrs.rs | 11 +- compiler/rustc_parse/src/validate_attr.rs | 7 +- compiler/rustc_passes/src/check_attr.rs | 17 ++- tests/ui/attributes/multiple-invalid.stderr | 18 +-- tests/ui/force-inlining/invalid.rs | 7 +- tests/ui/force-inlining/invalid.stderr | 136 +++++++----------- tests/ui/issues/issue-43988.rs | 4 +- tests/ui/issues/issue-43988.stderr | 34 ++--- .../lint/unused/unused-attr-duplicate.stderr | 36 ++--- .../genercs-in-path-with-prettry-hir.stdout | 2 +- 11 files changed, 143 insertions(+), 153 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index eea08ae4a49db..74d09c0835867 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -64,14 +64,24 @@ impl SingleAttributeParser for RustcForceInlineParser { let reason = match args { ArgParser::NoArgs => None, ArgParser::List(list) => { - cx.emit_err(IncorrectMetaItem { - span: list.span, - suggestion: None, - }); - return None + let Some(l) = list.single() else { + struct_span_code_err!(cx.dcx(), cx.attr_span, E0534, "expected one argument") + .emit(); + return None; + }; + + let Some(reason) = l.lit().and_then(|i| i.kind.str()) else { + cx.emit_err(IncorrectMetaItem { + span: l.span(), + suggestion: None, + }); + return None; + }; + + Some(reason) } ArgParser::NameValue(v) => { - let Some(str) = v.value_as_str() else { + let Some(reason) = v.value_as_str() else { cx.emit_err(IncorrectMetaItem { span: v.value_span, suggestion: None, @@ -79,7 +89,7 @@ impl SingleAttributeParser for RustcForceInlineParser { return None; }; - Some(str) + Some(reason) } }; diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 2b2dc9b4e73f9..976e097f3b543 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -86,7 +86,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { let rust_target_features = tcx.rust_target_features(LOCAL_CRATE); - let mut inline_span = None; let mut link_ordinal_span = None; let mut no_sanitize_span = None; let mut mixed_export_name_no_mangle_lint_state = MixedExportNameAndNoMangleState::default(); @@ -518,8 +517,13 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); - codegen_fn_attrs.inline = - find_attr!(attrs, AttributeKind::Inline(i, _) => *i).unwrap_or(InlineAttr::None); + + let inline_span; + (codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) = find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span)) { + (inline_attr, Some(span)) + } else { + (InlineAttr::None, None) + }; // naked function MUST NOT be inlined! This attribute is required for the rust compiler itself, // but not for the code generation backend because at that point the naked function will just be @@ -541,7 +545,6 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { return OptimizeAttr::Default; }; - inline_span = Some(attr.span()); let [item] = &items[..] else { err(attr.span(), "expected one argument"); return OptimizeAttr::Default; diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 86f673c100c19..c7976d4186c46 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -235,10 +235,15 @@ fn emit_malformed_attribute( name: Symbol, template: AttributeTemplate, ) { + // attrs with new parsers are locally validated so excluded here + if matches!(name, sym::inline | sym::rustc_force_inline) { + return + } + // Some of previously accepted forms were used in practice, // report them as warnings for now. let should_warn = |name| { - matches!(name, sym::doc | sym::ignore | sym::inline | sym::link | sym::test | sym::bench) + matches!(name, sym::doc | sym::ignore | sym::link | sym::test | sym::bench) }; let error_msg = format!("malformed `{name}` attribute input"); diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index e53ee3bfcb154..35e12434b9ce3 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -123,7 +123,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Stability { span, .. } | AttributeKind::ConstStability { span, .. }, ) => self.check_stability_promotable(*span, target), - Attribute::Parsed(AttributeKind::Inline(i, attr_span)) => { + Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force {..}, ..)) => {} // handled separately below + Attribute::Parsed(AttributeKind::Inline(_, attr_span)) => { self.check_inline(hir_id, *attr_span, span, target) } Attribute::Parsed(AttributeKind::AllowInternalUnstable(syms)) => self @@ -616,6 +617,18 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) => { continue; } + Attribute::Parsed( + AttributeKind::Inline(.., span), + ) => { + self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { + span: *span, + naked_span: attr.span(), + attr: sym::inline, + }); + + return; + } + // FIXME(jdonszelmann): make exhaustive _ => {} } @@ -2771,7 +2784,7 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) { let attrs = tcx.hir().attrs(item.hir_id()); - if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(_, span) => *span) { + if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(i, span) if !matches!(i, InlineAttr::Force{..}) => *span) { tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span }); } } diff --git a/tests/ui/attributes/multiple-invalid.stderr b/tests/ui/attributes/multiple-invalid.stderr index a8dba0ba37d3a..f4f7dd7c4f1f8 100644 --- a/tests/ui/attributes/multiple-invalid.stderr +++ b/tests/ui/attributes/multiple-invalid.stderr @@ -1,12 +1,3 @@ -error[E0518]: attribute should be applied to function or closure - --> $DIR/multiple-invalid.rs:4:1 - | -LL | #[inline] - | ^^^^^^^^^ -... -LL | const FOO: u8 = 0; - | ------------------ not a function or closure - error: attribute should be applied to a function definition --> $DIR/multiple-invalid.rs:6:1 | @@ -16,6 +7,15 @@ LL | LL | const FOO: u8 = 0; | ------------------ not a function definition +error[E0518]: attribute should be applied to function or closure + --> $DIR/multiple-invalid.rs:4:1 + | +LL | #[inline] + | ^^^^^^^^^ +... +LL | const FOO: u8 = 0; + | ------------------ not a function or closure + error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0518`. diff --git a/tests/ui/force-inlining/invalid.rs b/tests/ui/force-inlining/invalid.rs index 7574078b245c2..e531e1830ac18 100644 --- a/tests/ui/force-inlining/invalid.rs +++ b/tests/ui/force-inlining/invalid.rs @@ -9,22 +9,21 @@ // Test that invalid force inlining attributes error as expected. #[rustc_force_inline("foo")] -//~^ ERROR malformed `rustc_force_inline` attribute input pub fn forced1() { } #[rustc_force_inline(bar, baz)] -//~^ ERROR malformed `rustc_force_inline` attribute input +//~^ ERROR expected one argument pub fn forced2() { } #[rustc_force_inline(2)] -//~^ ERROR malformed `rustc_force_inline` attribute input +//~^ ERROR expected a quoted string literal pub fn forced3() { } #[rustc_force_inline = 2] -//~^ ERROR malformed `rustc_force_inline` attribute input +//~^ ERROR expected a quoted string literal pub fn forced4() { } diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr index 92b3c314bad18..d086148b66235 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -1,71 +1,29 @@ -error: malformed `rustc_force_inline` attribute input - --> $DIR/invalid.rs:11:1 - | -LL | #[rustc_force_inline("foo")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[rustc_force_inline("foo")] -LL + #[rustc_force_inline = "reason"] - | -LL - #[rustc_force_inline("foo")] -LL + #[rustc_force_inline] +error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters + --> $DIR/invalid.rs:132:11 | +LL | fn barqux(#[rustc_force_inline] _x: u32) {} + | ^^^^^^^^^^^^^^^^^^^^^ -error: malformed `rustc_force_inline` attribute input - --> $DIR/invalid.rs:16:1 +error[E0534]: expected one argument + --> $DIR/invalid.rs:15:1 | LL | #[rustc_force_inline(bar, baz)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[rustc_force_inline(bar, baz)] -LL + #[rustc_force_inline = "reason"] - | -LL - #[rustc_force_inline(bar, baz)] -LL + #[rustc_force_inline] - | -error: malformed `rustc_force_inline` attribute input - --> $DIR/invalid.rs:21:1 +error[E0539]: expected a quoted string literal + --> $DIR/invalid.rs:20:22 | LL | #[rustc_force_inline(2)] - | ^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[rustc_force_inline(2)] -LL + #[rustc_force_inline = "reason"] - | -LL - #[rustc_force_inline(2)] -LL + #[rustc_force_inline] - | + | ^ -error: malformed `rustc_force_inline` attribute input - --> $DIR/invalid.rs:26:1 +error[E0539]: expected a quoted string literal + --> $DIR/invalid.rs:25:24 | LL | #[rustc_force_inline = 2] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -help: the following are the possible correct uses - | -LL - #[rustc_force_inline = 2] -LL + #[rustc_force_inline = "reason"] - | -LL - #[rustc_force_inline = 2] -LL + #[rustc_force_inline] - | - -error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters - --> $DIR/invalid.rs:133:11 - | -LL | fn barqux(#[rustc_force_inline] _x: u32) {} - | ^^^^^^^^^^^^^^^^^^^^^ + | ^ error: attribute should be applied to a function - --> $DIR/invalid.rs:31:1 + --> $DIR/invalid.rs:30:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -74,7 +32,7 @@ LL | extern crate std as other_std; | ------------------------------ not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:35:1 + --> $DIR/invalid.rs:34:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -83,7 +41,7 @@ LL | use std::collections::HashMap; | ------------------------------ not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:39:1 + --> $DIR/invalid.rs:38:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -92,7 +50,7 @@ LL | static _FOO: &'static str = "FOO"; | ---------------------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:43:1 + --> $DIR/invalid.rs:42:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -101,7 +59,7 @@ LL | const _BAR: u32 = 3; | -------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:47:1 + --> $DIR/invalid.rs:46:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -110,7 +68,7 @@ LL | mod foo { } | ----------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:51:1 + --> $DIR/invalid.rs:50:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -125,7 +83,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:67:1 + --> $DIR/invalid.rs:66:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -134,7 +92,7 @@ LL | type Foo = u32; | --------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:71:1 + --> $DIR/invalid.rs:70:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -147,13 +105,13 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:73:10 + --> $DIR/invalid.rs:72:10 | LL | enum Bar<#[rustc_force_inline] T> { | ^^^^^^^^^^^^^^^^^^^^^ - not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:75:5 + --> $DIR/invalid.rs:74:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +120,7 @@ LL | Baz(std::marker::PhantomData), | -------------------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:80:1 + --> $DIR/invalid.rs:79:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -175,7 +133,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:83:5 + --> $DIR/invalid.rs:82:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -184,7 +142,7 @@ LL | field: u32, | ---------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:88:1 + --> $DIR/invalid.rs:87:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -196,7 +154,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:95:1 + --> $DIR/invalid.rs:94:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -211,7 +169,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:110:1 + --> $DIR/invalid.rs:109:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -220,7 +178,7 @@ LL | trait FooQux = FooBaz; | ---------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:114:1 + --> $DIR/invalid.rs:113:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -233,7 +191,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:122:1 + --> $DIR/invalid.rs:121:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -245,7 +203,7 @@ LL | | } | |_- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:129:1 + --> $DIR/invalid.rs:128:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -254,7 +212,7 @@ LL | macro_rules! barqux { ($foo:tt) => { $foo }; } | ---------------------------------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:133:11 + --> $DIR/invalid.rs:132:11 | LL | fn barqux(#[rustc_force_inline] _x: u32) {} | ^^^^^^^^^^^^^^^^^^^^^-------- @@ -262,7 +220,7 @@ LL | fn barqux(#[rustc_force_inline] _x: u32) {} | not a function definition error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:137:1 + --> $DIR/invalid.rs:136:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -271,7 +229,7 @@ LL | async fn async_foo() {} | -------------------- `async`, `gen` or `async gen` function error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:141:1 + --> $DIR/invalid.rs:140:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -280,7 +238,7 @@ LL | gen fn gen_foo() {} | ---------------- `async`, `gen` or `async gen` function error: attribute cannot be applied to a `async`, `gen` or `async gen` function - --> $DIR/invalid.rs:145:1 + --> $DIR/invalid.rs:144:1 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -289,19 +247,19 @@ LL | async gen fn async_gen_foo() {} | ---------------------------- `async`, `gen` or `async gen` function error: attribute should be applied to a function - --> $DIR/invalid.rs:150:14 + --> $DIR/invalid.rs:149:14 | LL | let _x = #[rustc_force_inline] || { }; | ^^^^^^^^^^^^^^^^^^^^^ ------ not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:152:14 + --> $DIR/invalid.rs:151:14 | LL | let _y = #[rustc_force_inline] 3 + 4; | ^^^^^^^^^^^^^^^^^^^^^ - not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:154:5 + --> $DIR/invalid.rs:153:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -310,7 +268,7 @@ LL | let _z = 3; | ----------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:159:9 + --> $DIR/invalid.rs:158:9 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -319,7 +277,7 @@ LL | 1 => (), | ------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:98:5 + --> $DIR/invalid.rs:97:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -328,7 +286,7 @@ LL | type Foo; | --------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:101:5 + --> $DIR/invalid.rs:100:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -337,7 +295,7 @@ LL | const Bar: i32; | --------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:105:5 + --> $DIR/invalid.rs:104:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -346,7 +304,7 @@ LL | fn foo() {} | ----------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:117:5 + --> $DIR/invalid.rs:116:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -355,7 +313,7 @@ LL | fn foo() {} | ----------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:54:5 + --> $DIR/invalid.rs:53:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -364,7 +322,7 @@ LL | static X: &'static u32; | ----------------------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:58:5 + --> $DIR/invalid.rs:57:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -373,7 +331,7 @@ LL | type Y; | ------- not a function definition error: attribute should be applied to a function - --> $DIR/invalid.rs:62:5 + --> $DIR/invalid.rs:61:5 | LL | #[rustc_force_inline] | ^^^^^^^^^^^^^^^^^^^^^ @@ -381,5 +339,7 @@ LL | LL | fn foo(); | --------- not a function definition -error: aborting due to 38 previous errors +error: aborting due to 37 previous errors +Some errors have detailed explanations: E0534, E0539. +For more information about an error, try `rustc --explain E0534`. diff --git a/tests/ui/issues/issue-43988.rs b/tests/ui/issues/issue-43988.rs index b114e8e03333d..0475e3f6e7a99 100644 --- a/tests/ui/issues/issue-43988.rs +++ b/tests/ui/issues/issue-43988.rs @@ -9,7 +9,7 @@ fn main() { #[inline(XYZ)] let _b = 4; - //~^^ ERROR attribute should be applied to function or closure + //~^^ ERROR invalid argument #[repr(nothing)] let _x = 0; @@ -29,7 +29,7 @@ fn main() { #[inline(ABC)] foo(); - //~^^ ERROR attribute should be applied to function or closure + //~^^ ERROR invalid argument let _z = #[repr] 1; //~^ ERROR malformed `repr` attribute diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index d629f199b223d..ded50d4fc67b1 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -10,6 +10,14 @@ error: malformed `repr` attribute input LL | let _z = #[repr] 1; | ^^^^^^^ help: must be of the form: `#[repr(C)]` +error[E0535]: invalid argument + --> $DIR/issue-43988.rs:10:14 + | +LL | #[inline(XYZ)] + | ^^^ + | + = help: valid inline arguments are `always` and `never` + error[E0552]: unrecognized representation hint --> $DIR/issue-43988.rs:14:12 | @@ -26,6 +34,14 @@ LL | #[repr(something_not_real)] | = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` +error[E0535]: invalid argument + --> $DIR/issue-43988.rs:30:14 + | +LL | #[inline(ABC)] + | ^^^ + | + = help: valid inline arguments are `always` and `never` + error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:5:5 | @@ -34,23 +50,7 @@ LL | #[inline] LL | let _a = 4; | ----------- not a function or closure -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43988.rs:10:5 - | -LL | #[inline(XYZ)] - | ^^^^^^^^^^^^^^ -LL | let _b = 4; - | ----------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43988.rs:30:5 - | -LL | #[inline(ABC)] - | ^^^^^^^^^^^^^^ -LL | foo(); - | ----- not a function or closure - error: aborting due to 7 previous errors -Some errors have detailed explanations: E0518, E0552. +Some errors have detailed explanations: E0518, E0535, E0552. For more information about an error, try `rustc --explain E0518`. diff --git a/tests/ui/lint/unused/unused-attr-duplicate.stderr b/tests/ui/lint/unused/unused-attr-duplicate.stderr index 769b174874b96..5ea623a713e85 100644 --- a/tests/ui/lint/unused/unused-attr-duplicate.stderr +++ b/tests/ui/lint/unused/unused-attr-duplicate.stderr @@ -1,3 +1,21 @@ +error: unused attribute + --> $DIR/unused-attr-duplicate.rs:74:1 + | +LL | #[inline(never)] + | ^^^^^^^^^^^^^^^^ help: remove this attribute + | +note: attribute also specified here + --> $DIR/unused-attr-duplicate.rs:73:1 + | +LL | #[inline(always)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +note: the lint level is defined here + --> $DIR/unused-attr-duplicate.rs:12:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + error: unused attribute --> $DIR/unused-attr-duplicate.rs:33:1 | @@ -9,11 +27,6 @@ note: attribute also specified here | LL | #[no_link] | ^^^^^^^^^^ -note: the lint level is defined here - --> $DIR/unused-attr-duplicate.rs:12:9 - | -LL | #![deny(unused_attributes)] - | ^^^^^^^^^^^^^^^^^ error: unused attribute --> $DIR/unused-attr-duplicate.rs:37:1 @@ -102,19 +115,6 @@ note: attribute also specified here LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ -error: unused attribute - --> $DIR/unused-attr-duplicate.rs:74:1 - | -LL | #[inline(never)] - | ^^^^^^^^^^^^^^^^ help: remove this attribute - | -note: attribute also specified here - --> $DIR/unused-attr-duplicate.rs:73:1 - | -LL | #[inline(always)] - | ^^^^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - error: unused attribute --> $DIR/unused-attr-duplicate.rs:77:1 | diff --git a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout index e8c88d2dcdf2c..51b160284499f 100644 --- a/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout +++ b/tests/ui/macros/genercs-in-path-with-prettry-hir.stdout @@ -7,7 +7,7 @@ extern crate std; // issue#97006 macro_rules! m { ($attr_path: path) => { #[$attr_path] fn f() {} } } -#[inline] +#[attr="Inline(Hint)")] fn f() { } fn main() { } From e0690b833c6efe149fecc4c44be562e2bc3e612d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Tue, 4 Mar 2025 17:15:47 +0100 Subject: [PATCH 23/26] implement consistent errors for attributes (and update `inline`) --- compiler/rustc_attr_parsing/messages.ftl | 5 ++ .../src/attributes/allow_unstable.rs | 3 + .../src/attributes/confusables.rs | 3 +- .../src/attributes/deprecation.rs | 6 ++ .../src/attributes/inline.rs | 43 ++++++----- .../rustc_attr_parsing/src/attributes/mod.rs | 13 +++- .../rustc_attr_parsing/src/attributes/repr.rs | 3 + .../src/attributes/stability.rs | 16 ++-- .../src/attributes/transparency.rs | 2 + compiler/rustc_attr_parsing/src/context.rs | 69 ++++++++++++++--- .../src/session_diagnostics.rs | 77 ++++++++++++++++++- compiler/rustc_feature/src/builtin_attrs.rs | 40 +++++++--- compiler/rustc_lint/src/lints.rs | 1 + tests/ui/error-codes/E0534.rs | 2 +- tests/ui/error-codes/E0534.stderr | 17 +++- ...43106-gating-of-builtin-attrs-error.stderr | 2 +- tests/ui/force-inlining/invalid.rs | 6 +- tests/ui/force-inlining/invalid.stderr | 60 +++++++++++++-- tests/ui/invalid/invalid-inline.rs | 4 +- tests/ui/invalid/invalid-inline.stderr | 33 +++++++- tests/ui/issues/issue-43988.rs | 4 +- tests/ui/issues/issue-43988.stderr | 34 ++++++-- .../ui/malformed/malformed-regressions.stderr | 18 ++--- tests/ui/span/E0535.rs | 2 +- tests/ui/span/E0535.stderr | 18 ++++- 25 files changed, 394 insertions(+), 87 deletions(-) diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index a5b1c291c03a7..064bd5b347a32 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -144,3 +144,8 @@ attr_parsing_unused_duplicate = .suggestion = remove this attribute .note = attribute also specified here .warn = {-passes_previously_accepted} + +attr_parsing_ill_formed_attribute_input = {$num_suggestions -> + [1] attribute must be of the form {$suggestions} + *[other] valid forms for the attribute are {$suggestions} + } diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 647ebd21b47c3..1bc2f9411b430 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -1,6 +1,7 @@ use std::iter; use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{template, AttributeTemplate}; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; @@ -13,6 +14,7 @@ impl CombineAttributeParser for AllowInternalUnstableParser { const PATH: &'static [rustc_span::Symbol] = &[sym::allow_internal_unstable]; type Item = (Symbol, Span); const CONVERT: ConvertFn = AttributeKind::AllowInternalUnstable; + const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ..."); fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, @@ -29,6 +31,7 @@ impl CombineAttributeParser for AllowConstFnUnstableParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_allow_const_fn_unstable]; type Item = Symbol; const CONVERT: ConvertFn = AttributeKind::AllowConstFnUnstable; + const TEMPLATE: AttributeTemplate = template!(Word, List: "feat1, feat2, ..."); fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index afd3c012f05ad..bc0d030d65201 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -1,4 +1,5 @@ use rustc_attr_data_structures::AttributeKind; +use rustc_feature::template; use rustc_span::{Span, Symbol, sym}; use thin_vec::ThinVec; @@ -13,7 +14,7 @@ pub(crate) struct ConfusablesParser { } impl AttributeParser for ConfusablesParser { - const ATTRIBUTES: AcceptMapping = &[(&[sym::rustc_confusables], |this, cx, args| { + const ATTRIBUTES: AcceptMapping = &[(&[sym::rustc_confusables], template!(List: r#""name1", "name2", ..."#), |this, cx, args| { let Some(list) = args.list() else { // FIXME(jdonszelmann): error when not a list? Bring validation code here. // NOTE: currently subsequent attributes are silently ignored using diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 71916e2b432e0..1b630a5e932e7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,4 +1,5 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; +use rustc_feature::{template, AttributeTemplate}; use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol, sym}; @@ -49,6 +50,11 @@ impl SingleAttributeParser for DeprecationParser { const PATH: &'static [rustc_span::Symbol] = &[sym::deprecated]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Error; + const TEMPLATE: AttributeTemplate = template!( + Word, + List: r#"/*opt*/ since = "version", /*opt*/ note = "reason""#, + NameValueStr: "reason" + ); fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { let features = cx.features(); diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 74d09c0835867..3b95c6670ad76 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -3,14 +3,16 @@ // SingleAttributeParser which is what we have two of here. use rustc_attr_data_structures::{AttributeKind, InlineAttr}; -use rustc_errors::{E0534, E0535, struct_span_code_err}; +use rustc_errors::DiagArgValue; +use rustc_feature::{template, AttributeTemplate}; +use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_span::sym; use super::{AcceptContext, AttributeOrder, OnDuplicate}; use crate::attributes::SingleAttributeParser; use crate::context::Stage; use crate::parser::ArgParser; -use crate::session_diagnostics::IncorrectMetaItem; +use crate::session_diagnostics::IllFormedAttributeInput; pub(crate) struct InlineParser; @@ -18,14 +20,14 @@ impl SingleAttributeParser for InlineParser { const PATH: &'static [rustc_span::Symbol] = &[sym::inline]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(Word, List: "always|never"); fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { match args { ArgParser::NoArgs => Some(AttributeKind::Inline(InlineAttr::Hint, cx.attr_span)), ArgParser::List(list) => { let Some(l) = list.single() else { - struct_span_code_err!(cx.dcx(), cx.attr_span, E0534, "expected one argument") - .emit(); + cx.expected_single_argument(list.span); return None; }; @@ -37,17 +39,24 @@ impl SingleAttributeParser for InlineParser { Some(AttributeKind::Inline(InlineAttr::Never, cx.attr_span)) } _ => { - struct_span_code_err!(cx.dcx(), l.span(), E0535, "invalid argument") - .with_help("valid inline arguments are `always` and `never`") - .emit(); + cx.expected_specific_argument(l.span(), vec!["always", "never"]); return None; } } } ArgParser::NameValue(_) => { - // silently ignored, we warn somewhere else. - // FIXME(jdonszelmann): that warning *should* go here. - None + let suggestions = >::TEMPLATE.suggestions(false, "inline"); + cx.emit_lint( + ILL_FORMED_ATTRIBUTE_INPUT, + cx.attr_span, + IllFormedAttributeInput { + num_suggestions: suggestions.len(), + suggestions: DiagArgValue::StrListSepByAnd( + suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), + ), + } + ); + return None; } } } @@ -59,22 +68,19 @@ impl SingleAttributeParser for RustcForceInlineParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_force_inline]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast; const ON_DUPLICATE: OnDuplicate = OnDuplicate::WarnButFutureError; + const TEMPLATE: AttributeTemplate = template!(Word, List: "reason", NameValueStr: "reason"); fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { let reason = match args { ArgParser::NoArgs => None, ArgParser::List(list) => { let Some(l) = list.single() else { - struct_span_code_err!(cx.dcx(), cx.attr_span, E0534, "expected one argument") - .emit(); + cx.expected_single_argument(list.span); return None; }; let Some(reason) = l.lit().and_then(|i| i.kind.str()) else { - cx.emit_err(IncorrectMetaItem { - span: l.span(), - suggestion: None, - }); + cx.expected_string_literal(l.span()); return None; }; @@ -82,10 +88,7 @@ impl SingleAttributeParser for RustcForceInlineParser { } ArgParser::NameValue(v) => { let Some(reason) = v.value_as_str() else { - cx.emit_err(IncorrectMetaItem { - span: v.value_span, - suggestion: None, - }); + cx.expected_string_literal(v.value_span); return None; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index d1790a46c397c..43d135f1981b1 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -17,6 +17,7 @@ use std::marker::PhantomData; use rustc_attr_data_structures::AttributeKind; +use rustc_feature::AttributeTemplate; use rustc_session::lint::builtin::UNUSED_ATTRIBUTES; use rustc_span::{Span, Symbol}; use thin_vec::ThinVec; @@ -36,7 +37,7 @@ pub(crate) mod transparency; pub(crate) mod util; type AcceptFn = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>); -type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AcceptFn)]; +type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AttributeTemplate, AcceptFn)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. /// @@ -80,6 +81,9 @@ pub(crate) trait SingleAttributeParser: 'static { const ATTRIBUTE_ORDER: AttributeOrder; const ON_DUPLICATE: OnDuplicate; + /// The template this attribute parser should implement. Used for diagnostics. + const TEMPLATE: AttributeTemplate; + /// Converts a single syntactical attribute to a single semantic attribute, or [`AttributeKind`] fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option; } @@ -97,7 +101,7 @@ impl, S: Stage> Default for Single { impl, S: Stage> AttributeParser for Single { const ATTRIBUTES: AcceptMapping = - &[(T::PATH, |group: &mut Single, cx, args| { + &[(T::PATH, >::TEMPLATE, |group: &mut Single, cx, args| { if let Some(pa) = T::convert(cx, args) { match T::ATTRIBUTE_ORDER { // keep the first and report immediately. ignore this attribute @@ -208,6 +212,9 @@ pub(crate) trait CombineAttributeParser: 'static { type Item; const CONVERT: ConvertFn; + /// The template this attribute parser should implement. Used for diagnostics. + const TEMPLATE: AttributeTemplate; + /// Converts a single syntactical attribute to a number of elements of the semantic attribute, or [`AttributeKind`] fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, @@ -228,7 +235,7 @@ impl, S: Stage> Default for Combine { impl, S: Stage> AttributeParser for Combine { const ATTRIBUTES: AcceptMapping = - &[(T::PATH, |group: &mut Combine, cx, args| group.1.extend(T::extend(cx, args)))]; + &[(T::PATH, >::TEMPLATE, |group: &mut Combine, cx, args| group.1.extend(T::extend(cx, args)))]; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 1ee4359dcdac1..65aa907503aa3 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,6 +1,7 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; +use rustc_feature::{template, AttributeTemplate}; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; @@ -23,6 +24,8 @@ impl CombineAttributeParser for ReprParser { type Item = (ReprAttr, Span); const PATH: &'static [rustc_span::Symbol] = &[sym::repr]; const CONVERT: ConvertFn = AttributeKind::Repr; + // FIXME(jdonszelmann): never used + const TEMPLATE: AttributeTemplate = template!(List: "C"); fn extend<'c>( cx: &'c mut AcceptContext<'_, '_, S>, diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 00b9e23d3a733..95b5e44cad2e0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -5,6 +5,7 @@ use rustc_attr_data_structures::{ StableSince, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_errors::ErrorGuaranteed; +use rustc_feature::{template, AttributeTemplate}; use rustc_span::{Span, Symbol, kw, sym}; use super::util::parse_version; @@ -43,7 +44,7 @@ impl StabilityParser { impl AttributeParser for StabilityParser { const ATTRIBUTES: AcceptMapping = &[ - (&[sym::stable], |this, cx, args| { + (&[sym::stable], template!(List: r#"feature = "name", since = "version""#), |this, cx, args| { reject_outside_std!(cx); if !this.check_duplicate(cx) && let Some((feature, level)) = parse_stability(cx, args) @@ -51,7 +52,7 @@ impl AttributeParser for StabilityParser { this.stability = Some((Stability { level, feature }, cx.attr_span)); } }), - (&[sym::unstable], |this, cx, args| { + (&[sym::unstable], template!(List: r#"feature = "name", reason = "...", issue = "N""#), |this, cx, args| { reject_outside_std!(cx); if !this.check_duplicate(cx) && let Some((feature, level)) = parse_unstability(cx, args) @@ -59,7 +60,7 @@ impl AttributeParser for StabilityParser { this.stability = Some((Stability { level, feature }, cx.attr_span)); } }), - (&[sym::rustc_allowed_through_unstable_modules], |this, cx, args| { + (&[sym::rustc_allowed_through_unstable_modules], template!(NameValueStr: "deprecation message"), |this, cx, args| { reject_outside_std!(cx); this.allowed_through_unstable_modules = Some(match args.name_value().and_then(|i| i.value_as_str()) { @@ -101,7 +102,7 @@ pub(crate) struct BodyStabilityParser { impl AttributeParser for BodyStabilityParser { const ATTRIBUTES: AcceptMapping = - &[(&[sym::rustc_default_body_unstable], |this, cx, args| { + &[(&[sym::rustc_default_body_unstable], template!(List: r#"feature = "name", reason = "...", issue = "N""#), |this, cx, args| { reject_outside_std!(cx); if this.stability.is_some() { cx.dcx() @@ -124,6 +125,7 @@ impl SingleAttributeParser for ConstStabilityIndirectParser { const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_const_stable_indirect]; const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepFirst; const ON_DUPLICATE: OnDuplicate = OnDuplicate::Ignore; + const TEMPLATE: AttributeTemplate = template!(Word); fn convert(_cx: &AcceptContext<'_, '_, S>, _args: &ArgParser<'_>) -> Option { Some(AttributeKind::ConstStabilityIndirect) @@ -150,7 +152,7 @@ impl ConstStabilityParser { impl AttributeParser for ConstStabilityParser { const ATTRIBUTES: AcceptMapping = &[ - (&[sym::rustc_const_stable], |this, cx, args| { + (&[sym::rustc_const_stable], template!(List: r#"feature = "name""#), |this, cx, args| { reject_outside_std!(cx); if !this.check_duplicate(cx) @@ -162,7 +164,7 @@ impl AttributeParser for ConstStabilityParser { )); } }), - (&[sym::rustc_const_unstable], |this, cx, args| { + (&[sym::rustc_const_unstable], template!(List: r#"feature = "name""#), |this, cx, args| { reject_outside_std!(cx); if !this.check_duplicate(cx) && let Some((feature, level)) = parse_unstability(cx, args) @@ -173,7 +175,7 @@ impl AttributeParser for ConstStabilityParser { )); } }), - (&[sym::rustc_promotable], |this, cx, _| { + (&[sym::rustc_promotable], template!(Word), |this, cx, _| { reject_outside_std!(cx); this.promotable = true; }), diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index f3d4327d897ed..55e69c9b4f6be 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,4 +1,5 @@ use rustc_attr_data_structures::AttributeKind; +use rustc_feature::{template, AttributeTemplate}; use rustc_span::hygiene::Transparency; use rustc_span::sym; @@ -17,6 +18,7 @@ impl SingleAttributeParser for TransparencyParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Custom(|cx, used, unused| { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); }); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "transparent|semitransparent|opaque"); fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { match args.name_value().and_then(|nv| nv.value_as_str()) { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index c3e5dba1b600c..0bfd595231d69 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -8,7 +8,7 @@ use rustc_ast::{self as ast, DelimArgs, NodeId}; use rustc_attr_data_structures::AttributeKind; use rustc_data_structures::sync::DynSend; use rustc_errors::{DiagCtxtHandle, Diagnostic, LintDiagnostic}; -use rustc_feature::Features; +use rustc_feature::{AttributeTemplate, Features}; use rustc_hir::{AttrArgs, AttrItem, AttrPath, Attribute, HashIgnoredAttrId, HirId}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; @@ -27,11 +27,12 @@ use crate::attributes::stability::{ use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single}; use crate::parser::{ArgParser, MetaItemParser}; +use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason}; macro_rules! group_type { ($stage: ty) => { LazyLock<( - BTreeMap<&'static [Symbol], Vec Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>>>, + BTreeMap<&'static [Symbol], Vec<(AttributeTemplate, Box Fn(&mut AcceptContext<'_, 'sess, $stage>, &ArgParser<'a>) + Send + Sync>)>>, Vec) -> Option>> )> }; @@ -60,7 +61,7 @@ macro_rules! attribute_groups { @[$ty: ty] pub(crate) static $name: ident = [$($names: ty),* $(,)?]; ) => { pub(crate) static $name: group_type!($ty) = LazyLock::new(|| { - let mut accepts = BTreeMap::<_, Vec Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>>>::new(); + let mut accepts = BTreeMap::<_, Vec<(AttributeTemplate, Box Fn(&mut AcceptContext<'_, 'sess, $ty>, &ArgParser<'a>) + Send + Sync>)>>::new(); let mut finalizes = Vec::) -> Option>>::new(); $( { @@ -68,12 +69,12 @@ macro_rules! attribute_groups { static STATE_OBJECT: RefCell<$names> = RefCell::new(<$names>::default()); }; - for (k, v) in <$names>::ATTRIBUTES { - accepts.entry(*k).or_default().push(Box::new(|cx, args| { + for (path, template, accept_fn) in <$names>::ATTRIBUTES { + accepts.entry(*path).or_default().push((*template, Box::new(|cx, args| { STATE_OBJECT.with_borrow_mut(|s| { - v(s, cx, args) + accept_fn(s, cx, args) }) - })); + }))); } finalizes.push(Box::new(|cx| { @@ -197,7 +198,6 @@ impl Stage for Late { span: Span, diag: impl DynSend + for<'x> LintDiagnostic<'x, ()> + 'static, ) { - println!("stashing lint"); dcx.delay_lint_during_ast_lowering((lint, id, span, Box::new(|x| { diag.decorate_lint(x) }))); @@ -216,6 +216,14 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { pub(crate) group_cx: FinalizeContext<'f, 'sess, S>, /// The span of the attribute currently being parsed pub(crate) attr_span: Span, + + /// The expected structure of the attribute. + /// + /// Used in reporting errors to give a hint to users what the attribute *should* look like. + pub(crate) template: &'f AttributeTemplate, + + /// The name of the attribute we're currently accepting. + pub(crate) attr_path: AttrPath } impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { @@ -223,6 +231,9 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { S::emit_err(&self.sess, diag) } + /// Emit a lint. This method is somewhat special, since lints emitted during attribute parsing + /// must be delayed until after HIR is built. This method will take care of the details of + /// that. pub(crate) fn emit_lint( & self, lint: &'static Lint, @@ -231,6 +242,44 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { ) { S::emit_lint(self.dcx(), lint, self.target_id, span, diag) } + + + pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed { + // 539? + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedStringLiteral, + }) + } + + // pub(crate) fn expected_any_arguments(&self, span: Span) -> ErrorGuaranteed { + // + // } + + pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed { + // E534? + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedSingleArgument, + }) + } + + pub(crate) fn expected_specific_argument(&self, span: Span, options: Vec<&'static str>) -> ErrorGuaranteed { + // E535? + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedSpecificArgument(options), + }) + } } impl<'f, 'sess, S: Stage> Deref for AcceptContext<'f, 'sess, S> { @@ -417,10 +466,12 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> { let parts = path.segments().map(|i| i.name).collect::>(); if let Some(accepts) = S::parsers().0.get(parts.as_slice()) { - for f in accepts { + for (template, f) in accepts { let mut cx: AcceptContext<'_, 'sess, S> = AcceptContext { group_cx: FinalizeContext { cx: self, target_span, target_id }, attr_span: lower_span(attr.span), + template, + attr_path: path.get_attribute_path(), }; f(&mut cx, args) diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 8698cf0e5839e..964fb79f0bf33 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -1,8 +1,10 @@ use std::num::IntErrorKind; use rustc_ast as ast; -use rustc_errors::codes::*; +use rustc_errors::{codes::*, DiagArgValue}; use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; +use rustc_feature::AttributeTemplate; +use rustc_hir::AttrPath; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -462,6 +464,14 @@ pub(crate) struct UnusedDuplicate { pub warning: bool, } +// FIXME(jdonszelmann): duplicated in rustc_lints, should be moved here completely. +#[derive(LintDiagnostic)] +#[diag(attr_parsing_ill_formed_attribute_input)] +pub(crate) struct IllFormedAttributeInput { + pub num_suggestions: usize, + pub suggestions: DiagArgValue, +} + #[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd { @@ -490,3 +500,68 @@ pub(crate) struct UnrecognizedReprHint { #[primary_span] pub span: Span, } + +pub(crate) enum AttributeParseErrorReason { + ExpectedStringLiteral, + ExpectedSingleArgument, + ExpectedSpecificArgument(Vec<&'static str>), +} + +pub(crate) struct AttributeParseError { + pub(crate) span: Span, + pub(crate) attr_span: Span, + pub(crate) template: AttributeTemplate, + pub(crate) attribute: AttrPath, + pub(crate) reason: AttributeParseErrorReason, +} + +impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { + fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { + let name = self.attribute.to_string(); + + let mut diag = Diag::new( + dcx, + level, + format!("malformed `{name}` attribute input") + ); + diag.span(self.attr_span); + diag.code(E0539); + match self.reason { + AttributeParseErrorReason::ExpectedStringLiteral => { + diag.span_note(self.span, "expected a string literal here"); + }, + AttributeParseErrorReason::ExpectedSingleArgument => { + diag.span_note(self.span, "expected a single argument here"); + }, + AttributeParseErrorReason::ExpectedSpecificArgument(possibilities) => { + match possibilities.as_slice() { + &[] => {} + &[x] => { + diag.span_note(self.span, format!("the only valid argument here is `{x}`")); + } + [first, second] => { + diag.span_note(self.span, format!("valid arguments are `{first}` or `{second}`")); + } + [first@.., second_to_last, last] => { + let mut res = String::new(); + for i in first { + res.push_str(&format!("`{i}`, ")); + } + res.push_str(&format!("`{second_to_last}` or `{last}`")); + + diag.span_note(self.span, format!("valid arguments are {res}")); + } + } + }, + } + + let suggestions = self.template.suggestions(false, &name); + diag.span_suggestions(self.attr_span, if suggestions.len() == 1 { + "must be of the form" + } else { + "the following are possible correct uses" + }, suggestions, Applicability::HasPlaceholders); + + diag + } +} diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 306535bf7642e..7d8dcf1198f3e 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -98,6 +98,7 @@ impl AttributeGate { } } +// FIXME(jdonszelmann): move to rustc_attr_data_structures /// A template that the attribute input must match. /// Only top-level shape (`#[attr]` vs `#[attr(...)]` vs `#[attr = ...]`) is considered now. #[derive(Clone, Copy, Default)] @@ -114,6 +115,26 @@ pub struct AttributeTemplate { pub name_value_str: Option<&'static str>, } +impl AttributeTemplate { + pub fn suggestions(&self, inner: bool, name: impl std::fmt::Display) -> Vec { + let mut suggestions = vec![]; + let inner = if inner { "!" } else { "" }; + if self.word { + suggestions.push(format!("#{inner}[{name}]")); + } + if let Some(descr) = self.list { + suggestions.push(format!("#{inner}[{name}({descr})]")); + } + suggestions.extend(self.one_of.iter().map(|&word| format!("#{inner}[{name}({word})]"))); + if let Some(descr) = self.name_value_str { + suggestions.push(format!("#{inner}[{name} = \"{descr}\"]")); + } + suggestions.sort(); + + suggestions + } +} + /// How to handle multiple duplicate attributes on the same item. #[derive(Clone, Copy, Default)] pub enum AttributeDuplicates { @@ -168,20 +189,21 @@ pub enum AttributeDuplicates { /// A convenience macro for constructing attribute templates. /// E.g., `template!(Word, List: "description")` means that the attribute /// supports forms `#[attr]` and `#[attr(description)]`. +#[macro_export] macro_rules! template { - (Word) => { template!(@ true, None, &[], None) }; - (List: $descr: expr) => { template!(@ false, Some($descr), &[], None) }; - (OneOf: $one_of: expr) => { template!(@ false, None, $one_of, None) }; - (NameValueStr: $descr: expr) => { template!(@ false, None, &[], Some($descr)) }; - (Word, List: $descr: expr) => { template!(@ true, Some($descr), &[], None) }; - (Word, NameValueStr: $descr: expr) => { template!(@ true, None, &[], Some($descr)) }; + (Word) => { $crate::template!(@ true, None, &[], None) }; + (List: $descr: expr) => { $crate::template!(@ false, Some($descr), &[], None) }; + (OneOf: $one_of: expr) => { $crate::template!(@ false, None, $one_of, None) }; + (NameValueStr: $descr: expr) => { $crate::template!(@ false, None, &[], Some($descr)) }; + (Word, List: $descr: expr) => { $crate::template!(@ true, Some($descr), &[], None) }; + (Word, NameValueStr: $descr: expr) => { $crate::template!(@ true, None, &[], Some($descr)) }; (List: $descr1: expr, NameValueStr: $descr2: expr) => { - template!(@ false, Some($descr1), &[], Some($descr2)) + $crate::template!(@ false, Some($descr1), &[], Some($descr2)) }; (Word, List: $descr1: expr, NameValueStr: $descr2: expr) => { - template!(@ true, Some($descr1), &[], Some($descr2)) + $crate::template!(@ true, Some($descr1), &[], Some($descr2)) }; - (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr) => { AttributeTemplate { + (@ $word: expr, $list: expr, $one_of: expr, $name_value_str: expr) => { $crate::AttributeTemplate { word: $word, list: $list, one_of: $one_of, name_value_str: $name_value_str } }; } diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 0058630957291..d710277c082fe 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2572,6 +2572,7 @@ pub(crate) struct UnusedCrateDependency { pub local_crate: Symbol, } +// FIXME(jdonszelmann): duplicated in rustc_attr_parsing, should be moved there completely. #[derive(LintDiagnostic)] #[diag(lint_ill_formed_attribute_input)] pub(crate) struct IllFormedAttributeInput { diff --git a/tests/ui/error-codes/E0534.rs b/tests/ui/error-codes/E0534.rs index a424249941979..db29e6801f582 100644 --- a/tests/ui/error-codes/E0534.rs +++ b/tests/ui/error-codes/E0534.rs @@ -1,4 +1,4 @@ -#[inline()] //~ ERROR E0534 +#[inline()] //~ ERROR malformed `inline` attribute input pub fn something() {} fn main() { diff --git a/tests/ui/error-codes/E0534.stderr b/tests/ui/error-codes/E0534.stderr index 6983de7ab69c6..f63d80c220cec 100644 --- a/tests/ui/error-codes/E0534.stderr +++ b/tests/ui/error-codes/E0534.stderr @@ -1,9 +1,22 @@ -error[E0534]: expected one argument +error[E0539]: malformed `inline` attribute input --> $DIR/E0534.rs:1:1 | LL | #[inline()] | ^^^^^^^^^^^ + | +note: expected a single argument here + --> $DIR/E0534.rs:1:9 + | +LL | #[inline()] + | ^^ +help: the following are possible correct uses + | +LL | #[inline(always|never)] + | ++++++++++++ +LL - #[inline()] +LL + #[inline] + | error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0534`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr index 5c2a3ae699c03..d1eaeff01bd99 100644 --- a/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr +++ b/tests/ui/feature-gates/issue-43106-gating-of-builtin-attrs-error.stderr @@ -7,7 +7,7 @@ LL | #![rustc_main] = help: add `#![feature(rustc_attrs)]` 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: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]` +error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:44:5 | LL | #[inline = "2100"] fn f() { } diff --git a/tests/ui/force-inlining/invalid.rs b/tests/ui/force-inlining/invalid.rs index e531e1830ac18..e9f5712413e80 100644 --- a/tests/ui/force-inlining/invalid.rs +++ b/tests/ui/force-inlining/invalid.rs @@ -13,17 +13,17 @@ pub fn forced1() { } #[rustc_force_inline(bar, baz)] -//~^ ERROR expected one argument +//~^ ERROR malformed `rustc_force_inline` attribute input pub fn forced2() { } #[rustc_force_inline(2)] -//~^ ERROR expected a quoted string literal +//~^ ERROR malformed `rustc_force_inline` attribute input pub fn forced3() { } #[rustc_force_inline = 2] -//~^ ERROR expected a quoted string literal +//~^ ERROR malformed `rustc_force_inline` attribute input pub fn forced4() { } diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr index d086148b66235..26259a4d61fe0 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -4,23 +4,74 @@ error: allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed LL | fn barqux(#[rustc_force_inline] _x: u32) {} | ^^^^^^^^^^^^^^^^^^^^^ -error[E0534]: expected one argument +error[E0539]: malformed `rustc_force_inline` attribute input --> $DIR/invalid.rs:15:1 | LL | #[rustc_force_inline(bar, baz)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected a single argument here + --> $DIR/invalid.rs:15:21 + | +LL | #[rustc_force_inline(bar, baz)] + | ^^^^^^^^^^ +help: the following are possible correct uses + | +LL - #[rustc_force_inline(bar, baz)] +LL + #[rustc_force_inline = "reason"] + | +LL - #[rustc_force_inline(bar, baz)] +LL + #[rustc_force_inline(reason)] + | +LL - #[rustc_force_inline(bar, baz)] +LL + #[rustc_force_inline] + | -error[E0539]: expected a quoted string literal +error[E0539]: malformed `rustc_force_inline` attribute input + --> $DIR/invalid.rs:20:1 + | +LL | #[rustc_force_inline(2)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected a string literal here --> $DIR/invalid.rs:20:22 | LL | #[rustc_force_inline(2)] | ^ +help: the following are possible correct uses + | +LL - #[rustc_force_inline(2)] +LL + #[rustc_force_inline = "reason"] + | +LL - #[rustc_force_inline(2)] +LL + #[rustc_force_inline(reason)] + | +LL - #[rustc_force_inline(2)] +LL + #[rustc_force_inline] + | -error[E0539]: expected a quoted string literal +error[E0539]: malformed `rustc_force_inline` attribute input + --> $DIR/invalid.rs:25:1 + | +LL | #[rustc_force_inline = 2] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected a string literal here --> $DIR/invalid.rs:25:24 | LL | #[rustc_force_inline = 2] | ^ +help: the following are possible correct uses + | +LL - #[rustc_force_inline = 2] +LL + #[rustc_force_inline = "reason"] + | +LL - #[rustc_force_inline = 2] +LL + #[rustc_force_inline(reason)] + | +LL - #[rustc_force_inline = 2] +LL + #[rustc_force_inline] + | error: attribute should be applied to a function --> $DIR/invalid.rs:30:1 @@ -341,5 +392,4 @@ LL | fn foo(); error: aborting due to 37 previous errors -Some errors have detailed explanations: E0534, E0539. -For more information about an error, try `rustc --explain E0534`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/invalid/invalid-inline.rs b/tests/ui/invalid/invalid-inline.rs index 2501b1e23f2f1..6735e1d814d89 100644 --- a/tests/ui/invalid/invalid-inline.rs +++ b/tests/ui/invalid/invalid-inline.rs @@ -1,10 +1,10 @@ #![allow(dead_code)] -#[inline(please,no)] //~ ERROR expected one argument +#[inline(please,no)] //~ ERROR malformed `inline` attribute fn a() { } -#[inline()] //~ ERROR expected one argument +#[inline()] //~ ERROR malformed `inline` attribute fn b() { } diff --git a/tests/ui/invalid/invalid-inline.stderr b/tests/ui/invalid/invalid-inline.stderr index 7edbf936b1b4d..965da7e756705 100644 --- a/tests/ui/invalid/invalid-inline.stderr +++ b/tests/ui/invalid/invalid-inline.stderr @@ -1,15 +1,42 @@ -error[E0534]: expected one argument +error[E0539]: malformed `inline` attribute input --> $DIR/invalid-inline.rs:3:1 | LL | #[inline(please,no)] | ^^^^^^^^^^^^^^^^^^^^ + | +note: expected a single argument here + --> $DIR/invalid-inline.rs:3:9 + | +LL | #[inline(please,no)] + | ^^^^^^^^^^^ +help: the following are possible correct uses + | +LL - #[inline(please,no)] +LL + #[inline(always|never)] + | +LL - #[inline(please,no)] +LL + #[inline] + | -error[E0534]: expected one argument +error[E0539]: malformed `inline` attribute input --> $DIR/invalid-inline.rs:7:1 | LL | #[inline()] | ^^^^^^^^^^^ + | +note: expected a single argument here + --> $DIR/invalid-inline.rs:7:9 + | +LL | #[inline()] + | ^^ +help: the following are possible correct uses + | +LL | #[inline(always|never)] + | ++++++++++++ +LL - #[inline()] +LL + #[inline] + | error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0534`. +For more information about this error, try `rustc --explain E0539`. diff --git a/tests/ui/issues/issue-43988.rs b/tests/ui/issues/issue-43988.rs index 0475e3f6e7a99..5fea5576b7f03 100644 --- a/tests/ui/issues/issue-43988.rs +++ b/tests/ui/issues/issue-43988.rs @@ -9,7 +9,7 @@ fn main() { #[inline(XYZ)] let _b = 4; - //~^^ ERROR invalid argument + //~^^ ERROR malformed `inline` attribute #[repr(nothing)] let _x = 0; @@ -29,7 +29,7 @@ fn main() { #[inline(ABC)] foo(); - //~^^ ERROR invalid argument + //~^^ ERROR malformed `inline` attribute let _z = #[repr] 1; //~^ ERROR malformed `repr` attribute diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index ded50d4fc67b1..74c3e81cb1c47 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -10,13 +10,25 @@ error: malformed `repr` attribute input LL | let _z = #[repr] 1; | ^^^^^^^ help: must be of the form: `#[repr(C)]` -error[E0535]: invalid argument +error[E0539]: malformed `inline` attribute input + --> $DIR/issue-43988.rs:10:5 + | +LL | #[inline(XYZ)] + | ^^^^^^^^^^^^^^ + | +note: valid arguments are `always` or `never` --> $DIR/issue-43988.rs:10:14 | LL | #[inline(XYZ)] | ^^^ +help: the following are possible correct uses + | +LL - #[inline(XYZ)] +LL + #[inline(always|never)] + | +LL - #[inline(XYZ)] +LL + #[inline] | - = help: valid inline arguments are `always` and `never` error[E0552]: unrecognized representation hint --> $DIR/issue-43988.rs:14:12 @@ -34,13 +46,25 @@ LL | #[repr(something_not_real)] | = help: valid reprs are `Rust` (default), `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize` -error[E0535]: invalid argument +error[E0539]: malformed `inline` attribute input + --> $DIR/issue-43988.rs:30:5 + | +LL | #[inline(ABC)] + | ^^^^^^^^^^^^^^ + | +note: valid arguments are `always` or `never` --> $DIR/issue-43988.rs:30:14 | LL | #[inline(ABC)] | ^^^ +help: the following are possible correct uses + | +LL - #[inline(ABC)] +LL + #[inline(always|never)] + | +LL - #[inline(ABC)] +LL + #[inline] | - = help: valid inline arguments are `always` and `never` error[E0518]: attribute should be applied to function or closure --> $DIR/issue-43988.rs:5:5 @@ -52,5 +76,5 @@ LL | let _a = 4; error: aborting due to 7 previous errors -Some errors have detailed explanations: E0518, E0535, E0552. +Some errors have detailed explanations: E0518, E0539, E0552. For more information about an error, try `rustc --explain E0518`. diff --git a/tests/ui/malformed/malformed-regressions.stderr b/tests/ui/malformed/malformed-regressions.stderr index e1dbdb9ab3c66..535db55a13d61 100644 --- a/tests/ui/malformed/malformed-regressions.stderr +++ b/tests/ui/malformed/malformed-regressions.stderr @@ -17,15 +17,6 @@ LL | #[ignore()] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 -error: valid forms for the attribute are `#[inline]` and `#[inline(always|never)]` - --> $DIR/malformed-regressions.rs:5:1 - | -LL | #[inline = ""] - | ^^^^^^^^^^^^^^ - | - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #57571 - error: attribute must be of the form `#[link(name = "...", /*opt*/ kind = "dylib|static|...", /*opt*/ wasm_import_module = "...", /*opt*/ import_name_type = "decorated|noprefix|undecorated")]` --> $DIR/malformed-regressions.rs:7:1 | @@ -44,5 +35,14 @@ LL | #[link = ""] = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #57571 +error: valid forms for the attribute are `#[inline(always|never)]` and `#[inline]` + --> $DIR/malformed-regressions.rs:5:1 + | +LL | #[inline = ""] + | ^^^^^^^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #57571 + error: aborting due to 5 previous errors diff --git a/tests/ui/span/E0535.rs b/tests/ui/span/E0535.rs index e26334e9bbdc6..e0c6dbfc591f6 100644 --- a/tests/ui/span/E0535.rs +++ b/tests/ui/span/E0535.rs @@ -1,4 +1,4 @@ -#[inline(unknown)] //~ ERROR E0535 +#[inline(unknown)] //~ ERROR malformed `inline` attribute pub fn something() {} fn main() { diff --git a/tests/ui/span/E0535.stderr b/tests/ui/span/E0535.stderr index 9060b687f508c..54dcdd8957902 100644 --- a/tests/ui/span/E0535.stderr +++ b/tests/ui/span/E0535.stderr @@ -1,11 +1,23 @@ -error[E0535]: invalid argument +error[E0539]: malformed `inline` attribute input + --> $DIR/E0535.rs:1:1 + | +LL | #[inline(unknown)] + | ^^^^^^^^^^^^^^^^^^ + | +note: valid arguments are `always` or `never` --> $DIR/E0535.rs:1:10 | LL | #[inline(unknown)] | ^^^^^^^ +help: the following are possible correct uses + | +LL - #[inline(unknown)] +LL + #[inline(always|never)] + | +LL - #[inline(unknown)] +LL + #[inline] | - = help: valid inline arguments are `always` and `never` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0535`. +For more information about this error, try `rustc --explain E0539`. From 245ed33042922c4645386ac5d16bcff0e9b8baf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 5 Mar 2025 14:35:54 +0100 Subject: [PATCH 24/26] use consistent attr errors in more places --- .../src/attributes/confusables.rs | 12 +-- .../src/attributes/deprecation.rs | 13 ++-- .../src/attributes/stability.rs | 5 +- .../src/attributes/transparency.rs | 10 ++- compiler/rustc_attr_parsing/src/context.rs | 54 ++++++++++--- .../src/session_diagnostics.rs | 50 ++++++------ compiler/rustc_parse/src/validate_attr.rs | 2 +- tests/ui/attributes/rustc_confusables.rs | 4 +- tests/ui/attributes/rustc_confusables.stderr | 31 +++++--- tests/ui/deprecation/deprecation-sanity.rs | 8 +- .../ui/deprecation/deprecation-sanity.stderr | 76 ++++++++++++++++++- .../stability-attribute-sanity.rs | 8 +- .../stability-attribute-sanity.stderr | 32 +++++++- 13 files changed, 213 insertions(+), 92 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index bc0d030d65201..03bb3cfe802e0 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -16,9 +16,7 @@ pub(crate) struct ConfusablesParser { impl AttributeParser for ConfusablesParser { const ATTRIBUTES: AcceptMapping = &[(&[sym::rustc_confusables], template!(List: r#""name1", "name2", ..."#), |this, cx, args| { let Some(list) = args.list() else { - // FIXME(jdonszelmann): error when not a list? Bring validation code here. - // NOTE: currently subsequent attributes are silently ignored using - // tcx.get_attr(). + cx.expected_list(cx.attr_span); return; }; @@ -30,13 +28,7 @@ impl AttributeParser for ConfusablesParser { let span = param.span(); let Some(lit) = param.lit() else { - cx.emit_err(session_diagnostics::IncorrectMetaItem { - span, - suggestion: Some(session_diagnostics::IncorrectMetaItemSuggestion { - lo: span.shrink_to_lo(), - hi: span.shrink_to_hi(), - }), - }); + cx.expected_string_literal(span); continue; }; diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 1b630a5e932e7..9d3fe764f239d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -40,8 +40,7 @@ fn get( None } } else { - // FIXME(jdonszelmann): suggestion? - cx.emit_err(session_diagnostics::IncorrectMetaItem { span: param_span, suggestion: None }); + cx.expected_name_value(param_span); None } } @@ -103,15 +102,15 @@ impl SingleAttributeParser for DeprecationParser { suggestion = Some(get(cx, ident, param_span, arg, &suggestion)?); } _ => { - cx.emit_err(session_diagnostics::UnknownMetaItem { - span: param_span, - item: ident.to_string(), - expected: if features.deprecated_suggestion() { + cx.unknown_key( + param_span, + ident.to_string(), + if features.deprecated_suggestion() { &["since", "note", "suggestion"] } else { &["since", "note"] }, - }); + ); return None; } } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 95b5e44cad2e0..4f7b286123c95 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -218,10 +218,7 @@ fn insert_value_into_option_or_error( *item = Some(s); Some(()) } else { - cx.emit_err(session_diagnostics::IncorrectMetaItem { - span: param.span(), - suggestion: None, - }); + cx.expected_name_value(param.span()); None } } diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 55e69c9b4f6be..5752625d51ede 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -21,12 +21,16 @@ impl SingleAttributeParser for TransparencyParser { const TEMPLATE: AttributeTemplate = template!(NameValueStr: "transparent|semitransparent|opaque"); fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { - match args.name_value().and_then(|nv| nv.value_as_str()) { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span); + return None; + }; + match nv.value_as_str() { Some(sym::transparent) => Some(Transparency::Transparent), Some(sym::semitransparent) => Some(Transparency::SemiTransparent), Some(sym::opaque) => Some(Transparency::Opaque), - Some(other) => { - cx.dcx().span_err(cx.attr_span, format!("unknown macro transparency: `{other}`")); + Some(_) => { + cx.expected_specific_argument_strings(nv.value_span, vec!["transparent", "semitransparent", "opaque"]); None } None => None, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 0bfd595231d69..04652f86d20b0 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -27,7 +27,7 @@ use crate::attributes::stability::{ use crate::attributes::transparency::TransparencyParser; use crate::attributes::{AttributeParser as _, Combine, Single}; use crate::parser::{ArgParser, MetaItemParser}; -use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason}; +use crate::session_diagnostics::{AttributeParseError, AttributeParseErrorReason, UnknownMetaItem}; macro_rules! group_type { ($stage: ty) => { @@ -243,9 +243,15 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { S::emit_lint(self.dcx(), lint, self.target_id, span, diag) } + pub(crate) fn unknown_key(&self, span: Span, found: String, options: &'static [&'static str]) -> ErrorGuaranteed { + self.emit_err(UnknownMetaItem { + span, + item: found, + expected: options, + }) + } pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed { - // 539? self.emit_err(AttributeParseError { span, attr_span: self.attr_span, @@ -255,12 +261,27 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } - // pub(crate) fn expected_any_arguments(&self, span: Span) -> ErrorGuaranteed { - // - // } + pub(crate) fn expected_list(&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::ExpectedList, + }) + } + + pub(crate) fn expected_name_value(&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::ExpectedNameValue, + }) + } pub(crate) fn expected_single_argument(&self, span: Span) -> ErrorGuaranteed { - // E534? self.emit_err(AttributeParseError { span, attr_span: self.attr_span, @@ -270,14 +291,29 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } - pub(crate) fn expected_specific_argument(&self, span: Span, options: Vec<&'static str>) -> ErrorGuaranteed { - // E535? + pub(crate) fn expected_specific_argument(&self, span: Span, possibilities: Vec<&'static str>) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::ExpectedSpecificArgument{ + possibilities, + strings: false + } + }) + } + + pub(crate) fn expected_specific_argument_strings(&self, span: Span, possibilities: Vec<&'static str>) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, attr_span: self.attr_span, template: self.template.clone(), attribute: self.attr_path.clone(), - reason: AttributeParseErrorReason::ExpectedSpecificArgument(options), + reason: AttributeParseErrorReason::ExpectedSpecificArgument{ + possibilities, + strings: true, + } }) } } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 964fb79f0bf33..129a4c8da70b9 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -43,28 +43,6 @@ pub(crate) struct MultipleItem { pub item: String, } -#[derive(Diagnostic)] -#[diag(attr_parsing_incorrect_meta_item, code = E0539)] -pub(crate) struct IncorrectMetaItem { - #[primary_span] - pub span: Span, - - #[subdiagnostic] - pub suggestion: Option, -} - -#[derive(Subdiagnostic)] -#[multipart_suggestion( - attr_parsing_incorrect_meta_item_suggestion, - applicability = "maybe-incorrect" -)] -pub(crate) struct IncorrectMetaItemSuggestion { - #[suggestion_part(code = "\"")] - pub lo: Span, - #[suggestion_part(code = "\"")] - pub hi: Span, -} - /// Error code: E0541 pub(crate) struct UnknownMetaItem<'a> { pub span: Span, @@ -504,7 +482,12 @@ pub(crate) struct UnrecognizedReprHint { pub(crate) enum AttributeParseErrorReason { ExpectedStringLiteral, ExpectedSingleArgument, - ExpectedSpecificArgument(Vec<&'static str>), + ExpectedList, + ExpectedNameValue, + ExpectedSpecificArgument { + possibilities: Vec<&'static str>, + strings: bool, + } } pub(crate) struct AttributeParseError { @@ -533,21 +516,32 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { AttributeParseErrorReason::ExpectedSingleArgument => { diag.span_note(self.span, "expected a single argument here"); }, - AttributeParseErrorReason::ExpectedSpecificArgument(possibilities) => { + AttributeParseErrorReason::ExpectedList => { + diag.span_note(self.span, "expected this to be a list"); + }, + AttributeParseErrorReason::ExpectedNameValue => { + diag.span_note(self.span, "expected this to be of the form `name = value`"); + }, + AttributeParseErrorReason::ExpectedSpecificArgument{possibilities, strings} => { + let quote = if strings { + '"' + } else { + '`' + }; match possibilities.as_slice() { &[] => {} &[x] => { - diag.span_note(self.span, format!("the only valid argument here is `{x}`")); + diag.span_note(self.span, format!("the only valid argument here is {quote}{x}{quote}")); } [first, second] => { - diag.span_note(self.span, format!("valid arguments are `{first}` or `{second}`")); + diag.span_note(self.span, format!("valid arguments are {quote}{first}{quote} or {quote}{second}{quote}")); } [first@.., second_to_last, last] => { let mut res = String::new(); for i in first { - res.push_str(&format!("`{i}`, ")); + res.push_str(&format!("{quote}{i}{quote}, ")); } - res.push_str(&format!("`{second_to_last}` or `{last}`")); + res.push_str(&format!("{quote}{second_to_last}{quote} or {quote}{last}{quote}")); diag.span_note(self.span, format!("valid arguments are {res}")); } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index c7976d4186c46..49d4f6130748d 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -236,7 +236,7 @@ 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) { + if matches!(name, sym::inline | sym::rustc_force_inline | sym::rustc_confusables) { return } diff --git a/tests/ui/attributes/rustc_confusables.rs b/tests/ui/attributes/rustc_confusables.rs index 93d9a7d572c77..a8095936cff7a 100644 --- a/tests/ui/attributes/rustc_confusables.rs +++ b/tests/ui/attributes/rustc_confusables.rs @@ -37,8 +37,8 @@ impl Bar { fn qux() {} #[rustc_confusables(invalid_meta_item)] - //~^ ERROR expected a quoted string literal - //~| HELP consider surrounding this with quotes + //~^ ERROR malformed `rustc_confusables` attribute input [E0539] + //~| HELP must be of the form fn quux() {} } diff --git a/tests/ui/attributes/rustc_confusables.stderr b/tests/ui/attributes/rustc_confusables.stderr index 55c9219a08a84..2c87890227cb4 100644 --- a/tests/ui/attributes/rustc_confusables.stderr +++ b/tests/ui/attributes/rustc_confusables.stderr @@ -1,25 +1,32 @@ -error: malformed `rustc_confusables` attribute input - --> $DIR/rustc_confusables.rs:34:5 - | -LL | #[rustc_confusables] - | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` - error: expected at least one confusable name --> $DIR/rustc_confusables.rs:30:5 | LL | #[rustc_confusables()] | ^^^^^^^^^^^^^^^^^^^^^^ -error[E0539]: expected a quoted string literal - --> $DIR/rustc_confusables.rs:39:25 +error[E0539]: malformed `rustc_confusables` attribute input + --> $DIR/rustc_confusables.rs:34:5 + | +LL | #[rustc_confusables] + | ^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` + | +note: expected this to be a list + --> $DIR/rustc_confusables.rs:34:5 + | +LL | #[rustc_confusables] + | ^^^^^^^^^^^^^^^^^^^^ + +error[E0539]: malformed `rustc_confusables` attribute input + --> $DIR/rustc_confusables.rs:39:5 | LL | #[rustc_confusables(invalid_meta_item)] - | ^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[rustc_confusables("name1", "name2", ...)]` | -help: consider surrounding this with quotes +note: expected a string literal here + --> $DIR/rustc_confusables.rs:39:25 | -LL | #[rustc_confusables("invalid_meta_item")] - | + + +LL | #[rustc_confusables(invalid_meta_item)] + | ^^^^^^^^^^^^^^^^^ error: attribute should be applied to an inherent method --> $DIR/rustc_confusables.rs:45:1 diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs index d5b149b18ed6a..fd8f90143a412 100644 --- a/tests/ui/deprecation/deprecation-sanity.rs +++ b/tests/ui/deprecation/deprecation-sanity.rs @@ -4,16 +4,16 @@ mod bogus_attribute_types_1 { #[deprecated(since = "a", note = "a", reason)] //~ ERROR unknown meta item 'reason' fn f1() { } - #[deprecated(since = "a", note)] //~ ERROR expected a quoted string literal + #[deprecated(since = "a", note)] //~ ERROR malformed `deprecated` attribute input [E0539] fn f2() { } - #[deprecated(since, note = "a")] //~ ERROR expected a quoted string literal + #[deprecated(since, note = "a")] //~ ERROR malformed `deprecated` attribute input [E0539] fn f3() { } - #[deprecated(since = "a", note(b))] //~ ERROR expected a quoted string literal + #[deprecated(since = "a", note(b))] //~ ERROR malformed `deprecated` attribute input [E0539] fn f5() { } - #[deprecated(since(b), note = "a")] //~ ERROR expected a quoted string literal + #[deprecated(since(b), note = "a")] //~ ERROR malformed `deprecated` attribute input [E0539] fn f6() { } #[deprecated(note = b"test")] //~ ERROR literal in `deprecated` value must be a string diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index 53047d40cb2ff..b5c046d075bc2 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -4,29 +4,97 @@ error[E0541]: unknown meta item 'reason' LL | #[deprecated(since = "a", note = "a", reason)] | ^^^^^^ expected one of `since`, `note` -error[E0539]: expected a quoted string literal +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:7:5 + | +LL | #[deprecated(since = "a", note)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected this to be of the form `name = value` --> $DIR/deprecation-sanity.rs:7:31 | LL | #[deprecated(since = "a", note)] | ^^^^ +help: the following are possible correct uses + | +LL - #[deprecated(since = "a", note)] +LL + #[deprecated = "reason"] + | +LL - #[deprecated(since = "a", note)] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated(since = "a", note)] +LL + #[deprecated] + | -error[E0539]: expected a quoted string literal +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:10:5 + | +LL | #[deprecated(since, note = "a")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected this to be of the form `name = value` --> $DIR/deprecation-sanity.rs:10:18 | LL | #[deprecated(since, note = "a")] | ^^^^^ +help: the following are possible correct uses + | +LL - #[deprecated(since, note = "a")] +LL + #[deprecated = "reason"] + | +LL - #[deprecated(since, note = "a")] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated(since, note = "a")] +LL + #[deprecated] + | -error[E0539]: expected a quoted string literal +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:13:5 + | +LL | #[deprecated(since = "a", note(b))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected this to be of the form `name = value` --> $DIR/deprecation-sanity.rs:13:31 | LL | #[deprecated(since = "a", note(b))] | ^^^^^^^ +help: the following are possible correct uses + | +LL - #[deprecated(since = "a", note(b))] +LL + #[deprecated = "reason"] + | +LL - #[deprecated(since = "a", note(b))] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated(since = "a", note(b))] +LL + #[deprecated] + | -error[E0539]: expected a quoted string literal +error[E0539]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:16:5 + | +LL | #[deprecated(since(b), note = "a")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: expected this to be of the form `name = value` --> $DIR/deprecation-sanity.rs:16:18 | LL | #[deprecated(since(b), note = "a")] | ^^^^^^^^ +help: the following are possible correct uses + | +LL - #[deprecated(since(b), note = "a")] +LL + #[deprecated = "reason"] + | +LL - #[deprecated(since(b), note = "a")] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated(since(b), note = "a")] +LL + #[deprecated] + | error[E0565]: literal in `deprecated` value must be a string --> $DIR/deprecation-sanity.rs:19:25 diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.rs b/tests/ui/stability-attribute/stability-attribute-sanity.rs index f46e35e1a72af..c4c86e12d267e 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity.rs @@ -8,16 +8,16 @@ mod bogus_attribute_types_1 { #[stable(feature = "a", since = "4.4.4", reason)] //~ ERROR unknown meta item 'reason' [E0541] fn f1() { } - #[stable(feature = "a", since)] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature = "a", since)] //~ ERROR malformed `stable` attribute input [E0539] fn f2() { } - #[stable(feature, since = "3.3.3")] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature, since = "3.3.3")] //~ ERROR malformed `stable` attribute input [E0539] fn f3() { } - #[stable(feature = "a", since(b))] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature = "a", since(b))] //~ ERROR malformed `stable` attribute input [E0539] fn f5() { } - #[stable(feature(b), since = "3.3.3")] //~ ERROR expected a quoted string literal [E0539] + #[stable(feature(b), since = "3.3.3")] //~ ERROR malformed `stable` attribute input [E0539] fn f6() { } } diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr index 2e2b5b509c896..7545e756c27d2 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -4,25 +4,49 @@ error[E0541]: unknown meta item 'reason' LL | #[stable(feature = "a", since = "4.4.4", reason)] | ^^^^^^ expected one of `feature`, `since` -error[E0539]: expected a quoted string literal +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:11:5 + | +LL | #[stable(feature = "a", since)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` + | +note: expected this to be of the form `name = value` --> $DIR/stability-attribute-sanity.rs:11:29 | LL | #[stable(feature = "a", since)] | ^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:14:5 + | +LL | #[stable(feature, since = "3.3.3")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` + | +note: expected this to be of the form `name = value` --> $DIR/stability-attribute-sanity.rs:14:14 | LL | #[stable(feature, since = "3.3.3")] | ^^^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:17:5 + | +LL | #[stable(feature = "a", since(b))] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` + | +note: expected this to be of the form `name = value` --> $DIR/stability-attribute-sanity.rs:17:29 | LL | #[stable(feature = "a", since(b))] | ^^^^^^^^ -error[E0539]: expected a quoted string literal +error[E0539]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity.rs:20:5 + | +LL | #[stable(feature(b), since = "3.3.3")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` + | +note: expected this to be of the form `name = value` --> $DIR/stability-attribute-sanity.rs:20:14 | LL | #[stable(feature(b), since = "3.3.3")] From e903b1055632c79d170c9e9e55026d2c1a4fd1a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 5 Mar 2025 16:04:19 +0100 Subject: [PATCH 25/26] change errors to be more consistent across parsed attributes --- .../src/attributes/deprecation.rs | 7 +--- .../src/attributes/stability.rs | 30 ++++++++------- .../src/attributes/transparency.rs | 2 +- compiler/rustc_attr_parsing/src/context.rs | 17 ++++++++- .../src/session_diagnostics.rs | 25 ++++++------- tests/ui/deprecation/deprecation-sanity.rs | 2 +- .../ui/deprecation/deprecation-sanity.stderr | 37 ++++++++++++++----- tests/ui/error-codes/E0534.stderr | 2 +- tests/ui/force-inlining/invalid.stderr | 6 +-- tests/ui/invalid/invalid-inline.stderr | 4 +- tests/ui/issues/issue-43988.stderr | 4 +- tests/ui/span/E0535.stderr | 2 +- .../stability-attribute-sanity-2.rs | 2 +- .../stability-attribute-sanity-2.stderr | 10 ++++- .../stability-attribute-sanity.stderr | 8 ++-- 15 files changed, 96 insertions(+), 62 deletions(-) diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index 9d3fe764f239d..de30d115ef451 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -20,10 +20,7 @@ fn get( item: &Option, ) -> Option { if item.is_some() { - cx.emit_err(session_diagnostics::MultipleItem { - span: param_span, - item: ident.to_string(), - }); + cx.duplicate_key(ident.span, ident.name); return None; } if let Some(v) = arg.name_value() { @@ -40,7 +37,7 @@ fn get( None } } else { - cx.expected_name_value(param_span); + cx.expected_name_value(param_span, Some(ident.name)); None } } diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 4f7b286123c95..3a6f339d7678d 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -6,7 +6,7 @@ use rustc_attr_data_structures::{ }; use rustc_errors::ErrorGuaranteed; use rustc_feature::{template, AttributeTemplate}; -use rustc_span::{Span, Symbol, kw, sym}; +use rustc_span::{sym, Ident, Span, Symbol}; use super::util::parse_version; use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; @@ -65,7 +65,10 @@ impl AttributeParser for StabilityParser { this.allowed_through_unstable_modules = Some(match args.name_value().and_then(|i| i.value_as_str()) { Some(msg) => msg, - None => kw::Empty, + None => { + cx.expected_name_value(cx.attr_span, None); + return; + }, }); }), ]; @@ -205,12 +208,10 @@ fn insert_value_into_option_or_error( cx: &AcceptContext<'_, '_, S>, param: &MetaItemParser<'_>, item: &mut Option, + name: Ident, ) -> Option<()> { if item.is_some() { - cx.emit_err(session_diagnostics::MultipleItem { - span: param.span(), - item: param.path_without_args().to_string(), - }); + cx.duplicate_key(name.span, name.name); None } else if let Some(v) = param.args().name_value() && let Some(s) = v.value_as_str() @@ -218,7 +219,7 @@ fn insert_value_into_option_or_error( *item = Some(s); Some(()) } else { - cx.expected_name_value(param.span()); + cx.expected_name_value(param.span(), Some(name.name)); None } } @@ -244,9 +245,10 @@ pub(crate) fn parse_stability( return None; }; - match param.word_or_empty_without_args().name { - sym::feature => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, - sym::since => insert_value_into_option_or_error(cx, ¶m, &mut since)?, + let name = param.word_or_empty_without_args(); + match name.name { + sym::feature => insert_value_into_option_or_error(cx, ¶m, &mut feature, name)?, + sym::since => insert_value_into_option_or_error(cx, ¶m, &mut since, name)?, _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param_span, @@ -314,10 +316,10 @@ pub(crate) fn parse_unstability( let (word, args) = param.word_or_empty(); match word.name { - sym::feature => insert_value_into_option_or_error(cx, ¶m, &mut feature)?, - sym::reason => insert_value_into_option_or_error(cx, ¶m, &mut reason)?, + sym::feature => insert_value_into_option_or_error(cx, ¶m, &mut feature, word)?, + sym::reason => insert_value_into_option_or_error(cx, ¶m, &mut reason, word)?, sym::issue => { - insert_value_into_option_or_error(cx, ¶m, &mut issue)?; + insert_value_into_option_or_error(cx, ¶m, &mut issue, word)?; // These unwraps are safe because `insert_value_into_option_or_error` ensures the meta item // is a name/value pair string literal. @@ -346,7 +348,7 @@ pub(crate) fn parse_unstability( } is_soft = true; } - sym::implied_by => insert_value_into_option_or_error(cx, ¶m, &mut implied_by)?, + sym::implied_by => insert_value_into_option_or_error(cx, ¶m, &mut implied_by, word)?, _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param.span(), diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 5752625d51ede..066b5816a1818 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -22,7 +22,7 @@ impl SingleAttributeParser for TransparencyParser { fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { let Some(nv) = args.name_value() else { - cx.expected_name_value(cx.attr_span); + cx.expected_name_value(cx.attr_span, None); return None; }; match nv.value_as_str() { diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 04652f86d20b0..5dbfff89a913e 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -271,13 +271,26 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } - pub(crate) fn expected_name_value(&self, span: Span) -> ErrorGuaranteed { + /// emit an error that a `name = value` pair was expected at this span. The symbol can be given for + /// a nicer error message talking about the specific name that was found lacking a value. + pub(crate) fn expected_name_value(&self, span: Span, name: Option) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, attr_span: self.attr_span, template: self.template.clone(), attribute: self.attr_path.clone(), - reason: AttributeParseErrorReason::ExpectedNameValue, + reason: AttributeParseErrorReason::ExpectedNameValue(name), + }) + } + + /// emit an error that a `name = value` pair was found where that name was already seen. + pub(crate) fn duplicate_key(&self, span: Span, key: Symbol) -> ErrorGuaranteed { + self.emit_err(AttributeParseError { + span, + attr_span: self.attr_span, + template: self.template.clone(), + attribute: self.attr_path.clone(), + reason: AttributeParseErrorReason::DuplicateKey(key), }) } diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 129a4c8da70b9..6627881114526 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -34,15 +34,6 @@ pub(crate) struct InvalidPredicate { pub predicate: String, } -#[derive(Diagnostic)] -#[diag(attr_parsing_multiple_item, code = E0538)] -pub(crate) struct MultipleItem { - #[primary_span] - pub span: Span, - - pub item: String, -} - /// Error code: E0541 pub(crate) struct UnknownMetaItem<'a> { pub span: Span, @@ -483,7 +474,8 @@ pub(crate) enum AttributeParseErrorReason { ExpectedStringLiteral, ExpectedSingleArgument, ExpectedList, - ExpectedNameValue, + ExpectedNameValue(Option), + DuplicateKey(Symbol), ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool, @@ -519,8 +511,15 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { AttributeParseErrorReason::ExpectedList => { diag.span_note(self.span, "expected this to be a list"); }, - AttributeParseErrorReason::ExpectedNameValue => { - diag.span_note(self.span, "expected this to be of the form `name = value`"); + AttributeParseErrorReason::DuplicateKey(key) => { + diag.span_note(self.span, format!("found `{key}` used as a key more than once")); + diag.code(E0538); + }, + AttributeParseErrorReason::ExpectedNameValue(None) => { + diag.span_note(self.span, format!("expected this to be of the form `{name} = \"...\"`")); + }, + AttributeParseErrorReason::ExpectedNameValue(Some(name)) => { + diag.span_note(self.span, format!("expected this to be of the form `{name} = \"...\"`")); }, AttributeParseErrorReason::ExpectedSpecificArgument{possibilities, strings} => { let quote = if strings { @@ -553,7 +552,7 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { diag.span_suggestions(self.attr_span, if suggestions.len() == 1 { "must be of the form" } else { - "the following are possible correct uses" + "try changing it to one of the following valid forms of the attribute" }, suggestions, Applicability::HasPlaceholders); diag diff --git a/tests/ui/deprecation/deprecation-sanity.rs b/tests/ui/deprecation/deprecation-sanity.rs index fd8f90143a412..e40b017378a6c 100644 --- a/tests/ui/deprecation/deprecation-sanity.rs +++ b/tests/ui/deprecation/deprecation-sanity.rs @@ -27,7 +27,7 @@ mod bogus_attribute_types_1 { #[deprecated(since = "a", note = "b")] //~ ERROR multiple `deprecated` attributes fn multiple1() { } -#[deprecated(since = "a", since = "b", note = "c")] //~ ERROR multiple 'since' items +#[deprecated(since = "a", since = "b", note = "c")] //~ ERROR malformed `deprecated` attribute input [E0538] fn f1() { } struct X; diff --git a/tests/ui/deprecation/deprecation-sanity.stderr b/tests/ui/deprecation/deprecation-sanity.stderr index b5c046d075bc2..8854ebb70d200 100644 --- a/tests/ui/deprecation/deprecation-sanity.stderr +++ b/tests/ui/deprecation/deprecation-sanity.stderr @@ -10,12 +10,12 @@ error[E0539]: malformed `deprecated` attribute input LL | #[deprecated(since = "a", note)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: expected this to be of the form `name = value` +note: expected this to be of the form `note = "..."` --> $DIR/deprecation-sanity.rs:7:31 | LL | #[deprecated(since = "a", note)] | ^^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[deprecated(since = "a", note)] LL + #[deprecated = "reason"] @@ -33,12 +33,12 @@ error[E0539]: malformed `deprecated` attribute input LL | #[deprecated(since, note = "a")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: expected this to be of the form `name = value` +note: expected this to be of the form `since = "..."` --> $DIR/deprecation-sanity.rs:10:18 | LL | #[deprecated(since, note = "a")] | ^^^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[deprecated(since, note = "a")] LL + #[deprecated = "reason"] @@ -56,12 +56,12 @@ error[E0539]: malformed `deprecated` attribute input LL | #[deprecated(since = "a", note(b))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: expected this to be of the form `name = value` +note: expected this to be of the form `note = "..."` --> $DIR/deprecation-sanity.rs:13:31 | LL | #[deprecated(since = "a", note(b))] | ^^^^^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[deprecated(since = "a", note(b))] LL + #[deprecated = "reason"] @@ -79,12 +79,12 @@ error[E0539]: malformed `deprecated` attribute input LL | #[deprecated(since(b), note = "a")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: expected this to be of the form `name = value` +note: expected this to be of the form `since = "..."` --> $DIR/deprecation-sanity.rs:16:18 | LL | #[deprecated(since(b), note = "a")] | ^^^^^^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[deprecated(since(b), note = "a")] LL + #[deprecated = "reason"] @@ -122,11 +122,28 @@ note: attribute also specified here LL | #[deprecated(since = "a", note = "b")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0538]: multiple 'since' items +error[E0538]: malformed `deprecated` attribute input + --> $DIR/deprecation-sanity.rs:30:1 + | +LL | #[deprecated(since = "a", since = "b", note = "c")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: found `since` used as a key more than once --> $DIR/deprecation-sanity.rs:30:27 | LL | #[deprecated(since = "a", since = "b", note = "c")] - | ^^^^^^^^^^^ + | ^^^^^ +help: try changing it to one of the following valid forms of the attribute + | +LL - #[deprecated(since = "a", since = "b", note = "c")] +LL + #[deprecated = "reason"] + | +LL - #[deprecated(since = "a", since = "b", note = "c")] +LL + #[deprecated(/*opt*/ since = "version", /*opt*/ note = "reason")] + | +LL - #[deprecated(since = "a", since = "b", note = "c")] +LL + #[deprecated] + | error: this `#[deprecated]` annotation has no effect --> $DIR/deprecation-sanity.rs:35:1 diff --git a/tests/ui/error-codes/E0534.stderr b/tests/ui/error-codes/E0534.stderr index f63d80c220cec..de97ef18b7356 100644 --- a/tests/ui/error-codes/E0534.stderr +++ b/tests/ui/error-codes/E0534.stderr @@ -9,7 +9,7 @@ note: expected a single argument here | LL | #[inline()] | ^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[inline(always|never)] | ++++++++++++ diff --git a/tests/ui/force-inlining/invalid.stderr b/tests/ui/force-inlining/invalid.stderr index 26259a4d61fe0..a12f633b3f26d 100644 --- a/tests/ui/force-inlining/invalid.stderr +++ b/tests/ui/force-inlining/invalid.stderr @@ -15,7 +15,7 @@ note: expected a single argument here | LL | #[rustc_force_inline(bar, baz)] | ^^^^^^^^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[rustc_force_inline(bar, baz)] LL + #[rustc_force_inline = "reason"] @@ -38,7 +38,7 @@ note: expected a string literal here | LL | #[rustc_force_inline(2)] | ^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[rustc_force_inline(2)] LL + #[rustc_force_inline = "reason"] @@ -61,7 +61,7 @@ note: expected a string literal here | LL | #[rustc_force_inline = 2] | ^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[rustc_force_inline = 2] LL + #[rustc_force_inline = "reason"] diff --git a/tests/ui/invalid/invalid-inline.stderr b/tests/ui/invalid/invalid-inline.stderr index 965da7e756705..8a230351d324f 100644 --- a/tests/ui/invalid/invalid-inline.stderr +++ b/tests/ui/invalid/invalid-inline.stderr @@ -9,7 +9,7 @@ note: expected a single argument here | LL | #[inline(please,no)] | ^^^^^^^^^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[inline(please,no)] LL + #[inline(always|never)] @@ -29,7 +29,7 @@ note: expected a single argument here | LL | #[inline()] | ^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL | #[inline(always|never)] | ++++++++++++ diff --git a/tests/ui/issues/issue-43988.stderr b/tests/ui/issues/issue-43988.stderr index 74c3e81cb1c47..8e731db6f2e39 100644 --- a/tests/ui/issues/issue-43988.stderr +++ b/tests/ui/issues/issue-43988.stderr @@ -21,7 +21,7 @@ note: valid arguments are `always` or `never` | LL | #[inline(XYZ)] | ^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[inline(XYZ)] LL + #[inline(always|never)] @@ -57,7 +57,7 @@ note: valid arguments are `always` or `never` | LL | #[inline(ABC)] | ^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[inline(ABC)] LL + #[inline(always|never)] diff --git a/tests/ui/span/E0535.stderr b/tests/ui/span/E0535.stderr index 54dcdd8957902..fb0b72c000105 100644 --- a/tests/ui/span/E0535.stderr +++ b/tests/ui/span/E0535.stderr @@ -9,7 +9,7 @@ note: valid arguments are `always` or `never` | LL | #[inline(unknown)] | ^^^^^^^ -help: the following are possible correct uses +help: try changing it to one of the following valid forms of the attribute | LL - #[inline(unknown)] LL + #[inline(always|never)] diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-2.rs b/tests/ui/stability-attribute/stability-attribute-sanity-2.rs index de3ea4eaca967..92e300d33d6ec 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-2.rs +++ b/tests/ui/stability-attribute/stability-attribute-sanity-2.rs @@ -4,7 +4,7 @@ #![stable(feature = "stable_test_feature", since = "1.0.0")] -#[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR multiple 'feature' items +#[stable(feature = "a", feature = "b", since = "1.0.0")] //~ ERROR malformed `stable` attribute input [E0538] fn f1() { } #[stable(feature = "a", sinse = "1.0.0")] //~ ERROR unknown meta item 'sinse' diff --git a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr index 8dbcc6c97efd5..412af87bad698 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity-2.stderr @@ -1,8 +1,14 @@ -error[E0538]: multiple 'feature' items +error[E0538]: malformed `stable` attribute input + --> $DIR/stability-attribute-sanity-2.rs:7:1 + | +LL | #[stable(feature = "a", feature = "b", since = "1.0.0")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` + | +note: found `feature` used as a key more than once --> $DIR/stability-attribute-sanity-2.rs:7:25 | LL | #[stable(feature = "a", feature = "b", since = "1.0.0")] - | ^^^^^^^^^^^^^ + | ^^^^^^^ error[E0541]: unknown meta item 'sinse' --> $DIR/stability-attribute-sanity-2.rs:10:25 diff --git a/tests/ui/stability-attribute/stability-attribute-sanity.stderr b/tests/ui/stability-attribute/stability-attribute-sanity.stderr index 7545e756c27d2..86284b0c1b816 100644 --- a/tests/ui/stability-attribute/stability-attribute-sanity.stderr +++ b/tests/ui/stability-attribute/stability-attribute-sanity.stderr @@ -10,7 +10,7 @@ error[E0539]: malformed `stable` attribute input LL | #[stable(feature = "a", since)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` | -note: expected this to be of the form `name = value` +note: expected this to be of the form `since = "..."` --> $DIR/stability-attribute-sanity.rs:11:29 | LL | #[stable(feature = "a", since)] @@ -22,7 +22,7 @@ error[E0539]: malformed `stable` attribute input LL | #[stable(feature, since = "3.3.3")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` | -note: expected this to be of the form `name = value` +note: expected this to be of the form `feature = "..."` --> $DIR/stability-attribute-sanity.rs:14:14 | LL | #[stable(feature, since = "3.3.3")] @@ -34,7 +34,7 @@ error[E0539]: malformed `stable` attribute input LL | #[stable(feature = "a", since(b))] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` | -note: expected this to be of the form `name = value` +note: expected this to be of the form `since = "..."` --> $DIR/stability-attribute-sanity.rs:17:29 | LL | #[stable(feature = "a", since(b))] @@ -46,7 +46,7 @@ error[E0539]: malformed `stable` attribute input LL | #[stable(feature(b), since = "3.3.3")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[stable(feature = "name", since = "version")]` | -note: expected this to be of the form `name = value` +note: expected this to be of the form `feature = "..."` --> $DIR/stability-attribute-sanity.rs:20:14 | LL | #[stable(feature(b), since = "3.3.3")] From 49b8b6c47716e052aea3c66f546dbc3f960f8a79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Wed, 5 Mar 2025 17:45:57 +0100 Subject: [PATCH 26/26] tidy --- compiler/rustc_ast_lowering/src/expr.rs | 15 ++-- compiler/rustc_ast_lowering/src/item.rs | 2 +- compiler/rustc_ast_lowering/src/lib.rs | 2 +- compiler/rustc_attr_parsing/messages.ftl | 26 +++--- .../src/attributes/allow_unstable.rs | 2 +- .../src/attributes/confusables.rs | 42 +++++----- .../src/attributes/deprecation.rs | 2 +- .../src/attributes/inline.rs | 14 ++-- .../rustc_attr_parsing/src/attributes/mod.rs | 19 +++-- .../rustc_attr_parsing/src/attributes/repr.rs | 2 +- .../src/attributes/stability.rs | 83 +++++++++++-------- .../src/attributes/transparency.rs | 10 ++- compiler/rustc_attr_parsing/src/context.rs | 55 ++++++------ .../src/session_diagnostics.rs | 75 +++++++++-------- .../rustc_codegen_ssa/src/codegen_attrs.rs | 5 +- compiler/rustc_errors/src/lib.rs | 7 +- compiler/rustc_parse/src/validate_attr.rs | 7 +- compiler/rustc_passes/src/check_attr.rs | 25 +++--- 18 files changed, 216 insertions(+), 177 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 727cda61b56b0..6f1ce238924b5 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -74,15 +74,12 @@ impl<'hir> LoweringContext<'_, 'hir> { // Merge attributes into the inner expression. if !e.attrs.is_empty() { let old_attrs = self.attrs.get(&ex.hir_id.local_id).copied().unwrap_or(&[]); - let new_attrs = self.lower_attrs_vec(&e.attrs, e.span, ex.hir_id) - .into_iter() - .chain(old_attrs.iter().cloned()); - self.attrs.insert( - ex.hir_id.local_id, - &*self.arena.alloc_from_iter( - new_attrs, - ), - ); + let new_attrs = self + .lower_attrs_vec(&e.attrs, e.span, ex.hir_id) + .into_iter() + .chain(old_attrs.iter().cloned()); + self.attrs + .insert(ex.hir_id.local_id, &*self.arena.alloc_from_iter(new_attrs)); } return ex; } diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 6b129bb030ffa..a4fc4b3e3a121 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -58,7 +58,7 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> { &mut self, owner: NodeId, f: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::OwnerNode<'hir>, - ) { + ) { let mut lctx = LoweringContext::new(self.tcx, self.resolver); lctx.with_hir_id_owner(owner, |lctx| f(lctx)); diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 8b3619acc128f..6c490dd3c1cce 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -52,7 +52,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::tagged_ptr::TaggedRef; use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; +use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId}; use rustc_hir::{ self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, ParamName, TraitCandidate, }; diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 064bd5b347a32..70de83f2f7443 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -23,8 +23,10 @@ attr_parsing_expects_feature_list = attr_parsing_expects_features = `{$name}` expects feature names -attr_parsing_incorrect_meta_item = expected a quoted string literal -attr_parsing_incorrect_meta_item_suggestion = consider surrounding this with quotes +attr_parsing_ill_formed_attribute_input = {$num_suggestions -> + [1] attribute must be of the form {$suggestions} + *[other] valid forms for the attribute are {$suggestions} + } attr_parsing_incorrect_repr_format_align_one_arg = incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses @@ -81,9 +83,6 @@ attr_parsing_missing_note = attr_parsing_missing_since = missing 'since' -attr_parsing_multiple_item = - multiple '{$item}' items - attr_parsing_multiple_stability_levels = multiple stability levels @@ -131,6 +130,12 @@ attr_parsing_unsupported_literal_generic = attr_parsing_unsupported_literal_suggestion = consider removing the prefix +attr_parsing_unused_duplicate = + unused attribute + .suggestion = remove this attribute + .note = attribute also specified here + .warn = {-passes_previously_accepted} + attr_parsing_unused_multiple = multiple `{$name}` attributes .suggestion = remove this attribute @@ -138,14 +143,3 @@ attr_parsing_unused_multiple = -attr_parsing_perviously_accepted = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - -attr_parsing_unused_duplicate = - unused attribute - .suggestion = remove this attribute - .note = attribute also specified here - .warn = {-passes_previously_accepted} - -attr_parsing_ill_formed_attribute_input = {$num_suggestions -> - [1] attribute must be of the form {$suggestions} - *[other] valid forms for the attribute are {$suggestions} - } diff --git a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs index 1bc2f9411b430..f151bc34b6fac 100644 --- a/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs +++ b/compiler/rustc_attr_parsing/src/attributes/allow_unstable.rs @@ -1,7 +1,7 @@ use std::iter; use rustc_attr_data_structures::AttributeKind; -use rustc_feature::{template, AttributeTemplate}; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; diff --git a/compiler/rustc_attr_parsing/src/attributes/confusables.rs b/compiler/rustc_attr_parsing/src/attributes/confusables.rs index 03bb3cfe802e0..f4505cbc0e1b7 100644 --- a/compiler/rustc_attr_parsing/src/attributes/confusables.rs +++ b/compiler/rustc_attr_parsing/src/attributes/confusables.rs @@ -14,29 +14,33 @@ pub(crate) struct ConfusablesParser { } impl AttributeParser for ConfusablesParser { - const ATTRIBUTES: AcceptMapping = &[(&[sym::rustc_confusables], template!(List: r#""name1", "name2", ..."#), |this, cx, args| { - let Some(list) = args.list() else { - cx.expected_list(cx.attr_span); - return; - }; - - if list.is_empty() { - cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span }); - } + const ATTRIBUTES: AcceptMapping = &[( + &[sym::rustc_confusables], + template!(List: r#""name1", "name2", ..."#), + |this, cx, args| { + let Some(list) = args.list() else { + cx.expected_list(cx.attr_span); + return; + }; - for param in list.mixed() { - let span = param.span(); + if list.is_empty() { + cx.emit_err(session_diagnostics::EmptyConfusables { span: cx.attr_span }); + } - let Some(lit) = param.lit() else { - cx.expected_string_literal(span); - continue; - }; + for param in list.mixed() { + let span = param.span(); - this.confusables.push(lit.symbol); - } + let Some(lit) = param.lit() else { + cx.expected_string_literal(span); + continue; + }; + + this.confusables.push(lit.symbol); + } - this.first_span.get_or_insert(cx.attr_span); - })]; + this.first_span.get_or_insert(cx.attr_span); + }, + )]; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.confusables.is_empty() { diff --git a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs index de30d115ef451..04dac13834886 100644 --- a/compiler/rustc_attr_parsing/src/attributes/deprecation.rs +++ b/compiler/rustc_attr_parsing/src/attributes/deprecation.rs @@ -1,5 +1,5 @@ use rustc_attr_data_structures::{AttributeKind, DeprecatedSince, Deprecation}; -use rustc_feature::{template, AttributeTemplate}; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::symbol::Ident; use rustc_span::{Span, Symbol, sym}; diff --git a/compiler/rustc_attr_parsing/src/attributes/inline.rs b/compiler/rustc_attr_parsing/src/attributes/inline.rs index 3b95c6670ad76..f968e9345f115 100644 --- a/compiler/rustc_attr_parsing/src/attributes/inline.rs +++ b/compiler/rustc_attr_parsing/src/attributes/inline.rs @@ -4,7 +4,7 @@ use rustc_attr_data_structures::{AttributeKind, InlineAttr}; use rustc_errors::DiagArgValue; -use rustc_feature::{template, AttributeTemplate}; +use rustc_feature::{AttributeTemplate, template}; use rustc_session::lint::builtin::ILL_FORMED_ATTRIBUTE_INPUT; use rustc_span::sym; @@ -45,16 +45,17 @@ impl SingleAttributeParser for InlineParser { } } ArgParser::NameValue(_) => { - let suggestions = >::TEMPLATE.suggestions(false, "inline"); + let suggestions = + >::TEMPLATE.suggestions(false, "inline"); cx.emit_lint( ILL_FORMED_ATTRIBUTE_INPUT, cx.attr_span, - IllFormedAttributeInput { + IllFormedAttributeInput { num_suggestions: suggestions.len(), suggestions: DiagArgValue::StrListSepByAnd( suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(), ), - } + }, ); return None; } @@ -96,6 +97,9 @@ impl SingleAttributeParser for RustcForceInlineParser { } }; - Some(AttributeKind::Inline(InlineAttr::Force { attr_span: cx.attr_span, reason }, cx.attr_span)) + Some(AttributeKind::Inline( + InlineAttr::Force { attr_span: cx.attr_span, reason }, + cx.attr_span, + )) } } diff --git a/compiler/rustc_attr_parsing/src/attributes/mod.rs b/compiler/rustc_attr_parsing/src/attributes/mod.rs index 43d135f1981b1..728077766a99a 100644 --- a/compiler/rustc_attr_parsing/src/attributes/mod.rs +++ b/compiler/rustc_attr_parsing/src/attributes/mod.rs @@ -37,7 +37,8 @@ pub(crate) mod transparency; pub(crate) mod util; type AcceptFn = for<'sess> fn(&mut T, &mut AcceptContext<'_, 'sess, S>, &ArgParser<'_>); -type AcceptMapping = &'static [(&'static [rustc_span::Symbol], AttributeTemplate, AcceptFn)]; +type AcceptMapping = + &'static [(&'static [rustc_span::Symbol], AttributeTemplate, AcceptFn)]; /// An [`AttributeParser`] is a type which searches for syntactic attributes. /// @@ -100,8 +101,10 @@ impl, S: Stage> Default for Single { } impl, S: Stage> AttributeParser for Single { - const ATTRIBUTES: AcceptMapping = - &[(T::PATH, >::TEMPLATE, |group: &mut Single, cx, args| { + const ATTRIBUTES: AcceptMapping = &[( + T::PATH, + >::TEMPLATE, + |group: &mut Single, cx, args| { if let Some(pa) = T::convert(cx, args) { match T::ATTRIBUTE_ORDER { // keep the first and report immediately. ignore this attribute @@ -122,7 +125,8 @@ impl, S: Stage> AttributeParser for Single group.1 = Some((pa, cx.attr_span)); } - })]; + }, + )]; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { Some(self.1?.0) @@ -234,8 +238,11 @@ impl, S: Stage> Default for Combine { } impl, S: Stage> AttributeParser for Combine { - const ATTRIBUTES: AcceptMapping = - &[(T::PATH, >::TEMPLATE, |group: &mut Combine, cx, args| group.1.extend(T::extend(cx, args)))]; + const ATTRIBUTES: AcceptMapping = &[( + T::PATH, + >::TEMPLATE, + |group: &mut Combine, cx, args| group.1.extend(T::extend(cx, args)), + )]; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { if self.1.is_empty() { None } else { Some(T::CONVERT(self.1)) } diff --git a/compiler/rustc_attr_parsing/src/attributes/repr.rs b/compiler/rustc_attr_parsing/src/attributes/repr.rs index 65aa907503aa3..71b6b82b76947 100644 --- a/compiler/rustc_attr_parsing/src/attributes/repr.rs +++ b/compiler/rustc_attr_parsing/src/attributes/repr.rs @@ -1,7 +1,7 @@ use rustc_abi::Align; use rustc_ast::{IntTy, LitIntType, LitKind, UintTy}; use rustc_attr_data_structures::{AttributeKind, IntType, ReprAttr}; -use rustc_feature::{template, AttributeTemplate}; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::{Span, Symbol, sym}; use super::{CombineAttributeParser, ConvertFn}; diff --git a/compiler/rustc_attr_parsing/src/attributes/stability.rs b/compiler/rustc_attr_parsing/src/attributes/stability.rs index 3a6f339d7678d..4927817f99465 100644 --- a/compiler/rustc_attr_parsing/src/attributes/stability.rs +++ b/compiler/rustc_attr_parsing/src/attributes/stability.rs @@ -5,8 +5,8 @@ use rustc_attr_data_structures::{ StableSince, UnstableReason, VERSION_PLACEHOLDER, }; use rustc_errors::ErrorGuaranteed; -use rustc_feature::{template, AttributeTemplate}; -use rustc_span::{sym, Ident, Span, Symbol}; +use rustc_feature::{AttributeTemplate, template}; +use rustc_span::{Ident, Span, Symbol, sym}; use super::util::parse_version; use super::{AcceptMapping, AttributeOrder, AttributeParser, OnDuplicate, SingleAttributeParser}; @@ -44,33 +44,45 @@ impl StabilityParser { impl AttributeParser for StabilityParser { const ATTRIBUTES: AcceptMapping = &[ - (&[sym::stable], template!(List: r#"feature = "name", since = "version""#), |this, cx, args| { - reject_outside_std!(cx); - if !this.check_duplicate(cx) - && let Some((feature, level)) = parse_stability(cx, args) - { - this.stability = Some((Stability { level, feature }, cx.attr_span)); - } - }), - (&[sym::unstable], template!(List: r#"feature = "name", reason = "...", issue = "N""#), |this, cx, args| { - reject_outside_std!(cx); - if !this.check_duplicate(cx) - && let Some((feature, level)) = parse_unstability(cx, args) - { - this.stability = Some((Stability { level, feature }, cx.attr_span)); - } - }), - (&[sym::rustc_allowed_through_unstable_modules], template!(NameValueStr: "deprecation message"), |this, cx, args| { - reject_outside_std!(cx); - this.allowed_through_unstable_modules = - Some(match args.name_value().and_then(|i| i.value_as_str()) { - Some(msg) => msg, - None => { - cx.expected_name_value(cx.attr_span, None); - return; - }, - }); - }), + ( + &[sym::stable], + template!(List: r#"feature = "name", since = "version""#), + |this, cx, args| { + reject_outside_std!(cx); + if !this.check_duplicate(cx) + && let Some((feature, level)) = parse_stability(cx, args) + { + this.stability = Some((Stability { level, feature }, cx.attr_span)); + } + }, + ), + ( + &[sym::unstable], + template!(List: r#"feature = "name", reason = "...", issue = "N""#), + |this, cx, args| { + reject_outside_std!(cx); + if !this.check_duplicate(cx) + && let Some((feature, level)) = parse_unstability(cx, args) + { + this.stability = Some((Stability { level, feature }, cx.attr_span)); + } + }, + ), + ( + &[sym::rustc_allowed_through_unstable_modules], + template!(NameValueStr: "deprecation message"), + |this, cx, args| { + reject_outside_std!(cx); + this.allowed_through_unstable_modules = + Some(match args.name_value().and_then(|i| i.value_as_str()) { + Some(msg) => msg, + None => { + cx.expected_name_value(cx.attr_span, None); + return; + } + }); + }, + ), ]; fn finalize(mut self, cx: &FinalizeContext<'_, '_, S>) -> Option { @@ -104,8 +116,10 @@ pub(crate) struct BodyStabilityParser { } impl AttributeParser for BodyStabilityParser { - const ATTRIBUTES: AcceptMapping = - &[(&[sym::rustc_default_body_unstable], template!(List: r#"feature = "name", reason = "...", issue = "N""#), |this, cx, args| { + const ATTRIBUTES: AcceptMapping = &[( + &[sym::rustc_default_body_unstable], + template!(List: r#"feature = "name", reason = "...", issue = "N""#), + |this, cx, args| { reject_outside_std!(cx); if this.stability.is_some() { cx.dcx() @@ -113,7 +127,8 @@ impl AttributeParser for BodyStabilityParser { } else if let Some((feature, level)) = parse_unstability(cx, args) { this.stability = Some((DefaultBodyStability { level, feature }, cx.attr_span)); } - })]; + }, + )]; fn finalize(self, _cx: &FinalizeContext<'_, '_, S>) -> Option { let (stability, span) = self.stability?; @@ -348,7 +363,9 @@ pub(crate) fn parse_unstability( } is_soft = true; } - sym::implied_by => insert_value_into_option_or_error(cx, ¶m, &mut implied_by, word)?, + sym::implied_by => { + insert_value_into_option_or_error(cx, ¶m, &mut implied_by, word)? + } _ => { cx.emit_err(session_diagnostics::UnknownMetaItem { span: param.span(), diff --git a/compiler/rustc_attr_parsing/src/attributes/transparency.rs b/compiler/rustc_attr_parsing/src/attributes/transparency.rs index 066b5816a1818..3f86606187970 100644 --- a/compiler/rustc_attr_parsing/src/attributes/transparency.rs +++ b/compiler/rustc_attr_parsing/src/attributes/transparency.rs @@ -1,5 +1,5 @@ use rustc_attr_data_structures::AttributeKind; -use rustc_feature::{template, AttributeTemplate}; +use rustc_feature::{AttributeTemplate, template}; use rustc_span::hygiene::Transparency; use rustc_span::sym; @@ -18,7 +18,8 @@ impl SingleAttributeParser for TransparencyParser { const ON_DUPLICATE: OnDuplicate = OnDuplicate::Custom(|cx, used, unused| { cx.dcx().span_err(vec![used, unused], "multiple macro transparency attributes"); }); - const TEMPLATE: AttributeTemplate = template!(NameValueStr: "transparent|semitransparent|opaque"); + const TEMPLATE: AttributeTemplate = + template!(NameValueStr: "transparent|semitransparent|opaque"); fn convert(cx: &AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option { let Some(nv) = args.name_value() else { @@ -30,7 +31,10 @@ impl SingleAttributeParser for TransparencyParser { Some(sym::semitransparent) => Some(Transparency::SemiTransparent), Some(sym::opaque) => Some(Transparency::Opaque), Some(_) => { - cx.expected_specific_argument_strings(nv.value_span, vec!["transparent", "semitransparent", "opaque"]); + cx.expected_specific_argument_strings( + nv.value_span, + vec!["transparent", "semitransparent", "opaque"], + ); None } None => None, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index 5dbfff89a913e..61f8e81995450 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -198,9 +198,7 @@ impl Stage for Late { span: Span, diag: impl DynSend + for<'x> LintDiagnostic<'x, ()> + 'static, ) { - dcx.delay_lint_during_ast_lowering((lint, id, span, Box::new(|x| { - diag.decorate_lint(x) - }))); + dcx.delay_lint_during_ast_lowering((lint, id, span, Box::new(|x| diag.decorate_lint(x)))); } } @@ -223,7 +221,7 @@ pub(crate) struct AcceptContext<'f, 'sess, S: Stage> { pub(crate) template: &'f AttributeTemplate, /// The name of the attribute we're currently accepting. - pub(crate) attr_path: AttrPath + pub(crate) attr_path: AttrPath, } impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { @@ -235,7 +233,7 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { /// must be delayed until after HIR is built. This method will take care of the details of /// that. pub(crate) fn emit_lint( - & self, + &self, lint: &'static Lint, span: Span, diag: impl DynSend + for<'x> LintDiagnostic<'x, ()> + 'static, @@ -243,12 +241,13 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { S::emit_lint(self.dcx(), lint, self.target_id, span, diag) } - pub(crate) fn unknown_key(&self, span: Span, found: String, options: &'static [&'static str]) -> ErrorGuaranteed { - self.emit_err(UnknownMetaItem { - span, - item: found, - expected: options, - }) + pub(crate) fn unknown_key( + &self, + span: Span, + found: String, + options: &'static [&'static str], + ) -> ErrorGuaranteed { + self.emit_err(UnknownMetaItem { span, item: found, expected: options }) } pub(crate) fn expected_string_literal(&self, span: Span) -> ErrorGuaranteed { @@ -304,29 +303,37 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> { }) } - pub(crate) fn expected_specific_argument(&self, span: Span, possibilities: Vec<&'static str>) -> ErrorGuaranteed { + pub(crate) fn expected_specific_argument( + &self, + span: Span, + possibilities: Vec<&'static str>, + ) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, attr_span: self.attr_span, template: self.template.clone(), attribute: self.attr_path.clone(), - reason: AttributeParseErrorReason::ExpectedSpecificArgument{ + reason: AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, - strings: false - } + strings: false, + }, }) } - pub(crate) fn expected_specific_argument_strings(&self, span: Span, possibilities: Vec<&'static str>) -> ErrorGuaranteed { + pub(crate) fn expected_specific_argument_strings( + &self, + span: Span, + possibilities: Vec<&'static str>, + ) -> ErrorGuaranteed { self.emit_err(AttributeParseError { span, attr_span: self.attr_span, template: self.template.clone(), attribute: self.attr_path.clone(), - reason: AttributeParseErrorReason::ExpectedSpecificArgument{ + reason: AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings: true, - } + }, }) } } @@ -417,12 +424,12 @@ impl<'sess> AttributeParser<'sess, Early> { ) -> Option { let mut p = Self { features: None, tools: Vec::new(), parse_only: Some(sym), sess }; let mut parsed = p.parse_attribute_list( - attrs, - target_span, - target_node_id, - OmitDoc::Skip, - std::convert::identity, - ); + attrs, + target_span, + target_node_id, + OmitDoc::Skip, + std::convert::identity, + ); assert!(parsed.len() <= 1); parsed.pop() diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 6627881114526..93e82659d7da5 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -1,8 +1,10 @@ use std::num::IntErrorKind; use rustc_ast as ast; -use rustc_errors::{codes::*, DiagArgValue}; -use rustc_errors::{Applicability, Diag, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level}; +use rustc_errors::codes::*; +use rustc_errors::{ + Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, EmissionGuarantee, Level, +}; use rustc_feature::AttributeTemplate; use rustc_hir::AttrPath; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -476,10 +478,7 @@ pub(crate) enum AttributeParseErrorReason { ExpectedList, ExpectedNameValue(Option), DuplicateKey(Symbol), - ExpectedSpecificArgument { - possibilities: Vec<&'static str>, - strings: bool, - } + ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool }, } pub(crate) struct AttributeParseError { @@ -494,66 +493,74 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError { fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, G> { let name = self.attribute.to_string(); - let mut diag = Diag::new( - dcx, - level, - format!("malformed `{name}` attribute input") - ); + let mut diag = Diag::new(dcx, level, format!("malformed `{name}` attribute input")); diag.span(self.attr_span); diag.code(E0539); match self.reason { AttributeParseErrorReason::ExpectedStringLiteral => { diag.span_note(self.span, "expected a string literal here"); - }, + } AttributeParseErrorReason::ExpectedSingleArgument => { diag.span_note(self.span, "expected a single argument here"); - }, + } AttributeParseErrorReason::ExpectedList => { diag.span_note(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.code(E0538); - }, + } AttributeParseErrorReason::ExpectedNameValue(None) => { - diag.span_note(self.span, format!("expected this to be of the form `{name} = \"...\"`")); - }, + diag.span_note( + self.span, + format!("expected this to be of the form `{name} = \"...\"`"), + ); + } AttributeParseErrorReason::ExpectedNameValue(Some(name)) => { - diag.span_note(self.span, format!("expected this to be of the form `{name} = \"...\"`")); - }, - AttributeParseErrorReason::ExpectedSpecificArgument{possibilities, strings} => { - let quote = if strings { - '"' - } else { - '`' - }; + diag.span_note( + self.span, + format!("expected this to be of the form `{name} = \"...\"`"), + ); + } + AttributeParseErrorReason::ExpectedSpecificArgument { possibilities, strings } => { + let quote = if strings { '"' } else { '`' }; match possibilities.as_slice() { &[] => {} &[x] => { - diag.span_note(self.span, format!("the only valid argument here is {quote}{x}{quote}")); + diag.span_note( + 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}")); } - [first@.., second_to_last, last] => { + [first @ .., second_to_last, last] => { let mut res = String::new(); for i in first { res.push_str(&format!("{quote}{i}{quote}, ")); } - res.push_str(&format!("{quote}{second_to_last}{quote} or {quote}{last}{quote}")); + res.push_str(&format!( + "{quote}{second_to_last}{quote} or {quote}{last}{quote}" + )); diag.span_note(self.span, format!("valid arguments are {res}")); } } - }, + } } let suggestions = self.template.suggestions(false, &name); - diag.span_suggestions(self.attr_span, if suggestions.len() == 1 { - "must be of the form" - } else { - "try changing it to one of the following valid forms of the attribute" - }, suggestions, Applicability::HasPlaceholders); + diag.span_suggestions( + self.attr_span, + if suggestions.len() == 1 { + "must be of the form" + } else { + "try changing it to one of the following valid forms of the attribute" + }, + suggestions, + Applicability::HasPlaceholders, + ); diag } diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 976e097f3b543..22eddcb879d88 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -517,9 +517,10 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { mixed_export_name_no_mangle_lint_state.lint_if_mixed(tcx); - let inline_span; - (codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) = find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span)) { + (codegen_fn_attrs.inline, inline_span) = if let Some((inline_attr, span)) = + find_attr!(attrs, AttributeKind::Inline(i, span) => (*i, *span)) + { (inline_attr, Some(span)) } else { (InlineAttr::None, None) diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 67a29edd6609e..9b1e80b24ac3f 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -53,8 +53,6 @@ pub use diagnostic_impls::{ DiagArgFromDisplay, DiagSymbolList, ElidedLifetimeInPathSubdiag, ExpectedLifetimeParameter, IndicateAnonymousLifetime, SingleLabelManySpans, }; -use rustc_lint_defs::Lint; -use rustc_hir::HirId; pub use emitter::ColorConfig; use emitter::{DynEmitter, Emitter, is_case_difference, is_different}; use rustc_data_structures::AtomicRef; @@ -66,8 +64,9 @@ pub use rustc_error_messages::{ SubdiagMessage, fallback_fluent_bundle, fluent_bundle, }; use rustc_hashes::Hash128; -use rustc_lint_defs::LintExpectationId; +use rustc_hir::HirId; pub use rustc_lint_defs::{Applicability, listify, pluralize}; +use rustc_lint_defs::{Lint, LintExpectationId}; use rustc_macros::{Decodable, Encodable}; pub use rustc_span::ErrorGuaranteed; pub use rustc_span::fatal_error::{FatalError, FatalErrorMarker}; @@ -542,7 +541,7 @@ pub type HirDelayedLint = ( &'static Lint, HirId, Span, - Box FnOnce(&'b mut Diag<'a, ()>) + 'static> + Box FnOnce(&'b mut Diag<'a, ()>) + 'static>, ); /// This inner struct exists to keep it all behind a single lock; diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 49d4f6130748d..e3d25839e4dba 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -237,14 +237,13 @@ fn emit_malformed_attribute( ) { // attrs with new parsers are locally validated so excluded here if matches!(name, sym::inline | sym::rustc_force_inline | sym::rustc_confusables) { - return + return; } // Some of previously accepted forms were used in practice, // report them as warnings for now. - let should_warn = |name| { - matches!(name, sym::doc | sym::ignore | sym::link | sym::test | sym::bench) - }; + let should_warn = + |name| matches!(name, sym::doc | sym::ignore | sym::link | sym::test | sym::bench); let error_msg = format!("malformed `{name}` attribute input"); let mut suggestions = vec![]; diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 35e12434b9ce3..6e8ae19865637 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -10,7 +10,7 @@ use std::collections::hash_map::Entry; use rustc_abi::{Align, ExternAbi, Size}; use rustc_ast::{AttrStyle, LitKind, MetaItemInner, MetaItemKind, MetaItemLit, ast}; -use rustc_attr_parsing::{find_attr, AttributeKind, InlineAttr, ReprAttr}; +use rustc_attr_parsing::{AttributeKind, InlineAttr, ReprAttr, find_attr}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, DiagCtxtHandle, IntoDiagArg, MultiSpan, StashKey}; use rustc_feature::{AttributeDuplicates, AttributeType, BUILTIN_ATTRIBUTE_MAP, BuiltinAttribute}; @@ -123,7 +123,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { AttributeKind::Stability { span, .. } | AttributeKind::ConstStability { span, .. }, ) => self.check_stability_promotable(*span, target), - Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force {..}, ..)) => {} // handled separately below + Attribute::Parsed(AttributeKind::Inline(InlineAttr::Force { .. }, ..)) => {} // handled separately below Attribute::Parsed(AttributeKind::Inline(_, attr_span)) => { self.check_inline(hir_id, *attr_span, span, target) } @@ -617,9 +617,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> { ) => { continue; } - Attribute::Parsed( - AttributeKind::Inline(.., span), - ) => { + Attribute::Parsed(AttributeKind::Inline(.., span)) => { self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute { span: *span, naked_span: attr.span(), @@ -2561,7 +2559,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { span: Span, target: Target, ) { - match (target, find_attr!(attrs, AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span)) { + match ( + target, + find_attr!(attrs, AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span), + ) { (Target::Closure, None) => { let is_coro = matches!( self.tcx.hir().expect_expr(hir_id).kind, @@ -2577,13 +2578,10 @@ impl<'tcx> CheckAttrVisitor<'tcx> { if let Some(attr_span) = find_attr!( self.tcx.get_all_attrs(parent_did), AttributeKind::Inline(InlineAttr::Force { attr_span, .. }, _) => *attr_span - ) - && is_coro + ) && is_coro { - self.dcx().emit_err(errors::RustcForceInlineCoro { - attr_span, - span: parent_span, - }); + self.dcx() + .emit_err(errors::RustcForceInlineCoro { attr_span, span: parent_span }); } } (Target::Fn, _) => (), @@ -2784,7 +2782,8 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { fn check_non_exported_macro_for_invalid_attrs(tcx: TyCtxt<'_>, item: &Item<'_>) { let attrs = tcx.hir().attrs(item.hir_id()); - if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(i, span) if !matches!(i, InlineAttr::Force{..}) => *span) { + if let Some(attr_span) = find_attr!(attrs, AttributeKind::Inline(i, span) if !matches!(i, InlineAttr::Force{..}) => *span) + { tcx.dcx().emit_err(errors::NonExportedMacroInvalidAttrs { attr_span }); } }