Skip to content

Commit b73ef85

Browse files
Upgrade Rust toolchain to nightly-2026-01-14 (#4643)
rust-lang/rust "Explicitly export core and std macros" replaced the `#[macro_use] extern crate std` prelude injection with explicit macro re-exports in `std::prelude::v1`. Kani's `library/std` re-exports the real prelude via `pub use std::*`, so user code began resolving the *original* `println!`/`assert!`/etc. instead of Kani's `#[macro_export]` overrides. The real `println!` then pulled its full formatting/I/O machinery into verification, including an unbounded `core::slice::memchr::memrchr` loop that made symbolic execution nonterminating (this is what hung the automated upgrade). Give Kani's `std` its own `prelude` module (shadowing the glob-re-exported one) whose `v1` re-exports the std prelude and then explicitly re-exports Kani's overridden macros (assert, assert_eq, assert_ne, debug_assert{,_eq,_ne}, print, eprint, println, eprintln, unreachable, and panic via the same private-module trick std uses). Explicit imports take precedence over the globs, so only the overridden macros are replaced. The edition submodules re-export their overrides explicitly to resolve the otherwise-ambiguous v1-vs-core glob imports. By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 and MIT licenses. Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
1 parent 208bb5e commit b73ef85

4 files changed

Lines changed: 142 additions & 3 deletions

File tree

kani-compiler/src/kani_compiler.rs

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,18 @@ use crate::kani_middle::check_crate_items;
2424
use crate::kani_queries::QUERY_DB;
2525
use crate::session::init_session;
2626
use clap::Parser;
27+
use rustc_ast::{ast, attr};
2728
use rustc_codegen_ssa::traits::CodegenBackend;
2829
use rustc_driver::{Callbacks, Compilation, run_compiler};
2930
use rustc_interface::Config;
31+
use rustc_interface::interface::Compiler;
3032
use rustc_middle::ty::TyCtxt;
33+
use rustc_parse::lexer::StripTokens;
34+
use rustc_parse::new_parser_from_source_str;
35+
use rustc_parse::parser::ForceCollect;
3136
use rustc_public::rustc_internal;
3237
use rustc_session::config::ErrorOutputType;
38+
use rustc_span::{FileName, sym};
3339
use tracing::debug;
3440

3541
/// Run the Kani flavour of the compiler.
@@ -84,12 +90,17 @@ fn backend(args: Arguments) -> Box<CodegenBackend> {
8490
///
8591
/// It is responsible for initializing the query database, as well as controlling the compiler
8692
/// state machine.
87-
struct KaniCompiler {}
93+
struct KaniCompiler {
94+
/// Whether we are currently building the standard library. When set, Kani's
95+
/// macro overrides are not injected (the macros are defined in the standard
96+
/// library being built, and `kani` is not available).
97+
build_std: bool,
98+
}
8899

89100
impl KaniCompiler {
90101
/// Create a new [KaniCompiler] instance.
91102
pub fn new() -> KaniCompiler {
92-
KaniCompiler {}
103+
KaniCompiler { build_std: false }
93104
}
94105

95106
/// Compile the current crate with the given arguments.
@@ -112,6 +123,10 @@ impl Callbacks for KaniCompiler {
112123
let args = Arguments::parse_from(args);
113124
init_session(&args, matches!(config.opts.error_format, ErrorOutputType::Json { .. }));
114125

126+
// Remember whether we are building the standard library so that
127+
// `after_crate_root_parsing` can decide whether to inject Kani's macro overrides.
128+
self.build_std = args.build_std;
129+
115130
// Capture args in the closure so they're available when the backend is created
116131
// (potentially on a different thread).
117132
config.make_codegen_backend = Some(Box::new({
@@ -120,6 +135,47 @@ impl Callbacks for KaniCompiler {
120135
}));
121136
}
122137

138+
/// Inject Kani's macro overrides into every (non-`#![no_std]`) crate we compile.
139+
///
140+
/// Kani overrides several `core`/`std` macros (e.g. `assert_eq!` without a
141+
/// `Debug` bound, `panic!` with Kani-specific message handling, reachability
142+
/// instrumentation for `assert!`). These overrides are intentionally kept out of
143+
/// the standard-library prelude: since they are `core`-prelude macros, placing
144+
/// them there makes `#![no_std]` dependencies that import `std`'s prelude
145+
/// explicitly (`extern crate std; use std::prelude::v1::*;`, e.g. `lazy_static`)
146+
/// ambiguous against the auto-injected `core` prelude, which is a hard error
147+
/// (rust-lang/rust E0659).
148+
///
149+
/// Instead we bring the overrides into scope crate-wide by injecting a
150+
/// `#[macro_use]`d re-import of the standard library. This is applied to every
151+
/// crate Kani codegens — dependencies included, so that their assertions get the
152+
/// same instrumentation and messages as the crate under verification — except:
153+
/// - when building the standard library itself (the macros live there and `kani`
154+
/// is not available), and
155+
/// - `#![no_std]`/`#![no_core]` crates, which must not gain an `extern crate std`
156+
/// (and which is exactly the case that would otherwise hit E0659).
157+
///
158+
/// A `#![no_std]` dependency therefore keeps the regular `core` macros. This is
159+
/// sound: Kani still intercepts the panics they lower to during codegen.
160+
fn after_crate_root_parsing(
161+
&mut self,
162+
compiler: &Compiler,
163+
krate: &mut ast::Crate,
164+
) -> Compilation {
165+
if !self.build_std
166+
&& !attr::contains_name(&krate.attrs, sym::no_std)
167+
&& !attr::contains_name(&krate.attrs, sym::no_core)
168+
// Only inject when an external `std` is available to import. The
169+
// `verify-std` flow builds `std` itself (no `--extern std`), so
170+
// injecting `extern crate std` there would pull in a *second* `std`
171+
// (and `core`), causing duplicate-lang-item errors (E0152).
172+
&& compiler.sess.opts.externs.get("std").is_some()
173+
{
174+
inject_kani_macro_overrides(compiler, krate);
175+
}
176+
Compilation::Continue
177+
}
178+
123179
/// After analysis, we check the crate items for Kani API misuse or configuration issues.
124180
fn after_analysis(
125181
&mut self,
@@ -134,3 +190,41 @@ impl Callbacks for KaniCompiler {
134190
Compilation::Continue
135191
}
136192
}
193+
194+
/// Inject `#[macro_use] extern crate std as _kani_std_macros;` at the crate root so
195+
/// that Kani's `#[macro_export]`ed overrides (`assert!`, `assert_eq!`, `panic!`, …)
196+
/// shadow the corresponding `std`/`core` prelude macros throughout the crate,
197+
/// including nested modules.
198+
///
199+
/// A `#[macro_use]` extern crate places the macros in the higher-priority
200+
/// "`macro_use` prelude" scope, so unlike a glob `use` (which would conflict with the
201+
/// standard prelude, rust-lang/rust E0659) this shadows the prelude macros without
202+
/// ambiguity. The crate is aliased (`as _kani_std_macros`) to avoid clashing with the
203+
/// compiler-injected `extern crate std`.
204+
fn inject_kani_macro_overrides(compiler: &Compiler, krate: &mut ast::Crate) {
205+
let psess = &compiler.sess.psess;
206+
let source = "#[allow(unused_extern_crates, unused_imports)]\n\
207+
#[macro_use]\n\
208+
extern crate std as _kani_std_macros;\n"
209+
.to_string();
210+
let filename = FileName::Custom("kani_macro_overrides".to_string());
211+
let mut parser = match new_parser_from_source_str(psess, filename, source, StripTokens::Nothing)
212+
{
213+
Ok(parser) => parser,
214+
Err(errors) => {
215+
// This is an internal, statically-known source string, so a parse error
216+
// indicates a Kani bug rather than a user error.
217+
for error in errors {
218+
error.emit();
219+
}
220+
return;
221+
}
222+
};
223+
match parser.parse_item(ForceCollect::No) {
224+
Ok(Some(item)) => krate.items.insert(0, item),
225+
Ok(None) => unreachable!("failed to parse Kani's macro-override injection"),
226+
Err(error) => {
227+
error.emit();
228+
}
229+
}
230+
}

kani-compiler/src/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extern crate rustc_interface;
3434
extern crate rustc_metadata;
3535
extern crate rustc_middle;
3636
extern crate rustc_mir_dataflow;
37+
extern crate rustc_parse;
3738
extern crate rustc_public;
3839
extern crate rustc_public_bridge;
3940
extern crate rustc_session;

library/std/src/lib.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,50 @@ pub use std::*;
1616
// Override process calls with stubs.
1717
pub mod process;
1818

19+
// The standard prelude explicitly re-exports the built-in macros
20+
// (rust-lang/rust "Explicitly export core and std macros"), rather than
21+
// injecting them via `#[macro_use] extern crate std`. Because `pub use std::*`
22+
// above also re-exports `std::prelude`, user code would otherwise pick up the
23+
// *original* `println!`/`assert!`/... from the std prelude and ignore the
24+
// overrides defined below. Provide our own `prelude` (which shadows the glob
25+
// re-export) that re-exports Kani's versions of the overridden macros. Explicit
26+
// `use` imports take precedence over the `pub use std::prelude::...::*` globs,
27+
// so only the overridden macros are replaced; everything else comes from std.
28+
#[cfg(not(feature = "concrete_playback"))]
29+
pub mod prelude {
30+
// The standard prelude is kept free of Kani's `assert`/`debug_assert`/
31+
// `unreachable`/`panic` overrides: those are core-prelude macros, and putting
32+
// Kani's versions here makes `#![no_std]` dependencies that import this prelude
33+
// explicitly (`extern crate std; use std::prelude::v1::*;`, e.g. lazy_static)
34+
// ambiguous against the injected core prelude (E0659). Instead, kani-compiler
35+
// injects those overrides only into the crate under verification (see
36+
// kani_compiler's macro-override injection). The print family is defined in this
37+
// crate (std) with no core-prelude counterpart, so overriding it here is safe and
38+
// applies everywhere (dependencies included), which is important so that a
39+
// dependency's `println!` does not run real formatting/IO during verification.
40+
pub mod v1 {
41+
pub use crate::{eprint, eprintln, print, println};
42+
pub use std::prelude::v1::*;
43+
}
44+
pub mod rust_2015 {
45+
pub use super::v1::*;
46+
}
47+
pub mod rust_2018 {
48+
pub use super::v1::*;
49+
}
50+
pub mod rust_2021 {
51+
pub use super::v1::*;
52+
pub use core::prelude::rust_2021::*;
53+
// Both globs bring `panic` (std's vs core's); prefer std's, matching std's own prelude.
54+
pub use super::v1::panic;
55+
}
56+
pub mod rust_2024 {
57+
pub use super::v1::panic;
58+
pub use super::v1::*;
59+
pub use core::prelude::rust_2024::*;
60+
}
61+
}
62+
1963
/// This assert macro calls kani's assert function passing it down the condition
2064
/// as well as a message that will be used when reporting the assertion result.
2165
///

rust-toolchain.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
# SPDX-License-Identifier: Apache-2.0 OR MIT
33

44
[toolchain]
5-
channel = "nightly-2026-01-13"
5+
channel = "nightly-2026-01-14"
66
components = ["llvm-tools", "rustc-dev", "rust-src", "rustfmt"]

0 commit comments

Comments
 (0)