diff options
Diffstat (limited to 'codegen/mod.rs')
-rw-r--r-- | codegen/mod.rs | 600 |
1 files changed, 459 insertions, 141 deletions
diff --git a/codegen/mod.rs b/codegen/mod.rs index 0dd3228..41f6e3a 100644 --- a/codegen/mod.rs +++ b/codegen/mod.rs @@ -20,6 +20,10 @@ use self::struct_layout::StructLayoutTracker; use super::BindgenOptions; use crate::callbacks::{DeriveInfo, TypeKind as DeriveTypeKind}; +use crate::codegen::helpers::{ + CppSemanticAttributeAdder, CppSemanticAttributeCreator, + CppSemanticAttributeSingle, +}; use crate::ir::analysis::{HasVtable, Sizedness}; use crate::ir::annotations::{ Annotations, FieldAccessorKind, FieldVisibilityKind, @@ -441,12 +445,13 @@ impl AppendImplicitTemplateParams for proc_macro2::TokenStream { _ => {} } - let params: Vec<_> = item - .used_template_params(ctx) + let (used_template_params, _) = item.used_template_params(ctx); + let params: Vec<_> = used_template_params .iter() .map(|p| { p.try_to_rust_ty(ctx, &()) .expect("template params cannot fail to be a rust type") + .ignore_annotations() }) .collect(); if !params.is_empty() { @@ -662,7 +667,10 @@ impl CodeGenerator for Var { attrs.push(attributes::doc(comment)); } - let ty = self.ty().to_rust_ty_or_opaque(ctx, &()); + let ty = self + .ty() + .to_rust_ty_or_opaque(ctx, &()) + .ignore_annotations(); if let Some(val) = self.val() { match *val { @@ -904,7 +912,8 @@ impl CodeGenerator for Type { return; } - let mut outer_params = item.used_template_params(ctx); + let (mut outer_params, has_unused_template_args) = + item.used_template_params(ctx); let is_opaque = item.is_opaque(ctx, &()); let inner_rust_type = if is_opaque { @@ -914,9 +923,12 @@ impl CodeGenerator for Type { // 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. - let mut inner_ty = inner_item + let (mut inner_ty, _) = inner_item .try_to_rust_ty_or_opaque(ctx, &()) - .unwrap_or_else(|_| self.to_opaque(ctx, item)); + .map(|ty| ty.into_outer_type()) + .unwrap_or_else(|_| { + (self.to_opaque(ctx, item), RustTyAnnotation::None) + }); inner_ty.append_implicit_template_params(ctx, inner_item); inner_ty }; @@ -951,6 +963,18 @@ impl CodeGenerator for Type { } else { quote! {} }; + let mut semantic_annotations = + CppSemanticAttributeSingle::new(ctx.options()); + // We are handling (essentially) type X = Y; + // We want to denote only if X has unused template params, e.g. + // type X<A> = Y; + // We don't want to note whether Y has unused template params, e.g. + // type X = Y<B> + // because that information will be recorded against the definition of Y. + if has_unused_template_args { + semantic_annotations.discards_template_param(); + } + tokens.append_all(semantic_annotations.result()); let alias_style = if ctx.options().type_alias.matches(&name) { AliasVariation::TypeAlias @@ -983,8 +1007,21 @@ impl CodeGenerator for Type { return; } + let mut attributes = Vec::new(); + if let Some(original_name) = item.original_name(ctx) { + if name != original_name { + let mut semantic_annotations = + CppSemanticAttributeAdder::new( + ctx.options(), + &mut attributes, + ); + semantic_annotations.original_name(&original_name); + } + } + tokens.append_all(match alias_style { AliasVariation::TypeAlias => quote! { + #( #attributes )* pub type #rust_name }, AliasVariation::NewType | AliasVariation::NewTypeDeref => { @@ -1031,7 +1068,7 @@ impl CodeGenerator for Type { .map(|p| { p.try_to_rust_ty(ctx, &()).expect( "type parameters can always convert to rust ty OK", - ) + ).ignore_annotations() }) .collect(); @@ -1147,8 +1184,8 @@ impl<'a> CodeGenerator for Vtable<'a> { // FIXME: Need to account for overloading with times_seen (separately from regular function path). let function_name = ctx.rust_ident(function_name); - let mut args = utils::fnsig_arguments(ctx, signature); - let ret = utils::fnsig_return_ty(ctx, signature); + let (mut args, _) = utils::fnsig_arguments(ctx, signature); + let (ret, _) = utils::fnsig_return_ty(ctx, signature); args[0] = if m.is_const() { quote! { this: *const #class_ident } @@ -1193,11 +1230,12 @@ impl<'a> TryToRustTy for Vtable<'a> { &self, ctx: &BindgenContext, _: &(), - ) -> error::Result<proc_macro2::TokenStream> { + ) -> error::Result<RustTy> { let name = ctx.rust_ident(self.canonical_name(ctx)); Ok(quote! { #name - }) + } + .into()) } } @@ -1247,7 +1285,8 @@ impl CodeGenerator for TemplateInstantiation { let fn_name = ctx.rust_ident_raw(fn_name); let prefix = ctx.trait_prefix(); - let ident = item.to_rust_ty_or_opaque(ctx, &()); + let ident = + item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations(); let size_of_expr = quote! { ::#prefix::mem::size_of::<#ident>() }; @@ -1396,7 +1435,8 @@ impl<'a> FieldCodegen<'a> for FieldData { let field_item = self.ty().into_resolver().through_type_refs().resolve(ctx); let field_ty = field_item.expect_type(); - let mut ty = self.ty().to_rust_ty_or_opaque(ctx, &()); + let ty = self.ty().to_rust_ty_or_opaque(ctx, &()); + let (mut ty, ty_annotations) = ty.into_outer_type(); ty.append_implicit_template_params(ctx, field_item); // NB: If supported, we use proper `union` types. @@ -1405,7 +1445,8 @@ impl<'a> FieldCodegen<'a> for FieldData { } else if let Some(item) = field_ty.is_incomplete_array(ctx) { result.saw_incomplete_array(); - let inner = item.to_rust_ty_or_opaque(ctx, &()); + let inner = + item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations(); if ctx.options().enable_cxx_namespaces { quote! { @@ -1449,19 +1490,33 @@ impl<'a> FieldCodegen<'a> for FieldData { let accessor_kind = self.annotations().accessor_kind().unwrap_or(accessor_kind); + let mut attributes = Vec::new(); + let mut csaa = + CppSemanticAttributeAdder::new(ctx.options(), &mut attributes); + match ty_annotations { + RustTyAnnotation::Reference => csaa.field_type_reference(), + RustTyAnnotation::RValueReference => { + csaa.field_type_rvalue_reference() + } + _ => {} + }; + match visibility { FieldVisibilityKind::Private => { field.append_all(quote! { + #(#attributes),* #field_ident : #ty , }); } FieldVisibilityKind::PublicCrate => { field.append_all(quote! { + #(#attributes),* pub(crate) #field_ident : #ty , }); } FieldVisibilityKind::Public => { field.append_all(quote! { + #(#attributes),* pub #field_ident : #ty , }); } @@ -1723,8 +1778,9 @@ impl<'a> FieldCodegen<'a> for BitfieldUnit { let param_name = bitfield_getter_name(ctx, bf); let bitfield_ty_item = ctx.resolve_item(bf.ty()); let bitfield_ty = bitfield_ty_item.expect_type(); - let bitfield_ty = - bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); + let bitfield_ty = bitfield_ty + .to_rust_ty_or_opaque(ctx, bitfield_ty_item) + .ignore_annotations(); ctor_params.push(quote! { #param_name : #bitfield_ty @@ -1819,8 +1875,9 @@ impl<'a> FieldCodegen<'a> for Bitfield { } }; - let bitfield_ty = - bitfield_ty.to_rust_ty_or_opaque(ctx, bitfield_ty_item); + let bitfield_ty = bitfield_ty + .to_rust_ty_or_opaque(ctx, bitfield_ty_item) + .ignore_annotations(); let offset = self.offset_into_unit(); let width = self.width() as u8; @@ -1936,6 +1993,7 @@ impl CodeGenerator for CompInfo { let vtable_type = vtable .try_to_rust_ty(ctx, &()) .expect("vtable to Rust type conversion is infallible") + .ignore_annotations() .to_ptr(true); fields.push(quote! { @@ -1951,7 +2009,9 @@ impl CodeGenerator for CompInfo { } let inner_item = ctx.resolve_item(base.ty); - let mut inner = inner_item.to_rust_ty_or_opaque(ctx, &()); + let mut inner = inner_item + .to_rust_ty_or_opaque(ctx, &()) + .ignore_annotations(); inner.append_implicit_template_params(ctx, inner_item); let field_name = ctx.rust_ident(&base.field_name); @@ -2115,7 +2175,9 @@ impl CodeGenerator for CompInfo { let mut generic_param_names = vec![]; - for (idx, ty) in item.used_template_params(ctx).iter().enumerate() { + let (used_template_params, unused_template_params) = + item.used_template_params(ctx); + for (idx, ty) in used_template_params.iter().enumerate() { let param = ctx.resolve_type(*ty); let name = param.name().unwrap(); let ident = ctx.rust_ident(name); @@ -2159,6 +2221,15 @@ impl CodeGenerator for CompInfo { } else { attributes.push(attributes::repr("C")); } + let mut semantic_annotations = + CppSemanticAttributeAdder::new(ctx.options(), &mut attributes); + if unused_template_params { + semantic_annotations.discards_template_param(); + } + semantic_annotations.visibility(self.visibility()); + if let Some(layout) = layout { + semantic_annotations.layout(&layout); + } if ctx.options().rust_features().repr_align { if let Some(explicit) = explicit_align { @@ -2225,6 +2296,16 @@ impl CodeGenerator for CompInfo { attributes.push(attributes::derives(&derives)) } + if let Some(original_name) = item.original_name(ctx) { + if canonical_name != original_name { + let mut semantic_annotations = CppSemanticAttributeAdder::new( + ctx.options(), + &mut attributes, + ); + semantic_annotations.original_name(&original_name); + } + } + if item.must_use(ctx) { attributes.push(attributes::must_use()); } @@ -2604,8 +2685,9 @@ impl Method { write!(&mut function_name, "{}", times_seen).unwrap(); } let function_name = ctx.rust_ident(function_name); - let mut args = utils::fnsig_arguments(ctx, signature); - let mut ret = utils::fnsig_return_ty(ctx, signature); + let (mut args, args_attributes) = + utils::fnsig_arguments(ctx, signature); + let (mut ret, ret_attr) = utils::fnsig_return_ty(ctx, signature); if !self.is_static() && !self.is_constructor() { args[0] = if self.is_const() { @@ -2681,7 +2763,9 @@ impl Method { let block = ctx.wrap_unsafe_ops(quote! ( #( #stmts );*)); - let mut attrs = vec![attributes::inline()]; + let mut attrs = args_attributes; + attrs.push(ret_attr); + attrs.push(attributes::inline()); if signature.must_use() && ctx.options().rust_features().must_use_function @@ -3202,6 +3286,15 @@ impl CodeGenerator for Enum { let mut attrs = vec![]; + let mut semantic_annotations = + CppSemanticAttributeAdder::new(ctx.options(), &mut attrs); + if let Some(original_name) = item.original_name(ctx) { + if name != original_name { + semantic_annotations.original_name(&original_name); + } + } + semantic_annotations.visibility(self.visibility); + // TODO(emilio): Delegate this to the builders? match variation { EnumVariation::Rust { non_exhaustive } => { @@ -3296,7 +3389,7 @@ impl CodeGenerator for Enum { }); } - let repr = repr.to_rust_ty_or_opaque(ctx, item); + let repr = repr.to_rust_ty_or_opaque(ctx, item).ignore_annotations(); let has_typedef = ctx.is_enum_typedef_combo(item.id()); let mut builder = @@ -3304,7 +3397,8 @@ impl CodeGenerator for Enum { // A map where we keep a value -> variant relation. let mut seen_values = HashMap::<_, Ident>::default(); - let enum_rust_ty = item.to_rust_ty_or_opaque(ctx, &()); + let enum_rust_ty = + item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations(); let is_toplevel = item.is_toplevel(ctx); // Used to mangle the constants we generate in the unnamed-enum case. @@ -3606,9 +3700,9 @@ trait TryToOpaque { &self, ctx: &BindgenContext, extra: &Self::Extra, - ) -> error::Result<proc_macro2::TokenStream> { + ) -> error::Result<RustTy> { self.try_get_layout(ctx, extra) - .map(|layout| helpers::blob(ctx, layout)) + .map(|layout| helpers::blob(ctx, layout).into()) } } @@ -3654,7 +3748,7 @@ trait TryToRustTy { &self, ctx: &BindgenContext, extra: &Self::Extra, - ) -> error::Result<proc_macro2::TokenStream>; + ) -> error::Result<RustTy>; } /// Fallible conversion to a Rust type or an opaque blob with the correct size @@ -3669,7 +3763,7 @@ trait TryToRustTyOrOpaque: TryToRustTy + TryToOpaque { &self, ctx: &BindgenContext, extra: &<Self as TryToRustTyOrOpaque>::Extra, - ) -> error::Result<proc_macro2::TokenStream>; + ) -> error::Result<RustTy>; } impl<E, T> TryToRustTyOrOpaque for T @@ -3682,10 +3776,10 @@ where &self, ctx: &BindgenContext, extra: &E, - ) -> error::Result<proc_macro2::TokenStream> { + ) -> error::Result<RustTy> { self.try_to_rust_ty(ctx, extra).or_else(|_| { if let Ok(layout) = self.try_get_layout(ctx, extra) { - Ok(helpers::blob(ctx, layout)) + Ok(helpers::blob(ctx, layout).into()) } else { Err(error::Error::NoLayoutForOpaqueBlob) } @@ -3717,7 +3811,7 @@ trait ToRustTyOrOpaque: TryToRustTy + ToOpaque { &self, ctx: &BindgenContext, extra: &<Self as ToRustTyOrOpaque>::Extra, - ) -> proc_macro2::TokenStream; + ) -> RustTy; } impl<E, T> ToRustTyOrOpaque for T @@ -3726,13 +3820,9 @@ where { type Extra = E; - fn to_rust_ty_or_opaque( - &self, - ctx: &BindgenContext, - extra: &E, - ) -> proc_macro2::TokenStream { + fn to_rust_ty_or_opaque(&self, ctx: &BindgenContext, extra: &E) -> RustTy { self.try_to_rust_ty(ctx, extra) - .unwrap_or_else(|_| self.to_opaque(ctx, extra)) + .unwrap_or_else(|_| RustTy::new_opaque(self.to_opaque(ctx, extra))) } } @@ -3761,7 +3851,7 @@ where &self, ctx: &BindgenContext, _: &(), - ) -> error::Result<proc_macro2::TokenStream> { + ) -> error::Result<RustTy> { ctx.resolve_item((*self).into()).try_to_rust_ty(ctx, &()) } } @@ -3785,7 +3875,7 @@ impl TryToRustTy for Item { &self, ctx: &BindgenContext, _: &(), - ) -> error::Result<proc_macro2::TokenStream> { + ) -> error::Result<RustTy> { self.kind().expect_type().try_to_rust_ty(ctx, self) } } @@ -3802,6 +3892,111 @@ impl TryToOpaque for Type { } } +enum RustTyAnnotation { + None, + Reference, + RValueReference, + HasUnusedTemplateArgs, + Opaque, +} + +struct RustTy { + ts: proc_macro2::TokenStream, + annotation: RustTyAnnotation, +} + +impl From<proc_macro2::TokenStream> for RustTy { + fn from(ts: proc_macro2::TokenStream) -> Self { + RustTy::new(ts) + } +} + +impl RustTy { + fn new(ts: proc_macro2::TokenStream) -> Self { + Self { + ts, + annotation: RustTyAnnotation::None, + } + } + + fn new_opaque(ts: proc_macro2::TokenStream) -> Self { + Self { + ts, + annotation: RustTyAnnotation::Opaque, + } + } + + fn new_reference( + ts: proc_macro2::TokenStream, + inner: RustTyAnnotation, + ) -> Self { + let annotation = match inner { + RustTyAnnotation::HasUnusedTemplateArgs | + RustTyAnnotation::Opaque => inner, + _ => RustTyAnnotation::Reference, + }; + Self { ts, annotation } + } + + fn new_rvalue_reference( + ts: proc_macro2::TokenStream, + inner: RustTyAnnotation, + ) -> Self { + let annotation = match inner { + RustTyAnnotation::HasUnusedTemplateArgs | + RustTyAnnotation::Opaque => inner, + _ => RustTyAnnotation::RValueReference, + }; + Self { ts, annotation } + } + + // We're constructing some outer type composed of an inner type, + // e.g. a reference to a T - the inner type is T + fn wraps(ts: proc_macro2::TokenStream, inner: RustTyAnnotation) -> Self { + let annotation = match inner { + RustTyAnnotation::HasUnusedTemplateArgs => { + RustTyAnnotation::HasUnusedTemplateArgs + } + _ => RustTyAnnotation::None, + }; + Self { ts, annotation } + } + + fn with_unused_template_args( + ts: proc_macro2::TokenStream, + has_unused_args: bool, + ) -> Self { + Self { + ts, + annotation: if has_unused_args { + RustTyAnnotation::HasUnusedTemplateArgs + } else { + RustTyAnnotation::None + }, + } + } + + // Where this is called, we're discarding information about whether + // a type is a reference or a pointer. This is not desirable. + fn ignore_annotations(self) -> proc_macro2::TokenStream { + self.ts + } + + // Use when this is an inner type and will become part of an outer type. + // Pass the annotation into [wraps] + fn into_outer_type(self) -> (proc_macro2::TokenStream, RustTyAnnotation) { + (self.ts, self.annotation) + } + + fn into_unannotated_ts(self) -> error::Result<proc_macro2::TokenStream> { + if matches!(self.annotation, RustTyAnnotation::None) { + Ok(self.ts) + } else { + Err(error::Error::ReferenceButCouldNotRecord) + } + } +} + impl TryToRustTy for Type { type Extra = Item; @@ -3809,28 +4004,30 @@ impl TryToRustTy for Type { &self, ctx: &BindgenContext, item: &Item, - ) -> error::Result<proc_macro2::TokenStream> { + ) -> error::Result<RustTy> { use self::helpers::ast_ty::*; match *self.kind() { - TypeKind::Void => Ok(c_void(ctx)), + TypeKind::Void => Ok(c_void(ctx).into()), // TODO: we should do something smart with nullptr, or maybe *const // c_void is enough? - TypeKind::NullPtr => Ok(c_void(ctx).to_ptr(true)), + TypeKind::NullPtr => Ok(c_void(ctx).to_ptr(true).into()), TypeKind::Int(ik) => { match ik { - IntKind::Bool => Ok(quote! { bool }), - IntKind::Char { .. } => Ok(raw_type(ctx, "c_char")), - IntKind::SChar => 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::Bool => Ok(quote! { bool }.into()), + IntKind::Char { .. } => Ok(raw_type(ctx, "c_char").into()), + IntKind::SChar => Ok(raw_type(ctx, "c_schar").into()), + IntKind::UChar => Ok(raw_type(ctx, "c_uchar").into()), + IntKind::Short => Ok(raw_type(ctx, "c_short").into()), + IntKind::UShort => Ok(raw_type(ctx, "c_ushort").into()), + IntKind::Int => Ok(raw_type(ctx, "c_int").into()), + IntKind::UInt => Ok(raw_type(ctx, "c_uint").into()), + IntKind::Long => Ok(raw_type(ctx, "c_long").into()), + IntKind::ULong => Ok(raw_type(ctx, "c_ulong").into()), + IntKind::LongLong => Ok(raw_type(ctx, "c_longlong").into()), + IntKind::ULongLong => { + Ok(raw_type(ctx, "c_ulonglong").into()) + } IntKind::WChar => { let layout = self .layout(ctx) @@ -3838,19 +4035,22 @@ impl TryToRustTy for Type { let ty = Layout::known_type_for_size(ctx, layout.size) .expect("Non-representable wchar_t?"); let ident = ctx.rust_ident_raw(ty); - Ok(quote! { #ident }) + Ok(quote! { #ident }.into()) } - IntKind::I8 => Ok(quote! { i8 }), - IntKind::U8 => Ok(quote! { u8 }), - IntKind::I16 => Ok(quote! { i16 }), - IntKind::U16 => Ok(quote! { u16 }), - IntKind::I32 => Ok(quote! { i32 }), - IntKind::U32 => Ok(quote! { u32 }), - IntKind::I64 => Ok(quote! { i64 }), - IntKind::U64 => Ok(quote! { u64 }), + IntKind::I8 => Ok(quote! { i8 }.into()), + IntKind::U8 => Ok(quote! { u8 }.into()), + IntKind::I16 => Ok(quote! { i16 }.into()), + IntKind::Char16 => Ok(quote! { c_char16_t }.into()), + IntKind::U16 => Ok(quote! { u16 }.into()), + IntKind::I32 => Ok(quote! { i32 }.into()), + IntKind::U32 => Ok(quote! { u32 }.into()), + IntKind::I64 => Ok(quote! { i64 }.into()), + IntKind::U64 => Ok(quote! { u64 }.into()), IntKind::Custom { name, .. } => { - Ok(proc_macro2::TokenStream::from_str(name).unwrap()) + Ok(proc_macro2::TokenStream::from_str(name) + .unwrap() + .into()) } IntKind::U128 => { Ok(if ctx.options().rust_features.i128_and_u128 { @@ -3859,19 +4059,21 @@ impl TryToRustTy for Type { // Best effort thing, but wrong alignment // unfortunately. quote! { [u64; 2] } - }) + } + .into()) } IntKind::I128 => { Ok(if ctx.options().rust_features.i128_and_u128 { quote! { i128 } } else { quote! { [u64; 2] } - }) + } + .into()) } } } TypeKind::Float(fk) => { - Ok(float_kind_rust_type(ctx, fk, self.layout(ctx))) + Ok(float_kind_rust_type(ctx, fk, self.layout(ctx)).into()) } TypeKind::Complex(fk) => { let float_path = @@ -3886,31 +4088,35 @@ impl TryToRustTy for Type { quote! { __BindgenComplex<#float_path> } - }) + } + .into()) } TypeKind::Function(ref fs) => { // 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 ty = fs.try_to_rust_ty(ctx, &())?.into_unannotated_ts()?; let prefix = ctx.trait_prefix(); Ok(quote! { ::#prefix::option::Option<#ty> - }) + } + .into()) } TypeKind::Array(item, len) | TypeKind::Vector(item, len) => { - let ty = item.try_to_rust_ty(ctx, &())?; + let ty = + item.try_to_rust_ty(ctx, &())?.into_unannotated_ts()?; Ok(quote! { [ #ty ; #len ] - }) + } + .into()) } TypeKind::Enum(..) => { let path = item.namespace_aware_canonical_path(ctx); let path = proc_macro2::TokenStream::from_str(&path.join("::")) .unwrap(); - Ok(quote!(#path)) + Ok(quote!(#path).into()) } TypeKind::TemplateInstantiation(ref inst) => { inst.try_to_rust_ty(ctx, item) @@ -3921,22 +4127,22 @@ impl TryToRustTy for Type { TypeKind::BlockPointer(..) => { if self.is_block_pointer() && !ctx.options().generate_block { let void = c_void(ctx); - return Ok(void.to_ptr(/* is_const = */ false)); + return Ok(void.to_ptr(/* is_const = */ false).into()); } - if item.is_opaque(ctx, &()) && - item.used_template_params(ctx) - .into_iter() - .any(|param| param.is_template_param(ctx, &())) - { + let (used_template_params, _) = item.used_template_params(ctx); + let has_used_template_params = used_template_params + .into_iter() + .any(|param| param.is_template_param(ctx, &())); + if item.is_opaque(ctx, &()) && has_used_template_params { self.try_to_opaque(ctx, item) } else if let Some(ty) = self .name() .and_then(|name| utils::type_from_named(ctx, name)) { - Ok(ty) + Ok(ty.into()) } else { - utils::build_path(item, ctx) + Ok(utils::build_path(item, ctx)?.into()) } } TypeKind::Comp(ref info) => { @@ -3947,11 +4153,15 @@ impl TryToRustTy for Type { return self.try_to_opaque(ctx, item); } - utils::build_path(item, ctx) + Ok(utils::build_path(item, ctx)?.into()) } TypeKind::Opaque => self.try_to_opaque(ctx, item), - TypeKind::Pointer(inner) | TypeKind::Reference(inner) => { + TypeKind::Pointer(inner) | TypeKind::Reference(inner, _) => { let is_const = ctx.resolve_type(inner).is_const(); + let is_reference = + matches!(self.kind(), TypeKind::Reference(_, false)); + let is_rvalue_reference = + matches!(self.kind(), TypeKind::Reference(_, true)); let inner = inner.into_resolver().through_type_refs().resolve(ctx); @@ -3963,16 +4173,24 @@ impl TryToRustTy for Type { // 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 mut ty = inner.to_rust_ty_or_opaque(ctx, &()); + let (mut ty, inner_annotations) = + inner.to_rust_ty_or_opaque(ctx, &()).into_outer_type(); ty.append_implicit_template_params(ctx, inner); // Avoid the first function pointer level, since it's already // represented in Rust. if inner_ty.canonical_type(ctx).is_function() || is_objc_pointer { - Ok(ty) + Ok(RustTy::wraps(ty, inner_annotations)) } else { - Ok(ty.to_ptr(is_const)) + let ty_ptr = ty.to_ptr(is_const); + Ok(if is_rvalue_reference { + RustTy::new_rvalue_reference(ty_ptr, inner_annotations) + } else if is_reference { + RustTy::new_reference(ty_ptr, inner_annotations) + } else { + RustTy::wraps(ty_ptr, inner_annotations) + }) } } TypeKind::TypeParam => { @@ -3980,19 +4198,23 @@ impl TryToRustTy for Type { let ident = ctx.rust_ident(name); Ok(quote! { #ident - }) + } + .into()) } TypeKind::ObjCSel => Ok(quote! { objc::runtime::Sel - }), + } + .into()), TypeKind::ObjCId => Ok(quote! { id - }), + } + .into()), TypeKind::ObjCInterface(ref interface) => { let name = ctx.rust_ident(interface.name()); Ok(quote! { #name - }) + } + .into()) } ref u @ TypeKind::UnresolvedTypeRef(..) => { unreachable!("Should have been resolved after parsing {:?}!", u) @@ -4022,7 +4244,7 @@ impl TryToRustTy for TemplateInstantiation { &self, ctx: &BindgenContext, item: &Item, - ) -> error::Result<proc_macro2::TokenStream> { + ) -> error::Result<RustTy> { if self.is_opaque(ctx, item) { return Err(error::Error::InstantiationOfOpaqueType); } @@ -4066,19 +4288,32 @@ impl TryToRustTy for TemplateInstantiation { .filter(|&(_, param)| ctx.uses_template_parameter(def.id(), *param)) .map(|(arg, _)| { let arg = arg.into_resolver().through_type_refs().resolve(ctx); - let mut ty = arg.try_to_rust_ty(ctx, &())?; + let mut ty = + arg.try_to_rust_ty(ctx, &())?.into_unannotated_ts()?; ty.append_implicit_template_params(ctx, arg); Ok(ty) }) .collect::<error::Result<Vec<_>>>()?; + let has_unused_template_args = def_params + .iter() + // Only pass type arguments for the type parameters that + // the def uses. + .any(|param| !ctx.uses_template_parameter(def.id(), *param)); + if template_args.is_empty() { - return Ok(ty); + return Ok(RustTy::with_unused_template_args( + ty, + has_unused_template_args, + )); } - Ok(quote! { - #ty < #( #template_args ),* > - }) + Ok(RustTy::with_unused_template_args( + quote! { + #ty < #( #template_args ),* > + }, + has_unused_template_args, + )) } } @@ -4089,39 +4324,40 @@ impl TryToRustTy for FunctionSig { &self, ctx: &BindgenContext, _: &(), - ) -> error::Result<proc_macro2::TokenStream> { + ) -> error::Result<RustTy> { // 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); + let (ret, _) = utils::fnsig_return_ty(ctx, self); + let (arguments, _) = utils::fnsig_arguments(ctx, self); match self.abi(ctx, None) { ClangAbi::Known(Abi::ThisCall) if !ctx.options().rust_features().thiscall_abi => { warn!("Skipping function with thiscall ABI that isn't supported by the configured Rust target"); - Ok(proc_macro2::TokenStream::new()) + Ok(proc_macro2::TokenStream::new().into()) } ClangAbi::Known(Abi::Vectorcall) if !ctx.options().rust_features().vectorcall_abi => { warn!("Skipping function with vectorcall ABI that isn't supported by the configured Rust target"); - Ok(proc_macro2::TokenStream::new()) + Ok(proc_macro2::TokenStream::new().into()) } ClangAbi::Known(Abi::CUnwind) if !ctx.options().rust_features().c_unwind_abi => { warn!("Skipping function with C-unwind ABI that isn't supported by the configured Rust target"); - Ok(proc_macro2::TokenStream::new()) + Ok(proc_macro2::TokenStream::new().into()) } ClangAbi::Known(Abi::EfiApi) if !ctx.options().rust_features().abi_efiapi => { warn!("Skipping function with efiapi ABI that isn't supported by the configured Rust target"); - Ok(proc_macro2::TokenStream::new()) + Ok(proc_macro2::TokenStream::new().into()) } abi => Ok(quote! { unsafe extern #abi fn ( #( #arguments ),* ) #ret - }), + } + .into()), } } } @@ -4150,14 +4386,19 @@ impl CodeGenerator for Function { return None; } - // Pure virtual methods have no actual symbol, so we can't generate - // something meaningful for them. - let is_dynamic_function = match self.kind() { - FunctionKind::Method(ref method_kind) - if method_kind.is_pure_virtual() => - { - return None; + let is_pure_virtual = match self.kind() { + FunctionKind::Method(ref method_kind) => { + method_kind.is_pure_virtual() } + _ => false, + }; + + let is_virtual = matches!( + self.kind(), + FunctionKind::Method(MethodKind::Virtual { .. }) + ); + + let is_dynamic_function = match self.kind() { FunctionKind::Function => { ctx.options().dynamic_library_name.is_some() } @@ -4194,10 +4435,11 @@ impl CodeGenerator for Function { _ => panic!("Signature kind is not a Function: {:?}", signature), }; - let args = utils::fnsig_arguments(ctx, signature); - let ret = utils::fnsig_return_ty(ctx, signature); + let (args, args_attrs) = utils::fnsig_arguments(ctx, signature); + let (ret, ret_attr) = utils::fnsig_return_ty(ctx, signature); - let mut attributes = vec![]; + let mut attributes = args_attrs; + attributes.push(ret_attr); if ctx.options().rust_features().must_use_function { let must_use = signature.must_use() || { @@ -4218,6 +4460,19 @@ impl CodeGenerator for Function { attributes.push(attributes::doc(comment)); } + let mut semantic_annotations = + CppSemanticAttributeAdder::new(ctx.options(), &mut attributes); + + if is_pure_virtual { + semantic_annotations.is_pure_virtual(); + } + + if is_virtual { + semantic_annotations.is_virtual(); + } + + semantic_annotations.visibility(self.visibility()); + let abi = match signature.abi(ctx, Some(name)) { ClangAbi::Known(Abi::ThisCall) if !ctx.options().rust_features().thiscall_abi => @@ -4291,6 +4546,19 @@ impl CodeGenerator for Function { if times_seen > 0 { write!(&mut canonical_name, "{}", times_seen).unwrap(); } + if canonical_name != self.name() { + semantic_annotations.original_name(self.name()); + } + + if let Some(special_member_kind) = self.special_member() { + semantic_annotations.special_member(special_member_kind); + } + if self.deleted_fn() { + semantic_annotations.deleted_fn(); + } + if self.defaulted_fn() { + semantic_annotations.defaulted_fn(); + } let mut has_link_name_attr = false; if let Some(link_name) = self.link_name() { @@ -4345,7 +4613,7 @@ impl CodeGenerator for Function { args, args_identifiers, ret, - ret_ty, + ret_ty.0, attributes, ctx, ); @@ -4418,8 +4686,9 @@ fn objc_method_codegen( } let signature = method.signature(); - let fn_args = utils::fnsig_arguments(ctx, signature); - let fn_ret = utils::fnsig_return_ty(ctx, signature); + let (fn_args, _) = utils::fnsig_arguments(ctx, signature); + let (fn_ret, _) = utils::fnsig_return_ty(ctx, signature); + // We disregard reference vs pointer attributes for objc methods for now. let sig = if method.is_class_method() { quote! { @@ -4732,7 +5001,13 @@ pub(crate) fn codegen( pub(crate) mod utils { use super::serialize::CSerialize; - use super::{error, CodegenError, CodegenResult, ToRustTyOrOpaque}; + use super::{ + error, CodegenError, CodegenResult, RustTy, RustTyAnnotation, + ToRustTyOrOpaque, + }; + use crate::codegen::helpers::{ + CppSemanticAttributeCreator, CppSemanticAttributeSingle, + }; use crate::ir::context::BindgenContext; use crate::ir::function::{Abi, ClangAbi, FunctionSig}; use crate::ir::item::{Item, ItemCanonicalPath}; @@ -5128,12 +5403,12 @@ pub(crate) mod utils { ctx: &BindgenContext, sig: &FunctionSig, include_arrow: bool, - ) -> proc_macro2::TokenStream { + ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { if sig.is_divergent() { return if include_arrow { - quote! { -> ! } + (quote! { -> ! }, quote! {}) } else { - quote! { ! } + (quote! { ! }, quote! {}) }; } @@ -5149,35 +5424,54 @@ pub(crate) mod utils { if let TypeKind::Void = canonical_type_kind { return if include_arrow { - quote! {} + (quote! {}, quote! {}) } else { - quote! { () } + (quote! { () }, quote! {}) }; } let ret_ty = sig.return_type().to_rust_ty_or_opaque(ctx, &()); - if include_arrow { + let annotations = ret_ty.annotation; + let ret_ty = ret_ty.ts; + let ts = if include_arrow { quote! { -> #ret_ty } } else { ret_ty - } + }; + + let mut semantic_annotation = + CppSemanticAttributeSingle::new(ctx.options()); + match annotations { + super::RustTyAnnotation::None => {} + super::RustTyAnnotation::Reference => { + semantic_annotation.ret_type_reference() + } + super::RustTyAnnotation::RValueReference => { + semantic_annotation.ret_type_rvalue_reference() + } + super::RustTyAnnotation::HasUnusedTemplateArgs | + super::RustTyAnnotation::Opaque => { + semantic_annotation.incomprehensible_param_in_arg_or_return() + } + }; + (ts, semantic_annotation.result()) } pub(crate) fn fnsig_return_ty( ctx: &BindgenContext, sig: &FunctionSig, - ) -> proc_macro2::TokenStream { + ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { fnsig_return_ty_internal(ctx, sig, /* include_arrow = */ true) } pub(crate) fn fnsig_arguments( ctx: &BindgenContext, sig: &FunctionSig, - ) -> Vec<proc_macro2::TokenStream> { + ) -> (Vec<proc_macro2::TokenStream>, Vec<proc_macro2::TokenStream>) { use super::ToPtr; let mut unnamed_arguments = 0; - let mut args = sig + let mut args: (Vec<_>, Vec<_>) = sig .argument_types() .iter() .map(|&(ref name, ty)| { @@ -5192,15 +5486,19 @@ pub(crate) mod utils { // the array type derivation. // // [1]: http://c0x.coding-guidelines.com/6.7.5.3.html - let arg_ty = match *arg_ty.canonical_type(ctx).kind() { + let arg_details = match *arg_ty.canonical_type(ctx).kind() { TypeKind::Array(t, _) => { - let stream = + let rust_ty = if ctx.options().array_pointers_in_arguments { arg_ty.to_rust_ty_or_opaque(ctx, arg_item) } else { t.to_rust_ty_or_opaque(ctx, &()) }; - stream.to_ptr(ctx.resolve_type(t).is_const()) + let (inner_ty, annotations) = rust_ty.into_outer_type(); + RustTy::wraps( + inner_ty.to_ptr(ctx.resolve_type(t).is_const()), + annotations, + ) } TypeKind::Pointer(inner) => { let inner = ctx.resolve_item(inner); @@ -5209,15 +5507,16 @@ pub(crate) mod utils { *inner_ty.canonical_type(ctx).kind() { let name = ctx.rust_ident(interface.name()); - quote! { + RustTy::new(quote! { #name - } + }) } else { arg_item.to_rust_ty_or_opaque(ctx, &()) } } _ => arg_item.to_rust_ty_or_opaque(ctx, &()), }; + let arg_ty = arg_details.ts; let arg_name = match *name { Some(ref name) => ctx.rust_mangle(name).into_owned(), @@ -5229,15 +5528,33 @@ pub(crate) mod utils { assert!(!arg_name.is_empty()); let arg_name = ctx.rust_ident(arg_name); + let mut semantic_annotation = + CppSemanticAttributeSingle::new(ctx.options()); + match arg_details.annotation { + RustTyAnnotation::None => {} + RustTyAnnotation::Reference => { + semantic_annotation.arg_type_reference(&arg_name) + } + RustTyAnnotation::RValueReference => { + semantic_annotation.arg_type_rvalue_reference(&arg_name) + } + RustTyAnnotation::HasUnusedTemplateArgs | + RustTyAnnotation::Opaque => semantic_annotation + .incomprehensible_param_in_arg_or_return(), + }; - quote! { - #arg_name : #arg_ty - } + ( + quote! { + #arg_name : #arg_ty + }, + semantic_annotation.result(), + ) }) - .collect::<Vec<_>>(); + .unzip(); if sig.is_variadic() { - args.push(quote! { ... }) + args.0.push(quote! { ... }); + args.1.push(quote! {}); } args @@ -5279,12 +5596,13 @@ pub(crate) mod utils { let args = sig.argument_types().iter().map(|&(_, ty)| { let arg_item = ctx.resolve_item(ty); - arg_item.to_rust_ty_or_opaque(ctx, &()) + arg_item.to_rust_ty_or_opaque(ctx, &()).ignore_annotations() }); let ret_ty = fnsig_return_ty_internal( ctx, sig, /* include_arrow = */ false, - ); + ) + .0; quote! { *const ::block::Block<(#(#args,)*), #ret_ty> } |