From d90e86377e2bb529f4966f41cb9f538385f00cbf Mon Sep 17 00:00:00 2001 From: Michael Tautschnig Date: Tue, 14 Jul 2026 19:14:11 +0000 Subject: [PATCH] Upgrade Rust toolchain to nightly-2026-02-06 rust-lang/rust stopped encoding *optimized* MIR for ADT constructors (`instance_mir` uses `mir_for_ctfe` for them). As a result, `rustc_public::Instance::body()` returns `None` for constructors imported from other crates (its `has_body` check keys off `is_mir_available`, i.e. optimized MIR), so codegenning a constructor used as a function value (e.g. `.map(Some)`) panicked on `instance.body().unwrap()`. Reconstruct the missing constructor body the same way `rustc_public`'s `BodyBuilder` would (fetch `instance_mir`, monomorphize, convert to stable MIR) when `body()` is `None` and the instance is a constructor; any other bodyless instance still panics. A regression test is added under `tests/kani/FunctionCall/ctor_as_fn_value.rs`, exercising cross-crate constructors (`Some`, `std::num::Wrapping`) and a local constructor used as function values; the cross-crate harnesses panic the compiler without this fix. Co-authored-by: Kiro --- .../src/kani_middle/transform/mod.rs | 31 +++++++++++++++++-- rust-toolchain.toml | 2 +- tests/kani/FunctionCall/ctor_as_fn_value.rs | 30 ++++++++++++++++++ 3 files changed, 60 insertions(+), 3 deletions(-) create mode 100644 tests/kani/FunctionCall/ctor_as_fn_value.rs diff --git a/kani-compiler/src/kani_middle/transform/mod.rs b/kani-compiler/src/kani_middle/transform/mod.rs index 0431f2da02c2..b55d69b6fa86 100644 --- a/kani-compiler/src/kani_middle/transform/mod.rs +++ b/kani-compiler/src/kani_middle/transform/mod.rs @@ -29,15 +29,42 @@ use crate::kani_middle::transform::stubs::{ExternFnStubPass, FnStubPass}; use crate::kani_queries::QueryDb; use automatic::{AutomaticArbitraryPass, AutomaticHarnessPass}; use dump_mir_pass::DumpMirPass; -use rustc_middle::ty::TyCtxt; +use rustc_hir::def::DefKind; +use rustc_middle::ty::{EarlyBinder, TyCtxt, TypingEnv}; use rustc_public::mir::Body; use rustc_public::mir::mono::{Instance, MonoItem}; +use rustc_public::rustc_internal; use std::collections::HashMap; use std::fmt::Debug; use crate::kani_middle::transform::rustc_intrinsics::RustcIntrinsicsPass; pub use internal_mir::RustcInternalMir; +/// Build the `Body` for an instance whose body `rustc_public` does not surface. +/// +/// This currently only handles ADT constructors: rust-lang/rust stopped encoding +/// *optimized* MIR for constructors (`instance_mir` uses `mir_for_ctfe` for them), +/// which makes `rustc_public::Instance::body()` return `None` for constructors +/// imported from other crates even though rustc can still build their (trivial) +/// shim body. We reconstruct it here the same way `rustc_public`'s `BodyBuilder` +/// would: fetch the instance MIR and monomorphize it, then convert to the stable +/// representation. Any other bodyless instance is a genuine error and panics. +fn build_missing_body(tcx: TyCtxt, instance: Instance) -> Body { + let internal_instance = rustc_internal::internal(tcx, instance); + assert!( + matches!(tcx.def_kind(internal_instance.def_id()), DefKind::Ctor(..)), + "expected a body for instance `{}`", + instance.name() + ); + let internal_body = tcx.instance_mir(internal_instance.def).clone(); + let mono_body = internal_instance.instantiate_mir_and_normalize_erasing_regions( + tcx, + TypingEnv::fully_monomorphized(), + EarlyBinder::bind(internal_body), + ); + rustc_internal::stable(&mono_body) +} + mod automatic; pub(crate) mod body; mod check_uninit; @@ -118,7 +145,7 @@ impl BodyTransformation { .entry(instance) .or_insert_with(|| { // Transform and add to the cache if there's no existing entry. - let mut body = instance.body().unwrap(); + let mut body = instance.body().unwrap_or_else(|| build_missing_body(tcx, instance)); let mut modified = false; for pass in self.stub_passes.iter_mut().chain(self.inst_passes.iter_mut()) { diff --git a/rust-toolchain.toml b/rust-toolchain.toml index 5e989b87faf8..d0dd6a86454d 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -2,5 +2,5 @@ # SPDX-License-Identifier: Apache-2.0 OR MIT [toolchain] -channel = "nightly-2026-02-05" +channel = "nightly-2026-02-06" components = ["llvm-tools", "rustc-dev", "rust-src", "rustfmt"] diff --git a/tests/kani/FunctionCall/ctor_as_fn_value.rs b/tests/kani/FunctionCall/ctor_as_fn_value.rs new file mode 100644 index 000000000000..5c2952adbcf8 --- /dev/null +++ b/tests/kani/FunctionCall/ctor_as_fn_value.rs @@ -0,0 +1,30 @@ +// Copyright Kani Contributors +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//! Checks that ADT constructors defined in other crates can be used as function +//! values. As of nightly-2026-02-06, rustc no longer encodes optimized MIR for +//! ADT constructors, so their bodies are unavailable through +//! `rustc_public::Instance::body()` for constructors imported from other crates +//! and Kani must reconstruct them (see `BodyTransformation::body`). Passing +//! `Some` or `std::num::Wrapping` to `Iterator::map` exercises exactly that +//! path; a local constructor is included for contrast. + +struct Local(u8); + +#[kani::proof] +fn check_cross_crate_ctor_as_fn_value() { + let x: u8 = kani::any(); + // `Some` is `Option`'s constructor, defined in `core`. + let v = std::iter::once(x).map(Some).next().unwrap(); + assert_eq!(v, Some(x)); + // A tuple-struct constructor defined in `core` (re-exported by `std`). + let w = std::iter::once(x).map(std::num::Wrapping).next().unwrap(); + assert_eq!(w.0, x); +} + +#[kani::proof] +fn check_local_ctor_as_fn_value() { + let x: u8 = kani::any(); + let l = std::iter::once(x).map(Local).next().unwrap(); + assert_eq!(l.0, x); +}