Skip to content

assertion failed when two generic enums share variant names and are monomorphized over the same concrete type #1166

Description

@kyli87

cbindgen panics during monomorphization if two distinct #[repr(C)] enums declare a data-bearing variant with the same name (e.g. both have an Ok(T) variant) and both get monomorphized over the same concrete type.

The payload struct that cbindgen synthesizes for each enum variant is named solely after the variant identifier, independent of the enclosing enum:

let path = Path::new(format!("{}_Body", variant.ident));

(src/bindgen/ir/enumeration.rs)

So EnumA<T>::Ok and EnumB<T>::Ok both produce a payload path Ok_Body, and instantiating both with the same T tries to register Ok_Body<T> twice, triggering the debug_assert!(!self.contains(&replacement_path)) in src/bindgen/monomorph.rs.

It seems cbindgen:prefix-with-name=true config also doesn't help because it applies later, and does not affect the path used during monomorph.rs

Minimial Repro

use std::os::raw::c_void;
#[repr(C)]
pub enum ResultA<T> {
    Ok(T),
    Err(*mut c_void),
}
// Same `Ok`/`Err` variant *names* as ResultA.
#[repr(C)]
pub enum ResultB<T> {
    Ok(T),
    Err(*mut c_void),
}
#[repr(C)]
pub struct Payload {
    pub x: i32,
}
// Force both enums to be monomorphized over the SAME type.
#[no_mangle]
pub extern "C" fn use_a(_a: ResultA<Payload>) {}
#[no_mangle]
pub extern "C" fn use_b(_b: ResultB<Payload>) {}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions