From a57c184fa5bf17bd7f3163d369423f413ce85a44 Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Mon, 8 Dec 2025 21:16:20 +0100 Subject: [PATCH 1/3] `cfg_select!` macro --- src/conditional-compilation.md | 37 ++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index f03362063c..72ee872094 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -31,7 +31,7 @@ r[cfg.general] *Conditionally compiled source code* is source code that is compiled only under certain conditions. r[cfg.attributes-macro] -Source code can be made conditionally compiled using the [`cfg`] and [`cfg_attr`] [attributes] and the built-in [`cfg` macro]. +Source code can be made conditionally compiled using the [`cfg`] and [`cfg_attr`] [attributes] and the built-in [`cfg!`] and [`cfg_select!`] [macros]. r[cfg.conditional] Whether to compile can depend on the target architecture of the compiled crate, arbitrary values passed to the compiler, and other things further described below. @@ -466,11 +466,43 @@ let machine_kind = if cfg!(unix) { println!("I'm running on a {} machine!", machine_kind); ``` +r[cfg.cfg_select] +### The `cfg_select` macro + +The built-in `cfg_select` macro expands to the right-hand side of the first configuration predicate that evaluates to `true`. + +For example: + +```rust +cfg_select! { + unix => { + fn foo() { /* unix specific functionality */ } + } + target_pointer_width = "32" => { + fn foo() { /* non-unix, 32-bit functionality */ } + } + _ => { + fn foo() { /* fallback implementation */ } + } +} +``` +The `cfg_select` macro can also be used in expression position: + +```rust +let is_unix_str = cfg_select! { + unix => "unix", + _ => "not unix", +}; +``` + +A `_` can be used to write a configuration predicate that always evaluates to `true`. + [Testing]: attributes/testing.md [`--cfg`]: ../rustc/command-line-arguments.html#--cfg-configure-the-compilation-environment [`--test`]: ../rustc/command-line-arguments.html#--test-build-a-test-harness [`cfg`]: #the-cfg-attribute -[`cfg` macro]: #the-cfg-macro +[`cfg!`]: #the-cfg-macro +[`cfg_select!`]: #the-cfg_select-macro [`cfg_attr`]: #the-cfg_attr-attribute [`crate_name`]: crates-and-source-files.md#the-crate_name-attribute [`crate_type`]: linkage.md @@ -479,4 +511,5 @@ println!("I'm running on a {} machine!", machine_kind); [attributes]: attributes.md [cargo-feature]: ../cargo/reference/features.html [crate type]: linkage.md +[macros]: macros.md [static C runtime]: linkage.md#static-and-dynamic-c-runtimes From c5067fe3af3ebe420d563546b8ef620c10ca1d2e Mon Sep 17 00:00:00 2001 From: Folkert de Vries Date: Wed, 17 Dec 2025 17:58:37 +0100 Subject: [PATCH 2/3] more detail --- src/conditional-compilation.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index 72ee872094..82135dc65e 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -469,7 +469,21 @@ println!("I'm running on a {} machine!", machine_kind); r[cfg.cfg_select] ### The `cfg_select` macro -The built-in `cfg_select` macro expands to the right-hand side of the first configuration predicate that evaluates to `true`. +r[cfg.cfg_select.syntax] +```grammar,configuration +CfgSelect -> + cfg_select! `{` CfgSelectBranch* `}` + +CfgSelectConfigurationPredicate -> + ConfigurationPredicate | `_` + +CfgSelectBranch -> + CfgSelectConfigurationPredicate `=>` `{` TokenTree `}` + | CfgSelectConfigurationPredicate `=>` TokenTree `,` +``` + +r[cfg.cfg_select.general] +The built-in `cfg_select` macro expands to the `TokenTree` on the right-hand side of the first configuration predicate that evaluates to `true`. For example: @@ -495,8 +509,26 @@ let is_unix_str = cfg_select! { }; ``` +r[cfg.cfg_select.wildcard] A `_` can be used to write a configuration predicate that always evaluates to `true`. +r[cfg.cfg_select.fallthrough] +If none of the predicates evaluates to `true`, a compiler error is emitted. + +r[cfg.cfg_select.positions] +The `cfg_select!` macro is accepted in the following macro expansion positions + +- items +- statements +- expression +- impl items +- trait impl items +- trait items +- foreign items + +r[cfg.cfg_select.well-formed] +Each right-hand side must syntactically be valid expansion for the position that the macro is invoked in. + [Testing]: attributes/testing.md [`--cfg`]: ../rustc/command-line-arguments.html#--cfg-configure-the-compilation-environment [`--test`]: ../rustc/command-line-arguments.html#--test-build-a-test-harness From daa84b99b4890dca582ed00739483334afc19010 Mon Sep 17 00:00:00 2001 From: Travis Cross Date: Sat, 17 Jan 2026 01:37:26 +0000 Subject: [PATCH 3/3] Add more correct grammar for `cfg_select!` Macros can be renamed when imported and can delimit their bodies with different tokens, so we don't want to document the outer part of the call; we just want to document the input to the macro. Doing this for `cfg_select!` is a bit tricky since an expression with a block doesn't need to be followed by a comma while an expression without a block does unless it's the last one. We don't want to handle this the way that the `match` grammar does, currently, since we want to move toward finite lookahead. So, instead, we handle this with right recursion in `CfgSelectArms`. Unlike `match`, outer attributes aren't allowed on the RHS expressions. To handle this, we need to refactor `ExpressionWithoutBlock` and `ExpressionWithBlock`. We also document that the outer braces are removed during expansion when the payload is a block expression. (We called it the arm "payload" after running out of other options.) --- src/conditional-compilation.md | 17 +++++---- src/expressions.md | 66 +++++++++++++++++----------------- 2 files changed, 43 insertions(+), 40 deletions(-) diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index 82135dc65e..c47bd26054 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -471,19 +471,22 @@ r[cfg.cfg_select] r[cfg.cfg_select.syntax] ```grammar,configuration -CfgSelect -> - cfg_select! `{` CfgSelectBranch* `}` +@root CfgSelect -> CfgSelectArms? + +CfgSelectArms -> + CfgSelectConfigurationPredicate `=>` + ( + `{` ^ TokenTree `}` CfgSelectArms? + | ExpressionWithBlockNoAttrs `,`? CfgSelectArms? + | ExpressionWithoutBlockNoAttrs ( `,` CfgSelectArms? )? + ) CfgSelectConfigurationPredicate -> ConfigurationPredicate | `_` - -CfgSelectBranch -> - CfgSelectConfigurationPredicate `=>` `{` TokenTree `}` - | CfgSelectConfigurationPredicate `=>` TokenTree `,` ``` r[cfg.cfg_select.general] -The built-in `cfg_select` macro expands to the `TokenTree` on the right-hand side of the first configuration predicate that evaluates to `true`. +The built-in `cfg_select` macro expands to the arm payload of the first configuration predicate that evaluates to `true`. If the payload is wrapped in curly braces, those are removed during expansion. For example: diff --git a/src/expressions.md b/src/expressions.md index 9abc51ae59..cc600fc1b7 100644 --- a/src/expressions.md +++ b/src/expressions.md @@ -8,41 +8,41 @@ Expression -> | ExpressionWithBlock ExpressionWithoutBlock -> - OuterAttribute* - ( - LiteralExpression - | PathExpression - | OperatorExpression - | GroupedExpression - | ArrayExpression - | AwaitExpression - | IndexExpression - | TupleExpression - | TupleIndexingExpression - | StructExpression - | CallExpression - | MethodCallExpression - | FieldExpression - | ClosureExpression - | AsyncBlockExpression - | ContinueExpression - | BreakExpression - | RangeExpression - | ReturnExpression - | UnderscoreExpression - | MacroInvocation - ) + OuterAttribute* ExpressionWithoutBlockNoAttrs + +ExpressionWithoutBlockNoAttrs -> + LiteralExpression + | PathExpression + | OperatorExpression + | GroupedExpression + | ArrayExpression + | AwaitExpression + | IndexExpression + | TupleExpression + | TupleIndexingExpression + | StructExpression + | CallExpression + | MethodCallExpression + | FieldExpression + | ClosureExpression + | AsyncBlockExpression + | ContinueExpression + | BreakExpression + | RangeExpression + | ReturnExpression + | UnderscoreExpression + | MacroInvocation ExpressionWithBlock -> - OuterAttribute* - ( - BlockExpression - | ConstBlockExpression - | UnsafeBlockExpression - | LoopExpression - | IfExpression - | MatchExpression - ) + OuterAttribute* ExpressionWithBlockNoAttrs + +ExpressionWithBlockNoAttrs -> + BlockExpression + | ConstBlockExpression + | UnsafeBlockExpression + | LoopExpression + | IfExpression + | MatchExpression ``` r[expr.intro]