Nudging users off 2015 edition

There are real costs to having 2015-edition Rust source code, and arguably no benefits. I think rustc and Cargo should start warning about crates still using the 2015 edition and encourage moving to a newer edition.

  • users who try to use rustc directly get caught by the edition 2015 default, and find Rust being "weird" and rejecting code that works in Cargo and the Rust playground. Even tough invoking rustc directly isn't the best way to get started with Rust, people coming from C expect this to work, at least for basic no-dependency cases to try things out. rust.godbolt.org struggled with the bad default and had to add an implicit default --edition flag, but for some reason they're not showing the flag in their UI, which makes local rustc invocations even more surprising.

  • the 2015 module system and bare trait syntax has unintuitive gotchas — it has been changed for a reason. Reviewing code and contributing to projects still on edition 2015 requires users learning the old behaviors that Rust has moved away from.

  • syn can't parse nameless function arguments allowed in edition 2015, which breaks syn-based Rust tooling on dependencies that haven't fixed that syntax.

OTOH there's no reason to stay on 2015 edition any more:

  • the last rustc that actually required it was 1.30. That version is completely truly utterly dead by now, and it's pretty unusable compared to modern Rust (no NLL, no async, no mut aliasing fixes in LLVM). In crates.io traffic less than 0.16% of all requests came from any Rust version older than 1.60.

  • there's cargo fix --edition

  • the 2018 edition doesn't have these problems, and it's still super super old, even older than Debian oldoldstable.

17 Likes

I think we're warning now when you don't provide an edition. If you explicitly say --edition=2015 or edition = "2015", I don't think we should do anything.

9 Likes

I think my core problem with this is that I don't know the avatar of who is still explicitly using 2015 who actually wants to upgrade. Seems like they would have already if they were going to.

Certainly anyone reviewing code on 2015 who's annoyed by the module system differences could just say "hey, we should migrate"; no lints needed.

(Unintentional use is different, but there's a new warning about that, as @chrefr said.)

But that's only relevant if the code in edition 2015 is using something using syn, right? If it's an old dependency that doesn't use syn, then whatever? (And of course syn itself can report errors suggesting upgrades without rust needing to do anything.)

5 Likes

That's the point. The remaining users are most likely unaware and using it by accident.

No. I don't mean it from proc-macro perspective. syn is used for more than that, including external tooling that parses other crates' code.

I'm writing a tool that aids in code reviews of deps for supply-chain-security purposes. I need to parse arbitrary crates, including some deps-of-deps of my deps that happen to still have edition 2015 syntax. My tool based on syn chokes on them (and I use syn despite its limitations, because running rustc or rust-analyzer on untrusted code is unwise).

2 Likes

Did syn explicitly make this choice, or is it a bug?

edit -- I found parsing issue noticed in cbindgen · Issue #733 · dtolnay/syn · GitHub

We don't support parsing 2015-only code in general.

4 Likes

Cargo warns but not bare rustc.

GCC has updated its defaults over the users so maybe rustc could start warning eventually.

This warning could/should be an error, and the message could indicate that upgrading is preferred over suppressing when --edition={$sufficiently_old}. But some percentage of crates are going to be 2015 until a plan is made to EOL it.

Base rustc warning was accepted less than a month ago: Emit `note` when calling `rustc` without specifying an edition · Issue #1019 · rust-lang/compiler-team · GitHub

It's planned to happen, even if it's not merged yet.

11 Likes

The entire point of editions is that they have no EOL.

15 Likes

Even if we never remove an edition, perhaps we could eventually make it an error to not pass an edition explicitly to rustc though. Or change what the default edition is (C and C++ compilers change the default over the years, but you can still pass -std=c89).

And perhaps it would be possible to start warning even when the edition is old enough even when it is passed explicitly. Something like "you probably didn't want this"

5 Likes

I would have said that the point is to ease transitions to newer versions of the language. I don't know what percentage of users are using the 2015 edition on purpose and for a good reason, but there ought to be some percentage that no longer outweighs incurred maintenance costs.

It would be nice if older editions could be "supported" by tools running cargo fix --edition and then running only against the modified code. But my guess is that's more effort than it sounds like.

1 Like

That sort of warning probably belongs in Clippy - if you've explicitly asked for an old edition (for whatever reason - maybe you've been given a codebase full of unjustified unsafe from 2017 to maintain, and need to bring it forward with care and thought), then it's obvious that you're on an ancient edition from the sources (since you'll find edition = 2015 in Cargo.toml or your Bazel rules file or whatever, or --edition 2015 in a rustc invocation from your custom build script).

But first step needs to be to require an explicit edition - I suspect that most of the problematic cases of edition 2015 code will be caught by not allowing an implicit edition, and suggesting cargo fix --edition to fix them up.

1 Like

I think there's value in not making it any harder than it already is to compile some code of yore, exhumed from a phpBB post attachment, that happens to solve a particular problem.

That said, I like the idea of gently encouraging developers of new code and maintainers of code that is maintained to use the latest edition. So, preferably, no to hard errors/enforcement, but yes to up-to-date defaults and notifications if they can be implemented such that they don't cause the former.

2 Likes

I don't agree. That would be breaking. The point of editions is that old projects keep working, and users upgrade on their own pace, even if that takes more than a decade.

It's okay to print warnings to complain. It may be okay to make the warning cause an error when -D warnings is used (that's user asking for spurious failures), but the old edition and bare invocation should continue working by default. rustc could be called indirectly by other tools, build systems, or some script that checks if a "hello world" compiles. It's annoying when such integrations break.

11 Likes

I think we're warning now when you don't provide an edition.

I created an empty 2015-edition project and removed the edition field from Cargo.toml:

  • cargo check: warning
  • rust-analyzer: no warning

Do you have check on save enabled? If yes, that's probably because the warning has no span attached to it.

Likely this is because the warning is coming from cargo, not rustc, and cargo does not report warnings or errors programmatically (yet).

One potential problem with this is that it limits the options for setting MSRV.

When writing a program, I have to decide which Rust versions I want to target with it. In other languages, this would normally be "target the oldest version which has all the features that I want to use" (as I don't see much of a reason to arbitrarily limit what platforms I can run on). Supporting old versions can matter if, e.g., you want to build the program on an old computer that only has an old version of the compiler available (because that's what's on the hard drive and because the computer doesn't or shouldn't be connected to the Internet, so it can't download a newer version).

In Rust, applying this rule can occasionally lead to being forced to use the 2015 edition (e.g. a crate I wrote recently would work back to 1.26 if I wrote it in the 2015 edition, because the newest feature it uses is argument-position impl Trait). One reason not to do this is doctests (you want them to be in modern syntax to make the documentation easier to read, which may require picking a later edition for the syntax to work), but in this case, none of the doctests were doing anything that would differ between 2015 and 2024 syntax. (While writing this comment, I decided to actually test the crate on 1.26 to make sure that it would work back that far. Not only did it work (after adjusting the syntax), 1.26 caught a bug that modern compilers seem to silently allow, and I noticed another bug while translating the syntax for the 2015 edition. So this "test a minimum version" exercise was actually useful.)

I'm one of those people who does sometimes need to use old Rust versions (in fact I once had to backport a program I had written from 2024 edition to 2021 edition because I had changed computer, and one of the computers had an older rustc than the other). I haven't needed to go all the way back from 2024 edition to 2015 edition, but it is at least theoretically possible.

As a side note, I don't think the download statistics mentioned above are useful: the people who are able to download and install new versions of rustc are obviously able to download and install the newest version, so those aren't the people who use old versions. Likewise, people who are able and happy to download and run dependencies via crates.io are probably also able and happy to download and run Rust via rustup. The people who need to use old versions therefore won't show up in the download statistics, and thus you can't rely on download statistics to figure out which specific old versions they are using.

If you as user of an old compiler on an airgapped system can't download crates from crates.io, there is no reason for crates on crates.io to take you into account when deciding the MSRV as you can't download these crates onto the airgapped system anyway, right? And if you somehow can get newer crates anyway but not newer compilers, are you paying the crate authors to support older compilers? If you are working with an airgapped system, your employer surely must have more than enough money to buy support rather than take advantage of volunteer work :slight_smile:

12 Likes

Curious to hear what the first "bug" was. I'm guessing something lifetime-related.