Code compiles on playground but fails when passed via stdin to rustc

I've run into the following very strange behaviour and am unsure whether it's some kind of weird bug that I should report or a subtle mistake on my part.

The following code compiles and runs fine on playground (as does an equivalent test locally)

#![allow(stable_features)]
#![allow(unused)]
#![feature(iterator_try_collect)]
fn main() {
    let foo: Option<Vec<_>> = [Some(1)].into_iter().try_collect();
    assert_eq!(foo.unwrap().len(), 1);
}

but when passed via stdin to rustc --crate-name flurb --crate-type=lib --out-dir target/flurb --emit=llvm-ir - it fails with

error[E0277]: the trait bound `&Option<{integer}>: Try` is not satisfied
    --> <anon>:5:53
     |
   5 |     let foo: Option<Vec<_>> = [Some(1)].into_iter().try_collect();
     |                                                     ^^^^^^^^^^^ the nightly-only, unstable trait `Try` is not implemented for `&Option<{integer}>`
     |
help: the trait `Try` is implemented for `Option<T>`
    --> /opt/rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/option.rs:2767:1
     |
2767 | impl<T> const ops::Try for Option<T> {
     | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to 1 previous error

For more information about this error, try `rustc --explain E0277`.

Is there a reason for the difference in output from a direct rustc invocation vs a cargo/playground based compilation?

--edition 2024

At a minimum. Probably there are other differences in the exact command, but this at least compiles it.

6 Likes

The playground defaults to edition 2024. Fails if you select edition 2015: Rust Playground (or 2018 for what it's worth).

works locally if you pick at least edition 2021:

rustc +nightly --crate-name flurb --crate-type=lib --out-dir target/flurb --emit=llvm-ir t.rs --edition 2021
6 Likes

Thanks both - so that looks like a subtle edition bug for try_collect() and an extra param for me to pass to autocfg

The relevant edition change for that error is 2021's IntoIterator for arrays.

Calls to IntoIterator::into_iter are hidden in Rust 2015 and Rust 2018 when using method call syntax (i.e., array.into_iter()). So, array.into_iter() still resolves to (&array).into_iter() as it has before.

4 Likes

Thanks. I was 2 minutes to fast opening an issue - now closed.

I think that, given the number and significance of edition differences that now exist, rustc ought to warn whenever it is invoked without an --edition, because almost nobody writing a rustc invocation today should be using the 2015 edition.

At one point I tried implementing such a warning; the complication I found was that very many of the “UI” tests (tests that compile code and look at the compiler output) were written without any edition set, and each one would gain a new warning unless modified to set the edition.

16 Likes

I think that if there is no edition and there's a compiler error (not just warning), compiling again with newer editions just for better diagnostics would be so damn cool.

Something like Note: this compiles on edition 2024 (or even on editions: 2021, 2024)

This makes code with no edition fail to compile slower, but people shouldn't be developing with no edition set (and code already developed usually doesn't fail to compile and isn't affected)

8 Likes

The various suites can set default flags, so you could add a -Z flag to not do that warning that's passed by default. (Or if it's a lint just the existing allow-a-lint flag.)

1 Like

It was a similar situation that led to my confusion. In this case it wasn't trybuild etc but rather autocfg which doesn't automatically set the edition.

I'd see the biggest "block" to those tools updating would be the lack of an immediately obvious basic cargo.toml parser in that part of the ecosystem that is fast and complete. As I'd assume the preffered approach would be to set the edition as per the crate's spec.

cargo_metadata has a runtime cost, which is annoying in tests & unsuitable in build scripts. cargo_toml uses serde, which adds extra build time. The workspace challenge makes simpler options less viable.

Would someone have the energy to write the MCP for merging this change? I believe that we might have to coordinate with cargo (to ensure the edition is being passed in always).

4 Likes

I believe Cargo unconditionally passes in the edition already.

3 Likes

It does. It used to be conditional, but that was 5 years ago.

2 Likes

I'll try to give it a go tomorrow. It'll be my first MCP. Thanks for picking this up! But ... Before I do ...

My worry would be autocfg. If anyone has probes with a leading #[deny(warnings)] then that could break with rather nasty consequences. (?) It'd be great if @cuviper could quickly weigh in as to whether that's a valid concern or not?

1 Like

IMO Rust never guaranteed it wouldn't add more warnings for code that was warning-free, so if you use deny(warnings), you're opting-in to breakage.

8 Likes

There exists some prior discussion with similar ideas by the way:


Judging by the PR linked from the abovementioned discussion

it sounds the relevant change is more like ~2 years ago? (And explicitly for the purpose of enabling what this thread now suggests.)

In other words, the coordination with cargo already happened :partying_face:

7 Likes

Yes, and probes really should aim to use a specific #[forbid(...)] etc. to change the specific case they are testing.

And yet ... In this case we are looking at potentially breaking build scripts silently with hard-to-spot and hard-to-debug consequences, not only for the crate in question but for anyone downstream and without any action needed on anyone's part (other than updating rustc) for the breakage to occur.

So, while I agree that "you really shouldn't have done that, so you have no-one else to blame" is the technically right call, I also don't feel comfortable putting an MCP in for this without a thumbs-up form someone more senior.

Unsure about T-compiler but T-cargo has decided to not support build probes, see Provide a way for build scripts to invoke rustc the way cargo would · Issue #11244 · rust-lang/cargo · GitHub

Without Cargo support, build probes have some gotchas.

Also, for fully general build probes, like autocfg, the edïtion should be set. The caller has to do this currently. We've approved telling build scripts the edition but it is unclear if that might get superseded by a compiler feature.

1 Like

I almost think it would be a good thing to break autocfg occasionally and try to influence people away from using it. I run into crates that have issues working on nightly over, and over, and over because of bad auto-detection. I would really like a way to just say "I'm on at least the latest stable when you were published, use all those features" and bypass any attempt at detecting for MSRV's I don't care about or unstable features I do not want used.

2 Likes

I agree that blanket deny(warnings) is a bad idea for feature probes, and even in general that makes compiler upgrades more likely to break your code.

If that's going to be another of these environment variables, perhaps something like CARGO_PKG_EDITION, then that sounds great, and I would probably change autocfg to use that by default. I don't know how a compiler feature could supersede that though, because I would want the edition of the package with the build script, not of autocfg itself.

1 Like