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.
This commit is contained in:
Emilio Cobos Álvarez 2019-03-06 13:01:18 +01:00
parent 3a6864cf9a
commit 9b6d0e84b4
10 changed files with 225 additions and 33 deletions

View File

@ -92,6 +92,17 @@ Released YYYY/MM/DD
* TODO (or remove section if none)
--------------------------------------------------------------------------------
# 0.48.1
Released 2019/03/06
## Fixed
* Bindgen will properly lay out types that use reference members. [#1531][]
[#1531]: https://github.com/rust-lang-nursery/rust-bindgen/issues/1531
--------------------------------------------------------------------------------

2
Cargo.lock generated
View File

@ -49,7 +49,7 @@ dependencies = [
[[package]]
name = "bindgen"
version = "0.48.0"
version = "0.48.1"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cexpr 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",

View File

@ -14,7 +14,7 @@ readme = "README.md"
repository = "https://github.com/rust-lang/rust-bindgen"
documentation = "https://docs.rs/bindgen"
homepage = "https://rust-lang.github.io/rust-bindgen/"
version = "0.48.0"
version = "0.48.1"
build = "build.rs"
include = [

View File

@ -7,6 +7,7 @@
use cexpr;
use clang_sys::*;
use regex;
use ir::context::BindgenContext;
use std::{mem, ptr, slice};
use std::ffi::{CStr, CString};
use std::fmt;
@ -933,35 +934,44 @@ impl Type {
#[inline]
fn is_non_deductible_auto_type(&self) -> bool {
self.kind() == CXType_Auto && self.canonical_type() == *self
debug_assert_eq!(self.kind(), CXType_Auto);
self.canonical_type() == *self
}
#[inline]
fn clang_size_of(&self) -> c_longlong {
if self.is_non_deductible_auto_type() {
return -6; // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
fn clang_size_of(&self, ctx: &BindgenContext) -> c_longlong {
match self.kind() {
// Work-around https://bugs.llvm.org/show_bug.cgi?id=40975
CXType_RValueReference |
CXType_LValueReference => ctx.target_pointer_size() as c_longlong,
// Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
CXType_Auto if self.is_non_deductible_auto_type() => return -6,
_ => unsafe { clang_Type_getSizeOf(self.x) },
}
unsafe { clang_Type_getSizeOf(self.x) }
}
#[inline]
fn clang_align_of(&self) -> c_longlong {
if self.is_non_deductible_auto_type() {
return -6; // Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
fn clang_align_of(&self, ctx: &BindgenContext) -> c_longlong {
match self.kind() {
// Work-around https://bugs.llvm.org/show_bug.cgi?id=40975
CXType_RValueReference |
CXType_LValueReference => ctx.target_pointer_size() as c_longlong,
// Work-around https://bugs.llvm.org/show_bug.cgi?id=40813
CXType_Auto if self.is_non_deductible_auto_type() => return -6,
_ => unsafe { clang_Type_getAlignOf(self.x) },
}
unsafe { clang_Type_getAlignOf(self.x) }
}
/// What is the size of this type? Paper over invalid types by returning `0`
/// for them.
pub fn size(&self) -> usize {
let val = self.clang_size_of();
pub fn size(&self, ctx: &BindgenContext) -> usize {
let val = self.clang_size_of(ctx);
if val < 0 { 0 } else { val as usize }
}
/// What is the size of this type?
pub fn fallible_size(&self) -> Result<usize, LayoutError> {
let val = self.clang_size_of();
pub fn fallible_size(&self, ctx: &BindgenContext) -> Result<usize, LayoutError> {
let val = self.clang_size_of(ctx);
if val < 0 {
Err(LayoutError::from(val as i32))
} else {
@ -971,14 +981,14 @@ impl Type {
/// What is the alignment of this type? Paper over invalid types by
/// returning `0`.
pub fn align(&self) -> usize {
let val = self.clang_align_of();
pub fn align(&self, ctx: &BindgenContext) -> usize {
let val = self.clang_align_of(ctx);
if val < 0 { 0 } else { val as usize }
}
/// What is the alignment of this type?
pub fn fallible_align(&self) -> Result<usize, LayoutError> {
let val = self.clang_align_of();
pub fn fallible_align(&self, ctx: &BindgenContext) -> Result<usize, LayoutError> {
let val = self.clang_align_of(ctx);
if val < 0 {
Err(LayoutError::from(val as i32))
} else {
@ -988,10 +998,10 @@ impl Type {
/// Get the layout for this type, or an error describing why it does not
/// have a valid layout.
pub fn fallible_layout(&self) -> Result<::ir::layout::Layout, LayoutError> {
pub fn fallible_layout(&self, ctx: &BindgenContext) -> Result<::ir::layout::Layout, LayoutError> {
use ir::layout::Layout;
let size = self.fallible_size()?;
let align = self.fallible_align()?;
let size = self.fallible_size(ctx)?;
let align = self.fallible_align(ctx)?;
Ok(Layout::new(size, align))
}

View File

@ -1755,7 +1755,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
sub_name,
template_decl_cursor
.cur_type()
.fallible_layout()
.fallible_layout(self)
.ok(),
sub_kind,
false,
@ -1821,7 +1821,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
let name = if name.is_empty() { None } else { Some(name) };
let ty = Type::new(
name,
ty.fallible_layout().ok(),
ty.fallible_layout(self).ok(),
type_kind,
ty.is_const(),
);
@ -1977,7 +1977,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
is_const: bool,
) -> TypeId {
let spelling = ty.spelling();
let layout = ty.fallible_layout().ok();
let layout = ty.fallible_layout(self).ok();
let type_kind = TypeKind::ResolvedTypeRef(wrapped_id);
let ty = Type::new(Some(spelling), layout, type_kind, is_const);
let item = Item::new(
@ -2018,7 +2018,7 @@ If you encounter an error missing from this list, please file an issue or a PR!"
CXType_UShort => TypeKind::Int(IntKind::UShort),
CXType_WChar => {
TypeKind::Int(IntKind::WChar {
size: ty.fallible_size().expect("Couldn't compute size of wchar_t?"),
size: ty.fallible_size(self).expect("Couldn't compute size of wchar_t?"),
})
},
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!"
let spelling = ty.spelling();
let is_const = ty.is_const();
let layout = ty.fallible_layout().ok();
let layout = ty.fallible_layout(self).ok();
let ty = Type::new(Some(spelling), layout, type_kind, is_const);
let id = self.next_item_id();
let item =

View File

@ -454,7 +454,7 @@ impl Item {
ty: &clang::Type,
ctx: &mut BindgenContext,
) -> TypeId {
let ty = Opaque::from_clang_ty(ty);
let ty = Opaque::from_clang_ty(ty, ctx);
let kind = ItemKind::Type(ty);
let parent = ctx.root_module().into();
ctx.add_item(Item::new(with_id, None, None, parent, kind), None, None);

View File

@ -100,8 +100,8 @@ pub struct Opaque(pub Layout);
impl Opaque {
/// Construct a new opaque type from the given clang type.
pub fn from_clang_ty(ty: &clang::Type) -> Type {
let layout = Layout::new(ty.size(), ty.align());
pub fn from_clang_ty(ty: &clang::Type, ctx: &BindgenContext) -> Type {
let layout = Layout::new(ty.size(ctx), ty.align(ctx));
let ty_kind = TypeKind::Opaque;
let is_const = ty.is_const();
Type::new(None, Some(layout), ty_kind, is_const)

View File

@ -730,7 +730,7 @@ impl Type {
}
}
let layout = ty.fallible_layout().ok();
let layout = ty.fallible_layout(ctx).ok();
let cursor = ty.declaration();
let mut name = cursor.spelling();
@ -780,7 +780,7 @@ impl Type {
opaque type instead."
);
return Ok(
ParseResult::New(Opaque::from_clang_ty(&canonical_ty), None),
ParseResult::New(Opaque::from_clang_ty(&canonical_ty, ctx), None),
);
}
@ -912,7 +912,7 @@ impl Type {
from class template or base \
specifier, using opaque blob"
);
let opaque = Opaque::from_clang_ty(ty);
let opaque = Opaque::from_clang_ty(ty, ctx);
return Ok(
ParseResult::New(opaque, None),
);

View File

@ -0,0 +1,150 @@
/* automatically generated by rust-bindgen */
#![allow(
dead_code,
non_snake_case,
non_camel_case_types,
non_upper_case_globals
)]
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Foo {
_unused: [u8; 0],
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Bar {
pub f: *const Foo,
pub m: ::std::os::raw::c_uint,
}
#[test]
fn bindgen_test_layout_Bar() {
assert_eq!(
::std::mem::size_of::<Bar>(),
16usize,
concat!("Size of: ", stringify!(Bar))
);
assert_eq!(
::std::mem::align_of::<Bar>(),
8usize,
concat!("Alignment of ", stringify!(Bar))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Bar>())).f as *const _ as usize },
0usize,
concat!("Offset of field: ", stringify!(Bar), "::", stringify!(f))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Bar>())).m as *const _ as usize },
8usize,
concat!("Offset of field: ", stringify!(Bar), "::", stringify!(m))
);
}
impl Default for Bar {
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Baz {
pub f: *mut Foo,
pub m: ::std::os::raw::c_uint,
}
#[test]
fn bindgen_test_layout_Baz() {
assert_eq!(
::std::mem::size_of::<Baz>(),
16usize,
concat!("Size of: ", stringify!(Baz))
);
assert_eq!(
::std::mem::align_of::<Baz>(),
8usize,
concat!("Alignment of ", stringify!(Baz))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Baz>())).f as *const _ as usize },
0usize,
concat!("Offset of field: ", stringify!(Baz), "::", stringify!(f))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Baz>())).m as *const _ as usize },
8usize,
concat!("Offset of field: ", stringify!(Baz), "::", stringify!(m))
);
}
impl Default for Baz {
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Tar {
pub f: *const Foo,
pub m: ::std::os::raw::c_uint,
}
#[test]
fn bindgen_test_layout_Tar() {
assert_eq!(
::std::mem::size_of::<Tar>(),
16usize,
concat!("Size of: ", stringify!(Tar))
);
assert_eq!(
::std::mem::align_of::<Tar>(),
8usize,
concat!("Alignment of ", stringify!(Tar))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Tar>())).f as *const _ as usize },
0usize,
concat!("Offset of field: ", stringify!(Tar), "::", stringify!(f))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Tar>())).m as *const _ as usize },
8usize,
concat!("Offset of field: ", stringify!(Tar), "::", stringify!(m))
);
}
impl Default for Tar {
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
}
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct Taz {
pub f: *mut Foo,
pub m: ::std::os::raw::c_uint,
}
#[test]
fn bindgen_test_layout_Taz() {
assert_eq!(
::std::mem::size_of::<Taz>(),
16usize,
concat!("Size of: ", stringify!(Taz))
);
assert_eq!(
::std::mem::align_of::<Taz>(),
8usize,
concat!("Alignment of ", stringify!(Taz))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Taz>())).f as *const _ as usize },
0usize,
concat!("Offset of field: ", stringify!(Taz), "::", stringify!(f))
);
assert_eq!(
unsafe { &(*(::std::ptr::null::<Taz>())).m as *const _ as usize },
8usize,
concat!("Offset of field: ", stringify!(Taz), "::", stringify!(m))
);
}
impl Default for Taz {
fn default() -> Self {
unsafe { ::std::mem::zeroed() }
}
}

View File

@ -0,0 +1,21 @@
struct Foo;
struct Bar {
const Foo& f;
unsigned m;
};
struct Baz {
Foo& f;
unsigned m;
};
struct Tar {
const Foo&& f;
unsigned m;
};
struct Taz {
Foo&& f;
unsigned m;
};