Rollup merge of #141413 - est31:cfg_version_env_var, r=jieyouxu

Make #[cfg(version)] respect RUSTC_OVERRIDE_VERSION_STRING

The `#[cfg(version(...))]` feature is currently under-tested. Part of it is the difficulty that it is hard to write a test that never changes, while the version of the Rust compiler indeed *does* change.

PR #81468 added the first and so far only test of `#[cfg(version(...))]`'s functionality (there is one other test for the *syntax*, that also acts as feature gate). But that test uses a proc macro that parses the version: the text of the test doesn't contain the actual `#[cfg(version(...))]`.

This PR makes `#[cfg(version(...))]` respect `RUSTC_OVERRIDE_VERSION_STRING`, added by PR #124339, allowing us to virtually pin the rustc version and write tests from all directions against some specific version.

The PR also adds a functional test of `#[cfg(version(...))]` that leverages `RUSTC_OVERRIDE_VERSION_STRING`.

Pulled out of #141137.

Tracking issue: #64796
This commit is contained in:
Guillaume Gomez 2025-05-25 15:11:47 +02:00 committed by GitHub
commit b0ae228007
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 71 additions and 2 deletions

View file

@ -1,4 +1,5 @@
use std::fmt::{self, Display};
use std::sync::OnceLock;
use rustc_macros::{
Decodable, Encodable, HashStable_Generic, PrintAttribute, current_rustc_version,
@ -16,8 +17,29 @@ pub struct RustcVersion {
impl RustcVersion {
pub const CURRENT: Self = current_rustc_version!();
pub fn current_overridable() -> Self {
*CURRENT_OVERRIDABLE.get_or_init(|| {
if let Ok(override_var) = std::env::var("RUSTC_OVERRIDE_VERSION_STRING")
&& let Some(override_) = Self::parse_str(&override_var)
{
override_
} else {
Self::CURRENT
}
})
}
fn parse_str(value: &str) -> Option<Self> {
// Ignore any suffixes such as "-dev" or "-nightly".
let mut components = value.split('-').next().unwrap().splitn(3, '.');
let major = components.next()?.parse().ok()?;
let minor = components.next()?.parse().ok()?;
let patch = components.next().unwrap_or("0").parse().ok()?;
Some(RustcVersion { major, minor, patch })
}
}
static CURRENT_OVERRIDABLE: OnceLock<RustcVersion> = OnceLock::new();
impl Display for RustcVersion {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{}.{}.{}", self.major, self.minor, self.patch)

View file

@ -129,9 +129,9 @@ pub fn eval_condition(
// See https://github.com/rust-lang/rust/issues/64796#issuecomment-640851454 for details
if sess.psess.assume_incomplete_release {
RustcVersion::CURRENT > min_version
RustcVersion::current_overridable() > min_version
} else {
RustcVersion::CURRENT >= min_version
RustcVersion::current_overridable() >= min_version
}
}
MetaItemKind::List(mis) => {

View file

@ -0,0 +1,30 @@
//@ run-pass
//@ rustc-env:RUSTC_OVERRIDE_VERSION_STRING=1.50.3
#![feature(cfg_version)]
#[cfg(version("1.49.0"))]
const ON_1_49_0: bool = true;
#[cfg(version("1.50"))]
const ON_1_50_0: bool = true;
#[cfg(not(version("1.51")))]
const ON_1_51_0: bool = false;
// This one uses the wrong syntax, so doesn't eval to true
#[warn(unexpected_cfgs)]
#[cfg(not(version = "1.48.0"))] //~ WARN unexpected `cfg` condition name: `version`
const ON_1_48_0: bool = false;
fn main() {
assert!(!ON_1_48_0);
assert!(ON_1_49_0);
assert!(ON_1_50_0);
assert!(!ON_1_51_0);
assert!(cfg!(version("1.1")));
assert!(cfg!(version("1.49")));
assert!(cfg!(version("1.50.0")));
assert!(cfg!(version("1.50.3")));
assert!(!cfg!(version("1.50.4")));
assert!(!cfg!(version("1.51")));
assert!(!cfg!(version("1.100")));
}

View file

@ -0,0 +1,17 @@
warning: unexpected `cfg` condition name: `version`
--> $DIR/cfg-version-expand.rs:15:11
|
LL | #[cfg(not(version = "1.48.0"))]
| ^^^^^^^^^^^^^^^^^^
|
= help: to expect this configuration use `--check-cfg=cfg(version, values("1.48.0"))`
= note: see <https://doc.rust-lang.org/nightly/rustc/check-cfg.html> for more information about checking conditional configuration
= note: `#[warn(unexpected_cfgs)]` on by default
help: there is a similar config predicate: `version("..")`
|
LL - #[cfg(not(version = "1.48.0"))]
LL + #[cfg(not(version("1.48.0")))]
|
warning: 1 warning emitted