diff --git a/bindgen-tests/tests/headers/long_double.h b/bindgen-tests/tests/headers/long_double.h index 91c4ed6ce9..a9d1e4604f 100644 --- a/bindgen-tests/tests/headers/long_double.h +++ b/bindgen-tests/tests/headers/long_double.h @@ -3,3 +3,5 @@ struct foo { long double bar; }; + +void take_ld(long double ld); diff --git a/bindgen/codegen/helpers.rs b/bindgen/codegen/helpers.rs index 0248e1b2a0..11fa113b3a 100644 --- a/bindgen/codegen/helpers.rs +++ b/bindgen/codegen/helpers.rs @@ -199,6 +199,7 @@ pub mod ast_ty { (FloatKind::LongDouble, ..) => { // TODO(emilio): If rust ever gains f80/f128 we should // use it here and below. + ctx.generated_bindgen_long_double(layout.expect("unknown layout for long double")); if ctx.options().enable_cxx_namespaces { quote! { root::__BindgenLongDouble diff --git a/bindgen/codegen/mod.rs b/bindgen/codegen/mod.rs index 9c472153e3..ee3572d0f5 100644 --- a/bindgen/codegen/mod.rs +++ b/bindgen/codegen/mod.rs @@ -217,9 +217,6 @@ struct CodegenResult<'a> { /// Whether a bitfield allocation unit has been seen at least once. saw_bitfield_unit: bool, - /// Whether a long double has been seen at least once. - saw_long_double: bool, - items_seen: HashSet, /// The set of generated function/var names, needed because in C/C++ is /// legal to do something like: @@ -256,7 +253,6 @@ impl<'a> CodegenResult<'a> { saw_objc: false, saw_block: false, saw_bitfield_unit: false, - saw_long_double: false, codegen_id, items_seen: Default::default(), functions_seen: Default::default(), @@ -289,10 +285,6 @@ impl<'a> CodegenResult<'a> { self.saw_bitfield_unit = true; } - fn saw_long_double(&mut self) { - self.saw_long_double = true; - } - fn seen>(&self, item: Id) -> bool { self.items_seen.contains(&item.into()) } @@ -548,6 +540,9 @@ impl CodeGenerator for Module { if ctx.need_bindgen_complex_type() { utils::prepend_complex_type(&mut *result); } + if let Some(layout) = ctx.need_bindgen_long_double() { + utils::prepend_long_double(layout, &mut *result); + } if result.saw_objc { utils::prepend_objc_header(ctx, &mut *result); } @@ -2459,7 +2454,7 @@ impl Method { let signature = match *signature_item.expect_type().kind() { TypeKind::Function(ref sig) => sig, - _ => panic!("How in the world?"), + _ => unreachable!(), }; if utils::sig_unsupported_types(ctx, signature) { @@ -4513,6 +4508,7 @@ pub mod utils { use crate::ir::context::BindgenContext; use crate::ir::function::{Abi, ClangAbi, FunctionSig}; use crate::ir::item::{Item, ItemCanonicalPath}; + use crate::ir::layout::Layout; use crate::ir::ty::TypeKind; use proc_macro2; use std::borrow::Cow; @@ -4785,6 +4781,21 @@ pub mod utils { result.extend(old_items.into_iter()); } + pub fn prepend_long_double( + layout: Layout, + result: &mut Vec, + ) { + let Layout { align, size, .. } = layout; + result.insert( + 0, + quote! { + #[derive(PartialEq, Copy, Clone, Hash, Debug, Default)] + #[repr(C, align(#align))] + pub struct __BindgenLongDouble([u8; #size]); + }, + ); + } + pub fn build_path( item: &Item, ctx: &BindgenContext, @@ -5078,12 +5089,12 @@ pub mod utils { pub fn sig_unsupported_types( ctx: &BindgenContext, - sig: &FunctionSig + sig: &FunctionSig, ) -> bool { - sig.argument_types().iter() + sig.argument_types() + .iter() .map(|(_, ty_id)| ty_id) .chain(std::iter::once(&sig.return_type())) - .find(|ty_id| ctx.lookup_never_by_value(*ty_id)) - .is_some() + .any(|ty_id| ctx.lookup_never_by_value(*ty_id)) } } diff --git a/bindgen/ir/analysis/never_by_value.rs b/bindgen/ir/analysis/never_by_value.rs index d8f813ffd9..14cb434c23 100644 --- a/bindgen/ir/analysis/never_by_value.rs +++ b/bindgen/ir/analysis/never_by_value.rs @@ -71,7 +71,7 @@ impl<'ctx> NeverByValue<'ctx> { was_not_already_in_set, "We shouldn't try and insert {:?} twice because if it was \ already in the set, `constrain` should have exited early.", - id + id ); ConstrainResult::Changed @@ -128,9 +128,13 @@ impl<'ctx> MonotoneFramework for NeverByValue<'ctx> { } TypeKind::Float(..) | TypeKind::Complex(..) => { - let size = ty.layout(self.ctx).expect("float with unknown layout").size; + let size = ty + .layout(self.ctx) + .expect("float with unknown layout") + .size; match (ty.kind(), size) { - (TypeKind::Float(..), 4 | 8) | (TypeKind::Complex(..), 8 | 16) => { + (TypeKind::Float(..), 4 | 8) | + (TypeKind::Complex(..), 8 | 16) => { info!(" skipped f32 or f64"); ConstrainResult::Same } @@ -156,10 +160,9 @@ impl<'ctx> MonotoneFramework for NeverByValue<'ctx> { } TypeKind::Comp(ref info) => { - let bases_have = info - .base_members() - .iter() - .any(|base| self.never_by_value.contains(&base.ty.into())); + let bases_have = info.base_members().iter().any(|base| { + self.never_by_value.contains(&base.ty.into()) + }); if bases_have { info!(" bases have float, so we also have"); return self.insert(id); @@ -168,10 +171,11 @@ impl<'ctx> MonotoneFramework for NeverByValue<'ctx> { Field::DataMember(ref data) => { self.never_by_value.contains(&data.ty().into()) } - Field::Bitfields(ref bfu) => bfu - .bitfields() - .iter() - .any(|b| self.never_by_value.contains(&b.ty().into())), + Field::Bitfields(ref bfu) => { + bfu.bitfields().iter().any(|b| { + self.never_by_value.contains(&b.ty().into()) + }) + } }); if fields_have { info!(" fields have float, so we also have"); diff --git a/bindgen/ir/context.rs b/bindgen/ir/context.rs index 68864a37d5..de96f5f50e 100644 --- a/bindgen/ir/context.rs +++ b/bindgen/ir/context.rs @@ -4,8 +4,8 @@ use super::super::time::Timer; use super::analysis::{ analyze, as_cannot_derive_set, CannotDerive, DeriveTrait, HasDestructorAnalysis, HasFloat, HasTypeParameterInArray, - HasVtableAnalysis, HasVtableResult, NeverByValue, - SizednessAnalysis, SizednessResult, UsedTemplateParameters, + HasVtableAnalysis, HasVtableResult, NeverByValue, SizednessAnalysis, + SizednessResult, UsedTemplateParameters, }; use super::derive::{ CanDerive, CanDeriveCopy, CanDeriveDebug, CanDeriveDefault, CanDeriveEq, @@ -20,6 +20,7 @@ use super::template::{TemplateInstantiation, TemplateParameters}; use super::traversal::{self, Edge, ItemTraversal}; use super::ty::{FloatKind, Type, TypeKind}; use crate::clang::{self, Cursor}; +use crate::ir::layout::Layout; use crate::BindgenOptions; use crate::{Entry, HashMap, HashSet}; use cexpr; @@ -375,6 +376,9 @@ pub struct BindgenContext { /// Whether a bindgen complex was generated generated_bindgen_complex: Cell, + /// Whether a bindgen long double was generated + generated_bindgen_long_double: Cell>, + /// The set of `ItemId`s that are allowlisted. This the very first thing /// computed after parsing our IR, and before running any of our analyses. allowlisted: Option, @@ -584,6 +588,7 @@ If you encounter an error missing from this list, please file an issue or a PR!" target_info, options, generated_bindgen_complex: Cell::new(false), + generated_bindgen_long_double: Cell::new(None), allowlisted: None, blocklisted_types_implement_traits: Default::default(), codegen_items: None, @@ -2504,6 +2509,20 @@ If you encounter an error missing from this list, please file an issue or a PR!" self.generated_bindgen_complex.get() } + /// Call if a bindgen long double is generated + pub fn generated_bindgen_long_double(&self, layout: Layout) { + if let Some(old) = + self.generated_bindgen_long_double.replace(Some(layout)) + { + assert_eq!(layout, old, "long doubles had different layout"); + } + } + + /// Whether we need to generate the bindgen long double type (and if so, get its layout) + pub fn need_bindgen_long_double(&self) -> Option { + self.generated_bindgen_long_double.get() + } + /// Compute which `enum`s have an associated `typedef` definition. fn compute_enum_typedef_combos(&mut self) { let _t = self.timer("compute_enum_typedef_combos");