Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix specialization of SomeType<N> when N is a const parameter. #762

Merged
merged 1 commit into from May 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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] } }
}