Skip to content

Add cfg_version support #15533

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open

Add cfg_version support #15533

wants to merge 5 commits into from

Conversation

mo8it
Copy link
Contributor

@mo8it mo8it commented May 16, 2025

What does this PR try to resolve?

#15531

@rustbot rustbot added A-build-scripts Area: build.rs scripts A-cfg-expr Area: Platform cfg expressions labels May 16, 2025
@mo8it
Copy link
Contributor Author

mo8it commented May 16, 2025

@epage I will of course take care of proper error handling, but I just want to get feedback on the initial direction.

cfg(nightly) can be already parsed as a Name.

@mo8it mo8it changed the title Start with cfg_version parsing cfg_version May 16, 2025
Copy link
Member

@weihanglo weihanglo left a comment

Choose a reason for hiding this comment

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

I just tweaked the PR description a bit. We usually keep a tracking issue open until stabilization.

@epage
Copy link
Contributor

epage commented May 16, 2025

cfg(nightly) can be already parsed as a Name.

I'm not sure what this is referring to as I don't see this in the RFC or the rustc version

@epage
Copy link
Contributor

epage commented May 19, 2025

Be sure to check out rust-lang/rust#141137 for a summary of what has changed from the RFC

@ehuss
Copy link
Contributor

ehuss commented May 20, 2025

A question came up about how older versions of cargo will handle this.

At least for a local package, this causes an error like:

failed to parse `version('1.80')` as a cfg expression: unexpected content `('1.80')` found after cfg expression

That seems fine to me.

However, I have a little more concern about how this impacts the index.

At a minimum, can you add a test that shows using a dependency from the index that itself uses a cfg() dependency? So, essentially, something like:

    Package::new("only_newer", "1.0.0").publish();
    Package::new("bar", "2.0.0")
        .file("src/lib.rs", "extern crate only_newer;")
        .target_dep("only_newer", "1.0", "cfg(version('1.89.0'))")
        .publish();

and having a regular dependency on bar. In my quick testing, this seems to be broken somehow, but I'm not sure how. Can you look into that?

Another thing to look into is if the crates.io parsing of the manifest will have any issues with this, or how it displays dependencies.

Unfortunately we don't have very good infrastructure for checking that older versions of cargo work with newer versions of the index. I think the best we have right now is #[cargo_test(requires_rustup_stable)], where we can make sure stable is compatible with what is generated by nightly. But that doesn't really help with a fixed version like "does rust 1.87 stay compatible with nightly". We have a whole module for doing that (https://github.com/rust-lang/cargo/blob/HEAD/tests/testsuite/old_cargos.rs), but those tests are disabled due to the cost.

If we are able to figure some way to test older versions, then one approach would be to make sure the index for a crate has a mix of old and new cfgs. So something like:

    Package::new("only_newer", "1.0.0").publish();
    Package::new("bar", "1.0.0").publish();
    Package::new("bar", "2.0.0")
        .file("src/lib.rs", "extern crate only_newer;")
        .target_dep("only_newer", "1.0", "cfg(version('1.89.0'))")
        .publish();

where you have a dependency on bar = "1.0" should still work on older versions of cargo (that is, they should not choke on the 2.0 index entry). AFAIK, that should be fine, since older cargos are supposed to ignore index entries it can't parse. However, I don't remember where cargo parses the cfg strings, and I don't want old versions to choke on that.

@rustbot rustbot added the A-build-execution Area: anything dealing with executing the compiler label May 20, 2025
@mo8it mo8it requested a review from epage May 20, 2025 17:59
@mo8it mo8it marked this pull request as ready for review May 20, 2025 17:59
@rustbot
Copy link
Collaborator

rustbot commented May 20, 2025

r? @ehuss

rustbot has assigned @ehuss.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label May 20, 2025
Comment on lines 171 to 201
match *self {
CfgExpr::Not(ref e) => !e.matches(cfg),
CfgExpr::All(ref e) => e.iter().all(|e| e.matches(cfg)),
CfgExpr::Any(ref e) => e.iter().any(|e| e.matches(cfg)),
CfgExpr::Not(ref e) => !e.matches(cfg, rustc_version),
CfgExpr::All(ref e) => e.iter().all(|e| e.matches(cfg, rustc_version)),
CfgExpr::Any(ref e) => e.iter().any(|e| e.matches(cfg, rustc_version)),
CfgExpr::Value(Cfg::Version(CfgRustVersion { minor, patch })) => {
match minor.cmp(&rustc_version.minor) {
Ordering::Less => true,
Ordering::Equal => patch <= rustc_version.patch,
Ordering::Greater => false,
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I believe the tracking issue mentions specific behavior for nightlies

  • 1.80 includes 1.80 nightlies
  • 1.80.0 does not include 1.80 nightlies

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not quite following this. Can you say more about where that is being discussed? That doesn't seem to be the current behavior.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe I'm misinterpeting what was said in

Ultimately, a compromise was agreed upon, in which nightly releases are treated as "complete" i.e. cfg(version(1.20)) evals to true on nightly builds with version 1.20.0, but there is a nightly flag -Z assume-incomplete-release to opt into the behaviour that doesn't do this assumption. This compromise was implemented in PR rust-lang/rust#81468.

The actual rustc tests should be checked to confirm. We probably should most or all of their tests.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Did I get the desired logic here?

let v89_nightly = semver::Version {
major: 1,
minor: 89,
patch: 0,
pre: Prerelease::new("nightly").unwrap(),
build: BuildMetadata::EMPTY,
};
assert!(e!(version(89)).matches(&[], &v89_nightly));
assert!(!e!(version(89, 0)).matches(&[], &v89_nightly));
assert!(e!(version(88)).matches(&[], &v89_nightly));
assert!(e!(version(88, 0)).matches(&[], &v89_nightly));

pub fn matches(&self, rustc_version: &semver::Version) -> bool {
match self.minor.cmp(&rustc_version.minor) {
Ordering::Less => true,
Ordering::Equal => match self.patch {
Some(patch) => {
if rustc_version.pre.as_str() == "nightly" {
false
} else {
patch <= rustc_version.patch
}
}
None => true,
},
Ordering::Greater => false,
}
}
}

Comment on lines +821 to +840
#[cargo_test]
fn cfg_version() {
let p = project()
.file(
"Cargo.toml",
r#"
[package]
name = "a"
edition = "2015"

[target.'cfg(version("1.87.0"))'.dependencies]
b = { path = 'b' }
"#,
)
.file("src/lib.rs", "extern crate b;")
.file("b/Cargo.toml", &basic_manifest("b", "0.0.1"))
.file("b/src/lib.rs", "")
.build();
p.cargo("check -v").run();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I wish we had a way to override the rust version so we could test with 1.2345 (the version we always use for "far future" in tests)

Copy link
Contributor

Choose a reason for hiding this comment

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

Could we use RUSTC_FORCE_RUSTC_VERSION?

@rustbot

This comment has been minimized.

@epage epage changed the title cfg_version Add cfg_version support May 21, 2025
@mo8it
Copy link
Contributor Author

mo8it commented May 21, 2025

@epage Thanks for rewriting the history. I found it a bit disappointing that I wasn't listed as an author anymore. Therefore, I updated the author information of the commits and hope that you are happy with the current state.

I also fixed the CI by removing dbg!(input).

Finally, I resolved the merge conflicts.

Learning jj today helped a lot :D

If we agree on #15533 (comment), then the PR should be ready for merging.

@epage
Copy link
Contributor

epage commented May 21, 2025

I found it a bit disappointing that I wasn't listed as an author anymore.

Sorry that I forgot to preserve that!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-build-execution Area: anything dealing with executing the compiler A-build-scripts Area: build.rs scripts A-cfg-expr Area: Platform cfg expressions S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants