aboutsummaryrefslogtreecommitdiff
path: root/codegen/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'codegen/mod.rs')
-rw-r--r--codegen/mod.rs600
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>
}