Skip to content

Commit 33d9ecf

Browse files
committed
Handle mangling pointers.
Ugly, but better than crashing. Closes #506. Closes #453.
1 parent 0fed9ee commit 33d9ecf

9 files changed

+194
-33
lines changed

src/bindgen/mangle.rs

Lines changed: 70 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,61 +5,98 @@
55
use crate::bindgen::ir::{Path, Type};
66

77
pub fn mangle_path(path: &Path, generic_values: &[Type]) -> Path {
8-
internal_mangle_path(path, generic_values, true)
8+
Path::new(mangle_name(path.name(), generic_values))
99
}
1010

1111
pub fn mangle_name(name: &str, generic_values: &[Type]) -> String {
12-
internal_mangle_name(name, generic_values, true)
12+
Mangler::new(name, generic_values, /* last = */ true).mangle()
1313
}
1414

15-
fn internal_mangle_path(path: &Path, generic_values: &[Type], last_in_parent: bool) -> Path {
16-
let name = path.name();
17-
let mangled_name = internal_mangle_name(name, generic_values, last_in_parent);
18-
Path::new(mangled_name)
15+
enum Separator {
16+
OpeningAngleBracket = 1,
17+
Comma,
18+
ClosingAngleBracket,
19+
BeginMutPtr,
20+
BeginConstPtr,
1921
}
2022

21-
fn internal_mangle_name(name: &str, generic_values: &[Type], last_in_parent: bool) -> String {
22-
if generic_values.is_empty() {
23-
return name.to_owned();
23+
struct Mangler<'a> {
24+
input: &'a str,
25+
generic_values: &'a [Type],
26+
output: String,
27+
last: bool,
28+
}
29+
30+
impl<'a> Mangler<'a> {
31+
fn new(input: &'a str, generic_values: &'a [Type], last: bool) -> Self {
32+
Self {
33+
input,
34+
generic_values,
35+
output: String::new(),
36+
last,
37+
}
2438
}
2539

26-
let mut mangled = name.to_owned();
40+
fn mangle(mut self) -> String {
41+
self.mangle_internal();
42+
self.output
43+
}
2744

28-
mangled.push_str("_"); // <
29-
for (i, ty) in generic_values.iter().enumerate() {
30-
if i != 0 {
31-
mangled.push_str("__"); // ,
32-
}
45+
fn push(&mut self, id: Separator) {
46+
let separator = '_';
47+
let count = id as usize;
48+
self.output.extend(std::iter::repeat(separator).take(count));
49+
}
3350

34-
let is_last = i == generic_values.len() - 1;
51+
fn append_mangled_type(&mut self, ty: &Type, last: bool) {
3552
match *ty {
3653
Type::Path(ref generic) => {
37-
mangled.push_str(&internal_mangle_name(
38-
generic.export_name(),
39-
generic.generics(),
40-
last_in_parent && is_last,
41-
));
54+
let sub_path =
55+
Mangler::new(generic.export_name(), generic.generics(), last).mangle();
56+
self.output.push_str(&sub_path);
4257
}
4358
Type::Primitive(ref primitive) => {
44-
mangled.push_str(primitive.to_repr_rust());
59+
self.output.push_str(primitive.to_repr_rust());
60+
}
61+
Type::Ptr(ref ty) | Type::MutRef(ref ty) => {
62+
self.push(Separator::BeginMutPtr);
63+
self.append_mangled_type(&**ty, last);
64+
}
65+
Type::ConstPtr(ref ty) | Type::Ref(ref ty) => {
66+
self.push(Separator::BeginConstPtr);
67+
self.append_mangled_type(&**ty, last);
4568
}
46-
Type::MutRef(..)
47-
| Type::Ref(..)
48-
| Type::ConstPtr(..)
49-
| Type::Ptr(..)
50-
| Type::Array(..)
51-
| Type::FuncPtr(..) => {
52-
panic!("Unable to mangle generic parameter {:?} for '{}'", ty, name);
69+
Type::Array(..) | Type::FuncPtr(..) => {
70+
unimplemented!(
71+
"Unable to mangle generic parameter {:?} for '{}'",
72+
ty,
73+
self.input
74+
);
5375
}
5476
}
77+
}
78+
79+
fn mangle_internal(&mut self) {
80+
debug_assert!(self.output.is_empty());
81+
self.output = self.input.to_owned();
82+
if self.generic_values.is_empty() {
83+
return;
84+
}
85+
86+
self.push(Separator::OpeningAngleBracket);
87+
for (i, ty) in self.generic_values.iter().enumerate() {
88+
if i != 0 {
89+
self.push(Separator::Comma);
90+
}
91+
let last = self.last && i == self.generic_values.len() - 1;
92+
self.append_mangled_type(ty, last);
93+
}
5594

5695
// Skip writing the trailing '>' mangling when possible
57-
if is_last && !last_in_parent {
58-
mangled.push_str("___"); // >
96+
if !self.last {
97+
self.push(Separator::ClosingAngleBracket)
5998
}
6099
}
61-
62-
mangled
63100
}
64101

65102
#[test]
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
typedef struct Foo_____u8 {
7+
uint8_t *a;
8+
} Foo_____u8;
9+
10+
typedef Foo_____u8 Boo;
11+
12+
void root(Boo x);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
typedef struct Foo_____u8 {
7+
uint8_t *a;
8+
} Foo_____u8;
9+
10+
typedef Foo_____u8 Boo;
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif // __cplusplus
15+
16+
void root(Boo x);
17+
18+
#ifdef __cplusplus
19+
} // extern "C"
20+
#endif // __cplusplus

tests/expectations/generic-pointer.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
typedef struct {
7+
uint8_t *a;
8+
} Foo_____u8;
9+
10+
typedef Foo_____u8 Boo;
11+
12+
void root(Boo x);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
typedef struct {
7+
uint8_t *a;
8+
} Foo_____u8;
9+
10+
typedef Foo_____u8 Boo;
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif // __cplusplus
15+
16+
void root(Boo x);
17+
18+
#ifdef __cplusplus
19+
} // extern "C"
20+
#endif // __cplusplus
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#include <cstdarg>
2+
#include <cstdint>
3+
#include <cstdlib>
4+
#include <new>
5+
6+
template<typename T>
7+
struct Foo {
8+
T a;
9+
};
10+
11+
using Boo = Foo<uint8_t*>;
12+
13+
extern "C" {
14+
15+
void root(Boo x);
16+
17+
} // extern "C"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
struct Foo_____u8 {
7+
uint8_t *a;
8+
};
9+
10+
typedef struct Foo_____u8 Boo;
11+
12+
void root(Boo x);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <stdarg.h>
2+
#include <stdbool.h>
3+
#include <stdint.h>
4+
#include <stdlib.h>
5+
6+
struct Foo_____u8 {
7+
uint8_t *a;
8+
};
9+
10+
typedef struct Foo_____u8 Boo;
11+
12+
#ifdef __cplusplus
13+
extern "C" {
14+
#endif // __cplusplus
15+
16+
void root(Boo x);
17+
18+
#ifdef __cplusplus
19+
} // extern "C"
20+
#endif // __cplusplus

tests/rust/generic-pointer.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[repr(C)]
2+
pub struct Foo<T> {
3+
a: T,
4+
}
5+
6+
pub type Boo = Foo<*mut u8>;
7+
8+
#[no_mangle]
9+
pub extern "C" fn root(
10+
x: Boo,
11+
) { }

0 commit comments

Comments
 (0)