Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 61 additions & 2 deletions src/conditional-compilation.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -31,7 +31,7 @@ r[cfg.intro]
*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.
Expand DownExpand Up@@ -436,17 +436,76 @@ let machine_kind = if cfg!(unix) {
println!("I'm running on a {} machine!", machine_kind);
```

r[cfg.cfg_select]
### The `cfg_select` macro

r[cfg.cfg_select.intro]
The built-in [`cfg_select!`][std::cfg_select] macro can be used to select code at compile-time based on multiple configuration predicates.

> [!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 */ }
> }
> }
>
> let is_unix_str = cfg_select! {
> unix => "unix",
> _ => "not unix",
> };
> ```

r[cfg.cfg_select.syntax]
```grammar,configuration
@root CfgSelect -> CfgSelectArms?

CfgSelectArms ->
CfgSelectConfigurationPredicate `=>`
(
`{` ^ TokenTree `}` `,`? CfgSelectArms?
| ExpressionWithBlockNoAttrs `,`? CfgSelectArms?
| ExpressionWithoutBlockNoAttrs ( `,` CfgSelectArms? )?
)

CfgSelectConfigurationPredicate ->
ConfigurationPredicate | `_`
```
Comment on lines +466 to +479

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This grammar doesn't quite look correct to me.

Some comments:

  • We don't have a precedent for documenting macro inputs. I don't think we can express it like `cfg_select!` `{` … `}` because the braces can also be () or [] (also ! is a separate token), and the macro name can be renamed. I would suggest just documenting what the input to the macro is, and not the surrounding invocation syntax.
  • This doesn't handle the difference in behavior of the last branch.
  • This doesn't specify that the non-braced value needs to be an expression of a certain kind.
  • This doesn't handle the optional , behavior.

I'm thinking the grammar would be something closer to:

@root CfgSelect ->
CfgSelectBranch*
LastCfgSelectBranch?
CfgSelectBranch ->
CfgSelectConfigurationPredicate `=>` `{` TokenTree `}`
| CfgSelectConfigurationPredicate `=>` ExpressionWithBlockX `,`?
| CfgSelectConfigurationPredicate `=>` ExpressionWithoutBlockX `,`
ExpressionWithBlockX ->
BlockExpression
| ConstBlockExpression
| UnsafeBlockExpression
| LoopExpression
| IfExpression
| MatchExpression
ExpressionWithoutBlockX ->
LiteralExpression
| PathExpression
| OperatorExpression
| GroupedExpression
| ArrayExpression
| AwaitExpression
| IndexExpression
| TupleExpression
| TupleIndexingExpression
| StructExpression
| CallExpression
| MethodCallExpression
| FieldExpression
| ClosureExpression
| AsyncBlockExpression
| ContinueExpression
| BreakExpression
| RangeExpression
| ReturnExpression
| UnderscoreExpression
| MacroInvocation
LastCfgSelectBranch ->
CfgSelectConfigurationPredicate => ExpressionX `,`?
ExpressionX -> ExpressionWithBlockX | ExpressionWithoutBlockX
CfgSelectConfigurationPredicate ->
ConfigurationPredicate | `_`

Where the X expressions are from the Expression grammar, but without the outer attributes. If this is correct, we'll need to rework Expression to support that.

Does that make sense?

@ehussehussJan 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though looking again, my suggestion above won't work because we are moving towards a grammar that does not have infinite lookahead for disambiguation. So the LastCfgSelectBranch won't work. I offhand can't think of a way to actually express that...

(Maybe lookahead is required?)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed something that might be closer.


r[cfg.cfg_select.first-arm]
`cfg_select` expands to the payload of the first arm whose configuration predicate evaluates to true.

r[cfg.cfg_select.braces]
If the entire payload is wrapped in curly braces, the braces are removed during expansion.

r[cfg.cfg_select.wildcard]
The configuration predicate `_` always evaluates to true.

r[cfg.cfg_select.fallthrough]
It is a compile error if none of the predicates evaluate to true.

r[cfg.cfg_select.well-formed]
Each right-hand side must be a syntactically valid expansion for the position in which the macro is invoked.

[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_attr`]: #the-cfg_attr-attribute
[`cfg_select!`]: #the-cfg_select-macro
[`crate_name`]: crates-and-source-files.md#the-crate_name-attribute
[`crate_type`]: linkage.md
[`target_feature` attribute]: attributes/codegen.md#the-target_feature-attribute
[attribute]: attributes.md
[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
66 changes: 33 additions & 33 deletions src/expressions.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -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]
Expand Down