diff --git a/.github/workflows/bindgen.yml b/.github/workflows/bindgen.yml index 53bd9beac9..3524249149 100644 --- a/.github/workflows/bindgen.yml +++ b/.github/workflows/bindgen.yml @@ -111,7 +111,7 @@ jobs: libtinfo: libtinfo5_6.3+20220423-2ubuntu0.1_amd64.deb - os: ubuntu-24.04-arm libtinfo: libtinfo5_6.3+20220423-2ubuntu0.1_arm64.deb - llvm_version: ["16.0", "20.1"] + llvm_version: ["16.0", "20.1", "21.1"] release_build: [0, 1] no_default_features: [0, 1] # FIXME: There are no pre-built static libclang libraries, so the @@ -125,7 +125,7 @@ jobs: - platform: os: ubuntu-latest libtinfo: libtinfo5_6.3+20220423-2ubuntu0.1_amd64.deb - llvm_version: "20.1" + llvm_version: "21.1" release_build: 0 no_default_features: 0 feature_extra_asserts: 1 @@ -133,7 +133,7 @@ jobs: # Ensure stuff works on macos too - platform: os: macos-latest - llvm_version: "20.1" + llvm_version: "21.1" release_build: 0 no_default_features: 0 feature_extra_asserts: 0 @@ -160,7 +160,7 @@ jobs: BINDGEN_FEATURE_RUNTIME: ${{matrix.feature_runtime}} BINDGEN_FEATURE_EXTRA_ASSERTS: ${{matrix.feature_extra_asserts}} BINDGEN_NO_DEFAULT_FEATURES: ${{matrix.no_default_features}} - BINDGEN_RUST_FOR_LINUX_TEST: ${{startsWith(matrix.platform.os, 'ubuntu') && matrix.llvm_version == '20.1' && matrix.feature_extra_asserts == 0 && 1 || 0}} + BINDGEN_RUST_FOR_LINUX_TEST: ${{startsWith(matrix.platform.os, 'ubuntu') && matrix.llvm_version == '21.1' && matrix.feature_extra_asserts == 0 && 1 || 0}} run: ./ci/test.sh test-book: diff --git a/bindgen-tests/Cargo.toml b/bindgen-tests/Cargo.toml index 2f3ec700c9..0e204902dd 100644 --- a/bindgen-tests/Cargo.toml +++ b/bindgen-tests/Cargo.toml @@ -26,3 +26,4 @@ runtime = ["bindgen/runtime"] __testing_only_extra_assertions = ["bindgen/__testing_only_extra_assertions"] __testing_only_libclang_16 = ["bindgen/__testing_only_libclang_16"] __testing_only_libclang_20 = ["bindgen/__testing_only_libclang_20"] +__testing_only_libclang_21 = [] diff --git a/bindgen-tests/tests/expectations/tests/libclang-21/issue-544-stylo-creduce-2.rs b/bindgen-tests/tests/expectations/tests/libclang-21/issue-544-stylo-creduce-2.rs new file mode 100644 index 0000000000..39139632ee --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/libclang-21/issue-544-stylo-creduce-2.rs @@ -0,0 +1,17 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct Foo { + pub member: *mut Foo_SecondAlias, +} +pub type Foo_FirstAlias = T; +pub type Foo_SecondAlias = Foo; +impl Default for Foo { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} diff --git a/bindgen-tests/tests/expectations/tests/libclang-21/nsBaseHashtable.rs b/bindgen-tests/tests/expectations/tests/libclang-21/nsBaseHashtable.rs new file mode 100644 index 0000000000..e8c90f2e06 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/libclang-21/nsBaseHashtable.rs @@ -0,0 +1,57 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct nsBaseHashtableET { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct nsTHashtable { + pub _address: u8, +} +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsBaseHashtable { + pub _address: u8, +} +pub type nsBaseHashtable_KeyType = KeyClass; +pub type nsBaseHashtable_EntryType = nsBaseHashtableET; +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct nsBaseHashtable_LookupResult { + pub mEntry: *mut nsBaseHashtable_EntryType, + pub mTable: *mut nsBaseHashtable, +} +impl Default for nsBaseHashtable_LookupResult { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Debug)] +pub struct nsBaseHashtable_EntryPtr { + pub mEntry: *mut nsBaseHashtable_EntryType, + pub mExistingEntry: bool, +} +impl Default for nsBaseHashtable_EntryPtr { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +impl Default for nsBaseHashtable { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} diff --git a/bindgen-tests/tests/expectations/tests/recursive_alias_canonicalization.rs b/bindgen-tests/tests/expectations/tests/recursive_alias_canonicalization.rs new file mode 100644 index 0000000000..bf4b4109e4 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/recursive_alias_canonicalization.rs @@ -0,0 +1,32 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +pub type test_AliasUnion = test_RecursiveUnion; +#[repr(C)] +#[derive(Copy, Clone)] +pub union test_RecursiveUnion { + pub x: ::std::os::raw::c_int, + pub self_ptr: *mut test_AliasUnion, +} +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + [ + "Size of test_RecursiveUnion", + ][::std::mem::size_of::() - 8usize]; + [ + "Alignment of test_RecursiveUnion", + ][::std::mem::align_of::() - 8usize]; + [ + "Offset of field: test_RecursiveUnion::x", + ][::std::mem::offset_of!(test_RecursiveUnion, x) - 0usize]; + [ + "Offset of field: test_RecursiveUnion::self_ptr", + ][::std::mem::offset_of!(test_RecursiveUnion, self_ptr) - 0usize]; +}; +impl Default for test_RecursiveUnion { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} diff --git a/bindgen-tests/tests/expectations/tests/transform-op.rs b/bindgen-tests/tests/expectations/tests/transform-op.rs index e1d27d15a4..1bcf40eb12 100644 --- a/bindgen-tests/tests/expectations/tests/transform-op.rs +++ b/bindgen-tests/tests/expectations/tests/transform-op.rs @@ -1,48 +1,5 @@ #![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] #[repr(C)] -pub struct __BindgenUnionField(::std::marker::PhantomData); -impl __BindgenUnionField { - #[inline] - pub const fn new() -> Self { - __BindgenUnionField(::std::marker::PhantomData) - } - #[inline] - pub const unsafe fn as_ref(&self) -> &T { - unsafe { ::std::mem::transmute(self) } - } - #[inline] - pub const unsafe fn as_mut(&mut self) -> &mut T { - unsafe { ::std::mem::transmute(self) } - } -} -impl ::std::default::Default for __BindgenUnionField { - #[inline] - fn default() -> Self { - Self::new() - } -} -impl ::std::clone::Clone for __BindgenUnionField { - #[inline] - fn clone(&self) -> Self { - *self - } -} -impl ::std::marker::Copy for __BindgenUnionField {} -impl ::std::fmt::Debug for __BindgenUnionField { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - fmt.write_str("__BindgenUnionField") - } -} -impl ::std::hash::Hash for __BindgenUnionField { - fn hash(&self, _state: &mut H) {} -} -impl ::std::cmp::PartialEq for __BindgenUnionField { - fn eq(&self, _other: &__BindgenUnionField) -> bool { - true - } -} -impl ::std::cmp::Eq for __BindgenUnionField {} -#[repr(C)] #[derive(Debug, Copy, Clone)] pub struct StylePoint { pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, @@ -59,14 +16,12 @@ impl Default for StylePoint { } } #[repr(C)] -#[repr(align(1))] -pub struct StyleFoo { +pub union StyleFoo { pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - pub __bindgen_anon_1: __BindgenUnionField, - pub foo: __BindgenUnionField>, - pub bar: __BindgenUnionField>, - pub baz: __BindgenUnionField>, - pub bindgen_union_field: [u8; 0usize], + pub __bindgen_anon_1: ::std::mem::ManuallyDrop, + pub foo: ::std::mem::ManuallyDrop>, + pub bar: ::std::mem::ManuallyDrop>, + pub baz: ::std::mem::ManuallyDrop>, } pub const StyleFoo_Tag_Foo: StyleFoo_Tag = 0; pub const StyleFoo_Tag_Bar: StyleFoo_Tag = 0; @@ -206,12 +161,11 @@ impl Default for StyleBar_StyleBar3_Body { } #[repr(C)] #[repr(align(1))] -pub struct StyleBar__bindgen_ty_1 { +pub union StyleBar__bindgen_ty_1 { pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, - pub bar1: __BindgenUnionField>, - pub bar2: __BindgenUnionField>, - pub bar3: __BindgenUnionField>, - pub bindgen_union_field: [u8; 0usize], + pub bar1: ::std::mem::ManuallyDrop>, + pub bar2: ::std::mem::ManuallyDrop>, + pub bar3: ::std::mem::ManuallyDrop>, } impl Default for StyleBar__bindgen_ty_1 { fn default() -> Self { diff --git a/bindgen-tests/tests/expectations/tests/variadic_template_union.rs b/bindgen-tests/tests/expectations/tests/variadic_template_union.rs new file mode 100644 index 0000000000..91c5ed4802 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/variadic_template_union.rs @@ -0,0 +1,59 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[repr(C)] +pub struct __BindgenUnionField(::std::marker::PhantomData); +impl __BindgenUnionField { + #[inline] + pub const fn new() -> Self { + __BindgenUnionField(::std::marker::PhantomData) + } + #[inline] + pub const unsafe fn as_ref(&self) -> &T { + unsafe { ::std::mem::transmute(self) } + } + #[inline] + pub const unsafe fn as_mut(&mut self) -> &mut T { + unsafe { ::std::mem::transmute(self) } + } +} +impl ::std::default::Default for __BindgenUnionField { + #[inline] + fn default() -> Self { + Self::new() + } +} +impl ::std::clone::Clone for __BindgenUnionField { + #[inline] + fn clone(&self) -> Self { + *self + } +} +impl ::std::marker::Copy for __BindgenUnionField {} +impl ::std::fmt::Debug for __BindgenUnionField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + fmt.write_str("__BindgenUnionField") + } +} +impl ::std::hash::Hash for __BindgenUnionField { + fn hash(&self, _state: &mut H) {} +} +impl ::std::cmp::PartialEq for __BindgenUnionField { + fn eq(&self, _other: &__BindgenUnionField) -> bool { + true + } +} +impl ::std::cmp::Eq for __BindgenUnionField {} +#[repr(C)] +pub struct test___union<_Arg0> { + pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<_Arg0>>, + pub __arg: __BindgenUnionField<_Arg0>, + pub __u: __BindgenUnionField>, +} +impl<_Arg0> Default for test___union<_Arg0> { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} diff --git a/bindgen-tests/tests/expectations/tests/variadic_template_union_alignment.rs b/bindgen-tests/tests/expectations/tests/variadic_template_union_alignment.rs new file mode 100644 index 0000000000..6953a6ab52 --- /dev/null +++ b/bindgen-tests/tests/expectations/tests/variadic_template_union_alignment.rs @@ -0,0 +1,53 @@ +#![allow(dead_code, non_snake_case, non_camel_case_types, non_upper_case_globals)] +#[test] +fn test_mixed_union_pointer_size() { + assert_eq!(::std::mem::size_of::(), 8); +} +#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)] +#[repr(C, align(8))] +pub struct __BindgenOpaqueArray8(pub T); +impl Default for __BindgenOpaqueArray8<[T; N]> { + fn default() -> Self { + Self([::default(); N]) + } +} +#[repr(C)] +pub union test_MixedUnionPointer { + pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell>, + pub val: ::std::mem::ManuallyDrop, + pub ptr: ::std::mem::ManuallyDrop<*mut test_MixedUnionPointer>, +} +impl Default for test_MixedUnionPointer { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct test_MixedUnionValue { + pub _address: u8, +} +impl Default for test_MixedUnionValue { + fn default() -> Self { + let mut s = ::std::mem::MaybeUninit::::uninit(); + unsafe { + ::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1); + s.assume_init() + } + } +} +pub type test_MixedCharPointer = test_MixedUnionPointer<::std::os::raw::c_char>; +pub type test_MixedCharDouble = __BindgenOpaqueArray8<[u8; 8usize]>; +#[allow(clippy::unnecessary_operation, clippy::identity_op)] +const _: () = { + [ + "Size of template specialization: test_MixedUnionPointer_open0_char_int_close0", + ][::std::mem::size_of::>() - 8usize]; + [ + "Align of template specialization: test_MixedUnionPointer_open0_char_int_close0", + ][::std::mem::align_of::>() - 8usize]; +}; diff --git a/bindgen-tests/tests/headers/recursive_alias_canonicalization.hpp b/bindgen-tests/tests/headers/recursive_alias_canonicalization.hpp new file mode 100644 index 0000000000..9ecfecf353 --- /dev/null +++ b/bindgen-tests/tests/headers/recursive_alias_canonicalization.hpp @@ -0,0 +1,11 @@ +// bindgen-flags: -- -std=c++14 + +namespace test { +union RecursiveUnion; +typedef RecursiveUnion AliasUnion; + +union RecursiveUnion { + int x; + AliasUnion* self_ptr; +}; +} diff --git a/bindgen-tests/tests/headers/variadic_template_union.hpp b/bindgen-tests/tests/headers/variadic_template_union.hpp new file mode 100644 index 0000000000..d8ef582df8 --- /dev/null +++ b/bindgen-tests/tests/headers/variadic_template_union.hpp @@ -0,0 +1,9 @@ +// bindgen-flags: -- -std=c++14 + +namespace test { +template +union __union { + _Arg0 __arg; + __union<_Args...> __u; +}; +} diff --git a/bindgen-tests/tests/headers/variadic_template_union_alignment.hpp b/bindgen-tests/tests/headers/variadic_template_union_alignment.hpp new file mode 100644 index 0000000000..e7647803ac --- /dev/null +++ b/bindgen-tests/tests/headers/variadic_template_union_alignment.hpp @@ -0,0 +1,33 @@ +// bindgen-flags: --raw-line '#[test] fn test_mixed_union_pointer_size() { assert_eq!(::std::mem::size_of::(), 8); }' --opaque-type '.*MixedUnionValue.*' -- -std=c++14 + +namespace test { + +template +union MixedUnionPointer { + T val; + MixedUnionPointer* ptr; +}; + +template +union MixedUnionPointer { + T val; +}; + +template +union MixedUnionValue { + T val; + MixedUnionValue next; +}; + +template +union MixedUnionValue { + T val; +}; + +using MixedCharPointer = MixedUnionPointer; +using MixedCharDouble = MixedUnionValue; + +static_assert(sizeof(MixedCharPointer) == 8, "Expected sizeof(MixedCharPointer) == 8 in C++"); +static_assert(sizeof(MixedCharDouble) == 8, "Expected sizeof(MixedCharDouble) == 8 in C++"); + +} diff --git a/bindgen-tests/tests/tests.rs b/bindgen-tests/tests/tests.rs index ad103eb592..f43671bcb1 100644 --- a/bindgen-tests/tests/tests.rs +++ b/bindgen-tests/tests/tests.rs @@ -141,16 +141,20 @@ fn compare_generated_header( { let mut expectation = expectation.clone(); - if cfg!(feature = "__testing_only_libclang_20") { + if cfg!(feature = "__testing_only_libclang_21") { + expectation.push("libclang-21"); + } else if cfg!(feature = "__testing_only_libclang_20") { expectation.push("libclang-20"); } else if cfg!(feature = "__testing_only_libclang_16") { expectation.push("libclang-16"); } else { match clang_version().parsed { - None => expectation.push("libclang-20"), + None => expectation.push("libclang-21"), Some(version) => { let (maj, min) = version; - let version_str = if maj >= 20 { + let version_str = if maj >= 21 { + "21".to_owned() + } else if maj >= 20 { "20".to_owned() } else if maj >= 16 { "16".to_owned() diff --git a/bindgen/ir/comp.rs b/bindgen/ir/comp.rs index 2760775cea..5fb4d8b73d 100644 --- a/bindgen/ir/comp.rs +++ b/bindgen/ir/comp.rs @@ -1163,6 +1163,12 @@ impl CompInfo { return None; } + // Uninstantiated template unions do not have layout in C++ and can cause + // infinite layout recursion if fields reference the union template. + if self.kind == CompKind::Union && !self.template_params.is_empty() { + return None; + } + let mut max_size = 0; // Don't allow align(0) let mut max_align = 1; @@ -1793,13 +1799,61 @@ impl CompInfo { ctx.options().default_non_copy_union_style }; + let field_can_copy = |field_data: &FieldData| -> bool { + let ty = field_data.ty(); + if !ty.can_derive_copy(ctx) { + return false; + } + if ctx.in_codegen_phase() && + ctx.uses_any_template_parameters(ty.into()) + { + return false; + } + true + }; + let all_can_copy = self.fields().iter().all(|f| match *f { + Field::DataMember(ref field_data) => field_can_copy(field_data), + Field::Bitfields(_) => true, + }); + + let has_generic_params = self.fields().iter().any(|f| match *f { Field::DataMember(ref field_data) => { - field_data.ty().can_derive_copy(ctx) + ctx.in_codegen_phase() && + ctx.uses_any_template_parameters(field_data.ty().into()) } - Field::Bitfields(_) => true, + Field::Bitfields(_) => false, }); + let has_by_value_recursive_field = + self.fields().iter().any(|f| match *f { + Field::DataMember(ref field_data) => { + let mut ty = ctx.safe_resolve_type(field_data.ty()); + while let Some(t) = ty { + if t.name().is_some_and(|n| name.ends_with(n)) { + return true; + } + match *t.kind() { + super::ty::TypeKind::ResolvedTypeRef(inner) | + super::ty::TypeKind::Alias(inner) => { + ty = ctx.safe_resolve_type(inner); + } + _ => return false, + } + } + false + } + Field::Bitfields(_) => false, + }); + + // If the union has generic template parameters and does not contain a recursive + // template field by value (which would produce E0072 in Rust), emit as a native + // Rust union with ManuallyDrop fields ((true, false)) so the Rust compiler + // computes the correct size and alignment upon instantiation. + if has_generic_params && !has_by_value_recursive_field { + return (true, false); + } + if !all_can_copy && union_style == NonCopyUnionStyle::BindgenWrapper { return (false, false); } diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index b5b6b4a000..3d5f6a8e79 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -350,6 +350,13 @@ pub(crate) struct BindgenContext { /// potentially break that assumption. currently_parsed_types: Vec, + /// A stack of items currently loaned out by `with_loaned_item`. + /// + /// This allows us to distinguish between: + /// 1) An existing item that is currently being traversed recursively. + /// 2) An unknown or invalid item ID (which should panic). + currently_loaned_items: Vec, + /// A map with all the already parsed macro names. This is done to avoid /// hard errors while parsing duplicated macros, as well to allow macro /// expression parsing. @@ -587,6 +594,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" current_module: root_module_id, semantic_parents: Default::default(), currently_parsed_types: vec![], + currently_loaned_items: vec![], parsed_macros: Default::default(), replacements: Default::default(), collected_typerefs: false, @@ -985,9 +993,13 @@ If you encounter an error missing from this list, please file an issue or a PR!" F: (FnOnce(&BindgenContext, &mut Item) -> T), { let mut item = self.items[id.0].take().unwrap(); + self.currently_loaned_items.push(id); let result = f(self, &mut item); + let popped = self.currently_loaned_items.pop(); + debug_assert_eq!(popped, Some(id)); + let existing = self.items[id.0].replace(item); assert!(existing.is_none()); @@ -1467,13 +1479,38 @@ If you encounter an error missing from this list, please file an issue or a PR!" self.resolve_item(func_id).kind().expect_function() } - /// Resolve the given `ItemId` as a type, or `None` if there is no item with - /// the given ID. + /// Returns `true` if `id` is currently loaned out by `with_loaned_item`. + pub(crate) fn is_currently_loaned_item>( + &self, + id: Id, + ) -> bool { + self.currently_loaned_items.contains(&id.into()) + } + + /// Resolve the given `ItemId` as a type. + /// + /// Returns `Some(&Type)` if the item resolves to a type. + /// Returns `None` if the item is currently loaned out by `with_loaned_item` + /// (indicating an intentional recursive reference). /// - /// Panics if the ID resolves to an item that is not a type. + /// Panics if bindgen has no awareness of the given type ID during codegen. pub(crate) fn safe_resolve_type(&self, type_id: TypeId) -> Option<&Type> { - self.resolve_item_fallible(type_id) - .map(|t| t.kind().expect_type()) + let id: ItemId = type_id.into(); + match self.items.get(id.0) { + Some(Some(item)) => item.kind().as_type(), + // When an item slot is `None` because it is currently loaned out by + // `with_loaned_item`, intentionally return `None` to signal recursion. + Some(None) if self.is_currently_loaned_item(id) => None, + _ => { + // During AST parsing and template resolution (`!self.in_codegen_phase()`), + // forward-declared items or template references may not yet be populated + // in `self.items`, so returning `None` is expected. During codegen, + // however, all valid IR items must be present in `self.items`. + assert!(!self.in_codegen_phase(), "Not an item: {type_id:?}"); + + None + } + } } /// Resolve the given `ItemId` into an `Item`, or `None` if no such item @@ -1627,8 +1664,9 @@ If you encounter an error missing from this list, please file an issue or a PR!" ty: &clang::Type, location: Cursor, ) -> Option { - let num_expected_args = - self.resolve_type(template).num_self_template_params(self); + let num_expected_args = self + .safe_resolve_type(template) + .map_or(0, |t| t.num_self_template_params(self)); if num_expected_args == 0 { warn!( "Tried to instantiate a template for which we could not \ diff --git a/bindgen/ir/enum_ty.rs b/bindgen/ir/enum_ty.rs index 8566622100..20b2de73b3 100644 --- a/bindgen/ir/enum_ty.rs +++ b/bindgen/ir/enum_ty.rs @@ -74,8 +74,8 @@ impl Enum { .and_then(|et| Item::from_ty(&et, declaration, None, ctx).ok()); let mut variants = vec![]; - let variant_ty = - repr.and_then(|r| ctx.resolve_type(r).safe_canonical_type(ctx)); + let variant_ty = repr + .and_then(|r| ctx.safe_resolve_type(r)?.safe_canonical_type(ctx)); let is_bool = variant_ty.is_some_and(Type::is_bool); // Assume signedness since the default type by the C standard is an int. diff --git a/bindgen/ir/ty.rs b/bindgen/ir/ty.rs index 805138b7a9..8c0a2fd0df 100644 --- a/bindgen/ir/ty.rs +++ b/bindgen/ir/ty.rs @@ -209,9 +209,9 @@ impl Type { None } } - TypeKind::ResolvedTypeRef(inner) => { - ctx.resolve_type(inner).is_incomplete_array(ctx) - } + TypeKind::ResolvedTypeRef(inner) => ctx + .safe_resolve_type(inner) + .and_then(|t| t.is_incomplete_array(ctx)), _ => None, } } @@ -223,7 +223,7 @@ impl Type { TypeKind::Comp(ref ci) => ci.layout(ctx), TypeKind::Array(inner, 0) => Some(Layout::new( 0, - ctx.resolve_type(inner).layout(ctx)?.align, + ctx.safe_resolve_type(inner)?.layout(ctx)?.align, )), // FIXME(emilio): This is a hack for anonymous union templates. // Use the actual pointer size! @@ -232,7 +232,7 @@ impl Type { ctx.target_pointer_size(), )), TypeKind::ResolvedTypeRef(inner) => { - ctx.resolve_type(inner).layout(ctx) + ctx.safe_resolve_type(inner)?.layout(ctx) } _ => None, } @@ -327,10 +327,10 @@ impl Type { TypeKind::ResolvedTypeRef(inner) | TypeKind::Alias(inner) | TypeKind::TemplateAlias(inner, _) => { - ctx.resolve_type(inner).safe_canonical_type(ctx) + ctx.safe_resolve_type(inner)?.safe_canonical_type(ctx) } TypeKind::TemplateInstantiation(ref inst) => ctx - .resolve_type(inst.template_definition()) + .safe_resolve_type(inst.template_definition())? .safe_canonical_type(ctx), TypeKind::UnresolvedTypeRef(..) => None,