Skip to content

Commit 319766e

Browse files
authored
Rollup merge of rust-lang#145233 - joshtriplett:cfg-select-expr, r=jieyouxu
cfg_select: Support unbraced expressions Tracking issue for `cfg_select`: rust-lang#115585 When operating on expressions, `cfg_select!` can now handle expressions without braces. (It still requires braces for other things, such as items.) Expand the test coverage and documentation accordingly. --- I'm not sure whether deciding to extend `cfg_select!` in this way is T-lang or T-libs-api. I've labeled for both, with the request that both teams don't block on each other. :)
2 parents 151728b + 38df158 commit 319766e

File tree

4 files changed

+60
-25
lines changed

4 files changed

+60
-25
lines changed

compiler/rustc_parse/src/parser/cfg_select.rs

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
use rustc_ast::token::Token;
22
use rustc_ast::tokenstream::{TokenStream, TokenTree};
3+
use rustc_ast::util::classify;
34
use rustc_ast::{MetaItemInner, token};
45
use rustc_errors::PResult;
56
use rustc_span::Span;
67

78
use crate::exp;
8-
use crate::parser::Parser;
9+
use crate::parser::{AttrWrapper, ForceCollect, Parser, Restrictions, Trailing, UsePreAttrPos};
910

1011
pub enum CfgSelectPredicate {
1112
Cfg(MetaItemInner),
@@ -23,19 +24,26 @@ pub struct CfgSelectBranches {
2324
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
2425
}
2526

26-
/// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where
27-
/// the surrounding braces are stripped.
27+
/// Parses a `TokenTree` consisting either of `{ /* ... */ }` (and strip the braces) or an
28+
/// expression followed by a comma (and strip the comma).
2829
fn parse_token_tree<'a>(p: &mut Parser<'a>) -> PResult<'a, TokenStream> {
29-
// Generate an error if the `=>` is not followed by `{`.
30-
if p.token != token::OpenBrace {
31-
p.expect(exp!(OpenBrace))?;
30+
if p.token == token::OpenBrace {
31+
// Strip the outer '{' and '}'.
32+
match p.parse_token_tree() {
33+
TokenTree::Token(..) => unreachable!("because of the expect above"),
34+
TokenTree::Delimited(.., tts) => return Ok(tts),
35+
}
3236
}
33-
34-
// Strip the outer '{' and '}'.
35-
match p.parse_token_tree() {
36-
TokenTree::Token(..) => unreachable!("because of the expect above"),
37-
TokenTree::Delimited(.., tts) => Ok(tts),
37+
let expr = p.collect_tokens(None, AttrWrapper::empty(), ForceCollect::Yes, |p, _| {
38+
p.parse_expr_res(Restrictions::STMT_EXPR, AttrWrapper::empty())
39+
.map(|(expr, _)| (expr, Trailing::No, UsePreAttrPos::No))
40+
})?;
41+
if !classify::expr_is_complete(&expr) && p.token != token::CloseBrace && p.token != token::Eof {
42+
p.expect(exp!(Comma))?;
43+
} else {
44+
let _ = p.eat(exp!(Comma));
3845
}
46+
Ok(TokenStream::from_ast(&expr))
3947
}
4048

4149
pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches> {

library/core/src/macros/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -223,13 +223,14 @@ pub macro assert_matches {
223223
/// }
224224
/// ```
225225
///
226-
/// The `cfg_select!` macro can also be used in expression position:
226+
/// The `cfg_select!` macro can also be used in expression position, with or without braces on the
227+
/// right-hand side:
227228
///
228229
/// ```
229230
/// #![feature(cfg_select)]
230231
///
231232
/// let _some_string = cfg_select! {
232-
/// unix => { "With great power comes great electricity bills" }
233+
/// unix => "With great power comes great electricity bills",
233234
/// _ => { "Behind every successful diet is an unwatched pizza" }
234235
/// };
235236
/// ```

tests/ui/macros/cfg_select.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,42 @@ fn print() {
88
});
99
}
1010

11-
fn arm_rhs_must_be_in_braces() -> i32 {
11+
fn print_2() {
12+
println!(cfg_select! {
13+
unix => "unix",
14+
_ => "not unix",
15+
});
16+
}
17+
18+
fn arm_rhs_expr_1() -> i32 {
1219
cfg_select! {
1320
true => 1
14-
//~^ ERROR: expected `{`, found `1`
21+
}
22+
}
23+
24+
fn arm_rhs_expr_2() -> i32 {
25+
cfg_select! {
26+
true => 1,
27+
false => 2
28+
}
29+
}
30+
31+
fn arm_rhs_expr_3() -> i32 {
32+
cfg_select! {
33+
true => 1,
34+
false => 2,
35+
true => { 42 }
36+
false => -1 as i32,
37+
true => 2 + 2,
38+
false => "",
39+
true => if true { 42 } else { 84 }
40+
false => if true { 42 } else { 84 },
41+
true => return 42,
42+
false => loop {}
43+
true => (1, 2),
44+
false => (1, 2,),
45+
true => todo!(),
46+
false => println!("hello"),
1547
}
1648
}
1749

tests/ui/macros/cfg_select.stderr

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
1-
error: expected `{`, found `1`
2-
--> $DIR/cfg_select.rs:13:17
3-
|
4-
LL | true => 1
5-
| ^ expected `{`
6-
71
warning: unreachable predicate
8-
--> $DIR/cfg_select.rs:20:5
2+
--> $DIR/cfg_select.rs:52:5
93
|
104
LL | _ => {}
115
| - always matches
126
LL | true => {}
137
| ^^^^ this predicate is never reached
148

159
error: none of the predicates in this `cfg_select` evaluated to true
16-
--> $DIR/cfg_select.rs:24:1
10+
--> $DIR/cfg_select.rs:56:1
1711
|
1812
LL | / cfg_select! {
1913
LL | |
@@ -22,10 +16,10 @@ LL | | }
2216
| |_^
2317

2418
error: none of the predicates in this `cfg_select` evaluated to true
25-
--> $DIR/cfg_select.rs:29:1
19+
--> $DIR/cfg_select.rs:61:1
2620
|
2721
LL | cfg_select! {}
2822
| ^^^^^^^^^^^^^^
2923

30-
error: aborting due to 3 previous errors; 1 warning emitted
24+
error: aborting due to 2 previous errors; 1 warning emitted
3125

0 commit comments

Comments
 (0)