Skip to content

Commit 6bd3273

Browse files
authored
Rollup merge of #143607 - JonathanBrouwer:proc_macro_attrs, r=jdonszelmann,traviscross
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 f8e355c + 97b6521 commit 6bd3273

File tree

26 files changed

+520
-393
lines changed

26 files changed

+520
-393
lines changed

compiler/rustc_attr_data_structures/src/attributes.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,12 +416,24 @@ pub enum AttributeKind {
416416
/// Represents `#[pointee]`
417417
Pointee(Span),
418418

419+
/// Represents `#[proc_macro]`
420+
ProcMacro(Span),
421+
422+
/// Represents `#[proc_macro_attribute]`
423+
ProcMacroAttribute(Span),
424+
425+
/// Represents `#[proc_macro_derive]`
426+
ProcMacroDerive { trait_name: Symbol, helper_attrs: ThinVec<Symbol>, span: Span },
427+
419428
/// Represents `#[rustc_pub_transparent]` (used by the `repr_transparent_external_private_fields` lint).
420429
PubTransparent(Span),
421430

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

434+
/// Represents `#[rustc_builtin_macro]`.
435+
RustcBuiltinMacro { builtin_name: Option<Symbol>, helper_attrs: ThinVec<Symbol>, span: Span },
436+
425437
/// Represents `#[rustc_layout_scalar_valid_range_end]`.
426438
RustcLayoutScalarValidRangeEnd(Box<u128>, Span),
427439

compiler/rustc_attr_data_structures/src/encode_cross_crate.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,12 @@ impl AttributeKind {
6161
PassByValue(..) => Yes,
6262
Path(..) => No,
6363
Pointee(..) => No,
64+
ProcMacro(..) => No,
65+
ProcMacroAttribute(..) => No,
66+
ProcMacroDerive { .. } => No,
6467
PubTransparent(..) => Yes,
6568
Repr { .. } => No,
69+
RustcBuiltinMacro { .. } => Yes,
6670
RustcLayoutScalarValidRangeEnd(..) => Yes,
6771
RustcLayoutScalarValidRangeStart(..) => Yes,
6872
RustcObjectLifetimeDefault => No,

compiler/rustc_attr_parsing/src/attributes/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ pub(crate) mod must_use;
4141
pub(crate) mod no_implicit_prelude;
4242
pub(crate) mod non_exhaustive;
4343
pub(crate) mod path;
44+
pub(crate) mod proc_macro_attrs;
4445
pub(crate) mod repr;
4546
pub(crate) mod rustc_internal;
4647
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: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@ use crate::attributes::must_use::MustUseParser;
3838
use crate::attributes::no_implicit_prelude::NoImplicitPreludeParser;
3939
use crate::attributes::non_exhaustive::NonExhaustiveParser;
4040
use crate::attributes::path::PathParser as PathAttributeParser;
41+
use crate::attributes::proc_macro_attrs::{
42+
ProcMacroAttributeParser, ProcMacroDeriveParser, ProcMacroParser, RustcBuiltinMacroParser,
43+
};
4144
use crate::attributes::repr::{AlignParser, ReprParser};
4245
use crate::attributes::rustc_internal::{
4346
RustcLayoutScalarValidRangeEnd, RustcLayoutScalarValidRangeStart,
@@ -154,6 +157,8 @@ attribute_parsers!(
154157
Single<MustUseParser>,
155158
Single<OptimizeParser>,
156159
Single<PathAttributeParser>,
160+
Single<ProcMacroDeriveParser>,
161+
Single<RustcBuiltinMacroParser>,
157162
Single<RustcForceInlineParser>,
158163
Single<RustcLayoutScalarValidRangeEnd>,
159164
Single<RustcLayoutScalarValidRangeStart>,
@@ -186,6 +191,8 @@ attribute_parsers!(
186191
Single<WithoutArgs<ParenSugarParser>>,
187192
Single<WithoutArgs<PassByValueParser>>,
188193
Single<WithoutArgs<PointeeParser>>,
194+
Single<WithoutArgs<ProcMacroAttributeParser>>,
195+
Single<WithoutArgs<ProcMacroParser>>,
189196
Single<WithoutArgs<PubTransparentParser>>,
190197
Single<WithoutArgs<SpecializationTraitParser>>,
191198
Single<WithoutArgs<StdInternalSymbolParser>>,

compiler/rustc_builtin_macros/src/proc_macro_harness.rs

Lines changed: 21 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,18 @@ 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+
None,
116+
)
103117
else {
104118
return;
105119
};
@@ -110,7 +124,7 @@ impl<'a> CollectProcMacros<'a> {
110124
span: item.span,
111125
trait_name,
112126
function_ident,
113-
attrs: proc_attrs,
127+
attrs: helper_attrs,
114128
}));
115129
} else {
116130
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)