Skip to content

Tracking issue for RFC 2523, #[cfg(version(..))] #64796

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
5 of 10 tasks
Centril opened this issue Sep 26, 2019 · 118 comments
Open
5 of 10 tasks

Tracking issue for RFC 2523, #[cfg(version(..))] #64796

Centril opened this issue Sep 26, 2019 · 118 comments
Labels
B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-cfg_version `#![feature(cfg_version)]` I-lang-radar Items that are on lang's radar and will need eventual work or consideration. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@Centril
Copy link
Contributor

Centril commented Sep 26, 2019

This is a tracking issue for #[cfg(version(..))] (rust-lang/rfcs#2523).

Steps:

Unresolved questions:

@Centril Centril added B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. T-lang Relevant to the language team, which will review and decide on the PR/issue. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC labels Sep 26, 2019
@Centril Centril added the F-cfg_version `#![feature(cfg_version)]` label Sep 26, 2019
csmoe added a commit to csmoe/rust that referenced this issue Sep 29, 2019
@pickfire
Copy link
Contributor

@csmoe Are you working on this? If not I might want to try out this task first since @petrochenkov mentioned that this task is easier than cfg(accessible = ::path).

@csmoe
Copy link
Member

csmoe commented Nov 16, 2019

@pickfire I didn't have much bandwidth on this, seems you have already made some progress on cfg(accessible = ::path), so feel free to check this :)
(Don't forget to assign yourself with @rustbot claim)

@pickfire
Copy link
Contributor

@csmoe Nice, thanks a lot for telling me that. I did not know such thing exist.

@rustbot claim

@rustbot rustbot self-assigned this Nov 16, 2019
@pickfire
Copy link
Contributor

Can anyone please help to write up the mentoring instructions. Based on what I know, this should be similar to #64797 (comment)

1. Syntax:
   
   1. Add a new `sym::accessible` in https://doc.rust-lang.org/nightly/nightly-rustc/src/syntax_pos/symbol.rs.html#22.
   2. Feature gate `accessible` in [`GATED_CFGS`](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/feature_gate/builtin_attrs/constant.GATED_CFGS.html). Also add `cfg_accessible` to `active.rs`: https://doc.rust-lang.org/nightly/nightly-rustc/src/syntax/feature_gate/active.rs.html#530. This will also require a new `sym::cfg_accessible`.
   3. Introduce a match arm for `sym::accessible` in [`cfg_matches`](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/attr/fn.cfg_matches.html). This should look mostly like [the case for `sym::not`](https://doc.rust-lang.org/nightly/nightly-rustc/src/syntax/attr/builtin.rs.html#591).
      Here you need to extract an [`&ast::Path`](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast/struct.Path.html) and delegate the interpretation to a function of the rough shape `fn is_accessible(sess: &ParseSess, path: &Path) -> bool { ... }`

2. Implement `fn is_accessible`.
   
   1. First do some validation. We want to emit errors if [`!path.is_global()`](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast/struct.Path.html#method.is_global). Use [`sess.span_diagnostic.struct_span_err`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_errors/struct.Handler.html#method.struct_span_err).

I believed step 1 and 2 should be the same. For step 3, based on what I know requires me to modify somewhere around

MetaItemKind::List(..) => {
error(cfg.span, "unexpected parentheses after `cfg` predicate key")
}
.

Based on fn is_accessible, the next thing to be done should be to implement fn min_version and then somehow reference version_check on how to do the min_version logic by checking the CFG_VERSION environment variable?

@mibac138
Copy link
Contributor

Hi, @pickfire. Are you still working on this?

@pickfire
Copy link
Contributor

No, I was stuck working on this and don't know how to proceed.

@mibac138
Copy link
Contributor

Ok, thanks for quick response. I'll take my shot at this.
@rustbot claim

@rustbot rustbot assigned rustbot and unassigned rustbot Apr 18, 2020
@pickfire
Copy link
Contributor

@mibac138 Do you want me to publish my progress?

@mibac138
Copy link
Contributor

@pickfire sure, that'd be great!

@pickfire
Copy link
Contributor

pickfire commented Apr 20, 2020

@mibac138 Err, no need. You have already done more than me, I don't know how to change the eval_condition. Oh, it didn't seemed that hard after looking at your PR but I didn't know how to work on that.

@petrochenkov
Copy link
Contributor

Status update: #71314 implemented this RFC with a slightly different syntax - #[cfg(version("1.2.3"))] instead of #[cfg(version(1.2.3))].

The reason is that 1.2.3 doesn't fit into some existing attribute-parsing infrastructure in the compiler (MetaItems), so it requires separate work.

Additionally, the version_check crate currently used to parse versions wants a string as an input, so we need to stringify 1.2.3 before passing it, which we can only do imprecisely (up to whitespaces).
So we can turn 1 . 2 .3 into e.g. "1.2.3" during stringification and it may be a problem depending on what exactly we are supposed to accept as a valid version.

Dylan-DPC-zz pushed a commit to Dylan-DPC-zz/rust that referenced this issue May 3, 2020
Implement RFC 2523, `#[cfg(version(..))]`

Hi! This is my first contribution to rust, I hope I didn't miss anything. I tried to implement this feature so that `#[cfg(version(1.44.0))]` works but the parser was printing an error that I wasn't sure how to fix so I just opted for implementing `#[cfg(version("1.44.0"))]` (note the quotes).

Tracking issue: rust-lang#64796
@roblabla
Copy link
Contributor

roblabla commented May 6, 2020

The RFC had an unresolved question about how this feature would interact with nightly/beta. Should #[cfg(version("1.45.0"))] return true or false for nightly/beta 1.45.0?

Currently, the implementation returns true. E.G. for rustc 1.45.0-nightly, the following code prints Yes:

#![feature(cfg_version)]
fn main() {
    test();
}

#[cfg(version("1.45.0"))]
fn test() {
    println!("Yes")
}

#[cfg(not(version("1.45.0")))]
fn test() {
    println!("No")
}

IMO, this is a mistake. The main use-case for cfg(version), at least for me, is to allow use of new features that are known to be stable at a given version. For instance, in the core-error crate, I was planning to use cfg(version) to implement my custom core::error::Error trait on the various error structures of libcore/liballoc automatically, based on cfg(version). Unfortunately, this is not possible as it will certainly cause breakage in the in-between nightly versions that are reported as implementing a version, whilst not having all the types associated with it.

@nikomatsakis
Copy link
Contributor

That sounds like good reasoning to me, but I've not been following this RFC that closely. @joshtriplett -- I feel like you were "liaison'ing" for this before we had a term for it, do you have a take?

@nikomatsakis
Copy link
Contributor

Nominating for lang-team meeting to discuss

@dekellum
Copy link

dekellum commented May 6, 2020

Currently, the implementation returns true

Which is most useful, the way it is, AFAICT.

Isn't there a way to combine this with cfg test(s) for "train", e.g. beta or nightly and unstable feature gates?

@Nemo157
Copy link
Member

Nemo157 commented May 6, 2020

Isn't there a way to combine this with cfg test(s) for "train", e.g. beta or nightly and unstable feature gates?

Code written for the stable compiler should not have to know about beta or nightly.

@dekellum
Copy link

dekellum commented May 6, 2020

I'm not surprised with that as a goal, but I can think of cases where for practical reasons I nead to dev on 1.45 nightly with expectation that it will then work on 1.45 stable. I'm surprised if I'm the only one.

@bjorn3
Copy link
Member

bjorn3 commented Aug 14, 2024

Be aware that the version field of stability attributes isn't always correct. For example if an item has been moved from libstd to libcore and re-exported in libstd, the libcore version has to retain the version when it was stabilized in libstd as re-exports can't override the version in which it was stabilized.

@Lokathor
Copy link
Contributor

Lokathor commented Aug 14, 2024

I'm unclear when a version cfg will always be false

@joshtriplett
Copy link
Member

@Lokathor With not. If you've written #[cfg(not(version(1.123)))] and you change your MSRV to be 1.123 or higher, Rust could offer to delete the code you've applied that conditional to. If you've written #[cfg(version(1.123))], Rust could offer to delete just the conditional while keeping the code you've applied it to.

@joshtriplett
Copy link
Member

joshtriplett commented Aug 14, 2024

@bjorn3 wrote:

Be aware that the version field of stability attributes isn't always correct. For example if an item has been moved from libstd to libcore and re-exported in libstd, the libcore version has to retain the version when it was stabilized in libstd as re-exports can't override the version in which it was stabilized.

Yeah, I realize. We won't necessarily be able to use the existing stability markers for library functions without additional care.

@Lokathor
Copy link
Contributor

Lokathor commented Aug 14, 2024

I think the main time a not would be applied is in a cfg-if context, in which case it would be really annoying to get warnings about that. So we could warn but the detection would have to be really smart

@joshtriplett
Copy link
Member

@Lokathor Even in cfg-if, it'd be helpful to get warnings to help you remove unused branches. But yes, we'll have to test and make sure we don't get false positives.

@RalfJung
Copy link
Member

RalfJung commented Oct 4, 2024

Regarding the question about what to do with nightly (which came up e.g. here and here), here's some real-world evidence: the fact that existing crates check the rustc version to decide which features they can use means if you are stuck on an old nightly, you may be unable to compile code even if that code's MSRV is older than the nightly you are using (i.e., a stable release from that time would work fine). See here for details.

So that would be an argument in favor of treating nightly with an off-by-1. Though it seems the current plan here is to add a -Z flag that does this, which would be sufficient as a work-around -- but could be hard to discover for affected users.

@juntyr
Copy link
Contributor

juntyr commented Oct 4, 2024

I’m working on a (so far) nightly-only crate and use cfg(version) to disable feature(…) attributes that are necessary for the crate’s MSRV but may no longer be needed on a later nightly.

I generally like the nightly+1 rule, since it errs on the side of robustness. However, the lint for using features that have already been stabilised starts firing as soon as stabilisation occurs on nightly. Whatever nightly version rule cfg(version) ends up going with, the lint should use the same one. If there is a mismatch, e.g. in case cfg(version) does use a nightly+1 rule again, the lint could be split into the current one which would also follow the +1 rule on nightly, and a separate one that would be allow-by-default and fire as soon as a feature is stabilised on nightly but only if the nightly version matches the stabilisation version.

@joshtriplett
Copy link
Member

joshtriplett commented May 14, 2025

I've been the primary person who has expressed that we need cfg(accessible(...)) before we stabilize cfg(version(...)), based on experience with the C ecosystem (e.g. compiler-version-based feature detection vs LLVM's much better __has_feature and __has_include and similar macros) and the browser ecosystem (feature detection vs version detection).

I'm withdrawing that objection, and I think we should go ahead and ship cfg(version(...)) as soon as it's ready to stabilize and we confirm that it behaves the way we expect.

I still believe it's incredibly important that we have accessible, and more things like it as well (e.g. named language features), in both rustc and cargo. But accessible has made good progress, and I trust that it'll still get finished and shipped even if version exists. And even once we have accessible, there will be more things we need as well to avoid version detection, and we shouldn't block version detection on all of them. Sometimes the easiest approach really is "this works in version 1.xy".

And on the flip side, the sooner we do ship version, the sooner the ecosystem can start using it, because only crates whose MSRVs are new enough to have stable cfg(version) support will be able to eliminate build scripts and similar.

cc @epage @rust-lang/lang

@traviscross
Copy link
Contributor

@rustbot labels -S-blocked +I-lang-radar

Given the above, if you are someone who is able and interested in putting together a stabilization PR with a stabilization report for cfg(version(..)), I'd encourage you to do that, and I'd estimate that it will receive a warm reception.

(Have a look at our new draft stabilization report template.)

@nvzqz
Copy link
Contributor

nvzqz commented May 14, 2025

@joshtriplett I appreciate the insight from your change in perspective. In particular:

the browser ecosystem (feature detection vs version detection)

This comparison to browsers puts into perspective for me that Rust using version detection in lieu of feature detection is actually fine, since Rust features are tied to versions unlike browser features which vary wildly across vendors.

Also, compile times have been a longstanding pain point of Rust adoption. So reducing the need for build scripts would be another big step along with the great effort that's been made in this area.

@rustbot rustbot added I-lang-radar Items that are on lang's radar and will need eventual work or consideration. and removed S-blocked Status: Blocked on something else such as an RFC or other implementation work. labels May 14, 2025
@epage
Copy link
Contributor

epage commented May 16, 2025

With this unblocked, I realized it would be good to stabilize the rustc and cargo sides at the same time. I've created rust-lang/cargo#15531 to track the Cargo side of this.

@est31
Copy link
Member

est31 commented May 16, 2025

I think a stabilization on the rust side should be pretty straightforward. The one big remaining issue I see is testing. There is only one test right now added by #71314, and it only checks the parsing, not the actual functionality. I suppose we can extend cfg(version) to read the env var added in #124339 and make a test based on that.

I will file a PR in the coming days. Also needs a stabilization report, but that one should be easy.

@est31
Copy link
Member

est31 commented May 17, 2025

Stabilization PR filed: #141137

I'd like the lang team to decide on whether stabilization should sync up with cargo, or it is better to have support for #[cfg(version)] in the language as early as possible.

There is also a limitation in the clippy lint incompatible_msrv, which should probably be addressed before stabilization: rust-lang/rust-clippy#14827

@Lokathor
Copy link
Contributor

I'm unclear on a point: What would be the effect of having it in rustc but not in cargo? Would it be usable on rustc somehow without the cargo support?

@est31
Copy link
Member

est31 commented May 17, 2025

@Lokathor the cargo side is tracked in rust-lang/cargo#15531. It's about supporting it in Cargo.toml, i.e.:

[target.'cfg(not(version(1.70.0))`.dependencies]
is-terminal = "0.4.2"

The rust side of course will work without cargo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. C-tracking-issue Category: An issue tracking the progress of sth. like the implementation of an RFC F-cfg_version `#![feature(cfg_version)]` I-lang-radar Items that are on lang's radar and will need eventual work or consideration. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests