Skip to content

Commit 9b6d0e8

Browse files
committed
Work around a libclang bug / limitation.
For references, libclang returns the size and align of the pointee. This actually matches how C++'s sizeof() and alignof() works, for some reason, though in this case we really want to know the pointer's layout. Anyhow, we know the target pointer size, so manually handle this case. Filed https://bugs.llvm.org/show_bug.cgi?id=40975 for this.
1 parent 3a6864c commit 9b6d0e8

File tree

10 files changed

+225
-33
lines changed

10 files changed

+225
-33
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,17 @@ Released YYYY/MM/DD
9292

9393
* TODO (or remove section if none)
9494

95+
--------------------------------------------------------------------------------
96+
97+
# 0.48.1
98+
99+
Released 2019/03/06
100+
101+
## Fixed
102+
103+
* Bindgen will properly lay out types that use reference members. [#1531][]
104+
105+
[#1531]: https://github.com/rust-lang-nursery/rust-bindgen/issues/1531
95106

96107
--------------------------------------------------------------------------------
97108

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ readme = "README.md"
1414
repository = "https://github.com/rust-lang/rust-bindgen"
1515
documentation = "https://docs.rs/bindgen"
1616
homepage = "https://rust-lang.github.io/rust-bindgen/"
17-
version = "0.48.0"
17+
version = "0.48.1"
1818
build = "build.rs"
1919

2020
include = [

src/clang.rs

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use cexpr;
88
use clang_sys::*;
99
use regex;
10+
use ir::context::BindgenContext;
1011
use std::{mem, ptr, slice};
1112
use std::ffi::{CStr, CString};
1213
use std::fmt;
@@ -933,35 +934,44 @@ impl Type {
933934

934935
#[inline]
935936
fn is_non_deductible_auto_type(&self) -> bool {
936-
self.kind() == CXType_Auto && self.canonical_type() == *self
937+
debug_assert_eq!(self.kind(), CXType_Auto);
938+
self.canonical_type() == *self
937939
}
938940

939941
#[inline]
940-
fn clang_size_of(&self) -> c_longlong {
941-
if self.is_non_deductible_auto_type() {
942-
return -6; // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
942+
fn clang_size_of(&self, ctx: &BindgenContext) -> c_longlong {
943+
match self.kind() {
944+
// Work-around https://bugs.llvm.org/show_bug.cgi?id=40975
945+
CXType_RValueReference |
946+
CXType_LValueReference => ctx.target_pointer_size() as c_longlong,
947+
// Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
948+
CXType_Auto if self.is_non_deductible_auto_type() => return -6,
949+
_ => unsafe { clang_Type_getSizeOf(self.x) },
943950
}
944-
unsafe { clang_Type_getSizeOf(self.x) }
945951
}
946952

947953
#[inline]
948-
fn clang_align_of(&self) -> c_longlong {
949-
if self.is_non_deductible_auto_type() {
950-
return -6; // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
954+
fn clang_align_of(&self, ctx: &BindgenContext) -> c_longlong {
955+
match self.kind() {
956+
// Work-around https://bugs.llvm.org/show_bug.cgi?id=40975
957+
CXType_RValueReference |
958+
CXType_LValueReference => ctx.target_pointer_size() as c_longlong,
959+
// Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
960+
CXType_Auto if self.is_non_deductible_auto_type() => return -6,
961+
_ => unsafe { clang_Type_getAlignOf(self.x) },
951962
}
952-
unsafe { clang_Type_getAlignOf(self.x) }
953963
}
954964

955965
/// What is the size of this type? Paper over invalid types by returning `0`
956966
/// for them.
957-
pub fn size(&self) -> usize {
958-
let val = self.clang_size_of();
967+
pub fn size(&self, ctx: &BindgenContext) -> usize {
968+
let val = self.clang_size_of(ctx);
959969
if val < 0 { 0 } else { val as usize }
960970
}
961971

962972
/// What is the size of this type?
963-
pub fn fallible_size(&self) -> Result<usize, LayoutError> {
964-
let val = self.clang_size_of();
973+
pub fn fallible_size(&self, ctx: &BindgenContext) -> Result<usize, LayoutError> {
974+
let val = self.clang_size_of(ctx);
965975
if val < 0 {
966976
Err(LayoutError::from(val as i32))
967977
} else {
@@ -971,14 +981,14 @@ impl Type {
971981

972982
/// What is the alignment of this type? Paper over invalid types by
973983
/// returning `0`.
974-
pub fn align(&self) -> usize {
975-
let val = self.clang_align_of();
984+
pub fn align(&self, ctx: &BindgenContext) -> usize {
985+
let val = self.clang_align_of(ctx);
976986
if val < 0 { 0 } else { val as usize }
977987
}
978988

979989
/// What is the alignment of this type?
980-
pub fn fallible_align(&self) -> Result<usize, LayoutError> {
981-
let val = self.clang_align_of();
990+
pub fn fallible_align(&self, ctx: &BindgenContext) -> Result<usize, LayoutError> {
991+
let val = self.clang_align_of(ctx);
982992
if val < 0 {
983993
Err(LayoutError::from(val as i32))
984994
} else {
@@ -988,10 +998,10 @@ impl Type {
988998

989999
/// Get the layout for this type, or an error describing why it does not
9901000
/// have a valid layout.
991-
pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> {
1001+
pub fn fallible_layout(&self, ctx: &BindgenContext) -> Result<::ir::layout::Layout, LayoutError> {
9921002
use ir::layout::Layout;
993-
let size = self.fallible_size()?;
994-
let align = self.fallible_align()?;
1003+
let size = self.fallible_size(ctx)?;
1004+
let align = self.fallible_align(ctx)?;
9951005
Ok(Layout::new(size, align))
9961006
}
9971007

src/ir/context.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1755,7 +1755,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
17551755
sub_name,
17561756
template_decl_cursor
17571757
.cur_type()
1758-
.fallible_layout()
1758+
.fallible_layout(self)
17591759
.ok(),
17601760
sub_kind,
17611761
false,
@@ -1821,7 +1821,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
18211821
let name = if name.is_empty() { None } else { Some(name) };
18221822
let ty = Type::new(
18231823
name,
1824-
ty.fallible_layout().ok(),
1824+
ty.fallible_layout(self).ok(),
18251825
type_kind,
18261826
ty.is_const(),
18271827
);
@@ -1977,7 +1977,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
19771977
is_const: bool,
19781978
) -> TypeId {
19791979
let spelling = ty.spelling();
1980-
let layout = ty.fallible_layout().ok();
1980+
let layout = ty.fallible_layout(self).ok();
19811981
let type_kind = TypeKind::ResolvedTypeRef(wrapped_id);
19821982
let ty = Type::new(Some(spelling), layout, type_kind, is_const);
19831983
let item = Item::new(
@@ -2018,7 +2018,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
20182018
CXType_UShort => TypeKind::Int(IntKind::UShort),
20192019
CXType_WChar => {
20202020
TypeKind::Int(IntKind::WChar {
2021-
size: ty.fallible_size().expect("Couldn't compute size of wchar_t?"),
2021+
size: ty.fallible_size(self).expect("Couldn't compute size of wchar_t?"),
20222022
})
20232023
},
20242024
CXType_Char16 => TypeKind::Int(IntKind::U16),
@@ -2056,7 +2056,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
20562056

20572057
let spelling = ty.spelling();
20582058
let is_const = ty.is_const();
2059-
let layout = ty.fallible_layout().ok();
2059+
let layout = ty.fallible_layout(self).ok();
20602060
let ty = Type::new(Some(spelling), layout, type_kind, is_const);
20612061
let id = self.next_item_id();
20622062
let item =

src/ir/item.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,7 @@ impl Item {
454454
ty: &clang::Type,
455455
ctx: &mut BindgenContext,
456456
) -> TypeId {
457-
let ty = Opaque::from_clang_ty(ty);
457+
let ty = Opaque::from_clang_ty(ty, ctx);
458458
let kind = ItemKind::Type(ty);
459459
let parent = ctx.root_module().into();
460460
ctx.add_item(Item::new(with_id, None, None, parent, kind), None, None);

src/ir/layout.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ pub struct Opaque(pub Layout);
100100

101101
impl Opaque {
102102
/// Construct a new opaque type from the given clang type.
103-
pub fn from_clang_ty(ty: &clang::Type) -> Type {
104-
let layout = Layout::new(ty.size(), ty.align());
103+
pub fn from_clang_ty(ty: &clang::Type, ctx: &BindgenContext) -> Type {
104+
let layout = Layout::new(ty.size(ctx), ty.align(ctx));
105105
let ty_kind = TypeKind::Opaque;
106106
let is_const = ty.is_const();
107107
Type::new(None, Some(layout), ty_kind, is_const)

src/ir/ty.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -730,7 +730,7 @@ impl Type {
730730
}
731731
}
732732

733-
let layout = ty.fallible_layout().ok();
733+
let layout = ty.fallible_layout(ctx).ok();
734734
let cursor = ty.declaration();
735735
let mut name = cursor.spelling();
736736

@@ -780,7 +780,7 @@ impl Type {
780780
opaque type instead."
781781
);
782782
return Ok(
783-
ParseResult::New(Opaque::from_clang_ty(&canonical_ty), None),
783+
ParseResult::New(Opaque::from_clang_ty(&canonical_ty, ctx), None),
784784
);
785785
}
786786

@@ -912,7 +912,7 @@ impl Type {
912912
from class template or base \
913913
specifier, using opaque blob"
914914
);
915-
let opaque = Opaque::from_clang_ty(ty);
915+
let opaque = Opaque::from_clang_ty(ty, ctx);
916916
return Ok(
917917
ParseResult::New(opaque, None),
918918
);
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/* automatically generated by rust-bindgen */
2+
3+
#![allow(
4+
dead_code,
5+
non_snake_case,
6+
non_camel_case_types,
7+
non_upper_case_globals
8+
)]
9+
10+
#[repr(C)]
11+
#[derive(Debug, Copy, Clone)]
12+
pub struct Foo {
13+
_unused: [u8; 0],
14+
}
15+
#[repr(C)]
16+
#[derive(Debug, Copy, Clone)]
17+
pub struct Bar {
18+
pub f: *const Foo,
19+
pub m: ::std::os::raw::c_uint,
20+
}
21+
#[test]
22+
fn bindgen_test_layout_Bar() {
23+
assert_eq!(
24+
::std::mem::size_of::<Bar>(),
25+
16usize,
26+
concat!("Size of: ", stringify!(Bar))
27+
);
28+
assert_eq!(
29+
::std::mem::align_of::<Bar>(),
30+
8usize,
31+
concat!("Alignment of ", stringify!(Bar))
32+
);
33+
assert_eq!(
34+
unsafe { &(*(::std::ptr::null::<Bar>())).f as *const _ as usize },
35+
0usize,
36+
concat!("Offset of field: ", stringify!(Bar), "::", stringify!(f))
37+
);
38+
assert_eq!(
39+
unsafe { &(*(::std::ptr::null::<Bar>())).m as *const _ as usize },
40+
8usize,
41+
concat!("Offset of field: ", stringify!(Bar), "::", stringify!(m))
42+
);
43+
}
44+
impl Default for Bar {
45+
fn default() -> Self {
46+
unsafe { ::std::mem::zeroed() }
47+
}
48+
}
49+
#[repr(C)]
50+
#[derive(Debug, Copy, Clone)]
51+
pub struct Baz {
52+
pub f: *mut Foo,
53+
pub m: ::std::os::raw::c_uint,
54+
}
55+
#[test]
56+
fn bindgen_test_layout_Baz() {
57+
assert_eq!(
58+
::std::mem::size_of::<Baz>(),
59+
16usize,
60+
concat!("Size of: ", stringify!(Baz))
61+
);
62+
assert_eq!(
63+
::std::mem::align_of::<Baz>(),
64+
8usize,
65+
concat!("Alignment of ", stringify!(Baz))
66+
);
67+
assert_eq!(
68+
unsafe { &(*(::std::ptr::null::<Baz>())).f as *const _ as usize },
69+
0usize,
70+
concat!("Offset of field: ", stringify!(Baz), "::", stringify!(f))
71+
);
72+
assert_eq!(
73+
unsafe { &(*(::std::ptr::null::<Baz>())).m as *const _ as usize },
74+
8usize,
75+
concat!("Offset of field: ", stringify!(Baz), "::", stringify!(m))
76+
);
77+
}
78+
impl Default for Baz {
79+
fn default() -> Self {
80+
unsafe { ::std::mem::zeroed() }
81+
}
82+
}
83+
#[repr(C)]
84+
#[derive(Debug, Copy, Clone)]
85+
pub struct Tar {
86+
pub f: *const Foo,
87+
pub m: ::std::os::raw::c_uint,
88+
}
89+
#[test]
90+
fn bindgen_test_layout_Tar() {
91+
assert_eq!(
92+
::std::mem::size_of::<Tar>(),
93+
16usize,
94+
concat!("Size of: ", stringify!(Tar))
95+
);
96+
assert_eq!(
97+
::std::mem::align_of::<Tar>(),
98+
8usize,
99+
concat!("Alignment of ", stringify!(Tar))
100+
);
101+
assert_eq!(
102+
unsafe { &(*(::std::ptr::null::<Tar>())).f as *const _ as usize },
103+
0usize,
104+
concat!("Offset of field: ", stringify!(Tar), "::", stringify!(f))
105+
);
106+
assert_eq!(
107+
unsafe { &(*(::std::ptr::null::<Tar>())).m as *const _ as usize },
108+
8usize,
109+
concat!("Offset of field: ", stringify!(Tar), "::", stringify!(m))
110+
);
111+
}
112+
impl Default for Tar {
113+
fn default() -> Self {
114+
unsafe { ::std::mem::zeroed() }
115+
}
116+
}
117+
#[repr(C)]
118+
#[derive(Debug, Copy, Clone)]
119+
pub struct Taz {
120+
pub f: *mut Foo,
121+
pub m: ::std::os::raw::c_uint,
122+
}
123+
#[test]
124+
fn bindgen_test_layout_Taz() {
125+
assert_eq!(
126+
::std::mem::size_of::<Taz>(),
127+
16usize,
128+
concat!("Size of: ", stringify!(Taz))
129+
);
130+
assert_eq!(
131+
::std::mem::align_of::<Taz>(),
132+
8usize,
133+
concat!("Alignment of ", stringify!(Taz))
134+
);
135+
assert_eq!(
136+
unsafe { &(*(::std::ptr::null::<Taz>())).f as *const _ as usize },
137+
0usize,
138+
concat!("Offset of field: ", stringify!(Taz), "::", stringify!(f))
139+
);
140+
assert_eq!(
141+
unsafe { &(*(::std::ptr::null::<Taz>())).m as *const _ as usize },
142+
8usize,
143+
concat!("Offset of field: ", stringify!(Taz), "::", stringify!(m))
144+
);
145+
}
146+
impl Default for Taz {
147+
fn default() -> Self {
148+
unsafe { ::std::mem::zeroed() }
149+
}
150+
}

tests/headers/issue-1443.hpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
struct Foo;
2+
3+
struct Bar {
4+
const Foo& f;
5+
unsigned m;
6+
};
7+
8+
struct Baz {
9+
Foo& f;
10+
unsigned m;
11+
};
12+
13+
struct Tar {
14+
const Foo&& f;
15+
unsigned m;
16+
};
17+
18+
struct Taz {
19+
Foo&& f;
20+
unsigned m;
21+
};

0 commit comments

Comments
 (0)