RFC: #[cfg(accessible(..) / version(..))] by Centril · Pull Request #2523 · rust-lang/rfcs (original) (raw)
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
[ Show hidden characters]({{ revealButtonHref }})
, Ixrec, est31, wesleywiser, stepancheg, liigo, retep998, tmccombs, imp, tux3, and 35 more reacted with thumbs up emoji upsuper, tmccombs, alexander-irbis, alexreg, shekohex, peddermaster2, and Kobzol reacted with hooray emoji Evrey, kinggoesgaming, alexander-irbis, glandium, shekohex, dhardy, oconnor663, estebank, jonhoo, fintelia, and 5 more reacted with heart emoji
Relevant to the language team, which will review and decide on the RFC.
label
Centril changed the title
RFC: #[cfg(accessible(..) / version(..) / nightly)] RFC: #[cfg(accessible(..) / version = ".." / nightly)]
(a) Might changing the name from
version
, to something likemin_rustc_version(1.38)
clarify that its both a>=
bounds and only relevant to rustc versions (not any other compiler)?
Two points here:
- It is relevant to all Rust compilers, not just
rustc
. ;) min_version
might be a reasonable attribute name if we collectively thinkversion
is too ambiguous.version(>= 1.37)
could also work. Tho I feel @joshtriplett provides a good rationale for whyversion(1.37)
makes sense (in fact, Cargo semver= X.Y.Z
is the inspiration for the concrete syntax). If people can cope with Cargo.toml's way of encoding bounds then they should be able to cope withversion(...)
.
(b) Feature names could be made as specific as necessary to account for changes during the stabilization process. So for example maybe a feature we effectively have now on latest nightly is named
async_await_2
. Prior versions (_1 or _0) might have been for theawait!()
macro or even for more minor but still breaking differences, like before rust-lang/rust#64292 was merged. If the feature changes in any other breaking ways before stabilization, then the stable version could be namedasync_await_3
, otherwise `async_await_2 could remain valid on stable releases with the benefit that code started on nightly could potentially just work on some subsequent stable.
The breaking ways may not affect everyone using a specific feature. As such, it may create needless churn on nightly and additionally discourage folks from using nightly. Speaking as a rustc developer myself, keeping track of this also doesn't sound like much fun to be honest.
On keeping the version
name:
like a Cargo semver bound,
version(>= 1.37) could also work
I'd personally favor using an explicit ^1.37
or >= 1.37
then, for clarity, just like I tend to do in Cargo.toml. That works for me. Note the former implies "<2", a hypothetical concern.
On my suggestion of versioning or sub-feature name suffixes:
keeping track of this also doesn't sound like much fun to be honest.
I'm just suggesting that the current RFCs feature design, would allow such a scheme as a tool to manage the breakage and selectively allow future-proofing. If you don't want to use that tool, that is your prerogative. :)
This flag requires that a `path` fragment be specified in it inside parenthesis |
---|
but not inside a string literal. The `$path` must start with leading `::` |
and may not refer to any parts of the own crate (e.g. with `::crate::foo`, |
`::self::foo`, or `::super::foo` if such paths are legal). |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this imply that #[cfg(accessible(path)]
can be used with dependencies other than core
or std
? For example, can I write #[cfg(accessible(::lazy_static::lazy_static)]
?
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, you can do that.
We say that a release announcement of a new version of Rust includes a new version of the language version. Before this RFC, this is purely a rhetorical/theoretical/social device. Nothing can see the language version. It doesn't exist mechanically. This RFC changes that to something that is mechanical, and that should, IMO, be mentioned as a drawback, if only for academic purposes. Any industrial second implementation (Note: I don't expect there to ever be one) would have to understand the feature set of each six week release to properly set their version.
It also semi-locks us into this release versioning scheme. I say semi-locks because we could at any time freeze the cfg(version(...)) version if we decide it's bad or retroactively tie it to rustc's version instead.
`rustc` in the numbering and what features it provides. This is probably not |
---|
too unreasonable as we can expect `rustc` to be the reference implementation |
and that other ones will probably lag behind. Indeed, this is the experience |
with `GHC` and alternative Haskell compilers. |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A drawback of this approach is that using #[cfg(version(1.28))]
would make libsyntax fail to parse this syntax on all pre-existing toolchains.
That is, if you have to support toolchains older than whatever toolchain version this attribute is this shipped in, you need to put the #[cfg(version(...))]
behind a feature gated module like this to avoid older toolchains from trying to parse it:
// In the module where you actually want to use #[cfg(version)]
cfg_if! {
if #[cfg(toolchain_supports_cfg_version)] {
mod internal;
use internal::*;
}
}
// and then in a separate internal.rs file #[cfg(version(1.42))] struct Foo;
and then have a build.rs
that detects the rust toolchain version and sets --cfg toolchain_supports_cfg_version
.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and then have a build.rs that detects the rust toolchain version and sets --cfg toolchain_supports_cfg_version.
I mean, at that point, we can just implement this as a library that can be easily used from build.rs
to define such config macros, which would allow the code above to just be written as:
// In the module where you actually want to use #[cfg(version)]
#[cfg(rust_ge_1_42_0)]
struct Foo;
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the following syntax does not have this problem and is IIRC backward compatible down to Rust 1.0:
#[cfg(rust_version = "1.42.0")] // in the cargo sense struct Foo;
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@gnzlbg I think everyone considering using this feature understands that it will only work going forward, in versions that support version
and accessible
. That's still quite useful.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@joshtriplett when it comes to older versions, there's a difference between "doesn't work" and "can't be parsed". I'd like to avoid the second situation if possible.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does bring though the idea that whichever release version
becomes stable will probably become the new minimum stable rust version that a lot of libraries will bump to. It might be good to pair it's release with a major feature(s) so that the most amount of people can be benefit from them.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably not that difficult to support two versions; it's mostly just a bit of parsing inside or outside the string and they'll be uniform otherwise.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@XAMPPRocky that's pretty clever =P will just have to find some major feature to couple with heh.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does bring though the idea that whichever release version becomes stable will probably become the new minimum stable rust version that a lot of libraries will bump to.
At best, depending on how cfg(version)
is shipped, projects might be able to just use it for detecting newer features, but it will live alongside the feature-detection code that these projects are already using. The "old" feature detection code is simple and low maintenance, so bumping the MSRV to be able to exclusively use cfg(version)
is something that doesn't add much value, while compromising something that's important for these project: the only reason a project would do feature detection is to be able to support older toolchains, so the project must see value in that.
I think that maybe eventually all projects might be able to just use cfg(version)
, but that will be a consequence of them bumping the MSRV due to other issues, and not because there is a lot of value in bumping the MSRV to a toolchain that supports cfg(version)
.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At best, depending on how cfg(version) is shipped, projects might be able to just use it for detecting newer features
I don't think cfg(version)
has to be immediately valuable. Eventually more features will be covered under cfg(version)
than those features that aren't, and then it will be more compelling for more libraries.
so bumping the MSRV to be able to exclusively use cfg(version) is something that doesn't add much value
Unless your MSRV is one version behind cfg(version)
your value won't be exclusively cfg(version)
. If your MSRV is 1.15 for example and cfg(version)
was released in 1.40.0 you'd be getting everything from 1.16.0–1.40.0, and you'd be able to use cfg(version)
to ease future feature development.
Another point is that things that are gated sill need to use valid rust grammar.
Let's assume that the version 1.42 adds support for throwing function, and using .if:
#[cfg(version(1.42))]
fn foo(x : bool) -> u32 throw(SomeError) {
x.if { something() } else { 0 }
}
This won't compile in current rust, even after this rfc is implemented, because this is not valid grammar, and rustc still check the grammar of items even if they are going to be removed by attribute macro or cfg attribute.
I suppose it would not make sense to relax the parsing rules of items that are disabled by #[cfg]
So one must wrap the item inside a macro such as cfg-if!{...}
but which would not expand the items for the disabled configuration. Something like this should work: #[cfg($cfg)] identity!{ <span class="katex"><span class="katex-mathml"><math xmlns="http://www.w3.org/1998/Math/MathML"><semantics><mrow><mo stretchy="false">(</mo></mrow><annotation encoding="application/x-tex">(</annotation></semantics></math></span><span class="katex-html" aria-hidden="true"><span class="base"><span class="strut" style="height:1em;vertical-align:-0.25em;"></span><span class="mopen">(</span></span></span></span>body)* }
.
Btw, I've made a crate with a macro if_rust_version
with macro_rules that allows conditional like that depending on the rust version: https://github.com/ogoffart/if_rust_version
The final comment period, with a disposition to merge, as per the review above, is now complete.
As the automated representative of the governance process, I would like to thank the author for their work and everyone else who contributed.
The RFC will be merged soon.
rfcbot removed the final-comment-period
Will be merged/postponed/closed in ~10 calendar days unless new substational objections are raised.
label
This was referenced
Sep 26, 2019
Centril deleted the rfc/cfg-path-version branch
epage mentioned this pull request
epage mentioned this pull request
epage mentioned this pull request
6 tasks
Reviewers
eddyb eddyb left review comments
Nemo157 Nemo157 left review comments
kennytm kennytm left review comments
joshtriplett joshtriplett left review comments
gnzlbg gnzlbg left review comments
jethrogb jethrogb left review comments
Aaron1011 Aaron1011 left review comments
jrvidal jrvidal left review comments
XAMPPRocky XAMPPRocky left review comments
pickfire pickfire left review comments
rizakrko rizakrko left review comments
Labels
Conditional compilation related proposals & ideas
Path related proposals & ideas
Versioning related proposals & ideas
This RFC is in PFCP or FCP with a disposition to merge it.
The final comment period is finished for this RFC.
Relevant to the language team, which will review and decide on the RFC.