Skip to content

Commit

Permalink
Fix specialization of SomeType<N> when N is a const parameter.
Browse files Browse the repository at this point in the history
Fixes #761.
  • Loading branch information
jorendorff authored and emilio committed May 25, 2022
1 parent 13b31dd commit a79a10d
Show file tree
Hide file tree
Showing 11 changed files with 273 additions and 1 deletion.
15 changes: 14 additions & 1 deletion src/bindgen/ir/generic_path.rs
Expand Up @@ -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()),
}
}
Expand Down
24 changes: 24 additions & 0 deletions tests/expectations/const_generics_thru.both.c
@@ -0,0 +1,24 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

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);
32 changes: 32 additions & 0 deletions tests/expectations/const_generics_thru.both.compat.c
@@ -0,0 +1,32 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

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
24 changes: 24 additions & 0 deletions tests/expectations/const_generics_thru.c
@@ -0,0 +1,24 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

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);
32 changes: 32 additions & 0 deletions tests/expectations/const_generics_thru.compat.c
@@ -0,0 +1,32 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

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
23 changes: 23 additions & 0 deletions tests/expectations/const_generics_thru.cpp
@@ -0,0 +1,23 @@
#include <cstdarg>
#include <cstdint>
#include <cstdlib>
#include <ostream>
#include <new>

template<uintptr_t N>
struct Inner {
uint8_t bytes[N];
};

template<uintptr_t N>
struct Outer {
Inner<N> inner;
};

extern "C" {

Outer<1> one();

Outer<2> two();

} // extern "C"
23 changes: 23 additions & 0 deletions 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();
24 changes: 24 additions & 0 deletions tests/expectations/const_generics_thru.tag.c
@@ -0,0 +1,24 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

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);
32 changes: 32 additions & 0 deletions tests/expectations/const_generics_thru.tag.compat.c
@@ -0,0 +1,32 @@
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>

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
23 changes: 23 additions & 0 deletions 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();
22 changes: 22 additions & 0 deletions tests/rust/const_generics_thru.rs
@@ -0,0 +1,22 @@
// Propagating const arguments through generics that use generics.

#[repr(C)]
pub struct Inner<const N: usize> {
pub bytes: [u8; N],
}

#[repr(C)]
pub struct Outer<const N: usize> {
pub inner: Inner<N>, // 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] } }
}

0 comments on commit a79a10d

Please sign in to comment.