Skip to content

Commit 360f8e6

Browse files
committed
Auto merge of #143607 - JonathanBrouwer:proc_macro_attrs, r=<try>
Port the proc macro attributes to the new attribute parsing infrastructure Ports `#[proc_macro]`, `#[proc_macro_attribute]`, `#[proc_macro_derive]` and `#[rustc_builtin_macro]` to the new attribute parsing infrastructure for #131229 (comment) I've split this PR into commits for reviewability, and left some comments to clarify things I did 4 related attributes in one PR because they share a lot of their code and logic, and doing them separately is kind of annoying as I need to leave both the old and new parsing in place then. r? `@oli-obk` cc `@jdonszelmann`
2 parents 855e0fe + f8c757f commit 360f8e6

File tree

28 files changed

+538
-395
lines changed

28 files changed

+538
-395
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

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

316+
/// Represents `#[proc_macro]`
317+
ProcMacro(Span),
318+
319+
/// Represents `#[proc_macro_attribute]`
320+
ProcMacroAttribute(Span),
321+
322+
/// Represents `#[proc_macro_derive]`
323+
ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span },
324+
316325
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
317326
PubTransparent(Span),
318327

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

331+
/// Represents `#[rustc_builtin_macro]`.
332+
RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
333+
322334
/// Represents `#[rustc_layout_scalar_valid_range_end]`.
323335
RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
324336

compiler/rustc_attr_data_structures/src/encode_cross_crate.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,12 @@ impl AttributeKind {
4545
Optimize(..) => No,
4646
PassByValue(..) => Yes,
4747
Path(..) => No,
48+
ProcMacro(..) => No,
49+
ProcMacroAttribute(..) => No,
50+
ProcMacroDerive { .. } => No,
4851
PubTransparent(..) => Yes,
4952
Repr { .. } => No,
53+
RustcBuiltinMacro { .. } => Yes,
5054
RustcLayoutScalarValidRangeEnd(..) => Yes,
5155
RustcLayoutScalarValidRangeStart(..) => Yes,
5256
RustcObjectLifetimeDefault => No,

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub(crate) mod must_use;
3939
pub(crate) mod no_implicit_prelude;
4040
pub(crate) mod non_exhaustive;
4141
pub(crate) mod path;
42+
pub(crate) mod proc_macro_attrs;
4243
pub(crate) mod repr;
4344
pub(crate) mod rustc_internal;
4445
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::KeepOutermost;
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::KeepOutermost;
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+
// For #[rustc_builtin_macro], it is permitted to leave out the trait name
65+
if args.no_args().is_ok() && !trait_name_mandatory {
66+
return Some((None, ThinVec::new()));
67+
}
68+
cx.expected_list(cx.attr_span);
69+
return None;
70+
};
71+
let mut items = list.mixed();
72+
73+
// Parse the name of the trait that is derived.
74+
let Some(trait_attr) = items.next() else {
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
@@ -33,6 +33,9 @@ use crate::attributes::must_use::MustUseParser;
3333
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
3434
use crate::attributes::non_exhaustive::NonExhaustiveParser;
3535
use crate::attributes::path::PathParser as PathAttributeParser;
36+
use crate::attributes::proc_macro_attrs::{
37+
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
38+
};
3639
use crate::attributes::repr::{AlignParser, ReprParser};
3740
use crate::attributes::rustc_internal::{
3841
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
@@ -140,6 +143,8 @@ attribute_parsers!(
140143
Single<MustUseParser>,
141144
Single<OptimizeParser>,
142145
Single<PathAttributeParser>,
146+
Single<ProcMacroDeriveParser>,
147+
Single<RustcBuiltinMacroParser>,
143148
Single<RustcForceInlineParser>,
144149
Single<RustcLayoutScalarValidRangeEnd>,
145150
Single<RustcLayoutScalarValidRangeStart>,
@@ -159,6 +164,8 @@ attribute_parsers!(
159164
Single<WithoutArgs<NoMangleParser>>,
160165
Single<WithoutArgs<NonExhaustiveParser>>,
161166
Single<WithoutArgs<PassByValueParser>>,
167+
Single<WithoutArgs<ProcMacroAttributeParser>>,
168+
Single<WithoutArgs<ProcMacroParser>>,
162169
Single<WithoutArgs<PubTransparentParser>>,
163170
Single<WithoutArgs<StdInternalSymbolParser>>,
164171
Single<WithoutArgs<TrackCallerParser>>,
@@ -427,6 +434,16 @@ impl<'f, 'sess: 'f, S: Stage> AcceptContext<'f, 'sess, S> {
427434
})
428435
}
429436

437+
pub(crate) fn expected_identifier(&self, span: Span) -> ErrorGuaranteed {
438+
self.emit_err(AttributeParseError {
439+
span,
440+
attr_span: self.attr_span,
441+
template: self.template.clone(),
442+
attribute: self.attr_path.clone(),
443+
reason: AttributeParseErrorReason::ExpectedIdentifier,
444+
})
445+
}
446+
430447
pub(crate) fn warn_empty_attribute(&mut self, span: Span) {
431448
self.emit_lint(AttributeLintKind::EmptyAttribute { first_span: span }, span);
432449
}

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_builtin_macros/src/proc_macro_harness.rs

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use std::mem;
1+
use std::{mem, slice};
22

33
use rustc_ast::ptr::P;
44
use rustc_ast::visit::{self, Visitor};
5-
use rustc_ast::{self as ast, NodeId, attr};
5+
use rustc_ast::{self as ast, HasNodeId, NodeId, attr};
66
use rustc_ast_pretty::pprust;
7+
use rustc_attr_data_structures::AttributeKind;
8+
use rustc_attr_parsing::AttributeParser;
79
use rustc_errors::DiagCtxtHandle;
8-
use rustc_expand::base::{ExtCtxt, ResolverExpand, parse_macro_name_and_helper_attrs};
10+
use rustc_expand::base::{ExtCtxt, ResolverExpand};
911
use rustc_expand::expand::{AstFragment, ExpansionConfig};
1012
use rustc_feature::Features;
1113
use rustc_session::Session;
@@ -22,7 +24,7 @@ struct ProcMacroDerive {
2224
trait_name: Symbol,
2325
function_ident: Ident,
2426
span: Span,
25-
attrs: Vec<Symbol>,
27+
attrs: ThinVec<Symbol>,
2628
}
2729

2830
struct ProcMacroDef {
@@ -41,6 +43,7 @@ struct CollectProcMacros<'a> {
4143
macros: Vec<ProcMacro>,
4244
in_root: bool,
4345
dcx: DiagCtxtHandle<'a>,
46+
session: &'a Session,
4447
source_map: &'a SourceMap,
4548
is_proc_macro_crate: bool,
4649
is_test_crate: bool,
@@ -63,6 +66,7 @@ pub fn inject(
6366
macros: Vec::new(),
6467
in_root: true,
6568
dcx,
69+
session: sess,
6670
source_map: sess.source_map(),
6771
is_proc_macro_crate,
6872
is_test_crate,
@@ -98,8 +102,17 @@ impl<'a> CollectProcMacros<'a> {
98102
function_ident: Ident,
99103
attr: &'a ast::Attribute,
100104
) {
101-
let Some((trait_name, proc_attrs)) =
102-
parse_macro_name_and_helper_attrs(self.dcx, attr, "derive")
105+
let Some(rustc_hir::Attribute::Parsed(AttributeKind::ProcMacroDerive {
106+
trait_name,
107+
helper_attrs,
108+
..
109+
})) = AttributeParser::parse_limited(
110+
self.session,
111+
slice::from_ref(attr),
112+
sym::proc_macro_derive,
113+
item.span,
114+
item.node_id(),
115+
)
103116
else {
104117
return;
105118
};
@@ -110,7 +123,7 @@ impl<'a> CollectProcMacros<'a> {
110123
span: item.span,
111124
trait_name,
112125
function_ident,
113-
attrs: proc_attrs,
126+
attrs: helper_attrs,
114127
}));
115128
} else {
116129
let msg = if !self.in_root {

compiler/rustc_expand/messages.ftl

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,8 @@
1-
expand_arg_not_attributes =
2-
second argument must be `attributes`
3-
4-
expand_attr_no_arguments =
5-
attribute must have either one or two arguments
6-
7-
expand_attribute_meta_item =
8-
attribute must be a meta item, not a literal
9-
10-
expand_attribute_single_word =
11-
attribute must only be a single word
12-
131
expand_attributes_on_expressions_experimental =
142
attributes on expressions are experimental
153
.help_outer_doc = `///` is used for outer documentation comments; for a plain comment, use `//`
164
.help_inner_doc = `//!` is used for inner documentation comments; for a plain comment, use `//` by removing the `!` or inserting a space in between them: `// !`
175
18-
expand_attributes_wrong_form =
19-
attribute must be of form: `attributes(foo, bar)`
20-
21-
expand_cannot_be_name_of_macro =
22-
`{$trait_ident}` cannot be a name of {$macro_type} macro
23-
246
expand_collapse_debuginfo_illegal =
257
illegal value for attribute #[collapse_debuginfo(no|external|yes)]
268
@@ -71,9 +53,6 @@ expand_glob_delegation_outside_impls =
7153
expand_glob_delegation_traitless_qpath =
7254
qualified path without a trait in glob delegation
7355
74-
expand_helper_attribute_name_invalid =
75-
`{$name}` cannot be a name of derive helper attribute
76-
7756
expand_incomplete_parse =
7857
macro expansion ignores {$descr} and any tokens following
7958
.label = caused by the macro expansion here
@@ -165,12 +144,6 @@ expand_mve_unrecognized_var =
165144
expand_non_inline_modules_in_proc_macro_input_are_unstable =
166145
non-inline modules in proc macro input are unstable
167146
168-
expand_not_a_meta_item =
169-
not a meta item
170-
171-
expand_only_one_word =
172-
must only be one word
173-
174147
expand_proc_macro_back_compat = using an old version of `{$crate_name}`
175148
.note = older versions of the `{$crate_name}` crate no longer compile; please update to `{$crate_name}` v{$fixed_version}, or switch to one of the `{$crate_name}` alternatives
176149

0 commit comments

Comments
 (0)