diff options
Diffstat (limited to 'src/codegen/mod.rs')
-rw-r--r-- | src/codegen/mod.rs | 482 |
1 files changed, 333 insertions, 149 deletions
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs index 17769144..c69116f9 100644 --- a/src/codegen/mod.rs +++ b/src/codegen/mod.rs @@ -1,3 +1,4 @@ +mod error; mod helpers; mod struct_layout; @@ -433,7 +434,7 @@ impl CodeGenerator for Var { } result.saw_var(&canonical_name); - let ty = self.ty().to_rust_ty(ctx); + let ty = self.ty().to_rust_ty_or_opaque(ctx, &()); if let Some(val) = self.val() { let const_item = aster::AstBuilder::new() @@ -443,8 +444,7 @@ impl CodeGenerator for Var { .expr(); let item = match *val { VarType::Bool(val) => { - const_item.build(helpers::ast_ty::bool_expr(val)) - .build(ty) + const_item.build(helpers::ast_ty::bool_expr(val)).build(ty) } VarType::Int(val) => { const_item.build(helpers::ast_ty::int_expr(val)).build(ty) @@ -569,23 +569,13 @@ impl CodeGenerator for Type { let mut used_template_params = item.used_template_params(ctx); let inner_rust_type = if item.is_opaque(ctx) { used_template_params = None; - // Pray if there's no layout. - let layout = self.layout(ctx).unwrap_or_else(Layout::zero); - BlobTyBuilder::new(layout).build() + self.to_opaque(ctx, item) } else { - let inner_rust_ty = inner_item.to_rust_ty(ctx); - - // We get a unit if the inner type is a template definition - // that is opaque or has non-type template parameters and - // doesn't know its layout. Its possible that we have better - // information about the layout, and in the worst case, just - // make sure we don't return a zero-sized type. - if inner_rust_ty == aster::AstBuilder::new().ty().unit() { - let layout = self.layout(ctx).unwrap_or_else(|| Layout::for_size(1)); - BlobTyBuilder::new(layout).build() - } else { - inner_rust_ty - } + // Its possible that we have better layout information than + // the inner type does, so fall back to an opaque blob based + // on our layout if converting the inner item fails. + inner_item.try_to_rust_ty_or_opaque(ctx, &()) + .unwrap_or_else(|_| self.to_opaque(ctx, item)) }; { @@ -738,9 +728,13 @@ impl<'a> ItemCanonicalName for Vtable<'a> { } } -impl<'a> ItemToRustTy for Vtable<'a> { - fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> { - aster::ty::TyBuilder::new().id(self.canonical_name(ctx)) +impl<'a> TryToRustTy for Vtable<'a> { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) -> error::Result<P<ast::Ty>> { + Ok(aster::ty::TyBuilder::new().id(self.canonical_name(ctx))) } } @@ -813,10 +807,11 @@ impl<'a> Bitfield<'a> { } if let Some(name) = field.name() { + let field_item_ty = field_item.to_rust_ty_or_opaque(ctx, &()); bitfields.push((name, field_size_in_bits, width, - field_item.to_rust_ty(ctx).unwrap(), + field_item_ty.unwrap(), field_ty_layout)); } @@ -958,7 +953,7 @@ impl CodeGenerator for TemplateInstantiation { let fn_name = ctx.rust_ident_raw(&fn_name); let prefix = ctx.trait_prefix(); - let ident = item.to_rust_ty(ctx); + let ident = item.to_rust_ty_or_opaque(ctx, &()); let size_of_expr = quote_expr!(ctx.ext_cx(), ::$prefix::mem::size_of::<$ident>()); let align_of_expr = quote_expr!(ctx.ext_cx(), @@ -1095,7 +1090,9 @@ impl CodeGenerator for CompInfo { Vtable::new(item.id(), self.methods(), self.base_members()); vtable.codegen(ctx, result, whitelisted_items, item); - let vtable_type = vtable.to_rust_ty(ctx).to_ptr(true, ctx.span()); + let vtable_type = vtable.try_to_rust_ty(ctx, &()) + .expect("vtable to Rust type conversion is infallible") + .to_ptr(true, ctx.span()); let vtable_field = StructFieldBuilder::named("vtable_") .pub_() @@ -1123,7 +1120,7 @@ impl CodeGenerator for CompInfo { continue; } - let inner = base.ty.to_rust_ty(ctx); + let inner = base.ty.to_rust_ty_or_opaque(ctx, &()); let field_name = if i == 0 { "_base".into() } else { @@ -1204,7 +1201,7 @@ impl CodeGenerator for CompInfo { continue; } - let ty = field.ty().to_rust_ty(ctx); + let ty = field.ty().to_rust_ty_or_opaque(ctx, &()); // NB: In unstable rust we use proper `union` types. let ty = if is_union && !ctx.options().unstable_rust { @@ -1217,7 +1214,7 @@ impl CodeGenerator for CompInfo { field_ty.is_incomplete_array(ctx) { result.saw_incomplete_array(); - let inner = item.to_rust_ty(ctx); + let inner = item.to_rust_ty_or_opaque(ctx, &()); if ctx.options().enable_cxx_namespaces { quote_ty!(ctx.ext_cx(), root::__IncompleteArrayField<$inner>) @@ -2069,7 +2066,7 @@ impl CodeGenerator for Enum { } let repr = self.repr() - .map(|repr| repr.to_rust_ty(ctx)) + .and_then(|repr| repr.try_to_rust_ty_or_opaque(ctx, &()).ok()) .unwrap_or_else(|| helpers::ast_ty::raw_type(ctx, repr_name)); let mut builder = EnumBuilder::new(builder, @@ -2080,7 +2077,7 @@ impl CodeGenerator for Enum { // A map where we keep a value -> variant relation. let mut seen_values = HashMap::<_, String>::new(); - let enum_rust_ty = item.to_rust_ty(ctx); + let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &()); let is_toplevel = item.is_toplevel(ctx); // Used to mangle the constants we generate in the unnamed-enum case. @@ -2191,107 +2188,294 @@ impl CodeGenerator for Enum { } } -trait ToRustTy { +/// Fallible conversion to an opaque blob. +/// +/// Implementors of this trait should provide the `try_get_layout` method to +/// fallibly get this thing's layout, which the provided `try_to_opaque` trait +/// method will use to convert the `Layout` into an opaque blob Rust type. +trait TryToOpaque { type Extra; - fn to_rust_ty(&self, + /// Get the layout for this thing, if one is available. + fn try_get_layout(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> error::Result<Layout>; + + /// Do not override this provided trait method. + fn try_to_opaque(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> error::Result<P<ast::Ty>> { + self.try_get_layout(ctx, extra) + .map(|layout| BlobTyBuilder::new(layout).build()) + } +} + +/// Infallible conversion of an IR thing to an opaque blob. +/// +/// The resulting layout is best effort, and is unfortunately not guaranteed to +/// be correct. When all else fails, we fall back to a single byte layout as a +/// last resort, because C++ does not permit zero-sized types. See the note in +/// the `ToRustTyOrOpaque` doc comment about fallible versus infallible traits +/// and when each is appropriate. +/// +/// Don't implement this directly. Instead implement `TryToOpaque`, and then +/// leverage the blanket impl for this trait. +trait ToOpaque: TryToOpaque { + fn get_layout(&self, ctx: &BindgenContext, extra: &Self::Extra) - -> P<ast::Ty>; + -> Layout { + self.try_get_layout(ctx, extra) + .unwrap_or_else(|_| Layout::for_size(1)) + } + + fn to_opaque(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> P<ast::Ty> { + let layout = self.get_layout(ctx, extra); + BlobTyBuilder::new(layout).build() + } +} + +impl<T> ToOpaque for T + where T: TryToOpaque +{} + +/// Fallible conversion from an IR thing to an *equivalent* Rust type. +/// +/// If the C/C++ construct represented by the IR thing cannot (currently) be +/// represented in Rust (for example, instantiations of templates with +/// const-value generic parameters) then the impl should return an `Err`. It +/// should *not* attempt to return an opaque blob with the correct size and +/// alignment. That is the responsibility of the `TryToOpaque` trait. +trait TryToRustTy { + type Extra; + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + extra: &Self::Extra) + -> error::Result<P<ast::Ty>>; +} + +/// Fallible conversion to a Rust type or an opaque blob with the correct size +/// and alignment. +/// +/// Don't implement this directly. Instead implement `TryToRustTy` and +/// `TryToOpaque`, and then leverage the blanket impl for this trait below. +trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque { + type Extra; + + fn try_to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &<Self as TryToRustTyOrOpaque>::Extra) + -> error::Result<P<ast::Ty>>; +} + +impl<E, T> TryToRustTyOrOpaque for T + where T: TryToRustTy<Extra=E> + TryToOpaque<Extra=E> +{ + type Extra = E; + + fn try_to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &E) + -> error::Result<P<ast::Ty>> { + self.try_to_rust_ty(ctx, extra) + .or_else(|_| { + if let Ok(layout) = self.try_get_layout(ctx, extra) { + Ok(BlobTyBuilder::new(layout).build()) + } else { + Err(error::Error::NoLayoutForOpaqueBlob) + } + }) + } +} + +/// Infallible conversion to a Rust type, or an opaque blob with a best effort +/// of correct size and alignment. +/// +/// Don't implement this directly. Instead implement `TryToRustTy` and +/// `TryToOpaque`, and then leverage the blanket impl for this trait below. +/// +/// ### Fallible vs. Infallible Conversions to Rust Types +/// +/// When should one use this infallible `ToRustTyOrOpaque` trait versus the +/// fallible `TryTo{RustTy, Opaque, RustTyOrOpaque}` triats? All fallible trait +/// implementations that need to convert another thing into a Rust type or +/// opaque blob in a nested manner should also use fallible trait methods and +/// propagate failure up the stack. Only infallible functions and methods like +/// CodeGenerator implementations should use the infallible +/// `ToRustTyOrOpaque`. The further out we push error recovery, the more likely +/// we are to get a usable `Layout` even if we can't generate an equivalent Rust +/// type for a C++ construct. +trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { + type Extra; + + fn to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &<Self as ToRustTyOrOpaque>::Extra) + -> P<ast::Ty>; +} + +impl<E, T> ToRustTyOrOpaque for T + where T: TryToRustTy<Extra=E> + ToOpaque<Extra=E> +{ + type Extra = E; + + fn to_rust_ty_or_opaque(&self, + ctx: &BindgenContext, + extra: &E) + -> P<ast::Ty> { + self.try_to_rust_ty(ctx, extra) + .unwrap_or_else(|_| self.to_opaque(ctx, extra)) + } } -trait ItemToRustTy { - fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty>; +impl TryToOpaque for ItemId { + type Extra = (); + + fn try_get_layout(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result<Layout> { + ctx.resolve_item(*self).try_get_layout(ctx, &()) + } } -// Convenience implementation. -impl ItemToRustTy for ItemId { - fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> { - ctx.resolve_item(*self).to_rust_ty(ctx) +impl TryToRustTy for ItemId { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result<P<ast::Ty>> { + ctx.resolve_item(*self).try_to_rust_ty(ctx, &()) } } -impl ItemToRustTy for Item { - fn to_rust_ty(&self, ctx: &BindgenContext) -> P<ast::Ty> { - self.kind().expect_type().to_rust_ty(ctx, self) +impl TryToOpaque for Item { + type Extra = (); + + fn try_get_layout(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result<Layout> { + self.kind().expect_type().try_get_layout(ctx, self) } } -impl ToRustTy for Type { +impl TryToRustTy for Item { + type Extra = (); + + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result<P<ast::Ty>> { + self.kind().expect_type().try_to_rust_ty(ctx, self) + } +} + +impl TryToOpaque for Type { + type Extra = Item; + + fn try_get_layout(&self, + ctx: &BindgenContext, + _: &Item) + -> error::Result<Layout> { + self.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) + } +} + +impl TryToRustTy for Type { type Extra = Item; - fn to_rust_ty(&self, ctx: &BindgenContext, item: &Item) -> P<ast::Ty> { + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + item: &Item) + -> error::Result<P<ast::Ty>> { use self::helpers::ast_ty::*; match *self.kind() { - TypeKind::Void => raw_type(ctx, "c_void"), + TypeKind::Void => Ok(raw_type(ctx, "c_void")), // TODO: we should do something smart with nullptr, or maybe *const // c_void is enough? TypeKind::NullPtr => { - raw_type(ctx, "c_void").to_ptr(true, ctx.span()) + Ok(raw_type(ctx, "c_void").to_ptr(true, ctx.span())) } TypeKind::Int(ik) => { match ik { - IntKind::Bool => aster::ty::TyBuilder::new().bool(), - IntKind::Char => raw_type(ctx, "c_schar"), - IntKind::UChar => raw_type(ctx, "c_uchar"), - IntKind::Short => raw_type(ctx, "c_short"), - IntKind::UShort => raw_type(ctx, "c_ushort"), - IntKind::Int => raw_type(ctx, "c_int"), - IntKind::UInt => raw_type(ctx, "c_uint"), - IntKind::Long => raw_type(ctx, "c_long"), - IntKind::ULong => raw_type(ctx, "c_ulong"), - IntKind::LongLong => raw_type(ctx, "c_longlong"), - IntKind::ULongLong => raw_type(ctx, "c_ulonglong"), - - IntKind::I8 => aster::ty::TyBuilder::new().i8(), - IntKind::U8 => aster::ty::TyBuilder::new().u8(), - IntKind::I16 => aster::ty::TyBuilder::new().i16(), - IntKind::U16 => aster::ty::TyBuilder::new().u16(), - IntKind::I32 => aster::ty::TyBuilder::new().i32(), - IntKind::U32 => aster::ty::TyBuilder::new().u32(), - IntKind::I64 => aster::ty::TyBuilder::new().i64(), - IntKind::U64 => aster::ty::TyBuilder::new().u64(), + IntKind::Bool => Ok(aster::ty::TyBuilder::new().bool()), + IntKind::Char => Ok(raw_type(ctx, "c_schar")), + IntKind::UChar => Ok(raw_type(ctx, "c_uchar")), + IntKind::Short => Ok(raw_type(ctx, "c_short")), + IntKind::UShort => Ok(raw_type(ctx, "c_ushort")), + IntKind::Int => Ok(raw_type(ctx, "c_int")), + IntKind::UInt => Ok(raw_type(ctx, "c_uint")), + IntKind::Long => Ok(raw_type(ctx, "c_long")), + IntKind::ULong => Ok(raw_type(ctx, "c_ulong")), + IntKind::LongLong => Ok(raw_type(ctx, "c_longlong")), + IntKind::ULongLong => Ok(raw_type(ctx, "c_ulonglong")), + + IntKind::I8 => Ok(aster::ty::TyBuilder::new().i8()), + IntKind::U8 => Ok(aster::ty::TyBuilder::new().u8()), + IntKind::I16 => Ok(aster::ty::TyBuilder::new().i16()), + IntKind::U16 => Ok(aster::ty::TyBuilder::new().u16()), + IntKind::I32 => Ok(aster::ty::TyBuilder::new().i32()), + IntKind::U32 => Ok(aster::ty::TyBuilder::new().u32()), + IntKind::I64 => Ok(aster::ty::TyBuilder::new().i64()), + IntKind::U64 => Ok(aster::ty::TyBuilder::new().u64()), IntKind::Custom { name, .. } => { let ident = ctx.rust_ident_raw(name); - quote_ty!(ctx.ext_cx(), $ident) + Ok(quote_ty!(ctx.ext_cx(), $ident)) } // FIXME: This doesn't generate the proper alignment, but we // can't do better right now. We should be able to use // i128/u128 when they're available. IntKind::U128 | IntKind::I128 => { - aster::ty::TyBuilder::new().array(2).u64() + Ok(aster::ty::TyBuilder::new().array(2).u64()) } } } - TypeKind::Float(fk) => float_kind_rust_type(ctx, fk), + TypeKind::Float(fk) => Ok(float_kind_rust_type(ctx, fk)), TypeKind::Complex(fk) => { let float_path = float_kind_rust_type(ctx, fk); ctx.generated_bindegen_complex(); - if ctx.options().enable_cxx_namespaces { + Ok(if ctx.options().enable_cxx_namespaces { quote_ty!(ctx.ext_cx(), root::__BindgenComplex<$float_path>) } else { quote_ty!(ctx.ext_cx(), __BindgenComplex<$float_path>) - } + }) } TypeKind::Function(ref fs) => { - let ty = fs.to_rust_ty(ctx, item); + // We can't rely on the sizeof(Option<NonZero<_>>) == + // sizeof(NonZero<_>) optimization with opaque blobs (because + // they aren't NonZero), so don't *ever* use an or_opaque + // variant here. + let ty = fs.try_to_rust_ty(ctx, &())?; + let prefix = ctx.trait_prefix(); - quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>) + Ok(quote_ty!(ctx.ext_cx(), ::$prefix::option::Option<$ty>)) } TypeKind::Array(item, len) => { - let ty = item.to_rust_ty(ctx); - aster::ty::TyBuilder::new().array(len).build(ty) + let ty = item.try_to_rust_ty(ctx, &())?; + Ok(aster::ty::TyBuilder::new().array(len).build(ty)) } TypeKind::Enum(..) => { let path = item.namespace_aware_canonical_path(ctx); - aster::AstBuilder::new().ty().path().ids(path).build() + Ok(aster::AstBuilder::new() + .ty() + .path() + .ids(path) + .build()) } TypeKind::TemplateInstantiation(ref inst) => { - inst.to_rust_ty(ctx, self) + inst.try_to_rust_ty(ctx, self) } - TypeKind::ResolvedTypeRef(inner) => inner.to_rust_ty(ctx), + TypeKind::ResolvedTypeRef(inner) => inner.try_to_rust_ty(ctx, &()), TypeKind::TemplateAlias(inner, _) | TypeKind::Alias(inner) => { let template_params = item.used_template_params(ctx) @@ -2302,13 +2486,11 @@ impl ToRustTy for Type { let spelling = self.name().expect("Unnamed alias?"); if item.is_opaque(ctx) && !template_params.is_empty() { - // Pray if there's no available layout. - let layout = self.layout(ctx).unwrap_or_else(Layout::zero); - BlobTyBuilder::new(layout).build() + self.try_to_opaque(ctx, item) } else if let Some(ty) = utils::type_from_named(ctx, spelling, inner) { - ty + Ok(ty) } else { utils::build_templated_path(item, ctx, template_params) } @@ -2317,55 +2499,51 @@ impl ToRustTy for Type { let template_params = item.used_template_params(ctx); if info.has_non_type_template_params() || (item.is_opaque(ctx) && template_params.is_some()) { - return match self.layout(ctx) { - Some(layout) => BlobTyBuilder::new(layout).build(), - None => { - warn!("Couldn't compute layout for a type with non \ - type template params or opaque, expect \ - dragons!"); - aster::AstBuilder::new().ty().unit() - } - }; + return self.try_to_opaque(ctx, item); } + let template_params = template_params.unwrap_or(vec![]); utils::build_templated_path(item, ctx, - template_params.unwrap_or(vec![])) + template_params) } TypeKind::Opaque => { - BlobTyBuilder::new(self.layout(ctx).unwrap_or(Layout::zero())) - .build() + self.try_to_opaque(ctx, item) } TypeKind::BlockPointer => { let void = raw_type(ctx, "c_void"); - void.to_ptr(/* is_const = */ - false, - ctx.span()) + Ok(void.to_ptr(/* is_const = */ + false, + ctx.span())) } TypeKind::Pointer(inner) | TypeKind::Reference(inner) => { let inner = ctx.resolve_item(inner); let inner_ty = inner.expect_type(); - let ty = inner.to_rust_ty(ctx); + + // Regardless if we can properly represent the inner type, we + // should always generate a proper pointer here, so use + // infallible conversion of the inner type. + let ty = inner.to_rust_ty_or_opaque(ctx, &()); // Avoid the first function pointer level, since it's already // represented in Rust. if inner_ty.canonical_type(ctx).is_function() { - ty + Ok(ty) } else { let is_const = self.is_const() || inner.expect_type().is_const(); - ty.to_ptr(is_const, ctx.span()) + Ok(ty.to_ptr(is_const, ctx.span())) } } TypeKind::Named => { let name = item.canonical_name(ctx); let ident = ctx.rust_ident(&name); - quote_ty!(ctx.ext_cx(), $ident) + Ok(quote_ty!(ctx.ext_cx(), $ident)) } - TypeKind::ObjCSel => quote_ty!(ctx.ext_cx(), objc::runtime::Sel), + TypeKind::ObjCSel => Ok(quote_ty!(ctx.ext_cx(), objc::runtime::Sel)), TypeKind::ObjCId | - TypeKind::ObjCInterface(..) => quote_ty!(ctx.ext_cx(), id), + TypeKind::ObjCInterface(..) => Ok(quote_ty!(ctx.ext_cx(), id)), ref u @ TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing {:?}!", u) } @@ -2373,35 +2551,36 @@ impl ToRustTy for Type { } } -impl ToRustTy for TemplateInstantiation { +impl TryToOpaque for TemplateInstantiation { + type Extra = Type; + + fn try_get_layout(&self, + ctx: &BindgenContext, + self_ty: &Type) + -> error::Result<Layout> { + self_ty.layout(ctx).ok_or(error::Error::NoLayoutForOpaqueBlob) + } +} + +impl TryToRustTy for TemplateInstantiation { type Extra = Type; - fn to_rust_ty(&self, ctx: &BindgenContext, self_ty: &Type) -> P<ast::Ty> { + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &Type) + -> error::Result<P<ast::Ty>> { let decl = self.template_definition(); - let mut ty = decl.to_rust_ty(ctx).unwrap(); - - if ty == aster::AstBuilder::new().ty().unit().unwrap() { - // If we gave up when making a type for the template definition, - // check if maybe we can make a better opaque blob for the - // instantiation. If not, at least don't use a zero-sized type. - if let Some(layout) = self_ty.layout(ctx) { - return BlobTyBuilder::new(layout).build(); - } else { - return quote_ty!(ctx.ext_cx(), u8); - } - } + let mut ty = decl.try_to_rust_ty(ctx, &())?.unwrap(); let decl_params = match decl.self_template_params(ctx) { Some(params) => params, None => { - // This can happen if we generated an opaque type for a - // partial template specialization, in which case we just - // use the opaque type's layout. If we don't have a layout, - // we cross our fingers and hope for the best :-/ + // This can happen if we generated an opaque type for a partial + // template specialization, and we've hit an instantiation of + // that partial specialization. debug_assert!(ctx.resolve_type_through_type_refs(decl) - .is_opaque()); - let layout = self_ty.layout(ctx).unwrap_or(Layout::zero()); - return BlobTyBuilder::new(layout).build(); + .is_opaque()); + return Err(error::Error::InstantiationOfOpaqueType); } }; @@ -2420,8 +2599,8 @@ impl ToRustTy for TemplateInstantiation { // Only pass type arguments for the type parameters that // the decl uses. .filter(|&(_, param)| ctx.uses_template_parameter(decl, *param)) - .map(|(arg, _)| arg.to_rust_ty(ctx)) - .collect::<Vec<_>>(); + .map(|(arg, _)| arg.try_to_rust_ty(ctx, &())) + .collect::<error::Result<Vec<_>>>()?; path.segments.last_mut().unwrap().parameters = if template_args.is_empty() { @@ -2437,14 +2616,17 @@ impl ToRustTy for TemplateInstantiation { } } - P(ty) + Ok(P(ty)) } } -impl ToRustTy for FunctionSig { - type Extra = Item; +impl TryToRustTy for FunctionSig { + type Extra = (); - fn to_rust_ty(&self, ctx: &BindgenContext, _item: &Item) -> P<ast::Ty> { + fn try_to_rust_ty(&self, + ctx: &BindgenContext, + _: &()) + -> error::Result<P<ast::Ty>> { // TODO: we might want to consider ignoring the reference return value. let ret = utils::fnsig_return_ty(ctx, &self); let arguments = utils::fnsig_arguments(ctx, &self); @@ -2462,11 +2644,11 @@ impl ToRustTy for FunctionSig { decl: decl, })); - P(ast::Ty { + Ok(P(ast::Ty { id: ast::DUMMY_NODE_ID, node: fnty, span: ctx.span(), - }) + })) } } @@ -2712,7 +2894,7 @@ pub fn codegen(context: &mut BindgenContext) -> Vec<P<ast::Item>> { } mod utils { - use super::ItemToRustTy; + use super::{error, TryToRustTy, ToRustTyOrOpaque}; use aster; use ir::context::{BindgenContext, ItemId}; use ir::function::FunctionSig; @@ -2925,20 +3107,20 @@ mod utils { pub fn build_templated_path(item: &Item, ctx: &BindgenContext, template_params: Vec<ItemId>) - -> P<ast::Ty> { + -> error::Result<P<ast::Ty>> { let path = item.namespace_aware_canonical_path(ctx); let builder = aster::AstBuilder::new().ty().path(); let template_params = template_params.iter() - .map(|param| param.to_rust_ty(ctx)) - .collect::<Vec<_>>(); + .map(|param| param.try_to_rust_ty(ctx, &())) + .collect::<error::Result<Vec<_>>>()?; // XXX: I suck at aster. if path.len() == 1 { - return builder.segment(&path[0]) - .with_tys(template_params) - .build() - .build(); + return Ok(builder.segment(&path[0]) + .with_tys(template_params) + .build() + .build()); } let mut builder = builder.id(&path[0]); @@ -2954,7 +3136,7 @@ mod utils { } } - builder.build() + Ok(builder.build()) } fn primitive_ty(ctx: &BindgenContext, name: &str) -> P<ast::Ty> { @@ -2980,7 +3162,9 @@ mod utils { "uintptr_t" | "size_t" => primitive_ty(ctx, "usize"), - "intptr_t" | "ptrdiff_t" | "ssize_t" => primitive_ty(ctx, "isize"), + "intptr_t" | "ptrdiff_t" | "ssize_t" => { + primitive_ty(ctx, "isize") + } _ => return None, }) } @@ -2988,15 +3172,14 @@ mod utils { pub fn rust_fndecl_from_signature(ctx: &BindgenContext, sig: &Item) -> P<ast::FnDecl> { - use codegen::ToRustTy; - let signature = sig.kind().expect_type().canonical_type(ctx); let signature = match *signature.kind() { TypeKind::Function(ref sig) => sig, _ => panic!("How?"), }; - let decl_ty = signature.to_rust_ty(ctx, sig); + let decl_ty = signature.try_to_rust_ty(ctx, &()) + .expect("function signature to Rust type conversion is infallible"); match decl_ty.unwrap().node { ast::TyKind::BareFn(bare_fn) => bare_fn.unwrap().decl, _ => panic!("How did this happen exactly?"), @@ -3010,7 +3193,7 @@ mod utils { if let TypeKind::Void = *return_item.kind().expect_type().kind() { ast::FunctionRetTy::Default(ctx.span()) } else { - ast::FunctionRetTy::Ty(return_item.to_rust_ty(ctx)) + ast::FunctionRetTy::Ty(return_item.to_rust_ty_or_opaque(ctx, &())) } } @@ -3033,7 +3216,8 @@ mod utils { // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html let arg_ty = match *arg_ty.canonical_type(ctx).kind() { TypeKind::Array(t, _) => { - t.to_rust_ty(ctx).to_ptr(ctx.resolve_type(t).is_const(), ctx.span()) + t.to_rust_ty_or_opaque(ctx, &()) + .to_ptr(ctx.resolve_type(t).is_const(), ctx.span()) }, TypeKind::Pointer(inner) => { let inner = ctx.resolve_item(inner); @@ -3041,11 +3225,11 @@ mod utils { if let TypeKind::ObjCInterface(_) = *inner_ty.canonical_type(ctx).kind() { quote_ty!(ctx.ext_cx(), id) } else { - arg_item.to_rust_ty(ctx) + arg_item.to_rust_ty_or_opaque(ctx, &()) } }, _ => { - arg_item.to_rust_ty(ctx) + arg_item.to_rust_ty_or_opaque(ctx, &()) } }; |