Rollup merge of #149783 - folkertdev:stabilize-cfg-select, r=JonathanBrouwer

stabilize `cfg_select!`

*[View all comments](https://triagebot.infra.rust-lang.org/gh-comments/rust-lang/rust/pull/149783)*

tracking issue: https://github.com/rust-lang/rust/issues/115585
closes https://github.com/rust-lang/rust/issues/115585
reference PR:

- https://github.com/rust-lang/reference/pull/2103

# Request for Stabilization

## Summary

The `cfg_select!` macro picks the expansion corresponding to the first `cfg` condition that evaluates to `true`. It simplifies complex conditional expressions.

```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",
};
println!("{is_unix_str}");
```
## Semantics

The expansion of a `cfg_select!` call is the right-hand side of the first `cfg` rule that evaluates to true.

This can be roughly expressed using this macro:
```rust
macro_rules! cfg_select {
    ({ $($tt:tt)* }) => {{
        $crate::cfg_select! { $($tt)* }
    }};
    (_ => { $($output:tt)* }) => {
        $($output)*
    };
    (
        $cfg:meta => $output:tt
        $($( $rest:tt )+)?
    ) => {
        #[cfg($cfg)]
        $crate::cfg_select! { _ => $output }
        $(
            #[cfg(not($cfg))]
            $crate::cfg_select! { $($rest)+ }
        )?
    }
}
```

The actual implementation uses a builtin macro so that `cfg_select!` can be used both in item and expression position.

## Documentation

reference PR:

- https://github.com/rust-lang/reference/pull/2103

## Tests

The `cfg_select!` macro is already used extensively in the rust compiler codebase. It has several dedicated tests:

- [`tests/ui/check-cfg/cfg-select.rs`](https://github.com/rust-lang/rust/blob/main/tests/ui/check-cfg/cfg-select.rs)tests that warnings are emitted when an unexpected `cfg` condition is used.
- [`tests/ui/macros/cfg_select.rs`](https://github.com/rust-lang/rust/blob/main/tests/ui/macros/cfg_select.rs) tests that `cfg_select!` has the expected expansion, and tests that the expected syntax is accepted.
## History

- rust-lang/rust#115416
- rust-lang/rust#117162
- rust-lang/rust#133720
- rust-lang/rust#135625
- rust-lang/rust#137198
- rust-lang/rust#138993
- rust-lang/rust#138996
- rust-lang/rust#143461
- rust-lang/rust#143941
- rust-lang/rust#145233
- rust-lang/rust#148712
- rust-lang/rust#149380
- https://github.com/rust-lang/rust/pull/149925

# Resolved questions

# Unresolved questions

The style team has decided on how to format `cfg_select!`, but this formatting has not yet been implemented. See https://github.com/rust-lang/rust/pull/144323.

r? @traviscross

<!-- TRIAGEBOT_START -->

<!-- TRIAGEBOT_CONCERN-ISSUE_START -->

> [!NOTE]
> # Concerns (0 active)
>
> - ~~[allowing-comma-after-closing-brace](https://github.com/rust-lang/rust/pull/149783#issuecomment-3808533494)~~ resolved in [this comment](https://github.com/rust-lang/rust/pull/149783#issuecomment-3882251672)
>
> *Managed by `@rustbot`—see [help](https://forge.rust-lang.org/triagebot/concern.html) for details.*

<!-- TRIAGEBOT_CONCERN-ISSUE_END -->
<!-- TRIAGEBOT_END -->
This commit is contained in:
Stuart Cook
2026-02-23 13:31:59 +11:00
committed by GitHub
29 changed files with 41 additions and 100 deletions
@@ -1,6 +1,5 @@
#![crate_type = "staticlib"]
#![feature(c_variadic)]
#![feature(cfg_select)]
use std::ffi::{CStr, CString, VaList, c_char, c_double, c_int, c_long, c_longlong};
-1
View File
@@ -3,7 +3,6 @@
//@ revisions: reva revb
//@ only-x86_64
//@ run-pass
#![feature(cfg_select)]
use std::arch::{asm, naked_asm};
-1
View File
@@ -1,6 +1,5 @@
//@ check-pass
#![feature(cfg_select)]
#![crate_type = "lib"]
cfg_select! {
+2 -2
View File
@@ -1,5 +1,5 @@
warning: unexpected `cfg` condition name: `invalid_cfg1`
--> $DIR/cfg-select.rs:8:5
--> $DIR/cfg-select.rs:7:5
|
LL | invalid_cfg1 => {}
| ^^^^^^^^^^^^
@@ -10,7 +10,7 @@ LL | invalid_cfg1 => {}
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition name: `invalid_cfg2`
--> $DIR/cfg-select.rs:14:5
--> $DIR/cfg-select.rs:13:5
|
LL | invalid_cfg2 => {}
| ^^^^^^^^^^^^
@@ -1,11 +0,0 @@
#![warn(unreachable_cfg_select_predicates)]
//~^ WARN unknown lint: `unreachable_cfg_select_predicates`
cfg_select! {
//~^ ERROR use of unstable library feature `cfg_select`
_ => {}
// With the feature enabled, this branch would trip the unreachable_cfg_select_predicate lint.
true => {}
}
fn main() {}
@@ -1,25 +0,0 @@
error[E0658]: use of unstable library feature `cfg_select`
--> $DIR/feature-gate-cfg-select.rs:4:1
|
LL | cfg_select! {
| ^^^^^^^^^^
|
= note: see issue #115585 <https://github.com/rust-lang/rust/issues/115585> for more information
= help: add `#![feature(cfg_select)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
warning: unknown lint: `unreachable_cfg_select_predicates`
--> $DIR/feature-gate-cfg-select.rs:1:9
|
LL | #![warn(unreachable_cfg_select_predicates)]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the `unreachable_cfg_select_predicates` lint is unstable
= note: see issue #115585 <https://github.com/rust-lang/rust/issues/115585> for more information
= help: add `#![feature(cfg_select)]` to the crate attributes to enable
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
= note: `#[warn(unknown_lints)]` on by default
error: aborting due to 1 previous error; 1 warning emitted
For more information about this error, try `rustc --explain E0658`.
-1
View File
@@ -1,4 +1,3 @@
#![feature(cfg_select)]
#![crate_type = "lib"]
#![warn(unreachable_cfg_select_predicates)] // Unused warnings are disabled by default in UI tests.
+17 -17
View File
@@ -1,5 +1,5 @@
error: none of the predicates in this `cfg_select` evaluated to true
--> $DIR/cfg_select.rs:162:1
--> $DIR/cfg_select.rs:161:1
|
LL | / cfg_select! {
LL | |
@@ -8,55 +8,55 @@ LL | | }
| |_^
error: none of the predicates in this `cfg_select` evaluated to true
--> $DIR/cfg_select.rs:167:1
--> $DIR/cfg_select.rs:166:1
|
LL | cfg_select! {}
| ^^^^^^^^^^^^^^
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found `=>`
--> $DIR/cfg_select.rs:171:5
--> $DIR/cfg_select.rs:170:5
|
LL | => {}
| ^^
error: expected a literal (`1u8`, `1.0f32`, `"string"`, etc.) here, found expression
--> $DIR/cfg_select.rs:176:5
--> $DIR/cfg_select.rs:175:5
|
LL | () => {}
| ^^ expressions are not allowed here
error[E0539]: malformed `cfg_select` macro input
--> $DIR/cfg_select.rs:181:5
--> $DIR/cfg_select.rs:180:5
|
LL | "str" => {}
| ^^^^^ expected a valid identifier here
error[E0539]: malformed `cfg_select` macro input
--> $DIR/cfg_select.rs:186:5
--> $DIR/cfg_select.rs:185:5
|
LL | a::b => {}
| ^^^^ expected a valid identifier here
error[E0537]: invalid predicate `a`
--> $DIR/cfg_select.rs:191:5
--> $DIR/cfg_select.rs:190:5
|
LL | a() => {}
| ^^^
error: expected one of `(`, `::`, `=>`, or `=`, found `+`
--> $DIR/cfg_select.rs:196:7
--> $DIR/cfg_select.rs:195:7
|
LL | a + 1 => {}
| ^ expected one of `(`, `::`, `=>`, or `=`
error: expected one of `(`, `::`, `=>`, or `=`, found `!`
--> $DIR/cfg_select.rs:202:8
--> $DIR/cfg_select.rs:201:8
|
LL | cfg!() => {}
| ^ expected one of `(`, `::`, `=>`, or `=`
warning: unreachable configuration predicate
--> $DIR/cfg_select.rs:137:5
--> $DIR/cfg_select.rs:136:5
|
LL | _ => {}
| - always matches
@@ -64,13 +64,13 @@ LL | true => {}
| ^^^^ this configuration predicate is never reached
|
note: the lint level is defined here
--> $DIR/cfg_select.rs:3:9
--> $DIR/cfg_select.rs:2:9
|
LL | #![warn(unreachable_cfg_select_predicates)] // Unused warnings are disabled by default in UI tests.
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
warning: unreachable configuration predicate
--> $DIR/cfg_select.rs:143:5
--> $DIR/cfg_select.rs:142:5
|
LL | true => {}
| ---- always matches
@@ -78,25 +78,25 @@ LL | _ => {}
| ^ this configuration predicate is never reached
warning: unreachable configuration predicate
--> $DIR/cfg_select.rs:150:5
--> $DIR/cfg_select.rs:149:5
|
LL | _ => {}
| ^ this configuration predicate is never reached
warning: unreachable configuration predicate
--> $DIR/cfg_select.rs:156:5
--> $DIR/cfg_select.rs:155:5
|
LL | test => {}
| ^^^^ this configuration predicate is never reached
warning: unreachable configuration predicate
--> $DIR/cfg_select.rs:158:5
--> $DIR/cfg_select.rs:157:5
|
LL | _ => {}
| ^ this configuration predicate is never reached
warning: unexpected `cfg` condition name: `a`
--> $DIR/cfg_select.rs:196:5
--> $DIR/cfg_select.rs:195:5
|
LL | a + 1 => {}
| ^ help: found config with similar value: `target_feature = "a"`
@@ -107,7 +107,7 @@ LL | a + 1 => {}
= note: `#[warn(unexpected_cfgs)]` on by default
warning: unexpected `cfg` condition name: `cfg`
--> $DIR/cfg_select.rs:202:5
--> $DIR/cfg_select.rs:201:5
|
LL | cfg!() => {}
| ^^^
@@ -1,4 +1,3 @@
#![feature(cfg_select)]
#![crate_type = "lib"]
// Check that parse errors in arms that are not selected are still reported.
@@ -1,5 +1,5 @@
error: Rust has no postfix increment operator
--> $DIR/cfg_select_parse_error.rs:8:22
--> $DIR/cfg_select_parse_error.rs:7:22
|
LL | false => { 1 ++ 2 }
| ^^ not a valid postfix operator
@@ -11,7 +11,7 @@ LL + false => { { let tmp = 1 ; 1 += 1; tmp } 2 }
|
error: Rust has no postfix increment operator
--> $DIR/cfg_select_parse_error.rs:15:29
--> $DIR/cfg_select_parse_error.rs:14:29
|
LL | false => { fn foo() { 1 +++ 2 } }
| ^^ not a valid postfix operator