Skip to content

Support for std::underlying_type_t #2193

Open
@aleokdev

Description

@aleokdev

Input C/C++ Header

namespace std {
template <typename _Tp, _Tp __v> struct integral_constant {
  static constexpr _Tp value = __v;
  typedef _Tp value_type;
  typedef integral_constant<_Tp, __v> type;
  constexpr operator value_type() const noexcept { return value; }
#if __cplusplus > 201103L

#define __cpp_lib_integral_constant_callable 201304

  constexpr value_type operator()() const noexcept { return value; }
#endif
};

template <typename _Tp, _Tp __v>
constexpr _Tp integral_constant<_Tp, __v>::value;

typedef integral_constant<bool, true> true_type;

typedef integral_constant<bool, false> false_type;

template <bool __v> using __bool_constant = integral_constant<bool, __v>;

template <typename _Tp>
struct is_enum : public integral_constant<bool, __is_enum(_Tp)> {};

template <typename _Tp, bool = is_enum<_Tp>::value>
struct __underlying_type_impl {
  using type = __underlying_type(_Tp);
};

template <typename _Tp> struct __underlying_type_impl<_Tp, false> {};

template <typename _Tp>
struct underlying_type : public __underlying_type_impl<_Tp> {};

template <typename _Tp>
using underlying_type_t = typename underlying_type<_Tp>::type;
} // namespace std

enum MyEnum : int { A, B, C };

class EnumWrapper {
  std::underlying_type_t<MyEnum> inner;
};

Bindgen Invocation

bindgen::Builder::default()
        .clang_args(&["-std=c++20"])
        .allowlist_type("EnumWrapper")
        // The input header we would like to generate
        // bindings for.
        .header("header.hpp")
        .enable_cxx_namespaces()
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

Actual Results

running 3 tests
test root::__bindgen_test_layout_underlying_type_t_open0_MyEnum_close0_instantiation ... FAILED
test root::bindgen_test_layout_EnumWrapper ... FAILED
test test ... ok

failures:

---- root::__bindgen_test_layout_underlying_type_t_open0_MyEnum_close0_instantiation stdout ----
thread 'root::__bindgen_test_layout_underlying_type_t_open0_MyEnum_close0_instantiation' panicked at 'assertion failed: `(left == right)`
  left: `1`,
 right: `4`: Size of template specialization: root :: std :: underlying_type_t', /run/media/aleok/data/programming/bindgen-mre/target/debug/build/bindgen-mre-b0317d4ce440433c/out/bindings.rs:52:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

---- root::bindgen_test_layout_EnumWrapper stdout ----
thread 'root::bindgen_test_layout_EnumWrapper' panicked at 'assertion failed: `(left == right)`
  left: `1`,
 right: `4`: Size of: EnumWrapper', /run/media/aleok/data/programming/bindgen-mre/target/debug/build/bindgen-mre-b0317d4ce440433c/out/bindings.rs:29:9

This is because the bindings are incorrect and underlying_type is incorrectly opaque:

/* automatically generated by rust-bindgen 0.59.2 */

#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
pub mod root {
    #[allow(unused_imports)]
    use self::super::root;
    pub mod std {
        #[allow(unused_imports)]
        use self::super::super::root;
        pub type __underlying_type_impl_type<_Tp> = _Tp;
        #[repr(C)]
        #[derive(Debug, Copy, Clone)]
        pub struct underlying_type {
            pub _address: u8,
        }
        pub type underlying_type_t = root::std::underlying_type;
    }
    pub const MyEnum_A: root::MyEnum = 0;
    pub const MyEnum_B: root::MyEnum = 1;
    pub const MyEnum_C: root::MyEnum = 2;
    pub type MyEnum = ::std::os::raw::c_int;
    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct EnumWrapper {
        pub inner: root::std::underlying_type_t,
    }
    /* ... tests ... */
}

Expected Results

/* automatically generated by rust-bindgen 0.59.2 */

#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
pub mod root {
    #[allow(unused_imports)]
    use self::super::root;
    #[repr(C)]
    #[derive(Debug, Copy, Clone)]
    pub struct EnumWrapper {
        pub inner: root::EnumWrapper_type,
    }
    pub type EnumWrapper_type = ::std::os::raw::c_int;
}

Note that these are actually the bindings generated if we use std::underlying_type<MyEnum>::type instead of std::underlying_type_t<MyEnum>! The issue happens with std::underlying_type_t.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions