diff options
author | Patrick Walton <pcwalton@mimiga.net> | 2021-04-23 14:40:26 -0700 |
---|---|---|
committer | Emilio Cobos Álvarez <emilio@crisal.io> | 2021-04-27 01:32:44 +0200 |
commit | f597e2777355e358a8f2c5a96d98326f3bf624d9 (patch) | |
tree | 0378356544cb863d1ef67af02ba8a204b45e8e83 | |
parent | 91ec529f54398e3fc457b6f1a1ba4c1cf928cf9d (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.rs | 4 | ||||
-rw-r--r-- | src/ir/item.rs | 12 | ||||
-rw-r--r-- | tests/expectations/tests/libclang-3.9/template_instantiation_with_fn_local_type.rs | 60 | ||||
-rw-r--r-- | tests/expectations/tests/template_instantiation_with_fn_local_type.rs | 96 | ||||
-rw-r--r-- | tests/headers/template_instantiation_with_fn_local_type.hpp | 27 |
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>; + } +}; + |