Skip to content

thrust-rustc compiles at rustc's default edition (2015), not 2021 like its ui_test suite: annotation diagnostics are masked as E0433: missing crate 'core', and edition-sensitive programs behave differently #199

Description

@coord-e

Summary

thrust-rustc forwards its command line to rustc without setting --edition (see src/main.rs::main, which only appends --extern thrust_macros=…). As a result, when Thrust is invoked the way the README documents —

$ cargo run -- -Adead_code -C debug-assertions=false file.rs

— the input file is compiled at rustc's default edition, 2015. The ui_test harness, however, compiles every tests/ui file at edition 2021 (ui_test-0.30.7/src/config.rs:155: .add_custom("edition", Edition("2021".into())), reached via ui_test::Config::rustc(..) in tests/ui.rs). So the whole test suite runs at 2021 while the documented user-facing invocation runs at 2015, and the two diverge. Two concrete, user-visible consequences:

  1. Every malformed #[thrust_macros::…] annotation is misreported as error[E0433]: failed to resolve: you might be missing crate 'core', hiding the macro's real diagnostic.
  2. Edition-sensitive programs verify differently — e.g. a disjoint-field-capture closure verifies safe at --edition 2021 but aborts thrust-rustc at the default edition.

Adding --edition 2021 fixes both. Neither is exercised by the test suite because the suite is pinned to 2021.

Reproduction 1 — annotation diagnostics are masked

repro_sig.rs (a natural mistake: a sig on a unit-returning function, which the macro rejects because it wants an explicit return type):

#[thrust_macros::sig(fn(x: i64))]
fn f(x: i64) { let _ = x; }
fn main() {}
$ cargo run -q -- -Adead_code -C debug-assertions=false repro_sig.rs
error[E0433]: failed to resolve: you might be missing crate `core`
 --> repro_sig.rs:1:22
  |
1 | #[thrust_macros::sig(fn(x: i64))]
  |                      ^^ you might be missing crate `core`

$ cargo run -q -- -Adead_code -C debug-assertions=false --edition 2021 repro_sig.rs
error: expected `->` and a return type in sig annotation

The --edition 2021 run prints the diagnostic the macro actually intends (collect_sig_annotations in thrust-macros/src/rty.rs:152-157). At the default edition the user gets a baffling "missing crate core" pointing at the annotation and no hint about what is wrong.

This affects every thrust-macros error path, since they all route through syn::Error::to_compile_error(). For example a refinement type missing its |:

#[thrust_macros::param(x: { v: i64 })]   // should be { v: i64 | φ }
fn f(x: i64) { let _ = x; }
fn main() {}
$ cargo run -q -- … param_bad.rs                     # default edition
error[E0433]: failed to resolve: you might be missing crate `core`
$ cargo run -q -- … --edition 2021 param_bad.rs
error: refinement type must contain `|`

Direct confirmation that ::core is the unresolved path at the default edition:

fn main() { ::core::compile_error!("hello"); }
$ cargo run -q -- … core.rs            # default edition
error[E0433]: failed to resolve: you might be missing crate `core`
$ cargo run -q -- … --edition 2021 core.rs
error: hello

Reproduction 2 — verification behavior differs by edition

repro_closure.rs — a closure that captures a single struct field:

struct P { a: i64, b: i64 }
fn main() {
    let mut p = P { a: 0, b: 5 };
    let mut f = || { p.a += 1; };
    f();
    f();
    assert!(p.a == 2 && p.b == 5);
}
$ cargo run -q -- -Adead_code -C debug-assertions=false --edition 2021 repro_closure.rs && echo safe
safe

$ cargo run -q -- -Adead_code -C debug-assertions=false repro_closure.rs        # default edition
thread 'rustc' … panicked at src/refine/template.rs:440:21:
not implemented: ty: &'{erased} mut P

Under edition 2021, disjoint closure captures make the closure capture only p.a (a &mut i64, which Thrust handles), and the program verifies. At the default edition the closure captures the whole p, producing a &mut P capture that Thrust cannot model. The point is not that &mut P is unsupported — it is that the same source has a different Thrust outcome purely because of the implicit edition default, and the outcome under the documented invocation is the worse one.

Root cause

src/main.rs builds the rustc argument vector and appends only the thrust_macros extern:

if let Some(path) = thrust_macros_path() {
    args.push("--extern".to_owned());
    args.push(format!("thrust_macros={}", path.display()));}
let code = rustc_driver::catch_with_exit_code(|| {
    rustc_driver::run_compiler(&args, &mut CompilerCalls {})
});

No --edition is injected, so rustc uses its default (2015) unless the user happens to pass one. Meanwhile ui_test forces 2021 for the suite. At edition 2015 the extern prelude does not provide core, so the fully-qualified ::core::compile_error! { … } that syn's to_compile_error() emits fails to resolve (E0433), replacing every annotation diagnostic; and the older closure-capture semantics change what MIR Thrust analyzes.

Why it matters

  • Anyone following the README (which never passes --edition) who mistypes an annotation gets E0433: missing crate 'core' instead of the actual error — the surface-annotation DSL is effectively undebuggable through the documented workflow.
  • The behavior a user observes for the documented command can differ from what the test suite guarantees, for the same program.

Expected behavior

thrust-rustc should compile input at the same edition its test suite is validated against (inject --edition 2021 in src/main.rs unless the user overrides it), so that (a) to_compile_error() diagnostics resolve and annotation errors are readable, and (b) the documented invocation matches tested behavior. At minimum, the README examples should pass --edition 2021.

Relation to existing issues

Environment

  • thrust @ 6953863 (Merge pull request #185 …syn-3.0.2)
  • rustc nightly-2025-09-08 (per rust-toolchain.toml); rustc default edition = 2015
  • ui_test 0.30.7 (pins test edition to 2021)
  • Z3 5.0.0, default (spacer) configuration
  • Confirmed by running thrust-rustc (not inspection-only): the default-edition runs above emit E0433 / the &mut P abort; the --edition 2021 runs emit the real diagnostic / safe.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions