about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_parse/src/parser/cfg_select.rs30
-rw-r--r--library/core/src/macros/mod.rs5
-rw-r--r--tests/ui/macros/cfg_select.rs36
-rw-r--r--tests/ui/macros/cfg_select.stderr14
4 files changed, 60 insertions, 25 deletions
diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs
index 2c6fb224d70..08a71db4de8 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 c59290a757b..db8b527d593 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 461d2e0e8c1..9241141ef9a 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 6c18a7c189d..7280f35c16f 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