Skip to content

Commit d8632ad

Browse files
Parsers for the attributes
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
1 parent 0cbc3f2 commit d8632ad

File tree

4 files changed

+161
-0
lines changed

4 files changed

+161
-0
lines changed

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+
return None;
116+
};
117+
if let Err(e) = attr.args().no_args() {
118+
cx.expected_no_args(e);
119+
return None;
120+
};
121+
let Some(ident) = attr.path().word() else {
122+
cx.expected_identifier(attr.path().span());
123+
return None;
124+
};
125+
if !ident.name.can_be_raw() {
126+
cx.expected_identifier(ident.span);
127+
return None;
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);

0 commit comments

Comments
 (0)