Skip to content

Commit 7f83c78

Browse files
Allow passing expr metavariable as a cfg predicate
1 parent 9e973d8 commit 7f83c78

15 files changed

Lines changed: 227 additions & 92 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/cfg.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,7 @@ fn parse_cfg_attr_internal<'a>(
363363
let meta = MetaItemOrLitParser::parse_single(
364364
parser,
365365
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
366+
true,
366367
)?;
367368
let pred_span = pred_start.with_hi(parser.token.span.hi());
368369

compiler/rustc_attr_parsing/src/attributes/cfg_select.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub fn parse_cfg_select(
9494
let meta = MetaItemOrLitParser::parse_single(
9595
p,
9696
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
97+
true,
9798
)
9899
.map_err(|diag| diag.emit())?;
99100
let cfg_span = meta.span();

compiler/rustc_attr_parsing/src/interface.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ impl<'sess> AttributeParser<'sess, Early> {
139139
emit_errors: ShouldEmit,
140140
parse_fn: fn(cx: &mut AcceptContext<'_, '_, Early>, item: &ArgParser) -> Option<T>,
141141
template: &AttributeTemplate,
142+
allow_expr_metavar: bool,
142143
) -> Option<T> {
143144
let ast::AttrKind::Normal(normal_attr) = &attr.kind else {
144145
panic!("parse_single called on a doc attr")
@@ -152,6 +153,7 @@ impl<'sess> AttributeParser<'sess, Early> {
152153
&parts,
153154
&sess.psess,
154155
emit_errors,
156+
allow_expr_metavar,
155157
)?;
156158
Self::parse_single_args(
157159
sess,
@@ -333,6 +335,7 @@ impl<'sess, S: Stage> AttributeParser<'sess, S> {
333335
&parts,
334336
&self.sess.psess,
335337
self.stage.should_emit(),
338+
false,
336339
) else {
337340
continue;
338341
};

compiler/rustc_attr_parsing/src/parser.rs

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ impl ArgParser {
109109
parts: &[Symbol],
110110
psess: &'sess ParseSess,
111111
should_emit: ShouldEmit,
112+
allow_expr_metavar: bool,
112113
) -> Option<Self> {
113114
Some(match value {
114115
AttrArgs::Empty => Self::NoArgs,
@@ -122,6 +123,7 @@ impl ArgParser {
122123
args.dspan.entire(),
123124
psess,
124125
ShouldEmit::ErrorsAndLints { recovery: Recovery::Forbidden },
126+
allow_expr_metavar,
125127
) {
126128
Ok(p) => return Some(ArgParser::List(p)),
127129
Err(e) => {
@@ -147,9 +149,15 @@ impl ArgParser {
147149
}
148150

149151
Self::List(
150-
MetaItemListParser::new(&args.tokens, args.dspan.entire(), psess, should_emit)
151-
.map_err(|e| should_emit.emit_err(e))
152-
.ok()?,
152+
MetaItemListParser::new(
153+
&args.tokens,
154+
args.dspan.entire(),
155+
psess,
156+
should_emit,
157+
allow_expr_metavar,
158+
)
159+
.map_err(|e| should_emit.emit_err(e))
160+
.ok()?,
153161
)
154162
}
155163
AttrArgs::Eq { eq_span, expr } => Self::NameValue(NameValueParser {
@@ -217,8 +225,9 @@ impl MetaItemOrLitParser {
217225
pub fn parse_single<'sess>(
218226
parser: &mut Parser<'sess>,
219227
should_emit: ShouldEmit,
228+
allow_expr_metavar: bool,
220229
) -> PResult<'sess, MetaItemOrLitParser> {
221-
let mut this = MetaItemListParserContext { parser, should_emit };
230+
let mut this = MetaItemListParserContext { parser, should_emit, allow_expr_metavar };
222231
this.parse_meta_item_inner()
223232
}
224233

@@ -407,6 +416,7 @@ fn expr_to_lit<'sess>(
407416
struct MetaItemListParserContext<'a, 'sess> {
408417
parser: &'a mut Parser<'sess>,
409418
should_emit: ShouldEmit,
419+
allow_expr_metavar: bool,
410420
}
411421

412422
impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
@@ -448,19 +458,43 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
448458
}
449459

450460
fn parse_attr_item(&mut self) -> PResult<'sess, MetaItemParser> {
451-
if let Some(MetaVarKind::Meta { has_meta_form }) = self.parser.token.is_metavar_seq() {
452-
return if has_meta_form {
453-
let attr_item = self
454-
.parser
455-
.eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
456-
MetaItemListParserContext { parser: this, should_emit: self.should_emit }
461+
if let Some(metavar) = self.parser.token.is_metavar_seq() {
462+
match metavar {
463+
kind @ MetaVarKind::Expr { .. } if self.allow_expr_metavar => {
464+
return self
465+
.parser
466+
.eat_metavar_seq(kind, |this| {
467+
MetaItemListParserContext {
468+
parser: this,
469+
should_emit: self.should_emit,
470+
allow_expr_metavar: true,
471+
}
457472
.parse_attr_item()
458-
})
459-
.unwrap();
460-
Ok(attr_item)
461-
} else {
462-
self.parser.unexpected_any()
463-
};
473+
})
474+
.ok_or_else(|| {
475+
self.parser.unexpected_any::<core::convert::Infallible>().unwrap_err()
476+
});
477+
}
478+
MetaVarKind::Meta { has_meta_form } => {
479+
return if has_meta_form {
480+
let attr_item = self
481+
.parser
482+
.eat_metavar_seq(MetaVarKind::Meta { has_meta_form: true }, |this| {
483+
MetaItemListParserContext {
484+
parser: this,
485+
should_emit: self.should_emit,
486+
allow_expr_metavar: self.allow_expr_metavar,
487+
}
488+
.parse_attr_item()
489+
})
490+
.unwrap();
491+
Ok(attr_item)
492+
} else {
493+
self.parser.unexpected_any()
494+
};
495+
}
496+
_ => {}
497+
}
464498
}
465499

466500
let path = self.parser.parse_path(PathStyle::Mod)?;
@@ -469,8 +503,12 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
469503
let args = if self.parser.check(exp!(OpenParen)) {
470504
let start = self.parser.token.span;
471505
let (sub_parsers, _) = self.parser.parse_paren_comma_seq(|parser| {
472-
MetaItemListParserContext { parser, should_emit: self.should_emit }
473-
.parse_meta_item_inner()
506+
MetaItemListParserContext {
507+
parser,
508+
should_emit: self.should_emit,
509+
allow_expr_metavar: self.allow_expr_metavar,
510+
}
511+
.parse_meta_item_inner()
474512
})?;
475513
let end = self.parser.prev_token.span;
476514
ArgParser::List(MetaItemListParser { sub_parsers, span: start.with_hi(end.hi()) })
@@ -580,13 +618,15 @@ impl<'a, 'sess> MetaItemListParserContext<'a, 'sess> {
580618
psess: &'sess ParseSess,
581619
span: Span,
582620
should_emit: ShouldEmit,
621+
allow_expr_metavar: bool,
583622
) -> PResult<'sess, MetaItemListParser> {
584623
let mut parser = Parser::new(psess, tokens, None);
585624
if let ShouldEmit::ErrorsAndLints { recovery } = should_emit {
586625
parser = parser.recovery(recovery);
587626
}
588627

589-
let mut this = MetaItemListParserContext { parser: &mut parser, should_emit };
628+
let mut this =
629+
MetaItemListParserContext { parser: &mut parser, should_emit, allow_expr_metavar };
590630

591631
// Presumably, the majority of the time there will only be one attr.
592632
let mut sub_parsers = ThinVec::with_capacity(1);
@@ -618,8 +658,15 @@ impl MetaItemListParser {
618658
span: Span,
619659
psess: &'sess ParseSess,
620660
should_emit: ShouldEmit,
661+
allow_expr_metavar: bool,
621662
) -> Result<Self, Diag<'sess>> {
622-
MetaItemListParserContext::parse(tokens.clone(), psess, span, should_emit)
663+
MetaItemListParserContext::parse(
664+
tokens.clone(),
665+
psess,
666+
span,
667+
should_emit,
668+
allow_expr_metavar,
669+
)
623670
}
624671

625672
/// Lets you pick and choose as what you want to parse each element in the list

compiler/rustc_builtin_macros/src/cfg.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ fn parse_cfg(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream) -> Result<CfgEntry,
4444
let meta = MetaItemOrLitParser::parse_single(
4545
&mut parser,
4646
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
47+
true,
4748
)
4849
.map_err(|diag| diag.emit())?;
4950
let cfg = AttributeParser::parse_single_args(

compiler/rustc_expand/src/config.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ impl<'a> StripUnconfigured<'a> {
402402
emit_errors,
403403
parse_cfg,
404404
&CFG_TEMPLATE,
405+
true,
405406
) else {
406407
// Cfg attribute was not parsable, give up
407408
return EvalConfigResult::True;

compiler/rustc_expand/src/expand.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2224,6 +2224,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
22242224
ShouldEmit::ErrorsAndLints { recovery: Recovery::Allowed },
22252225
parse_cfg,
22262226
&CFG_TEMPLATE,
2227+
true,
22272228
) else {
22282229
// Cfg attribute was not parsable, give up
22292230
return EvalConfigResult::True;

library/std/src/sys/thread_local/os.rs

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -62,25 +62,7 @@ pub macro thread_local_inner {
6262
// by translating it into a `cfg`ed block and recursing.
6363
// https://doc.rust-lang.org/reference/conditional-compilation.html#railroad-ConfigurationPredicate
6464

65-
(@align $final_align:ident, cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
66-
#[cfg(true)]
67-
{
68-
$crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
69-
}
70-
71-
$($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
72-
},
73-
74-
(@align $final_align:ident, cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
75-
#[cfg(false)]
76-
{
77-
$crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);
78-
}
79-
80-
$($crate::thread::local_impl::thread_local_inner!(@align $final_align, $($attr_rest)+);)?
81-
},
82-
83-
(@align $final_align:ident, cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
65+
(@align $final_align:ident, cfg_attr($cfg_pred:expr, $($cfg_rhs:tt)*) $(, $($attr_rest:tt)+)?) => {
8466
#[cfg($cfg_pred)]
8567
{
8668
$crate::thread::local_impl::thread_local_inner!(@align $final_align, $($cfg_rhs)*);

library/std/src/thread/local.rs

Lines changed: 2 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -198,41 +198,10 @@ pub macro thread_local_process_attrs {
198198
);
199199
),
200200

201-
// it's a nested `cfg_attr(true, ...)`; recurse into RHS
202-
(
203-
[$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
204-
@processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(true, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
205-
$($rest:tt)*
206-
) => (
207-
$crate::thread::local_impl::thread_local_process_attrs!(
208-
[] [];
209-
@processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] };
210-
[$($prev_align_attrs)*] [$($prev_other_attrs)*];
211-
@processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] };
212-
$($rest)*
213-
);
214-
),
215-
216-
// it's a nested `cfg_attr(false, ...)`; recurse into RHS
217-
(
218-
[$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
219-
@processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr(false, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
220-
$($rest:tt)*
221-
) => (
222-
$crate::thread::local_impl::thread_local_process_attrs!(
223-
[] [];
224-
@processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] };
225-
[$($prev_align_attrs)*] [$($prev_other_attrs)*];
226-
@processing_cfg_attr { pred: ($($predicate)*), rhs: [$($($attr_rhs)*)?] };
227-
$($rest)*
228-
);
229-
),
230-
231-
232201
// it's a nested `cfg_attr(..., ...)`; recurse into RHS
233202
(
234203
[$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*];
235-
@processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:meta, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
204+
@processing_cfg_attr { pred: ($($predicate:tt)*), rhs: [cfg_attr($cfg_lhs:expr, $($cfg_rhs:tt)*) $(, $($attr_rhs:tt)*)?] };
236205
$($rest:tt)*
237206
) => (
238207
$crate::thread::local_impl::thread_local_process_attrs!(
@@ -268,28 +237,8 @@ pub macro thread_local_process_attrs {
268237
);
269238
),
270239

271-
// `cfg_attr(true, ...)` attribute; parse it
272-
([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(true, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
273-
$crate::thread::local_impl::thread_local_process_attrs!(
274-
[] [];
275-
@processing_cfg_attr { pred: (true), rhs: [$($cfg_rhs)*] };
276-
[$($prev_align_attrs)*] [$($prev_other_attrs)*];
277-
$($rest)*
278-
);
279-
),
280-
281-
// `cfg_attr(false, ...)` attribute; parse it
282-
([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr(false, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
283-
$crate::thread::local_impl::thread_local_process_attrs!(
284-
[] [];
285-
@processing_cfg_attr { pred: (false), rhs: [$($cfg_rhs)*] };
286-
[$($prev_align_attrs)*] [$($prev_other_attrs)*];
287-
$($rest)*
288-
);
289-
),
290-
291240
// `cfg_attr(..., ...)` attribute; parse it
292-
([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:meta, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
241+
([$($prev_align_attrs:tt)*] [$($prev_other_attrs:tt)*]; #[cfg_attr($cfg_pred:expr, $($cfg_rhs:tt)*)] $($rest:tt)*) => (
293242
$crate::thread::local_impl::thread_local_process_attrs!(
294243
[] [];
295244
@processing_cfg_attr { pred: ($cfg_pred), rhs: [$($cfg_rhs)*] };

tests/ui/macros/attr-expr.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
macro_rules! foo {
2+
($e:expr) => {
3+
#[$e]
4+
//~^ ERROR expected identifier, found metavariable
5+
fn foo() {}
6+
}
7+
}
8+
foo!(inline);
9+
fn main() {}

0 commit comments

Comments
 (0)