mozilla / cbindgen

A project for generating C bindings from Rust code
Mozilla Public License 2.0
2.27k stars 294 forks source link

WARN: Skip unsupported call expression #948

Open scovich opened 2 months ago

scovich commented 2 months ago

When generating FFI bindings for delta_kernel, the following construct:

pub enum PrimitiveType {
    Long,
}

pub enum DataType {
    Primitive(PrimitiveType),
}

impl DataType {
    pub const LONG: Self = DataType::Primitive(PrimitiveType::Long);
}

causes cbindgen to emit the following warning:

WARN: Skip delta_kernel::LONG - (Unsupported call expression. Call(... <snipped> ...))
Full warning text (indented for readability) ``` WARN: Skip delta_kernel::LONG - ( Unsupported call expression. Call( ExprCall { attrs: [], func: Path( ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [ PathSegment { ident: Ident(DataType), arguments: None }, Colon2, PathSegment { ident: Ident(Primitive), arguments: None } ] } } ), paren_token: Paren, args: [ Path( ExprPath { attrs: [], qself: None, path: Path { leading_colon: None, segments: [ PathSegment { ident: Ident(PrimitiveType), arguments: None }, Colon2, PathSegment { ident: Ident(Long), arguments: None } ] } } ) ] } ) ) ```

I suspect the problem is a shortcoming in the cbindgen parser, since the constant is ultimately just a nested struct initialization?

If I mark the types `#[repr(C)]` then cbindgen emits the following definitions for them: ```c++ enum class PrimitiveType { Long, }; struct DataType { enum class Tag { Primitive, }; struct Primitive_Body { PrimitiveType _0; }; Tag tag; union { Primitive_Body primitive; }; }; ``` ... and the following constant initializer compiles fine with both gcc and clang: ```c++ constexpr static const DataType DataType_LONG = DataType { DataType::Tag::Primitive, DataType::Primitive_Body { PrimitiveType::Long }, }; ``` (cbindgen should be able to tell this isn't an arbitrary function call, after having parsed the corresponding types)

Note that the pub const which triggers the warning is NOT intended for FFI export by the delta_kernel_ffi crate. It is actually defined in a dependent crate (delta_kernel), and neither DataType nor Primitive is #[repr(C)]. In fact, the types are not even emitted because no FFI function references them (but apparently constants don't have to be referenced to be exported). Thus, the warning is annoying but harmless in this specific case (see https://github.com/mozilla/cbindgen/issues/673)

Unfortunately, annotating the constant with /// cbindgen:no-export or /// cbindgen:ignore does NOT suppress the warning. Maybe that's a side effect of the fact that cbindgen does not seem to respect either annotation for constants in the first place (filed as https://github.com/mozilla/cbindgen/issues/947)?

emilio commented 2 months ago

Yeah, syntax-wise there's no way to know whether DataType::Primitive is a function or an enum initializer... So seems somewhat tricky to suppress this warning...