Skip to content

Commit 90f36af

Browse files
Port cfg_select! to the new attribute parsing system
Signed-off-by: Jonathan Brouwer <jonathantbrouwer@gmail.com>
1 parent c111ccc commit 90f36af

File tree

5 files changed

+113
-81
lines changed

5 files changed

+113
-81
lines changed

compiler/rustc_attr_parsing/src/attributes/cfg_select.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,47 @@
11
use rustc_ast::token::Token;
22
use rustc_ast::tokenstream::TokenStream;
3-
use rustc_ast::{MetaItemInner, token};
4-
use rustc_errors::PResult;
3+
use rustc_ast::{AttrStyle, NodeId, token};
4+
use rustc_feature::{AttributeTemplate, Features};
5+
use rustc_hir::AttrPath;
6+
use rustc_hir::attrs::CfgEntry;
57
use rustc_parse::exp;
68
use rustc_parse::parser::Parser;
7-
use rustc_span::Span;
9+
use rustc_session::Session;
10+
use rustc_span::{ErrorGuaranteed, Ident, Span};
11+
12+
use crate::parser::MetaItemOrLitParser;
13+
use crate::{AttributeParser, ParsedDescription, ShouldEmit, parse_cfg_entry};
814

915
pub enum CfgSelectPredicate {
10-
Cfg(MetaItemInner),
16+
Cfg(CfgEntry),
1117
Wildcard(Token),
1218
}
1319

1420
#[derive(Default)]
1521
pub struct CfgSelectBranches {
1622
/// All the conditional branches.
17-
pub reachable: Vec<(MetaItemInner, TokenStream, Span)>,
23+
pub reachable: Vec<(CfgEntry, TokenStream, Span)>,
1824
/// The first wildcard `_ => { ... }` branch.
1925
pub wildcard: Option<(Token, TokenStream, Span)>,
2026
/// All branches after the first wildcard, including further wildcards.
2127
/// These branches are kept for formatting.
2228
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
2329
}
2430

25-
pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches> {
31+
pub fn parse_cfg_select(
32+
p: &mut Parser<'_>,
33+
sess: &Session,
34+
features: Option<&Features>,
35+
lint_node_id: NodeId,
36+
) -> Result<CfgSelectBranches, ErrorGuaranteed> {
2637
let mut branches = CfgSelectBranches::default();
2738

2839
while p.token != token::Eof {
2940
if p.eat_keyword(exp!(Underscore)) {
3041
let underscore = p.prev_token;
31-
p.expect(exp!(FatArrow))?;
42+
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
3243

33-
let tts = p.parse_delimited_token_tree()?;
44+
let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
3445
let span = underscore.span.to(p.token.span);
3546

3647
match branches.wildcard {
@@ -40,17 +51,36 @@ pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches
4051
}
4152
}
4253
} else {
43-
let meta_item = p.parse_meta_item_inner()?;
44-
p.expect(exp!(FatArrow))?;
54+
let meta = MetaItemOrLitParser::parse_single(p, ShouldEmit::ErrorsAndLints)
55+
.map_err(|diag| diag.emit())?;
56+
let cfg_span = meta.span();
57+
let cfg = AttributeParser::parse_single_args(
58+
sess,
59+
cfg_span,
60+
cfg_span,
61+
AttrStyle::Inner,
62+
AttrPath {
63+
segments: vec![Ident::from_str("cfg_select")].into_boxed_slice(),
64+
span: cfg_span,
65+
},
66+
ParsedDescription::Macro,
67+
cfg_span,
68+
lint_node_id,
69+
features,
70+
ShouldEmit::ErrorsAndLints,
71+
&meta,
72+
parse_cfg_entry,
73+
&AttributeTemplate::default(),
74+
)?;
75+
76+
p.expect(exp!(FatArrow)).map_err(|e| e.emit())?;
4577

46-
let tts = p.parse_delimited_token_tree()?;
47-
let span = meta_item.span().to(p.token.span);
78+
let tts = p.parse_delimited_token_tree().map_err(|e| e.emit())?;
79+
let span = cfg_span.to(p.token.span);
4880

4981
match branches.wildcard {
50-
None => branches.reachable.push((meta_item, tts, span)),
51-
Some(_) => {
52-
branches.unreachable.push((CfgSelectPredicate::Cfg(meta_item), tts, span))
53-
}
82+
None => branches.reachable.push((cfg, tts, span)),
83+
Some(_) => branches.unreachable.push((CfgSelectPredicate::Cfg(cfg), tts, span)),
5484
}
5585
}
5686
}
Lines changed: 40 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use rustc_ast::tokenstream::TokenStream;
22
use rustc_attr_parsing as attr;
3-
use rustc_attr_parsing::{CfgSelectBranches, CfgSelectPredicate, parse_cfg_select};
3+
use rustc_attr_parsing::{
4+
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, ShouldEmit, parse_cfg_select,
5+
};
46
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacroExpanderResult};
57
use rustc_span::{Ident, Span, sym};
68

@@ -9,11 +11,11 @@ use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
911
/// Selects the first arm whose predicate evaluates to true.
1012
fn select_arm(ecx: &ExtCtxt<'_>, branches: CfgSelectBranches) -> Option<(TokenStream, Span)> {
1113
for (cfg, tt, arm_span) in branches.reachable {
12-
if attr::cfg_matches(
13-
&cfg,
14+
if let EvalConfigResult::True = attr::eval_config_entry(
1415
&ecx.sess,
16+
&cfg,
1517
ecx.current_expansion.lint_node_id,
16-
Some(ecx.ecfg.features),
18+
ShouldEmit::ErrorsAndLints,
1719
) {
1820
return Some((tt, arm_span));
1921
}
@@ -27,37 +29,41 @@ pub(super) fn expand_cfg_select<'cx>(
2729
sp: Span,
2830
tts: TokenStream,
2931
) -> MacroExpanderResult<'cx> {
30-
ExpandResult::Ready(match parse_cfg_select(&mut ecx.new_parser_from_tts(tts)) {
31-
Ok(branches) => {
32-
if let Some((underscore, _, _)) = branches.wildcard {
33-
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
34-
for (predicate, _, _) in &branches.unreachable {
35-
let span = match predicate {
36-
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
37-
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
38-
};
39-
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
40-
ecx.dcx().emit_warn(err);
32+
ExpandResult::Ready(
33+
match parse_cfg_select(
34+
&mut ecx.new_parser_from_tts(tts),
35+
ecx.sess,
36+
Some(ecx.ecfg.features),
37+
ecx.current_expansion.lint_node_id,
38+
) {
39+
Ok(branches) => {
40+
if let Some((underscore, _, _)) = branches.wildcard {
41+
// Warn for every unreachable predicate. We store the fully parsed branch for rustfmt.
42+
for (predicate, _, _) in &branches.unreachable {
43+
let span = match predicate {
44+
CfgSelectPredicate::Wildcard(underscore) => underscore.span,
45+
CfgSelectPredicate::Cfg(cfg) => cfg.span(),
46+
};
47+
let err = CfgSelectUnreachable { span, wildcard_span: underscore.span };
48+
ecx.dcx().emit_warn(err);
49+
}
4150
}
42-
}
4351

44-
if let Some((tts, arm_span)) = select_arm(ecx, branches) {
45-
return ExpandResult::from_tts(
46-
ecx,
47-
tts,
48-
sp,
49-
arm_span,
50-
Ident::with_dummy_span(sym::cfg_select),
51-
);
52-
} else {
53-
// Emit a compiler error when none of the predicates matched.
54-
let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
55-
DummyResult::any(sp, guar)
52+
if let Some((tts, arm_span)) = select_arm(ecx, branches) {
53+
return ExpandResult::from_tts(
54+
ecx,
55+
tts,
56+
sp,
57+
arm_span,
58+
Ident::with_dummy_span(sym::cfg_select),
59+
);
60+
} else {
61+
// Emit a compiler error when none of the predicates matched.
62+
let guar = ecx.dcx().emit_err(CfgSelectNoMatches { span: sp });
63+
DummyResult::any(sp, guar)
64+
}
5665
}
57-
}
58-
Err(err) => {
59-
let guar = err.emit();
60-
DummyResult::any(sp, guar)
61-
}
62-
})
66+
Err(guar) => DummyResult::any(sp, guar),
67+
},
68+
)
6369
}

compiler/rustc_hir/src/attrs/data_structures.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,18 @@ pub enum CfgEntry {
194194
Version(Option<RustcVersion>, Span),
195195
}
196196

197+
impl CfgEntry {
198+
pub fn span(&self) -> Span {
199+
let (CfgEntry::All(_, span)
200+
| CfgEntry::Any(_, span)
201+
| CfgEntry::Not(_, span)
202+
| CfgEntry::Bool(_, span)
203+
| CfgEntry::NameValue { span, .. }
204+
| CfgEntry::Version(_, span)) = self;
205+
*span
206+
}
207+
}
208+
197209
/// Possible values for the `#[linkage]` attribute, allowing to specify the
198210
/// linkage type for a `MonoItem`.
199211
///

tests/ui/macros/cfg_select.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,25 +63,25 @@ cfg_select! {}
6363

6464
cfg_select! {
6565
=> {}
66-
//~^ ERROR expected unsuffixed literal, found `=>`
66+
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>`
6767
}
6868

6969
cfg_select! {
7070
() => {}
71-
//~^ ERROR expected unsuffixed literal, found `(`
71+
//~^ ERROR expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `(`
7272
}
7373

74-
cfg_select! { //~ ERROR none of the predicates in this `cfg_select` evaluated to true
74+
cfg_select! {
7575
"str" => {}
76-
//~^ ERROR literal in `cfg` predicate value must be a boolean
76+
//~^ ERROR malformed `cfg_select` macro input [E0539]
7777
}
7878

7979
cfg_select! {
8080
a::b => {}
81-
//~^ ERROR `cfg` predicate key must be an identifier
81+
//~^ ERROR malformed `cfg_select` macro input [E0539]
8282
}
8383

84-
cfg_select! { //~ ERROR none of the predicates in this `cfg_select` evaluated to true
84+
cfg_select! {
8585
a() => {}
8686
//~^ ERROR invalid predicate `a` [E0537]
8787
}

tests/ui/macros/cfg_select.stderr

Lines changed: 9 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,54 +21,38 @@ error: none of the predicates in this `cfg_select` evaluated to true
2121
LL | cfg_select! {}
2222
| ^^^^^^^^^^^^^^
2323

24-
error: expected unsuffixed literal, found `=>`
24+
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>`
2525
--> $DIR/cfg_select.rs:65:5
2626
|
2727
LL | => {}
2828
| ^^
2929

30-
error: expected unsuffixed literal, found `(`
30+
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `(`
3131
--> $DIR/cfg_select.rs:70:5
3232
|
3333
LL | () => {}
3434
| ^
3535

36-
error[E0565]: literal in `cfg` predicate value must be a boolean
36+
error[E0539]: malformed `cfg_select` macro input
3737
--> $DIR/cfg_select.rs:75:5
3838
|
3939
LL | "str" => {}
40-
| ^^^^^
41-
42-
error: none of the predicates in this `cfg_select` evaluated to true
43-
--> $DIR/cfg_select.rs:74:1
40+
| ^^^^^ expected a valid identifier here
4441
|
45-
LL | / cfg_select! {
46-
LL | | "str" => {}
47-
LL | |
48-
LL | | }
49-
| |_^
5042

51-
error: `cfg` predicate key must be an identifier
43+
error[E0539]: malformed `cfg_select` macro input
5244
--> $DIR/cfg_select.rs:80:5
5345
|
5446
LL | a::b => {}
55-
| ^^^^
47+
| ^^^^ expected a valid identifier here
48+
|
5649

5750
error[E0537]: invalid predicate `a`
5851
--> $DIR/cfg_select.rs:85:5
5952
|
6053
LL | a() => {}
6154
| ^^^
6255

63-
error: none of the predicates in this `cfg_select` evaluated to true
64-
--> $DIR/cfg_select.rs:84:1
65-
|
66-
LL | / cfg_select! {
67-
LL | | a() => {}
68-
LL | |
69-
LL | | }
70-
| |_^
71-
7256
error: expected one of `(`, `::`, `=>`, or `=`, found `+`
7357
--> $DIR/cfg_select.rs:90:7
7458
|
@@ -81,7 +65,7 @@ error: expected one of `(`, `::`, `=>`, or `=`, found `!`
8165
LL | cfg!() => {}
8266
| ^ expected one of `(`, `::`, `=>`, or `=`
8367

84-
error: aborting due to 11 previous errors; 1 warning emitted
68+
error: aborting due to 9 previous errors; 1 warning emitted
8569

86-
Some errors have detailed explanations: E0537, E0565.
70+
Some errors have detailed explanations: E0537, E0539.
8771
For more information about an error, try `rustc --explain E0537`.

0 commit comments

Comments
 (0)