You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: text/0000-version-typed-cfgs.md
+5-3Lines changed: 5 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -253,6 +253,7 @@ This section is subject to change prior to stabilization.
253
253
- Making the perfect the enemy of the good. RFC 2523 was accepted, and an implementation of its `version()` predicate is ready.
254
254
- Increased compiler complexity. This introduces a new concept of "typed"`cfg`s into the compiler, which adds complexity to the parsing and evaluation logic for conditional compilation.
255
255
- Subtlety of MSRV-preserving patterns: The need for the "stacked `cfg`" pattern (`#[cfg(rust_version)] #[cfg(rust_version >= ...)]` and `#[cfg_attr(rust_version, cfg(rust_version >= ...))]`) is subtle. While we will add lints to guide users, it's less direct than a simple predicate. However, this subtlety is the explicit tradeoff made to achieve MSRV compatibility.
256
+
- The MSRV-preserving pattern still does not allow using the feature to check for versions prior to when this feature was introduced.
256
257
- The "stacked `cfg`" pattern does not work inside Cargo, so users will not be able to use this feature in Cargo until their MSRV is bumped. For cases where a dependency needs to be conditional on the Rust version, one can define a "polyfill" crate and make use of the MSRV-aware feature resolver, like the `is_terminal_polyfill` crate does.
257
258
- Conditional compilation adds testing complexity. In practice, most crate maintainers only test their MSRV and the latest stable.
258
259
- This does not support branching on specific nightly versions. rustversion supports this with syntax like `#[rustversion::since(2025-01-01)]`.
@@ -283,7 +284,7 @@ The syntax of this RFC was [left as an open question](https://github.com/rust-la
283
284
* The word `version` does not sufficiently communicate that it's the Rust version we're talking about.
284
285
* The mechanism is special-purpose and geared toward one use case (detecting the Rust version).
285
286
* The function-call syntax, chosen forconsistency with `cfg(accessible())`, isn't obvious enoughin its meaning and does not cleanly extend to new kinds of comparisons. A recent poll of the lang team showed that most people opposed extending that syntax to include other kinds of comparisons within the quotes, like `version("< 1.2.3")`. At the same time, it adds another level of nested parantheses, which can be hard for humans to parse.
286
-
* Crates supporting old MSRVs won't be able to use the feature until bumping their MSRV.
287
+
* Crates supporting old MSRVs won't be able to use the feature until bumping their MSRV. (Note that even in this RFC, crates with existing feature gates using build scripts won't be able remove their build scripts until the last legacy feature gate falls outside their MSRV window.)
287
288
* The RFC was accepted more than 6 years ago. During this time we've learned about more adjacent use cases and directions we would like to evolve the language. If designed today, the feature would look much more like this RFC than RFC 2523.
288
289
289
290
### Alternative 2: `#[cfg(rust_version = "1.85")]` (meaning `>=`)
@@ -341,7 +342,7 @@ This RFC aims to obviate the need for these external dependencies for the common
341
342
342
343
- **Clang/GCC (`__has_feature`, `__has_attribute`)**: These function-like macros allow forchecking for the presence of specific compiler features, rather than the overall language version. For example, `__has_feature(cxx_rvalue_references)` checks for a specific language feature. This approach is more granular but also more verbose if one needs to check for many features at once. This approach was discussedin RFC #2523, but rejected, in part because we wanted to reinforce the idea of Rust as "one language" instead of a common subset with many compiler-specific extensions.
343
344
344
-
- **Python (`sys.version_info`)**: Python exposes its version at runtime via `sys.version_info`, a tuple of integers `(major, minor, micro, ...)`. Code can check the version with standard tuple comparison, e.g., `if sys.version_info >= (3, 8):`. This component-wise comparison is very similar to the logic proposed in this RFC. However, because Python is interpreted, a file must be syntactically valid for the interpreter that is running it, which makes it difficult to use newer syntax in a file that must also run on an older interpreter. Rust, being a compiled language with a powerful conditional compilation system, does not have this limitation, and this RFC's design takes full advantage of that.
345
+
- **Python (`sys.version_info`)**: Python exposes its version at runtime via `sys.version_info`, a tuple of integers `(major, minor, micro, ...)`. Code can check the version with standard tuple comparison, e.g., `if sys.version_info >= (3, 8):`. This component-wise comparison is very similar to the logic proposed in this RFC. However, because Python is interpreted, a file must be syntactically valid forthe interpreter that is running it, which makes it difficult to use newer syntaxin a file that must also run on an older interpreter. Rust, being a compiled language with a powerful conditional compilation system, does not have this limitation, and this RFC's design takes full advantage of that. Python also supports sophisticated version handling in its packaging ecosystem (PEP 440), including arbitrary precision and pre/post releases.
345
346
346
347
## Versioning systems
347
348
@@ -361,8 +362,9 @@ Operating systems include many versions, including kernel versions, public OS ve
361
362
# Unresolved questions
362
363
[unresolved-questions]: #unresolved-questions
363
364
364
-
- How should pre-release identifiers in version strings be handled? This RFC proposes not supporting pre-release identifiers in version strings passed on the command line for now. For comparisons, this RFC proposes that if a pre-release identifier is present in a `cfg` predicate (e.g., `rust_version < "2.0-alpha"`), the pre-release part is ignored for the comparison (so it's treated as `2.0`), and a lint is emitted. This ensures forward compatibility, as comparisons like `cfg(all(foo >= "2.0-alpha", foo <"2.0"))` become trivially false on older compilers, which is a safe outcome. This behavior can be refined before stabilization.
365
+
- How should pre-release identifiers in version strings be handled? This RFC proposes not supporting pre-release identifiers in version strings passed on the command line fornow. For comparisons, this RFC proposes that if a pre-release identifier is presentin a `cfg` predicate (e.g., `rust_version <"2.0-alpha"`), the pre-release part is ignored for the comparison (so it's treated as `2.0`), and a lint is emitted. This ensures forward compatibility for valid versions, as comparisons like `cfg(all(foo >= "2.0-alpha", foo < "2.0"))` become trivially false on older compilers. However, if future semantics define `2.0-alpha < 2.0`, then ignoring the suffix now (treating `2.0-alpha` as `2.0`) means `foo < "2.0"` evaluates to `false` now but could evaluate to `true` later, which is a breaking change. We need to decide if this risk is acceptable or if we should error on pre-releases for now.
365
366
- Should the builtin `rust_version` and `rust_edition` be printed with `--print cfg` on the command line? We'd like the eventual answer to be "yes", but existing tools that parse the output might break with the new `rust_version=version("1.99")` syntax. If we can manage the breakage we should; otherwise we can gate it on a future edition.
367
+
- How should `cargo` expose version-typed `cfg`s to build scripts? Should `--cfg foo=version("1.0")` result in`CARGO_CFG_FOO=1.0` or `CARGO_CFG_FOO=version("1.0")`? This is technically out of scope for this RFC but important for the ecosystem.
0 commit comments