Skip to content

Commit ac77cb0

Browse files
Implement the proc macro attributes to the new attribute parsing infrastructure
1 parent 8df4a58 commit ac77cb0

File tree

7 files changed

+195
-11
lines changed

7 files changed

+195
-11
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -301,12 +301,24 @@ pub enum AttributeKind {
301301
/// Represents `#[path]`
302302
Path(Symbol, Span),
303303

304+
/// Represents `#[proc_macro]`
305+
ProcMacro(Span),
306+
307+
/// Represents `#[proc_macro_attribute]`
308+
ProcMacroAttribute(Span),
309+
310+
/// Represents `#[proc_macro_derive]`
311+
ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span },
312+
304313
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
305314
PubTransparent(Span),
306315

307316
/// Represents [`#[repr]`](https://doc.rust-lang.org/stable/reference/type-layout.html#representations).
308317
Repr { reprs: ThinVec<(ReprAttr, Span)>, first_span: Span },
309318

319+
/// Represents `#[rustc_builtin_macro]`.
320+
RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
321+
310322
/// Represents `#[rustc_layout_scalar_valid_range_end]`.
311323
RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
312324

compiler/rustc_attr_data_structures/src/encode_cross_crate.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,12 @@ impl AttributeKind {
4141
Optimize(..) => No,
4242
PassByValue(..) => Yes,
4343
Path(..) => No,
44+
ProcMacro(..) => No,
45+
ProcMacroAttribute(..) => No,
46+
ProcMacroDerive { .. } => No,
4447
PubTransparent(..) => Yes,
4548
Repr { .. } => No,
49+
RustcBuiltinMacro { .. } => Yes,
4650
RustcLayoutScalarValidRangeEnd(..) => Yes,
4751
RustcLayoutScalarValidRangeStart(..) => Yes,
4852
RustcObjectLifetimeDefault => No,

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ pub(crate) mod must_use;
3838
pub(crate) mod no_implicit_prelude;
3939
pub(crate) mod non_exhaustive;
4040
pub(crate) mod path;
41+
pub(crate) mod proc_macro_attrs;
4142
pub(crate) mod repr;
4243
pub(crate) mod rustc_internal;
4344
pub(crate) mod semantics;
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
use rustc_attr_data_structures::AttributeKind;
2+
use rustc_feature::{AttributeTemplate, template};
3+
use rustc_span::{Span, Symbol, sym};
4+
use thin_vec::ThinVec;
5+
6+
use crate::attributes::{
7+
AttributeOrder, NoArgsAttributeParser, OnDuplicate, SingleAttributeParser,
8+
};
9+
use crate::context::{AcceptContext, Stage};
10+
use crate::parser::ArgParser;
11+
12+
pub(crate) struct ProcMacroParser;
13+
impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroParser {
14+
const PATH: &[Symbol] = &[sym::proc_macro];
15+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
16+
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacro;
17+
}
18+
19+
pub(crate) struct ProcMacroAttributeParser;
20+
impl<S: Stage> NoArgsAttributeParser<S> for ProcMacroAttributeParser {
21+
const PATH: &[Symbol] = &[sym::proc_macro_attribute];
22+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
23+
const CREATE: fn(Span) -> AttributeKind = AttributeKind::ProcMacroAttribute;
24+
}
25+
26+
pub(crate) struct ProcMacroDeriveParser;
27+
impl<S: Stage> SingleAttributeParser<S> for ProcMacroDeriveParser {
28+
const PATH: &[Symbol] = &[sym::proc_macro_derive];
29+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
30+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
31+
const TEMPLATE: AttributeTemplate =
32+
template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
33+
34+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
35+
let (trait_name, helper_attrs) = parse_derive_like(cx, args, true)?;
36+
Some(AttributeKind::ProcMacroDerive {
37+
trait_name: trait_name.expect("Trait name is mandatory, so it is present"),
38+
helper_attrs,
39+
span: cx.attr_span,
40+
})
41+
}
42+
}
43+
44+
pub(crate) struct RustcBuiltinMacroParser;
45+
impl<S: Stage> SingleAttributeParser<S> for RustcBuiltinMacroParser {
46+
const PATH: &[Symbol] = &[sym::rustc_builtin_macro];
47+
const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepLast;
48+
const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error;
49+
const TEMPLATE: AttributeTemplate =
50+
template!(List: "TraitName, /*opt*/ attributes(name1, name2, ...)");
51+
52+
fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> {
53+
let (builtin_name, helper_attrs) = parse_derive_like(cx, args, false)?;
54+
Some(AttributeKind::RustcBuiltinMacro { builtin_name, helper_attrs, span: cx.attr_span })
55+
}
56+
}
57+
58+
fn parse_derive_like<S: Stage>(
59+
cx: &mut AcceptContext<'_, '_, S>,
60+
args: &ArgParser<'_>,
61+
trait_name_mandatory: bool,
62+
) -> Option<(Option<Symbol>, ThinVec<Symbol>)> {
63+
let Some(list) = args.list() else {
64+
cx.expected_list(cx.attr_span);
65+
return None;
66+
};
67+
let mut items = list.mixed();
68+
69+
// Parse the name of the trait that is derived.
70+
let Some(trait_attr) = items.next() else {
71+
// For #[rustc_builtin_macro], it is permitted to leave out the trait name
72+
if !trait_name_mandatory {
73+
return None;
74+
}
75+
cx.expected_at_least_one_argument(list.span);
76+
return None;
77+
};
78+
let Some(trait_attr) = trait_attr.meta_item() else {
79+
cx.unexpected_literal(trait_attr.span());
80+
return None;
81+
};
82+
let Some(trait_ident) = trait_attr.path().word() else {
83+
cx.expected_identifier(trait_attr.path().span());
84+
return None;
85+
};
86+
if !trait_ident.name.can_be_raw() {
87+
cx.expected_identifier(trait_ident.span);
88+
return None;
89+
}
90+
if let Err(e) = trait_attr.args().no_args() {
91+
cx.expected_no_args(e);
92+
return None;
93+
};
94+
95+
// Parse optional attributes
96+
let mut attributes = ThinVec::new();
97+
if let Some(attrs) = items.next() {
98+
let Some(attr_list) = attrs.meta_item() else {
99+
cx.expected_list(attrs.span());
100+
return None;
101+
};
102+
if !attr_list.path().word_is(sym::attributes) {
103+
cx.expected_specific_argument(attrs.span(), vec!["attributes"]);
104+
return None;
105+
}
106+
let Some(attr_list) = attr_list.args().list() else {
107+
cx.expected_list(attrs.span());
108+
return None;
109+
};
110+
111+
// Parse item in `attributes(...)` argument
112+
for attr in attr_list.mixed() {
113+
let Some(attr) = attr.meta_item() else {
114+
cx.expected_identifier(attr.span());
115+
continue;
116+
};
117+
if let Err(e) = attr.args().no_args() {
118+
cx.expected_no_args(e);
119+
continue;
120+
};
121+
let Some(ident) = attr.path().word() else {
122+
cx.expected_identifier(attr.path().span());
123+
continue;
124+
};
125+
if !ident.name.can_be_raw() {
126+
cx.expected_identifier(ident.span);
127+
continue;
128+
}
129+
attributes.push(ident.name);
130+
}
131+
}
132+
133+
// If anything else is specified, we should reject it
134+
if let Some(next) = items.next() {
135+
cx.expected_no_args(next.span());
136+
}
137+
138+
Some((Some(trait_ident.name), attributes))
139+
}

compiler/rustc_attr_parsing/src/context.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ use crate::attributes::must_use::MustUseParser;
2929
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
3030
use crate::attributes::non_exhaustive::NonExhaustiveParser;
3131
use crate::attributes::path::PathParser as PathAttributeParser;
32+
use crate::attributes::proc_macro_attrs::{
33+
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
34+
};
3235
use crate::attributes::repr::{AlignParser, ReprParser};
3336
use crate::attributes::rustc_internal::{
3437
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
@@ -135,6 +138,8 @@ attribute_parsers!(
135138
Single<MustUseParser>,
136139
Single<OptimizeParser>,
137140
Single<PathAttributeParser>,
141+
Single<ProcMacroDeriveParser>,
142+
Single<RustcBuiltinMacroParser>,
138143
Single<RustcForceInlineParser>,
139144
Single<RustcLayoutScalarValidRangeEnd>,
140145
Single<RustcLayoutScalarValidRangeStart>,
@@ -151,6 +156,8 @@ attribute_parsers!(
151156
Single<WithoutArgs<NoMangleParser>>,
152157
Single<WithoutArgs<NonExhaustiveParser>>,
153158
Single<WithoutArgs<PassByValueParser>>,
159+
Single<WithoutArgs<ProcMacroAttributeParser>>,
160+
Single<WithoutArgs<ProcMacroParser>>,
154161
Single<WithoutArgs<PubTransparentParser>>,
155162
Single<WithoutArgs<TrackCallerParser>>,
156163
// tidy-alphabetical-end
@@ -418,6 +425,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
418425
})
419426
}
420427

428+
pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed {
429+
self.emit_err(AttributeParseError {
430+
span,
431+
attr_span: self.attr_span,
432+
template: self.template.clone(),
433+
attribute: self.attr_path.clone(),
434+
reason: AttributeParseErrorReason::ExpectedIdentifier,
435+
})
436+
}
437+
421438
pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
422439
self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span);
423440
}

compiler/rustc_attr_parsing/src/session_diagnostics.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -525,6 +525,7 @@ pub(crate) enum AttributeParseErrorReason {
525525
ExpectedNameValue(Option<Symbol>),
526526
DuplicateKey(Symbol),
527527
ExpectedSpecificArgument { possibilities: Vec<&'static str>, strings: bool },
528+
ExpectedIdentifier,
528529
}
529530

530531
pub(crate) struct AttributeParseError {
@@ -618,6 +619,9 @@ impl<'a, G: EmissionGuarantee> Diagnostic<'a, G> for AttributeParseError {
618619
}
619620
}
620621
}
622+
AttributeParseErrorReason::ExpectedIdentifier => {
623+
diag.span_label(self.span, format!("expected a valid identifier here"));
624+
}
621625
}
622626

623627
let suggestions = self.template.suggestions(false, &name);

compiler/rustc_passes/src/check_attr.rs

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,22 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
120120
for attr in attrs {
121121
let mut style = None;
122122
match attr {
123+
Attribute::Parsed(AttributeKind::ProcMacro(_)) => {
124+
self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
125+
}
126+
Attribute::Parsed(AttributeKind::ProcMacroAttribute(_)) => {
127+
self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
128+
}
129+
Attribute::Parsed(AttributeKind::ProcMacroDerive { span: attr_span, .. }) => {
130+
self.check_generic_attr(
131+
hir_id,
132+
sym::proc_macro_derive,
133+
*attr_span,
134+
target,
135+
Target::Fn,
136+
);
137+
self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
138+
}
123139
Attribute::Parsed(AttributeKind::SkipDuringMethodDispatch {
124140
span: attr_span,
125141
..
@@ -207,7 +223,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
207223
Attribute::Parsed(
208224
AttributeKind::BodyStability { .. }
209225
| AttributeKind::ConstStabilityIndirect
210-
| AttributeKind::MacroTransparency(_),
226+
| AttributeKind::MacroTransparency(_)
227+
| AttributeKind::RustcBuiltinMacro { .. },
211228
) => { /* do nothing */ }
212229
Attribute::Parsed(AttributeKind::AsPtr(attr_span)) => {
213230
self.check_applied_to_fn_or_method(hir_id, *attr_span, span, target)
@@ -315,16 +332,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
315332
[sym::automatically_derived, ..] => {
316333
self.check_generic_attr_unparsed(hir_id, attr, target, Target::Impl)
317334
}
318-
[sym::proc_macro, ..] => {
319-
self.check_proc_macro(hir_id, target, ProcMacroKind::FunctionLike)
320-
}
321-
[sym::proc_macro_attribute, ..] => {
322-
self.check_proc_macro(hir_id, target, ProcMacroKind::Attribute);
323-
}
324-
[sym::proc_macro_derive, ..] => {
325-
self.check_generic_attr_unparsed(hir_id, attr, target, Target::Fn);
326-
self.check_proc_macro(hir_id, target, ProcMacroKind::Derive)
327-
}
328335
[sym::autodiff_forward, ..] | [sym::autodiff_reverse, ..] => {
329336
self.check_autodiff(hir_id, attr, span, target)
330337
}

0 commit comments

Comments
 (0)