diff options
| author | bors <bors@rust-lang.org> | 2025-07-13 18:34:13 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2025-07-13 18:34:13 +0000 |
| commit | e9182f195b8505c87c4bd055b9f6e114ccda0981 (patch) | |
| tree | b570601233e295aa02c88e5392f60d17b59ec5db /compiler/rustc_parse/src | |
| parent | 56835d7ac14da9f966e1ff39fd9ffd2e29b764d1 (diff) | |
| parent | 3689b80b75bb400e740897ec83e64be332098c0d (diff) | |
| download | rust-e9182f195b8505c87c4bd055b9f6e114ccda0981.tar.gz rust-e9182f195b8505c87c4bd055b9f6e114ccda0981.zip | |
Auto merge of #143461 - folkertdev:cfg-select-builtin-macro, r=petrochenkov
make `cfg_select` a builtin macro
tracking issue: https://github.com/rust-lang/rust/issues/115585
This parses mostly the same as the `macro cfg_select` version, except:
1. wrapping in double brackets is no longer supported (or needed): `cfg_select {{ /* ... */ }}` is now rejected.
2. in an expression context, the rhs is no longer wrapped in a block, so that this now works:
```rust
fn main() {
println!(cfg_select! {
unix => { "foo" }
_ => { "bar" }
});
}
```
3. a single wildcard rule is now supported: `cfg_select { _ => 1 }` now works
I've also added an error if none of the rules evaluate to true, and warnings for any arms that follow the `_` wildcard rule.
cc `@traviscross` if I'm missing any feature that should/should not be included
r? `@petrochenkov` for the macro logic details
Diffstat (limited to 'compiler/rustc_parse/src')
| -rw-r--r-- | compiler/rustc_parse/src/parser/cfg_select.rs | 73 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/mod.rs | 6 |
2 files changed, 78 insertions, 1 deletions
diff --git a/compiler/rustc_parse/src/parser/cfg_select.rs b/compiler/rustc_parse/src/parser/cfg_select.rs new file mode 100644 index 00000000000..24a05afff4a --- /dev/null +++ b/compiler/rustc_parse/src/parser/cfg_select.rs @@ -0,0 +1,73 @@ +use rustc_ast::token::Token; +use rustc_ast::tokenstream::{TokenStream, TokenTree}; +use rustc_ast::{MetaItemInner, token}; +use rustc_errors::PResult; +use rustc_span::Span; + +use crate::exp; +use crate::parser::Parser; + +pub enum CfgSelectRule { + Cfg(MetaItemInner), + Wildcard(Token), +} + +#[derive(Default)] +pub struct CfgSelectBranches { + /// All the conditional branches. + pub reachable: Vec<(MetaItemInner, TokenStream, Span)>, + /// The first wildcard `_ => { ... }` branch. + pub wildcard: Option<(Token, TokenStream, Span)>, + /// All branches after the first wildcard, including further wildcards. + /// These branches are kept for formatting. + pub unreachable: Vec<(CfgSelectRule, TokenStream, Span)>, +} + +/// Parses a `TokenTree` that must be of the form `{ /* ... */ }`, and returns a `TokenStream` where +/// the surrounding braces are stripped. +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))?; + } + + // Strip the outer '{' and '}'. + match p.parse_token_tree() { + TokenTree::Token(..) => unreachable!("because of the expect above"), + TokenTree::Delimited(.., tts) => Ok(tts), + } +} + +pub fn parse_cfg_select<'a>(p: &mut Parser<'a>) -> PResult<'a, CfgSelectBranches> { + let mut branches = CfgSelectBranches::default(); + + while p.token != token::Eof { + if p.eat_keyword(exp!(Underscore)) { + let underscore = p.prev_token; + p.expect(exp!(FatArrow))?; + + let tts = parse_token_tree(p)?; + let span = underscore.span.to(p.token.span); + + match branches.wildcard { + None => branches.wildcard = Some((underscore, tts, span)), + Some(_) => { + branches.unreachable.push((CfgSelectRule::Wildcard(underscore), tts, span)) + } + } + } else { + let meta_item = p.parse_meta_item_inner()?; + p.expect(exp!(FatArrow))?; + + let tts = parse_token_tree(p)?; + let span = meta_item.span().to(p.token.span); + + match branches.wildcard { + None => branches.reachable.push((meta_item, tts, span)), + Some(_) => branches.unreachable.push((CfgSelectRule::Cfg(meta_item), tts, span)), + } + } + } + + Ok(branches) +} diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 2787be46f33..90491e53249 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1,4 +1,3 @@ -pub mod asm; pub mod attr; mod attr_wrapper; mod diagnostics; @@ -12,6 +11,11 @@ mod stmt; pub mod token_type; mod ty; +// Parsers for non-functionlike builtin macros are defined in rustc_parse so they can be used by +// both rustc_builtin_macros and rustfmt. +pub mod asm; +pub mod cfg_select; + use std::assert_matches::debug_assert_matches; use std::{fmt, mem, slice}; |
