Skip to content

Commit e00ad06

Browse files
committed
go via ParserAnyMacro
1 parent f9d6aee commit e00ad06

File tree

4 files changed

+71
-58
lines changed

4 files changed

+71
-58
lines changed

compiler/rustc_attr_parsing/src/attributes/cfg_select.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,25 @@ pub struct CfgSelectBranches {
3131
impl CfgSelectBranches {
3232
/// Removes the top-most branch for which `predicate` returns `true`,
3333
/// or the wildcard if none of the reachable branches satisfied the predicate.
34-
pub fn pop_first_match<F>(&mut self, predicate: F) -> Option<TokenStream>
34+
pub fn pop_first_match<F>(&mut self, predicate: F) -> Option<(TokenStream, Span)>
3535
where
3636
F: Fn(&CfgEntry) -> bool,
3737
{
3838
for (index, (cfg, _, _)) in self.reachable.iter().enumerate() {
3939
if predicate(cfg) {
40-
return Some(self.reachable.remove(index).1);
40+
let matched = self.reachable.remove(index);
41+
return Some((matched.1, matched.2));
4142
}
4243
}
4344

44-
self.wildcard.take().map(|(_, tts, _)| tts)
45+
self.wildcard.take().map(|(_, tts, span)| (tts, span))
4546
}
4647

4748
/// Consume this value and iterate over all the `TokenStream`s that it stores.
48-
pub fn into_iter_tts(self) -> impl Iterator<Item = TokenStream> {
49-
let it1 = self.reachable.into_iter().map(|(_, tts, _)| tts);
50-
let it2 = self.wildcard.into_iter().map(|(_, tts, _)| tts);
51-
let it3 = self.unreachable.into_iter().map(|(_, tts, _)| tts);
49+
pub fn into_iter_tts(self) -> impl Iterator<Item = (TokenStream, Span)> {
50+
let it1 = self.reachable.into_iter().map(|(_, tts, span)| (tts, span));
51+
let it2 = self.wildcard.into_iter().map(|(_, tts, span)| (tts, span));
52+
let it3 = self.unreachable.into_iter().map(|(_, tts, span)| (tts, span));
5253

5354
it1.chain(it2).chain(it3)
5455
}

compiler/rustc_builtin_macros/src/cfg_select.rs

Lines changed: 35 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,59 @@
11
use rustc_ast::tokenstream::TokenStream;
2-
use rustc_ast::{Expr, ast, token};
3-
use rustc_ast_pretty::pprust;
2+
use rustc_ast::{Expr, ast};
43
use rustc_attr_parsing as attr;
54
use rustc_attr_parsing::{
65
CfgSelectBranches, CfgSelectPredicate, EvalConfigResult, parse_cfg_select,
76
};
87
use rustc_expand::base::{DummyResult, ExpandResult, ExtCtxt, MacResult, MacroExpanderResult};
9-
use rustc_parse::parser::ForceCollect;
10-
use rustc_span::Span;
8+
use rustc_span::{Ident, Span, sym};
119
use smallvec::SmallVec;
1210

13-
use crate::errors;
1411
use crate::errors::{CfgSelectNoMatches, CfgSelectUnreachable};
1512

1613
/// This intermediate structure is used to emit parse errors for the branches that are not chosen.
1714
/// The `MacResult` instance below parses all branches, emitting any errors it encounters, but only
1815
/// keeps the parse result for the selected branch.
1916
struct CfgSelectResult<'cx, 'sess> {
2017
ecx: &'cx mut ExtCtxt<'sess>,
18+
site_span: Span,
2119
selected_tts: TokenStream,
20+
selected_span: Span,
2221
other_branches: CfgSelectBranches,
2322
}
2423

24+
fn tts_to_mac_result<'cx, 'sess>(
25+
ecx: &'cx mut ExtCtxt<'sess>,
26+
site_span: Span,
27+
tts: TokenStream,
28+
span: Span,
29+
) -> Box<dyn MacResult + 'cx> {
30+
match ExpandResult::from_tts(ecx, tts, site_span, span, Ident::with_dummy_span(sym::cfg_select))
31+
{
32+
ExpandResult::Ready(x) => x,
33+
_ => unreachable!("from_tts always returns Ready"),
34+
}
35+
}
36+
2537
impl<'cx, 'sess> MacResult for CfgSelectResult<'cx, 'sess> {
2638
fn make_expr(self: Box<Self>) -> Option<Box<Expr>> {
27-
for tts in self.other_branches.into_iter_tts() {
28-
let mut p = self.ecx.new_parser_from_tts(tts);
29-
if let Err(diag) = p.parse_expr() {
30-
diag.emit();
31-
return None;
32-
}
33-
}
39+
let CfgSelectResult { ecx, site_span, selected_tts, selected_span, .. } = *self;
3440

35-
let mut p = self.ecx.new_parser_from_tts(self.selected_tts);
36-
p.parse_expr().ok()
37-
}
38-
39-
fn make_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::Item>; 1]>> {
40-
for tts in self.other_branches.into_iter_tts() {
41-
let _ = make_items(self.ecx, tts, false);
41+
for (tts, span) in self.other_branches.into_iter_tts() {
42+
let _ = tts_to_mac_result(ecx, site_span, tts, span).make_expr();
4243
}
4344

44-
make_items(self.ecx, self.selected_tts, true)
45+
tts_to_mac_result(ecx, site_span, selected_tts, selected_span).make_expr()
4546
}
46-
}
4747

48-
fn make_items<'cx>(
49-
ecx: &'cx mut ExtCtxt<'_>,
50-
tts: TokenStream,
51-
keep: bool,
52-
) -> Option<SmallVec<[Box<ast::Item>; 1]>> {
53-
let mut p = ecx.new_parser_from_tts(tts);
54-
let mut ret = SmallVec::new();
55-
loop {
56-
match p.parse_item(ForceCollect::No) {
57-
Err(err) => {
58-
err.emit();
59-
break;
60-
}
61-
Ok(Some(item)) => {
62-
if keep {
63-
ret.push(item)
64-
}
65-
}
66-
Ok(None) => {
67-
if p.token != token::Eof {
68-
p.dcx().emit_err(errors::ExpectedItem {
69-
span: p.token.span,
70-
token: &pprust::token_to_string(&p.token),
71-
});
72-
}
48+
fn make_items(self: Box<Self>) -> Option<SmallVec<[Box<ast::Item>; 1]>> {
49+
let CfgSelectResult { ecx, site_span, selected_tts, selected_span, .. } = *self;
7350

74-
break;
75-
}
51+
for (tts, span) in self.other_branches.into_iter_tts() {
52+
let _ = tts_to_mac_result(ecx, site_span, tts, span).make_items();
7653
}
54+
55+
tts_to_mac_result(ecx, site_span, selected_tts, selected_span).make_items()
7756
}
78-
Some(ret)
7957
}
8058

8159
pub(super) fn expand_cfg_select<'cx>(
@@ -103,10 +81,16 @@ pub(super) fn expand_cfg_select<'cx>(
10381
}
10482
}
10583

106-
if let Some(selected_tts) = branches.pop_first_match(|cfg| {
84+
if let Some((selected_tts, selected_span)) = branches.pop_first_match(|cfg| {
10785
matches!(attr::eval_config_entry(&ecx.sess, cfg), EvalConfigResult::True)
10886
}) {
109-
let mac = CfgSelectResult { ecx, selected_tts, other_branches: branches };
87+
let mac = CfgSelectResult {
88+
ecx,
89+
selected_tts,
90+
selected_span,
91+
other_branches: branches,
92+
site_span: sp,
93+
};
11094
return ExpandResult::Ready(Box::new(mac));
11195
} else {
11296
// Emit a compiler error when none of the predicates matched.

tests/ui/macros/cfg_select_parse_error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,13 @@
66
fn print() {
77
println!(cfg_select! {
88
false => { 1 ++ 2 }
9+
//~^ ERROR Rust has no postfix increment operator
910
_ => { "not unix" }
1011
});
1112
}
1213

1314
cfg_select! {
1415
false => { fn foo() { 1 +++ 2 } }
16+
//~^ ERROR Rust has no postfix increment operator
1517
_ => {}
1618
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: Rust has no postfix increment operator
2+
--> $DIR/cfg_select_parse_error.rs:8:22
3+
|
4+
LL | false => { 1 ++ 2 }
5+
| ^^ not a valid postfix operator
6+
|
7+
help: use `+= 1` instead
8+
|
9+
LL - false => { 1 ++ 2 }
10+
LL + false => { { let tmp = 1 ; 1 += 1; tmp } 2 }
11+
|
12+
13+
error: Rust has no postfix increment operator
14+
--> $DIR/cfg_select_parse_error.rs:15:29
15+
|
16+
LL | false => { fn foo() { 1 +++ 2 } }
17+
| ^^ not a valid postfix operator
18+
|
19+
help: use `+= 1` instead
20+
|
21+
LL - false => { fn foo() { 1 +++ 2 } }
22+
LL + false => { fn foo() { { let tmp = 1 ; 1 += 1; tmp }+ 2 } }
23+
|
24+
25+
error: aborting due to 2 previous errors
26+

0 commit comments

Comments
 (0)