summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Walton <pcwalton@mimiga.net>2021-04-23 14:40:26 -0700
committerEmilio Cobos Álvarez <emilio@crisal.io>2021-04-27 01:32:44 +0200
commitf597e2777355e358a8f2c5a96d98326f3bf624d9 (patch)
tree0378356544cb863d1ef67af02ba8a204b45e8e83
parent91ec529f54398e3fc457b6f1a1ba4c1cf928cf9d (diff)
Translate types that were declared inside functions as opaque types.
This fixes a panic with the following header: template<typename T> struct Foo {}; template<typename T> Foo<T> foo{}; void f() { struct Bar { Bar() {} }; foo<Bar>; } Because we don't parse the insides of function bodies, code like this could cause us to parse a type (here, `Bar`) that we didn't see in our initial pass, which can cause subtle problems. Closes #2036.
-rw-r--r--src/ir/function.rs4
-rw-r--r--src/ir/item.rs12
-rw-r--r--tests/expectations/tests/libclang-3.9/template_instantiation_with_fn_local_type.rs60
-rw-r--r--tests/expectations/tests/template_instantiation_with_fn_local_type.rs96
-rw-r--r--tests/headers/template_instantiation_with_fn_local_type.hpp27
5 files changed, 198 insertions, 1 deletions
diff --git a/src/ir/function.rs b/src/ir/function.rs
index a6f63a64..c0938b65 100644
--- a/src/ir/function.rs
+++ b/src/ir/function.rs
@@ -28,7 +28,9 @@ pub enum FunctionKind {
}
impl FunctionKind {
- fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> {
+ /// Given a clang cursor, return the kind of function it represents, or
+ /// `None` otherwise.
+ pub fn from_cursor(cursor: &clang::Cursor) -> Option<FunctionKind> {
// FIXME(emilio): Deduplicate logic with `ir::comp`.
Some(match cursor.kind() {
clang_sys::CXCursor_FunctionDecl => FunctionKind::Function,
diff --git a/src/ir/item.rs b/src/ir/item.rs
index d7c92ab4..ffb52664 100644
--- a/src/ir/item.rs
+++ b/src/ir/item.rs
@@ -1558,6 +1558,18 @@ impl ClangItemParser for Item {
}
}
+ // Treat all types that are declared inside functions as opaque. The Rust binding
+ // won't be able to do anything with them anyway.
+ //
+ // (If we don't do this check here, we can have subtle logic bugs because we generally
+ // ignore function bodies. See issue #2036.)
+ if let Some(ref parent) = ty.declaration().fallible_semantic_parent() {
+ if FunctionKind::from_cursor(parent).is_some() {
+ debug!("Skipping type declared inside function: {:?}", ty);
+ return Ok(Item::new_opaque_type(id, ty, ctx));
+ }
+ }
+
let decl = {
let decl = ty.declaration();
decl.definition().unwrap_or(decl)
diff --git a/tests/expectations/tests/libclang-3.9/template_instantiation_with_fn_local_type.rs b/tests/expectations/tests/libclang-3.9/template_instantiation_with_fn_local_type.rs
new file mode 100644
index 00000000..ba0c6e7b
--- /dev/null
+++ b/tests/expectations/tests/libclang-3.9/template_instantiation_with_fn_local_type.rs
@@ -0,0 +1,60 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Foo {
+ pub _address: u8,
+}
+extern "C" {
+ #[link_name = "\u{1}_Z1fv"]
+ pub fn f();
+}
+#[test]
+fn __bindgen_test_layout_Foo_open0__bindgen_ty_id_20_close0_instantiation() {
+ assert_eq!(
+ ::std::mem::size_of::<Foo>(),
+ 1usize,
+ concat!("Size of template specialization: ", stringify!(Foo))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Foo>(),
+ 1usize,
+ concat!("Alignment of template specialization: ", stringify!(Foo))
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Baz {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_Baz() {
+ assert_eq!(
+ ::std::mem::size_of::<Baz>(),
+ 1usize,
+ concat!("Size of: ", stringify!(Baz))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Baz>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(Baz))
+ );
+}
+ #[test]
+fn __bindgen_test_layout_Foo_open0__bindgen_ty_id_21_close0_instantiation() {
+ assert_eq!(
+ ::std::mem::size_of::<Foo>(),
+ 1usize,
+ concat!("Size of template specialization: ", stringify!(Foo))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Foo>(),
+ 1usize,
+ concat!("Alignment of template specialization: ", stringify!(Foo))
+ );
+}
diff --git a/tests/expectations/tests/template_instantiation_with_fn_local_type.rs b/tests/expectations/tests/template_instantiation_with_fn_local_type.rs
new file mode 100644
index 00000000..d968e71b
--- /dev/null
+++ b/tests/expectations/tests/template_instantiation_with_fn_local_type.rs
@@ -0,0 +1,96 @@
+#![allow(
+ dead_code,
+ non_snake_case,
+ non_camel_case_types,
+ non_upper_case_globals
+)]
+
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Foo {
+ pub _address: u8,
+}
+extern "C" {
+ #[link_name = "\u{1}_Z1fv"]
+ pub fn f();
+}
+#[test]
+fn __bindgen_test_layout_Foo_open0_Bar_close0_instantiation() {
+ assert_eq!(
+ ::std::mem::size_of::<Foo>(),
+ 1usize,
+ concat!("Size of template specialization: ", stringify!(Foo))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Foo>(),
+ 1usize,
+ concat!("Alignment of template specialization: ", stringify!(Foo))
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Baz {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_Baz() {
+ assert_eq!(
+ ::std::mem::size_of::<Baz>(),
+ 1usize,
+ concat!("Size of: ", stringify!(Baz))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Baz>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(Baz))
+ );
+}
+#[test]
+fn __bindgen_test_layout_Foo_open0_Boo_close0_instantiation() {
+ assert_eq!(
+ ::std::mem::size_of::<Foo>(),
+ 1usize,
+ concat!("Size of template specialization: ", stringify!(Foo))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Foo>(),
+ 1usize,
+ concat!("Alignment of template specialization: ", stringify!(Foo))
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Bar {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_Bar() {
+ assert_eq!(
+ ::std::mem::size_of::<Bar>(),
+ 1usize,
+ concat!("Size of: ", stringify!(Bar))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Bar>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(Bar))
+ );
+}
+#[repr(C)]
+#[derive(Debug, Default, Copy, Clone)]
+pub struct Boo {
+ pub _address: u8,
+}
+#[test]
+fn bindgen_test_layout_Boo() {
+ assert_eq!(
+ ::std::mem::size_of::<Boo>(),
+ 1usize,
+ concat!("Size of: ", stringify!(Boo))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<Boo>(),
+ 1usize,
+ concat!("Alignment of ", stringify!(Boo))
+ );
+}
diff --git a/tests/headers/template_instantiation_with_fn_local_type.hpp b/tests/headers/template_instantiation_with_fn_local_type.hpp
new file mode 100644
index 00000000..b7ff28b0
--- /dev/null
+++ b/tests/headers/template_instantiation_with_fn_local_type.hpp
@@ -0,0 +1,27 @@
+// bindgen-flags: -- -std=c++14
+//
+// https://github.com/rust-lang/rust-bindgen/issues/2036
+
+template<typename T>
+struct Foo {};
+template<typename T>
+Foo<T> foo{};
+
+// Struct inside function
+void f() {
+ struct Bar {
+ Bar() {}
+ };
+ foo<Bar>;
+}
+
+// Struct inside method
+class Baz {
+ void f() {
+ struct Boo {
+ Boo() {}
+ };
+ foo<Boo>;
+ }
+};
+