summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/codegen/mod.rs2
-rw-r--r--src/ir/context.rs37
-rw-r--r--src/ir/function.rs17
-rw-r--r--src/ir/item.rs4
-rw-r--r--src/ir/layout.rs3
-rw-r--r--src/ir/ty.rs17
-rw-r--r--tests/expectations/tests/const-const-mut-ptr.rs32
-rw-r--r--tests/headers/const-const-mut-ptr.h3
8 files changed, 92 insertions, 23 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index fd48ff2b..b6aabb17 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -3054,7 +3054,7 @@ impl TryToRustTy for Type {
}
TypeKind::Pointer(inner) |
TypeKind::Reference(inner) => {
- let is_const = self.is_const() || ctx.resolve_type(inner).is_const();
+ let is_const = ctx.resolve_type(inner).is_const();
let inner = inner.into_resolver().through_type_refs().resolve(ctx);
let inner_ty = inner.expect_type();
diff --git a/src/ir/context.rs b/src/ir/context.rs
index bbcc5698..ccb7b75a 100644
--- a/src/ir/context.rs
+++ b/src/ir/context.rs
@@ -1926,8 +1926,43 @@ impl BindgenContext {
parent_id: Option<ItemId>,
ty: &clang::Type,
) -> TypeId {
+ self.build_wrapper(
+ with_id,
+ wrapped_id,
+ parent_id,
+ ty,
+ ty.is_const(),
+ )
+ }
+
+ /// A wrapper over a type that adds a const qualifier explicitly.
+ ///
+ /// Needed to handle const methods in C++, wrapping the type .
+ pub fn build_const_wrapper(
+ &mut self,
+ with_id: ItemId,
+ wrapped_id: TypeId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type,
+ ) -> TypeId {
+ self.build_wrapper(
+ with_id,
+ wrapped_id,
+ parent_id,
+ ty,
+ /* is_const = */ true,
+ )
+ }
+
+ fn build_wrapper(
+ &mut self,
+ with_id: ItemId,
+ wrapped_id: TypeId,
+ parent_id: Option<ItemId>,
+ ty: &clang::Type,
+ is_const: bool,
+ ) -> TypeId {
let spelling = ty.spelling();
- let is_const = ty.is_const();
let layout = ty.fallible_layout().ok();
let type_kind = TypeKind::ResolvedTypeRef(wrapped_id);
let ty = Type::new(Some(spelling), layout, type_kind, is_const);
diff --git a/src/ir/function.rs b/src/ir/function.rs
index 602de80c..5e8d2fc8 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -402,14 +402,27 @@ impl FunctionSig {
let is_virtual = is_method && cursor.method_is_virtual();
let is_static = is_method && cursor.method_is_static();
if !is_static && !is_virtual {
- let class = Item::parse(cursor.semantic_parent(), None, ctx)
+ let parent = cursor.semantic_parent();
+ let class = Item::parse(parent, None, ctx)
.expect("Expected to parse the class");
// The `class` most likely is not finished parsing yet, so use
// the unchecked variant.
let class = class.as_type_id_unchecked();
+ let class = if is_const {
+ let const_class_id = ctx.next_item_id();
+ ctx.build_const_wrapper(
+ const_class_id,
+ class,
+ None,
+ &parent.cur_type(),
+ )
+ } else {
+ class
+ };
+
let ptr =
- Item::builtin_type(TypeKind::Pointer(class), is_const, ctx);
+ Item::builtin_type(TypeKind::Pointer(class), false, ctx);
args.insert(0, (Some("this".into()), ptr));
} else if is_virtual {
let void = Item::builtin_type(TypeKind::Void, false, ctx);
diff --git a/src/ir/item.rs b/src/ir/item.rs
index 1cb1d5f9..91ec22b3 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -1449,8 +1449,8 @@ impl ClangItemParser for Item {
return Ok(Item::new_opaque_type(id, ty, ctx));
}
- if let Some(id) = Item::type_param(Some(id), location, ctx) {
- return Ok(id);
+ if let Some(param_id) = Item::type_param(None, location, ctx) {
+ return Ok(ctx.build_ty_wrapper(id, param_id, None, ty));
}
}
diff --git a/src/ir/layout.rs b/src/ir/layout.rs
index bc3f8a5a..cca33cc3 100644
--- a/src/ir/layout.rs
+++ b/src/ir/layout.rs
@@ -88,7 +88,8 @@ impl Opaque {
pub fn from_clang_ty(ty: &clang::Type) -> Type {
let layout = Layout::new(ty.size(), ty.align());
let ty_kind = TypeKind::Opaque;
- Type::new(None, Some(layout), ty_kind, false)
+ let is_const = ty.is_const();
+ Type::new(None, Some(layout), ty_kind, is_const)
}
/// Return the known rust type we should use to create a correctly-aligned
diff --git a/src/ir/ty.rs b/src/ir/ty.rs
index b742dcc1..b805dd62 100644
--- a/src/ir/ty.rs
+++ b/src/ir/ty.rs
@@ -1195,22 +1195,7 @@ impl Type {
let name = if name.is_empty() { None } else { Some(name) };
- // Just using ty.is_const() is wrong here, because when we declare an
- // argument like 'int* const arg0', arg0 is considered
- // const but the pointer itself points to mutable data.
- //
- // Without canonicalizing the type to the pointer type, we'll get the
- // following mapping:
- //
- // arg0: *const c_int
- //
- // So by canonicalizing the type first, we can check constness by
- // calling is_const() on the pointer type.
- let is_const = if let Some(pty) = ty.pointee_type() {
- pty.is_const()
- } else {
- ty.is_const()
- };
+ let is_const = ty.is_const();
let ty = Type::new(name, layout, kind, is_const);
// TODO: maybe declaration.canonical()?
diff --git a/tests/expectations/tests/const-const-mut-ptr.rs b/tests/expectations/tests/const-const-mut-ptr.rs
new file mode 100644
index 00000000..ecfbf58f
--- /dev/null
+++ b/tests/expectations/tests/const-const-mut-ptr.rs
@@ -0,0 +1,32 @@
+/* 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 {
+ pub bar: *const *const *mut *const ::std::os::raw::c_int,
+}
+#[test]
+fn bindgen_test_layout_foo() {
+ assert_eq!(
+ ::std::mem::size_of::<foo>(),
+ 8usize,
+ concat!("Size of: ", stringify!(foo))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<foo>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(foo))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<foo>())).bar as *const _ as usize },
+ 0usize,
+ concat!("Offset of field: ", stringify!(foo), "::", stringify!(bar))
+ );
+}
+impl Default for foo {
+ fn default() -> Self {
+ unsafe { ::std::mem::zeroed() }
+ }
+}
diff --git a/tests/headers/const-const-mut-ptr.h b/tests/headers/const-const-mut-ptr.h
new file mode 100644
index 00000000..cc7daf7c
--- /dev/null
+++ b/tests/headers/const-const-mut-ptr.h
@@ -0,0 +1,3 @@
+struct foo {
+ const int** const* const* bar;
+};