[ICE]: `-Zautodiff=Enable` aborts in Enzyme `TypeTree::insert` ("illegal insertion") on a by-value array of `(&str, f64)`, in a crate with no autodiff code

Open
#165,470 2 comments 0 reactions 0 assignees View on GitHub

Maintainers usually reply within 1 day

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
54/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
rust
Domain
compilers

Research direction

Start with the reported rustc_codegen_llvm::typetree::add_tt path in typed_place_copy_with_flags and the Enzyme TypeTree::insert failure. Reproduce using the supplied Rust example with -Zautodiff=Enable, then compare the by-value array cases that abort with the reference and single-tuple cases that compile. Done means the reproducer compiles without aborting and the reported cases behave consistently.

Written by the indexing model from the issue text.

Description

C-bug F-autodiff I-ICE needs-triage T-compiler

With -Zautodiff=Enable, rustc aborts while compiling this crate, which contains no autodiff code at all. The abort comes from the Enzyme type tree that rustc's codegen attaches to a typed copy (rustc_codegen_llvm::typetree::add_tt in typed_place_copy_with_flags). Without -Zautodiff=Enable the same file compiles. I hit it in a larger crate whose functions are differentiated with std::autodiff: any crate compiled with the flag aborts as soon as it contains such an array.

Code
pub struct P { pub a: f64, pub b: f64, pub c: f64 }

pub fn check(p: &P) -> Result<(), String> {
    for (knob, value) in [("a", p.a), ("b", p.b), ("c", p.c)] {
        if !value.is_finite() {
            return Err(format!("{knob} = {value} must be finite"));
        }
    }
    Ok(())
}
rustc --edition=2024 --crate-type=rlib -Zautodiff=Enable lib.rs

It aborts the same way with -O, with -Copt-level=0, and through cargo with lto = "fat" (cargo rustc --release --lib -- -Zautodiff=Enable). Without -Zautodiff=Enable it compiles.

Which arrays trigger it (the same crate, one function body at a time):

body result
for (k, v) in [("a", p.a), ("b", p.b)] ([(&str, f64); 2] by value) abort
for (v, k) in [(p.a, "a"), (p.b, "b")] ([(f64, &str); 2]) abort
for (w, v) in [(&p.v, p.a), (&p.v, p.b)] ([(&Vec<f64>, f64); 2]) abort
for (k, v) in [(1usize, p.a), (2, p.b)] ([(usize, f64); 2]) abort
sink([("a", p.a), ("b", p.b)]) (the array passed by value to an #[inline(never)] fn, no loop) abort
for (k, v) in [("a", &p.a), ("b", &p.b)] ([(&str, &f64); 2]) compiles
for (k, v) in [("a", p.a), ("b", p.b)].iter() (by reference) compiles
for (k, v) in vec![("a", p.a), ("b", p.b)] compiles
sink(("a", p.a)) (a single tuple) compiles
for v in [p.a, p.b], for k in ["a", "b"] compiles

So an array copied by value whose element mixes an f64 with a pointer or an integer aborts. The tree in the message, {[0]:Pointer, [0,-1]:Pointer} receiving Float@double at [0,-1], looks like the element's fields being merged at offset -1 ("any offset" of the array), where an f64 and a pointer or integer cannot both sit.

Meta

rustc --version --verbose:

rustc 1.101.0-nightly (1c3a65069 2026-11-02)
binary: rustc
commit-hash: 1c3a6506966e21845b31de0b075d2527660db132
commit-date: 2026-11-02
host: aarch64-apple-darwin
release: 1.101.0-nightly
LLVM version: 23.1.5

(toolchain nightly-2026-11-03 with the enzyme rustup component)

Error output
inserting into : {[0]:Pointer, [0,-1]:Pointer} with [0,-1] of Float@double
illegal insertion
UNREACHABLE executed at /Users/runner/work/rust/rust/src/tools/enzyme/enzyme/Enzyme/TypeAnalysis/TypeTree.h:330!

rustc exits with status 134 (SIGABRT). Through cargo: process didn't exit successfully: ... (signal: 6, SIGABRT: process abort signal).

Backtrace

RUST_BACKTRACE=1 prints nothing (the abort is not a Rust panic), so this is from running the same rustc invocation under lldb:

frame #0: libsystem_kernel.dylib`__pthread_kill + 8
frame #1: libsystem_pthread.dylib`pthread_kill + 296
frame #2: libsystem_c.dylib`abort + 148
frame #3: libLLVM.dylib`llvm::llvm_unreachable_internal(char const*, char const*, unsigned int) + 552
frame #4: libEnzyme-23.dylib`TypeTree::insert(std::vector<int>, ConcreteType, bool) + 3644
frame #5: libEnzyme-23.dylib`EnzymeTypeTreeInsertEq + 376
frame #6: librustc_driver.dylib`<rustc_codegen_llvm::llvm::enzyme_ffi::TypeTree>::insert + 152
frame #7: librustc_driver.dylib`rustc_codegen_llvm::typetree::process_typetree_recursive + 188
frame #8: librustc_driver.dylib`rustc_codegen_llvm::typetree::process_typetree_recursive + 448
frame #9: librustc_driver.dylib`rustc_codegen_llvm::typetree::to_enzyme_typetree + 76
frame #10: librustc_driver.dylib`rustc_codegen_llvm::typetree::add_tt + 420
frame #11: librustc_driver.dylib`<rustc_codegen_llvm::builder::GenericBuilder<rustc_codegen_llvm::context::FullCx> as rustc_codegen_ssa::traits::builder::BuilderMethods>::typed_place_copy_with_flags + 516
frame #12: librustc_driver.dylib`<rustc_codegen_ssa::mir::operand::OperandValue<&rustc_codegen_llvm::llvm::ffi::Value>>::store_with_flags::<rustc_codegen_llvm::builder::GenericBuilder<rustc_codegen_llvm::context::FullCx>> + 128
frame #13: librustc_driver.dylib`<rustc_codegen_ssa::mir::operand::OperandRef<&rustc_codegen_llvm::llvm::ffi::Value>>::store_with_annotation_and_flags::<...>
frame #14: librustc_driver.dylib`<rustc_codegen_ssa::mir::FunctionCx<rustc_codegen_llvm::builder::GenericBuilder<rustc_codegen_llvm::context::FullCx>>>::codegen_rvalue + 1056
frame #15: librustc_driver.dylib`rustc_codegen_ssa::mir::codegen_mir::<rustc_codegen_llvm::builder::GenericBuilder<rustc_codegen_llvm::context::FullCx>> + 21972
frame #16: librustc_driver.dylib`rustc_codegen_llvm::base::compile_codegen_unit::module_codegen::{closure#1} + 9116
frame #17: librustc_driver.dylib`rustc_codegen_llvm::base::compile_codegen_unit::{closure#0} + 1296
frame #18: librustc_driver.dylib`<rustc_codegen_llvm::back::llvm_backend::LlvmCodegenBackend as rustc_codegen_ssa::traits::backend::ExtraBackendMethods>::compile_codegen_unit + 908
frame #19: librustc_driver.dylib`rustc_codegen_ssa::base::codegen_crate::<rustc_codegen_llvm::back::llvm_backend::LlvmCodegenBackend, rustc_codegen_llvm::back::llvm_backend::ModuleLlvm> + 11572
frame #20: librustc_driver.dylib`<rustc_codegen_llvm::back::llvm_backend::LlvmCodegenBackend as rustc_codegen_ssa::traits::backend::CodegenBackend>::codegen_crate + 284
frame #21: librustc_driver.dylib`<rustc_interface::queries::Linker>::codegen_and_build_linker + 2324

Related: #161819 (tape reuse in std::autodiff). This abort currently stops me from moving my autodiff code into the main crate, where I'd
use that API.

Dominant language
Rust
Stars
121k
Forks
17.3k
Avg merge
2d 21h
Merged PRs (30d)
531

Getting set up

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from rust-lang/rust

All issues in rust-lang/rust

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.