Skip to content
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

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

Open
2 of 6 tasks
Centril opened this issue Sep 26, 2019 · 110 comments
Open
2 of 6 tasks

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

Centril opened this issue Sep 26, 2019 · 110 comments
Labels
B-RFC-approved Blocker: Approved by a merged RFC but not yet implemented. C-tracking-issue Category: A tracking issue for an RFC or an unstable feature. F-cfg_version `#![feature(cfg_version)]` S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. 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: A tracking issue for an RFC or an unstable feature. 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.

@alex
Copy link
Member

alex commented Apr 23, 2023

#64797 appears to have stalled out somewhat. I'd like to make an argument for why I believe it'd be appropriate to consider stabilizing this even before cfg(accessible(...)) is stabilized:

  1. There are many use cases for version checking beyond core library types being available. A particularly common one I've seen is version checking to see whether a particular piece of functionality can be used in const contexts.
  2. 3rd party crates for this functionality are already quite common version_check and autocfg both have more than 100 million downloads from crates.io. Under many circumstances, availability of adequate 3rd party crates would ameliorate the need for an in-language solution, however in this case they have a major downside: they require the use of build scripts, which impose a non-trivial compilation time overhead. Build speed is of course a major area of interest -- in a survey of a crate with 56 items in Cargo.lock, about half the build scripts are solely to do version checks.
  3. Because this functionality ultimately is aimed at enabling folks to support multiple versions of Rust more easily, its users won't be able to adopt it until its been stable for quite a while. Therefore getting it out sooner is a big benefit.

@karolherbst
Copy link

karolherbst commented Oct 6, 2023

I hit a bug in Rustc today, where rustc fails to derive Send and Sync automatically in some cyclic type relation context. This is fixed with 1.72, so my use case here would be to #[cfg(version(..))] an unsafe Send block to make sure code compiles with older Rustc.

This is important for the project I'm working on as it's Mesa, the OpenGL/Vulkan/OpenCL/etc.. implementation for the Linux desktop and we need to be mindful of what Rustc version to support.

Edit: Apparently it was Sync stabilized in 1.72 for mpsc::Sender

@mqudsi
Copy link
Contributor

mqudsi commented May 13, 2024

There are many use cases for version checking beyond core library types being available.

+1 to this, because you have to take the entire ecosystem and tooling into account and not just the language itself. For example, in rsconf 0.2, I added an api that uses rustc --check-cfg syntax to inform the compiler of a cfg managed by build.rs, but now building under older versions of rust that were aware of the check-cfg syntax but didn't have support for it enabled without -Z check-cfg are broken (if you error on warnings). This isn't a language level change but a tooling change, and so I would have to use #[cfg(version(1.80))] on the println!("cargo:rustc-check-cfg...") statement to get this to not warn under certain rust versions.

@wesleywiser
Copy link
Member

Nominating for lang-team discussion. This was marked as blocked on #64797 two years ago but #64797 still has open design questions and does not appear ready for stabilization anytime soon whereas this feature has no open design questions and is fully implemented. Since #64797 does not address some important use cases such as conditionally using compiler or language features and use of version_check continues to grow (now at >229M all-time downloads and upward-trending daily downloads), I think it makes sense to revisit stabilization of this feature 🙂

@rustbot label +I-nominated

@wesleywiser wesleywiser added the I-lang-nominated Nominated for discussion during a lang team meeting. label Jun 26, 2024
@mqudsi
Copy link
Contributor

mqudsi commented Jun 26, 2024

Not to add to the pressure or anything, but for a feature with the raison d’être being backwards compatibility this one won't be a viable alternative to the version_check crate until the msrv of the codebase hits whatever version cfg(version) was stabilized under. So it really makes sense to try and get this out the gate on its own without blocking on other tangentially related issues.

@Kixunil
Copy link
Contributor

Kixunil commented Jun 27, 2024

@mqudsi yes, though if the cfg gets renamed to lang_version as was suggested then people can already start using it in old crates for features that are only available in whichever version it gets stabilized. (Because unknown cfgs are allowed and evaluate to false.)

@traviscross
Copy link
Contributor

We discussed this in the lang call today. We had a question:

What's the situation on stabilizing a minimum version of cfg(accessible(..)), i.e. one that just works for things in core, std, etc.?

We understood there were issues with a more general version of the feature, and we understand there are some issues with paths in attributes, but we were unclear on whether stabilizing the most minimal cfg(accessible(..)) that we could was within the realm of possibility.

If it is within the realm of possibility, the feeling was generally that we'd prefer to do that, and that such a minimum version would resolve the concern here and allow for the stabilization of cfg(version(..)).

On the other hand, if it's not within the realm of short-term possibility for some reason, then people were open to reevaluating the approach here and whether other options might be possible for moving this forward.

@traviscross
Copy link
Contributor

@rustbot labels -I-lang-nominated

Going to unnominate this for now, but please renominate when the answer to the question above is available.

@rustbot rustbot removed the I-lang-nominated Nominated for discussion during a lang team meeting. label Jul 10, 2024
@Skgland
Copy link
Contributor

Skgland commented Jul 25, 2024

@mqudsi yes, though if the cfg gets renamed to lang_version as was suggested then people can already start using it in old crates for features that are only available in whichever version it gets stabilized. (Because unknown cfgs are allowed and evaluate to false.)

If stabilizing this soon is out of the question and in case renaming the cfg is not desirable, would it be possible to change the error to a future incompatibility warning now.
That way if this is stabilized some time in the future under the current name, one only needs to wait with using it until the msrv reaches the change from error to future incompatibility warning.

Similar to how cargo switched public/private dependencies to a non-blocking feature gate rust-lang/cargo#13308

@joshtriplett
Copy link
Member

Quick note on a potentially useful enhancement to this, once we have it: cargo could pass the crate's MSRV (from the rust-version field) into rustc, and rustc could check if the MSRV means a cfg will always be true or always be false, with an autofix to remove the cfg or remove the entire cfg'd code, respectively.

@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.

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: A tracking issue for an RFC or an unstable feature. F-cfg_version `#![feature(cfg_version)]` S-blocked Status: Marked as blocked ❌ on something else such as an RFC or other implementation work. 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