rust-lang / rust-lang/rust-bindgen
bindgen panicked with message "Not an item: ItemId(...)" when parsing recursive union templates (breaks recent LLVM libc++ std::aligned_union)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 5.3k
- Forks
- 829
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 15
Description
We noticed that bindgen is panicing on our code base after we rolled our clang toolchain with libc++. We bisect the LLVM and found out the panic starts to appear after https://github.com/llvm/llvm-project/pull/185449 was landed. This PR revised the aligned_union with a recursive union template.
We created a small reproducer:
- Create a header file:
// test_union.h
template <class A0, class... As> union RUnion { A0 arg; RUnion<As...> u; };
template <class A> union RUnion<A> { A arg; };
struct Wrap { RUnion<int, float> u; };
- Run
bindgen test_union.h -- -x c++ -std=c++20
Expected Behavior
bindgen should successfully generate FFI bindings (or gracefully treat the recursive template union as opaque/unsupported) without crashing or panicking.
Actual Behavior
bindgen immediately crashes with the following panic:
panicked at bindgen/ir/context.rs:1495:21:
Not an item: ItemId(1)
The bindgen we use is 93726885850c20847ac445664bc7bb2b827d9642 .
Root Cause Analysis
The panic occurs due to an interaction between self-referential / cyclic type references in the AST and bindgen's temporary item borrowing mechanism (with_loaned_item):
- Self-Referential Type Reference: When bindgen parses union
RUnionwith memberRUnion<As...> u, fielduis represented as anUnresolvedTypeRefwhose target typeIDresolves back to unionRUnion's ownItemId. - IR Traversal Loaning (
with_loaned_item): During post-parsing IR analysis and modification passes (such ascompute_bitfield_unitsordeanonymize_fieldsinbindgen/ir/context.rs/bindgen/ir/comp.rs),
bindgen mutably borrows items fromBindgenContextusingwith_loaned_item:
fn with_loaned_item<F, T>(&mut self, id: ItemId, f: F) -> T {
let mut item = self.items[id.0].take().unwrap(); // Temporarily removes Item from self.items
// Executes closure on &mut item...
}
- The Panic: When
with_loaned_itemruns on unionRUnion (ItemId(1)),ItemId(1)is temporarily removed fromself.items(self.items[1] = None). As the pass inspects the members of unionRUnion, it traverses
fielduand attempts to resolve its target type (union RUnion's ItemId(1)) by callingctx.resolve_item(ItemId(1)). BecauseItemId(1)is currently loaned out,self.items[1]is None, causingresolve_itemto panic withNot an item: ItemId(1).
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by running the supplied test_union.h reproducer with bindgen, then inspect bindgen/ir/context.rs around with_loaned_item and the related passes in bindgen/ir/comp.rs. Trace how the recursive RUnion reference is resolved while its ItemId is loaned; done means the command no longer panics and produces bindings or treats the recursive union as opaque.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp, rust
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100