Rollup merge of #145233 - joshtriplett:cfg-select-expr, r=jieyouxu
cfg_select: Support unbraced expressions Tracking issue for `cfg_select`: rust-lang/rust#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. :)
This commit is contained in:
@@ -1,11 +1,12 @@
|
|||||||
use rustc_ast::token::Token;
|
use rustc_ast::token::Token;
|
||||||
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
use rustc_ast::tokenstream::{TokenStream, TokenTree};
|
||||||
|
use rustc_ast::util::classify;
|
||||||
use rustc_ast::{MetaItemInner, token};
|
use rustc_ast::{MetaItemInner, token};
|
||||||
use rustc_errors::PResult;
|
use rustc_errors::PResult;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
|
|
||||||
use crate::exp;
|
use crate::exp;
|
||||||
use crate::parser::Parser;
|
use crate::parser::{AttrWrapper, ForceCollect, Parser, Restrictions, Trailing, UsePreAttrPos};
|
||||||
|
|
||||||
pub enum CfgSelectPredicate {
|
pub enum CfgSelectPredicate {
|
||||||
Cfg(MetaItemInner),
|
Cfg(MetaItemInner),
|
||||||
@@ -23,19 +24,26 @@ pub struct CfgSelectBranches {
|
|||||||
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
|
pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where
|
/// Parses a `TokenTree` consisting either of `{ /* ... */ }` (and strip the braces) or an
|
||||||
/// the surrounding braces are stripped.
|
/// expression followed by a comma (and strip the comma).
|
||||||
fn parse_token_tree<'a>(p: &mut Parser<'a>) -> PResult<'a, TokenStream> {
|
fn parse_token_tree<'a>(p: &mut Parser<'a>) -> PResult<'a, TokenStream> {
|
||||||
// Generate an error if the `=>` is not followed by `{`.
|
if p.token == token::OpenBrace {
|
||||||
if p.token != token::OpenBrace {
|
// Strip the outer '{' and '}'.
|
||||||
p.expect(exp!(OpenBrace))?;
|
match p.parse_token_tree() {
|
||||||
|
TokenTree::Token(..) => unreachable!("because of the expect above"),
|
||||||
|
TokenTree::Delimited(.., tts) => return Ok(tts),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
let expr = p.collect_tokens(None, AttrWrapper::empty(), ForceCollect::Yes, |p, _| {
|
||||||
// Strip the outer '{' and '}'.
|
p.parse_expr_res(Restrictions::STMT_EXPR, AttrWrapper::empty())
|
||||||
match p.parse_token_tree() {
|
.map(|(expr, _)| (expr, Trailing::No, UsePreAttrPos::No))
|
||||||
TokenTree::Token(..) => unreachable!("because of the expect above"),
|
})?;
|
||||||
TokenTree::Delimited(.., tts) => Ok(tts),
|
if !classify::expr_is_complete(&expr) && p.token != token::CloseBrace && p.token != token::Eof {
|
||||||
|
p.expect(exp!(Comma))?;
|
||||||
|
} else {
|
||||||
|
let _ = p.eat(exp!(Comma));
|
||||||
}
|
}
|
||||||
|
Ok(TokenStream::from_ast(&expr))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches> {
|
pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches> {
|
||||||
|
|||||||
@@ -223,13 +223,14 @@ pub macro assert_matches {
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// The `cfg_select!` macro can also be used in expression position:
|
/// The `cfg_select!` macro can also be used in expression position, with or without braces on the
|
||||||
|
/// right-hand side:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// #![feature(cfg_select)]
|
/// #![feature(cfg_select)]
|
||||||
///
|
///
|
||||||
/// let _some_string = cfg_select! {
|
/// let _some_string = cfg_select! {
|
||||||
/// unix => { "With great power comes great electricity bills" }
|
/// unix => "With great power comes great electricity bills",
|
||||||
/// _ => { "Behind every successful diet is an unwatched pizza" }
|
/// _ => { "Behind every successful diet is an unwatched pizza" }
|
||||||
/// };
|
/// };
|
||||||
/// ```
|
/// ```
|
||||||
|
|||||||
@@ -8,10 +8,42 @@ fn print() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arm_rhs_must_be_in_braces() -> i32 {
|
fn print_2() {
|
||||||
|
println!(cfg_select! {
|
||||||
|
unix => "unix",
|
||||||
|
_ => "not unix",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arm_rhs_expr_1() -> i32 {
|
||||||
cfg_select! {
|
cfg_select! {
|
||||||
true => 1
|
true => 1
|
||||||
//~^ ERROR: expected `{`, found `1`
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arm_rhs_expr_2() -> i32 {
|
||||||
|
cfg_select! {
|
||||||
|
true => 1,
|
||||||
|
false => 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn arm_rhs_expr_3() -> i32 {
|
||||||
|
cfg_select! {
|
||||||
|
true => 1,
|
||||||
|
false => 2,
|
||||||
|
true => { 42 }
|
||||||
|
false => -1 as i32,
|
||||||
|
true => 2 + 2,
|
||||||
|
false => "",
|
||||||
|
true => if true { 42 } else { 84 }
|
||||||
|
false => if true { 42 } else { 84 },
|
||||||
|
true => return 42,
|
||||||
|
false => loop {}
|
||||||
|
true => (1, 2),
|
||||||
|
false => (1, 2,),
|
||||||
|
true => todo!(),
|
||||||
|
false => println!("hello"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
error: expected `{`, found `1`
|
|
||||||
--> $DIR/cfg_select.rs:13:17
|
|
||||||
|
|
|
||||||
LL | true => 1
|
|
||||||
| ^ expected `{`
|
|
||||||
|
|
||||||
warning: unreachable predicate
|
warning: unreachable predicate
|
||||||
--> $DIR/cfg_select.rs:20:5
|
--> $DIR/cfg_select.rs:52:5
|
||||||
|
|
|
|
||||||
LL | _ => {}
|
LL | _ => {}
|
||||||
| - always matches
|
| - always matches
|
||||||
@@ -13,7 +7,7 @@ LL | true => {}
|
|||||||
| ^^^^ this predicate is never reached
|
| ^^^^ this predicate is never reached
|
||||||
|
|
||||||
error: none of the predicates in this `cfg_select` evaluated to true
|
error: none of the predicates in this `cfg_select` evaluated to true
|
||||||
--> $DIR/cfg_select.rs:24:1
|
--> $DIR/cfg_select.rs:56:1
|
||||||
|
|
|
|
||||||
LL | / cfg_select! {
|
LL | / cfg_select! {
|
||||||
LL | |
|
LL | |
|
||||||
@@ -22,10 +16,10 @@ LL | | }
|
|||||||
| |_^
|
| |_^
|
||||||
|
|
||||||
error: none of the predicates in this `cfg_select` evaluated to true
|
error: none of the predicates in this `cfg_select` evaluated to true
|
||||||
--> $DIR/cfg_select.rs:29:1
|
--> $DIR/cfg_select.rs:61:1
|
||||||
|
|
|
|
||||||
LL | cfg_select! {}
|
LL | cfg_select! {}
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: aborting due to 3 previous errors; 1 warning emitted
|
error: aborting due to 2 previous errors; 1 warning emitted
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user