diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs index 2c6fb224d70d6..08a71db4de853 100644 --- a/compiler/rustc_parse/src/parser/cfg_select.rs +++ b/compiler/rustc_parse/src/parser/cfg_select.rs @@ -1,11 +1,12 @@ use rustc_ast::token::Token; use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::util::classify; use rustc_ast::{MetaItemInner, token}; use rustc_errors::PResult; use rustc_span::Span; use crate::exp; -use crate::parser::Parser; +use crate::parser::{AttrWrapper, ForceCollect, Parser, Restrictions, Trailing, UsePreAttrPos}; pub enum CfgSelectPredicate { Cfg(MetaItemInner), @@ -23,19 +24,26 @@ pub struct CfgSelectBranches { pub unreachable: Vec<(CfgSelectPredicate, TokenStream, Span)>, } -/// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where -/// the surrounding braces are stripped. +/// Parses a `TokenTree` consisting either of `{ /* ... */ }` (and strip the braces) or an +/// expression followed by a comma (and strip the comma). 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 { - p.expect(exp!(OpenBrace))?; + if p.token == token::OpenBrace { + // Strip the outer '{' and '}'. + match p.parse_token_tree() { + TokenTree::Token(..) => unreachable!("because of the expect above"), + TokenTree::Delimited(.., tts) => return Ok(tts), + } } - - // Strip the outer '{' and '}'. - match p.parse_token_tree() { - TokenTree::Token(..) => unreachable!("because of the expect above"), - TokenTree::Delimited(.., tts) => Ok(tts), + let expr = p.collect_tokens(None, AttrWrapper::empty(), ForceCollect::Yes, |p, _| { + p.parse_expr_res(Restrictions::STMT_EXPR, AttrWrapper::empty()) + .map(|(expr, _)| (expr, Trailing::No, UsePreAttrPos::No)) + })?; + 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> { diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index c59290a757b67..db8b527d59312 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -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)] /// /// 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" } /// }; /// ``` diff --git a/tests/ui/macros/cfg_select.rs b/tests/ui/macros/cfg_select.rs index 461d2e0e8c1f5..9241141ef9a6c 100644 --- a/tests/ui/macros/cfg_select.rs +++ b/tests/ui/macros/cfg_select.rs @@ -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! { 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"), } } diff --git a/tests/ui/macros/cfg_select.stderr b/tests/ui/macros/cfg_select.stderr index 6c18a7c189dcc..7280f35c16f93 100644 --- a/tests/ui/macros/cfg_select.stderr +++ b/tests/ui/macros/cfg_select.stderr @@ -1,11 +1,5 @@ -error: expected `{`, found `1` - --> $DIR/cfg_select.rs:13:17 - | -LL | true => 1 - | ^ expected `{` - warning: unreachable predicate - --> $DIR/cfg_select.rs:20:5 + --> $DIR/cfg_select.rs:52:5 | LL | _ => {} | - always matches @@ -13,7 +7,7 @@ LL | true => {} | ^^^^ this predicate is never reached 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 | | @@ -22,10 +16,10 @@ LL | | } | |_^ 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! {} | ^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +error: aborting due to 2 previous errors; 1 warning emitted