Idea: rustc & cargo should warn on unspecified edition

A moderately common source of beginner confusion is that they encounter unexpected behavior due to not specifying a language edition, and getting the default 2015 edition. This can be either due to calling rustc instead of cargo and not specifying any options, or writing a Cargo.toml from scratch (that is, not using cargo new) without remembering to include the edition field.

Users in this position encounter various surprising behaviors, such as needing extern crate to use dependencies, and not being able to write async code. As new language editions are released, the number of such surprises will increase.

Therefore, I propose that tools should warn if the edition is unspecified. More precisely, there should be a warning in any of the cases where 2015 is chosen by default:

  • rustc shall warn if no --edition is passed.
  • cargo shall warn if the manifest of a package does not contain a package.edition in its Cargo.toml.

The warning would of course be hidden for downloaded dependencies, like other warnings already are. It would tell the reader that "2015" should be used if the code is old code not being modified, and the current edition should be used for new code.


There's some mildly interesting complications in implementing this — for example, Cargo currently translates explicit edition = "2015" into not passing --edition to rustc at all, and there are a very large number of UI tests (tests that assert the output of the compiler, including warnings) in the rust-lang/rust repository that have unspecified edition. All that I know of are solvable, but it made the problem bigger than "I'll just make a PR or two" as I thought when I came up with this idea.

So, I'd like to know: Does this sound like the right direction to go in? Are there situations where the warning would not be straightforwardly fixable?

44 Likes

I'm all for it. I presumably know what I'm doing and have still confused myself with an accidentally missing edition specification as well. I'd even suggest doing so for virtual workspace manifests without a resolver key (usually inferred from package edition) as well.

While it's a bigger change, the change should still be reasonably straightforward:

  • Make cargo always pass --edition.
  • Emit the warning. Bless the changed UI test outputs containing the warning to automatically update them.
  • Slowly update UI tests over time to specify edition.
5 Likes

Cargo already warns if you have a 2021 edition crate in a workspace without explicit resolver version.

3 Likes

I’d say:

  • rustc should use the latest edition by default.
  • cargo should flat out error if the edition is unspecified (with a carve out for dependencies)

2015 default is going to look increasingly ridiculous as the time goes by, so it seems like it’s the question of when.

And now seems like a decent time: 2015 was a while ago, and a lot of code from those days doesn’t build any more anyway (there were a couple of breaking macro changes, and mem::unitialized).

4 Likes

This would break backwards compatibility, repeatedly. Emitting a loud warning seems fine, but using the latest edition by default would break existing Rust 2015 code in mysterious ways.

Worse, using the latest edition would induce new code to rely on that, which will then cause that code to get broken every 3 years, eliminating some of the benefit of the edition system.

If we were going to change the default and break such builds, I'd say we should change rustc to error out without an edition specified, rather than using the latest edition. But before we consider doing that we'd need to warn for a nice long time.

For a first pass, I think it makes sense to emit a warning, and let the usual warning-suppression for dependencies handle it. That'll get any actively maintained crate switching over, which will then just leave all the existing crates.

13 Likes

I'm fine with a warning on an unset Edition in Cargo.toml.

Since cargo-script is a new thing and needs very low overhead for its target audience, it defaults the edition to "current" with a warning that it is unset. I feel this gets us a nice middle ground of people assuming they will get the currently documented behavior while ensuring long-lived scripts don't break (since they'll be annoyed into silencing the warning).

8 Likes

For what it's worth, feel free to file tickets for errors that are caused by using later edition features in earlier editions. There's precedent for errors telling you that you're using the wrong edition and to pass in --edition=2021 when needed, but I'm sure there are tons of cases we don't handle today.

5 Likes

I think doing this in cargo is a treat idea. I'm less sure about doing it for rustc. My workflow of working on the compiler is certainly not standard, but I (and everyone else who frequently invoked rustc for testing things probably) would find such a warning really annoying and would probably try to hack in some environment variable to turn it off (that I would also want to enable in UI tests). I guess adding such an environment variable would be fine, but also comes with downsides. No one should be using rustc directly anyways, but I'm not sure how we can effectively tell people about that.

Why wouldn't you just pass in --edition 2015?

1 Like

Many people do, and it's valid to use rustc without cargo. (It's annoying when those uses break other rust conventions, or make it deliberately difficult to integrate crates and cargo as well, but it's still a valid use case.)

2 Likes

Do we promise a stable cli for rustc across versions? I searched the rustc dev guide and the rustc book but didn't see anything definitive.

To clarify, you mean Rust 2015 code using a build system other than cargo?

Thoughts not necessarily directed at you, but which I want to write down before I forget

Build systems which wrap around rustc (e.g. cargo, buck) should already be passing --edition for every invocation. This might be an unnamed rule in the software world, but I generally expect wrapper tools to provide the "maximal set" of flags to the tools they wrap, even those flags that could technically be omitted.

As for users who are directly using the rustc cli, I suspect they skew towards experts in build-systems and compilers who are well-accustomed to working in very unstable corners of the Rust ecosystem. Breaking changes are their bread and butter.

For what it's worth, the discussion of the default for rustc --edition in the original "Evolving Rust through Epochs" RFC is here and here.

4 Likes

I wouldn't go as far as "maximal set", but I agree that build systems that invoke rustc for the user should always be passing --edition. (Of course, if the user is writing the rustc invocation themselves without help from the build tool, then they're the one responsible for adding --edition.)

I think it's a reasonable idea to furthermore include a suggestion to use cargo in the warning that invocation of rustc without --edition would generate. I think a significant portion of the users that use rustc manually and forget the --edition argument are users that mainly made the mistake of not using cargo; this is in line with the "no one should be using rustc directly anyways" kind of sentiment above, the weaker version of which is "no one should be using rustc directly unless they know exactly why they 'need' to use it manually"[1]

Also, in addition to usage of explicit --edition 2015 for silencing the warning, it might also be reasonable to silence the warning when flags are detected that are characteristic for rustc invocation by automatic tooling, such as cargo; the warning is meant to address manual users of the rustc command, after all. This way, it would even be an option that cargo keeps current behavior of not passing --edition 2015. (I'm not sure what the best contenders are. For example, cargo probably always uses JSON output mode, so that's one potential candidate. Maybe there is no good candidate, or this is deemed too inconsistent, I'm only meaning this as an idea that might be sensible, anyways.)


  1. and the set of users that don't know why they use rustc manually and the set of users that don't know how to use rustc manually (i.e. to pass --edition) should have good overlap ↩︎

5 Likes

My gut feeling is that the overwhelming majority of cargo-less rustc invocations are just people trying isolated snippets of code, as a local playground of sorts.

5 Likes

This use case will be fixed by cargo scripts, right? And if it doesn't, for this use case you almost certainly don't want to use the 2015 edition and explicitly specifying the edition would suppress the warning.

1 Like

No, because at least two-thirds of the time, if I'm messing with an isolated snippet, I'm about to file a bug report on something, and I want to know whether the problem changes or disappears if I take cargo out of the loop.

I might want cargo to tell me the options I need to give rustc to make some already-built dependency crate available to the test program, but that's it.

Indeed. In the context of test snippets, I wouldn't mind it being an error not to specify an edition.


Come to think of it, why can't I specify the edition in the code? Like

#![rust_edition(2021)]

at the top of the crate root.

7 Likes

4 posts were merged into an existing topic: Specifying the edition in the source file