diff --git a/src/bindgen/ir/generic_path.rs b/src/bindgen/ir/generic_path.rs index 861d51a07..ef14890ab 100644 --- a/src/bindgen/ir/generic_path.rs +++ b/src/bindgen/ir/generic_path.rs @@ -159,7 +159,20 @@ pub enum GenericArgument { impl GenericArgument { pub fn specialize(&self, mappings: &[(&Path, &GenericArgument)]) -> GenericArgument { match *self { - GenericArgument::Type(ref ty) => GenericArgument::Type(ty.specialize(mappings)), + GenericArgument::Type(ref ty) => { + if let Type::Path(ref path) = *ty { + if path.is_single_identifier() { + // See note on `GenericArgument` above: `ty` may + // actually be the name of a const. Check for that now. + for &(name, value) in mappings { + if *name == path.path { + return value.clone(); + } + } + } + } + GenericArgument::Type(ty.specialize(mappings)) + } GenericArgument::Const(ref expr) => GenericArgument::Const(expr.clone()), } } diff --git a/tests/expectations/const_generics_thru.both.c b/tests/expectations/const_generics_thru.both.c new file mode 100644 index 000000000..4f5d5b357 --- /dev/null +++ b/tests/expectations/const_generics_thru.both.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +typedef struct Inner_1 { + uint8_t bytes[1]; +} Inner_1; + +typedef struct Outer_1 { + struct Inner_1 inner; +} Outer_1; + +typedef struct Inner_2 { + uint8_t bytes[2]; +} Inner_2; + +typedef struct Outer_2 { + struct Inner_2 inner; +} Outer_2; + +struct Outer_1 one(void); + +struct Outer_2 two(void); diff --git a/tests/expectations/const_generics_thru.both.compat.c b/tests/expectations/const_generics_thru.both.compat.c new file mode 100644 index 000000000..8659d4e4b --- /dev/null +++ b/tests/expectations/const_generics_thru.both.compat.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +typedef struct Inner_1 { + uint8_t bytes[1]; +} Inner_1; + +typedef struct Outer_1 { + struct Inner_1 inner; +} Outer_1; + +typedef struct Inner_2 { + uint8_t bytes[2]; +} Inner_2; + +typedef struct Outer_2 { + struct Inner_2 inner; +} Outer_2; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct Outer_1 one(void); + +struct Outer_2 two(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_thru.c b/tests/expectations/const_generics_thru.c new file mode 100644 index 000000000..31031e971 --- /dev/null +++ b/tests/expectations/const_generics_thru.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +typedef struct { + uint8_t bytes[1]; +} Inner_1; + +typedef struct { + Inner_1 inner; +} Outer_1; + +typedef struct { + uint8_t bytes[2]; +} Inner_2; + +typedef struct { + Inner_2 inner; +} Outer_2; + +Outer_1 one(void); + +Outer_2 two(void); diff --git a/tests/expectations/const_generics_thru.compat.c b/tests/expectations/const_generics_thru.compat.c new file mode 100644 index 000000000..d80c949ea --- /dev/null +++ b/tests/expectations/const_generics_thru.compat.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +typedef struct { + uint8_t bytes[1]; +} Inner_1; + +typedef struct { + Inner_1 inner; +} Outer_1; + +typedef struct { + uint8_t bytes[2]; +} Inner_2; + +typedef struct { + Inner_2 inner; +} Outer_2; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +Outer_1 one(void); + +Outer_2 two(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_thru.cpp b/tests/expectations/const_generics_thru.cpp new file mode 100644 index 000000000..0ca252926 --- /dev/null +++ b/tests/expectations/const_generics_thru.cpp @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include + +template +struct Inner { + uint8_t bytes[N]; +}; + +template +struct Outer { + Inner inner; +}; + +extern "C" { + +Outer<1> one(); + +Outer<2> two(); + +} // extern "C" diff --git a/tests/expectations/const_generics_thru.pyx b/tests/expectations/const_generics_thru.pyx new file mode 100644 index 000000000..784662e9d --- /dev/null +++ b/tests/expectations/const_generics_thru.pyx @@ -0,0 +1,23 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + ctypedef struct Inner_1: + uint8_t bytes[1]; + + ctypedef struct Outer_1: + Inner_1 inner; + + ctypedef struct Inner_2: + uint8_t bytes[2]; + + ctypedef struct Outer_2: + Inner_2 inner; + + Outer_1 one(); + + Outer_2 two(); diff --git a/tests/expectations/const_generics_thru.tag.c b/tests/expectations/const_generics_thru.tag.c new file mode 100644 index 000000000..624fe8ff1 --- /dev/null +++ b/tests/expectations/const_generics_thru.tag.c @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +struct Inner_1 { + uint8_t bytes[1]; +}; + +struct Outer_1 { + struct Inner_1 inner; +}; + +struct Inner_2 { + uint8_t bytes[2]; +}; + +struct Outer_2 { + struct Inner_2 inner; +}; + +struct Outer_1 one(void); + +struct Outer_2 two(void); diff --git a/tests/expectations/const_generics_thru.tag.compat.c b/tests/expectations/const_generics_thru.tag.compat.c new file mode 100644 index 000000000..55d58f216 --- /dev/null +++ b/tests/expectations/const_generics_thru.tag.compat.c @@ -0,0 +1,32 @@ +#include +#include +#include +#include + +struct Inner_1 { + uint8_t bytes[1]; +}; + +struct Outer_1 { + struct Inner_1 inner; +}; + +struct Inner_2 { + uint8_t bytes[2]; +}; + +struct Outer_2 { + struct Inner_2 inner; +}; + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +struct Outer_1 one(void); + +struct Outer_2 two(void); + +#ifdef __cplusplus +} // extern "C" +#endif // __cplusplus diff --git a/tests/expectations/const_generics_thru.tag.pyx b/tests/expectations/const_generics_thru.tag.pyx new file mode 100644 index 000000000..cc8a0fcd8 --- /dev/null +++ b/tests/expectations/const_generics_thru.tag.pyx @@ -0,0 +1,23 @@ +from libc.stdint cimport int8_t, int16_t, int32_t, int64_t, intptr_t +from libc.stdint cimport uint8_t, uint16_t, uint32_t, uint64_t, uintptr_t +cdef extern from *: + ctypedef bint bool + ctypedef struct va_list + +cdef extern from *: + + cdef struct Inner_1: + uint8_t bytes[1]; + + cdef struct Outer_1: + Inner_1 inner; + + cdef struct Inner_2: + uint8_t bytes[2]; + + cdef struct Outer_2: + Inner_2 inner; + + Outer_1 one(); + + Outer_2 two(); diff --git a/tests/rust/const_generics_thru.rs b/tests/rust/const_generics_thru.rs new file mode 100644 index 000000000..51b279cb0 --- /dev/null +++ b/tests/rust/const_generics_thru.rs @@ -0,0 +1,22 @@ +// Propagating const arguments through generics that use generics. + +#[repr(C)] +pub struct Inner { + pub bytes: [u8; N], +} + +#[repr(C)] +pub struct Outer { + pub inner: Inner, // don't declare two different structs named `Inner_N` +} + +#[no_mangle] +pub extern "C" fn one() -> Outer<1> { + Outer { inner: Inner { bytes: [0] } } +} + +#[no_mangle] +pub extern "C" fn two() -> Outer<2> { + Outer { inner: Inner { bytes: [0, 0] } } +} +