From 3392e5ce332fc58cfaaee5845eaad2db5cd51a20 Mon Sep 17 00:00:00 2001 From: Matthew Maurer Date: Mon, 12 Jun 2023 18:22:45 +0000 Subject: Add autocxx support Test: Build autocxx, m rust Bug: 276464273 Change-Id: Ife4bb9342a669cbb81182cadb742409e2aeaab5c --- Android.bp | 1 + clang.rs | 15 + codegen/error.rs | 6 + codegen/helpers.rs | 171 +++- codegen/mod.rs | 600 ++++++++++--- ir/analysis/has_vtable.rs | 2 +- ir/comp.rs | 24 + ir/context.rs | 3 + ir/enum_ty.rs | 15 +- ir/function.rs | 167 +++- ir/int.rs | 9 +- ir/item.rs | 32 + ir/layout.rs | 8 +- ir/template.rs | 19 +- ir/ty.rs | 30 +- lib.rs | 3 + options/mod.rs | 55 ++ patches/autocxx.patch | 2190 +++++++++++++++++++++++++++++++++++++++++++++ 18 files changed, 3164 insertions(+), 186 deletions(-) create mode 100644 patches/autocxx.patch diff --git a/Android.bp b/Android.bp index 0f0d867..af0cb35 100644 --- a/Android.bp +++ b/Android.bp @@ -66,6 +66,7 @@ rust_library_host { "libpeeking_take_while", "libprettyplease", "libproc_macro2", + "libitertools", "libquote", "libregex", "librustc_hash", diff --git a/clang.rs b/clang.rs index 0060213..4f8de24 100644 --- a/clang.rs +++ b/clang.rs @@ -833,6 +833,21 @@ impl Cursor { unsafe { clang_isVirtualBase(self.x) != 0 } } + // Is this cursor's referent a default constructor? + pub fn is_default_constructor(&self) -> bool { + unsafe { clang_CXXConstructor_isDefaultConstructor(self.x) != 0 } + } + + // Is this cursor's referent a copy constructor? + pub fn is_copy_constructor(&self) -> bool { + unsafe { clang_CXXConstructor_isCopyConstructor(self.x) != 0 } + } + + // Is this cursor's referent a move constructor? + pub fn is_move_constructor(&self) -> bool { + unsafe { clang_CXXConstructor_isMoveConstructor(self.x) != 0 } + } + /// Try to evaluate this cursor. pub(crate) fn evaluate(&self) -> Option { EvalResult::new(*self) diff --git a/codegen/error.rs b/codegen/error.rs index ead3496..f38a1c6 100644 --- a/codegen/error.rs +++ b/codegen/error.rs @@ -11,6 +11,9 @@ pub(crate) enum Error { /// definition that is too difficult for us to understand (like a partial /// template specialization). InstantiationOfOpaqueType, + + /// Type was a reference not a pointer, but we had nowhere to record that fact. + ReferenceButCouldNotRecord, } impl fmt::Display for Error { @@ -23,6 +26,9 @@ impl fmt::Display for Error { "Instantiation of opaque template type or partial template \ specialization" } + Error::ReferenceButCouldNotRecord => { + "Type was a reference in a context where we only expected other types" + } }) } } diff --git a/codegen/helpers.rs b/codegen/helpers.rs index 726fe75..113e93d 100644 --- a/codegen/helpers.rs +++ b/codegen/helpers.rs @@ -1,7 +1,9 @@ //! Helpers for code generation that don't need macro expansion. -use crate::ir::context::BindgenContext; +use crate::ir::comp::SpecialMemberKind; +use crate::ir::function::Visibility; use crate::ir::layout::Layout; +use crate::{ir::context::BindgenContext, BindgenOptions}; use proc_macro2::{Ident, Span, TokenStream}; use quote::TokenStreamExt; @@ -77,6 +79,173 @@ pub(crate) mod attributes { } } +pub trait CppSemanticAttributeCreator { + fn do_add(&mut self, ts: TokenStream); + fn is_enabled(&self) -> bool; + + fn add(&mut self, tokens: TokenStream) { + if self.is_enabled() { + self.do_add(quote! { + #[cpp_semantics(#tokens)] + }) + } + } + + fn add_ident(&mut self, desc: &str) { + if self.is_enabled() { + let id = Ident::new(desc, Span::call_site()); + self.add(quote! { #id }) + } + } + + fn special_member(&mut self, kind: SpecialMemberKind) { + let kind_str = match kind { + SpecialMemberKind::DefaultConstructor => "default_ctor", + SpecialMemberKind::CopyConstructor => "copy_ctor", + SpecialMemberKind::MoveConstructor => "move_ctor", + SpecialMemberKind::Destructor => "dtor", + SpecialMemberKind::AssignmentOperator => "assignment_operator", + }; + self.add(quote! { + special_member(#kind_str) + }) + } + + fn original_name(&mut self, name: &str) { + self.add(quote! { + original_name(#name) + }) + } + + fn ret_type_reference(&mut self) { + self.add_ident("ret_type_reference") + } + + fn ret_type_rvalue_reference(&mut self) { + self.add_ident("ret_type_rvalue_reference") + } + + fn arg_type_reference(&mut self, arg_name: &Ident) { + self.add(quote! { + arg_type_reference(#arg_name) + }) + } + + fn field_type_reference(&mut self) { + self.add_ident("reference") + } + + fn field_type_rvalue_reference(&mut self) { + self.add_ident("rvalue_reference") + } + + fn is_virtual(&mut self) { + self.add_ident("bindgen_virtual") + } + + fn arg_type_rvalue_reference(&mut self, arg_name: &Ident) { + self.add(quote! { + arg_type_rvalue_reference(#arg_name) + }) + } + + fn is_pure_virtual(&mut self) { + self.add_ident("pure_virtual") + } + + fn visibility(&mut self, visibility: Visibility) { + match visibility { + Visibility::Protected => self.add_ident("visibility_protected"), + Visibility::Private => self.add_ident("visibility_private"), + _ => {} + } + } + + fn incomprehensible_param_in_arg_or_return(&mut self) { + self.add_ident("incomprehensible_param_in_arg_or_return") + } + + fn discards_template_param(&mut self) { + self.add_ident("unused_template_param") + } + + fn deleted_fn(&mut self) { + self.add_ident("deleted") + } + + fn defaulted_fn(&mut self) { + self.add_ident("defaulted") + } + + fn layout(&mut self, layout: &Layout) { + let sz = ast_ty::int_expr(layout.size as i64); + let align = ast_ty::int_expr(layout.align as i64); + let packed = if layout.packed { + quote! { true } + } else { + quote! { false } + }; + self.add(quote! { + layout(#sz, #align, #packed) + }) + } +} + +pub struct CppSemanticAttributeAdder<'a> { + enabled: bool, + attrs: &'a mut Vec, +} + +impl<'a> CppSemanticAttributeAdder<'a> { + pub(crate) fn new( + opts: &BindgenOptions, + attrs: &'a mut Vec, + ) -> Self { + Self { + enabled: opts.cpp_semantic_attributes, + attrs, + } + } +} + +impl<'a> CppSemanticAttributeCreator for CppSemanticAttributeAdder<'a> { + fn do_add(&mut self, ts: TokenStream) { + self.attrs.push(ts) + } + + fn is_enabled(&self) -> bool { + self.enabled + } +} + +pub struct CppSemanticAttributeSingle { + enabled: bool, + attr: TokenStream, +} + +impl CppSemanticAttributeSingle { + pub(crate) fn new(opts: &BindgenOptions) -> Self { + Self { + enabled: opts.cpp_semantic_attributes, + attr: quote! {}, + } + } + + pub(crate) fn result(self) -> TokenStream { + self.attr + } +} + +impl CppSemanticAttributeCreator for CppSemanticAttributeSingle { + fn do_add(&mut self, ts: TokenStream) { + self.attr = ts; + } + + fn is_enabled(&self) -> bool { + self.enabled + } +} + /// Generates a proper type for a field or type with a given `Layout`, that is, /// a type with the correct size and alignment restrictions. pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream { 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 = Y; + // We don't want to note whether Y has unused template params, e.g. + // type X = Y + // 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 { + ) -> error::Result { 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 { + ) -> error::Result { 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; + ) -> error::Result; } /// 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: &::Extra, - ) -> error::Result; + ) -> error::Result; } impl TryToRustTyOrOpaque for T @@ -3682,10 +3776,10 @@ where &self, ctx: &BindgenContext, extra: &E, - ) -> error::Result { + ) -> error::Result { 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: &::Extra, - ) -> proc_macro2::TokenStream; + ) -> RustTy; } impl 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 { + ) -> error::Result { ctx.resolve_item((*self).into()).try_to_rust_ty(ctx, &()) } } @@ -3785,7 +3875,7 @@ impl TryToRustTy for Item { &self, ctx: &BindgenContext, _: &(), - ) -> error::Result { + ) -> error::Result { 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 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 { + 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 { + ) -> error::Result { 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>) == // 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 { + ) -> error::Result { 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::>>()?; + 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 { + ) -> error::Result { // 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 { + ) -> (Vec, Vec) { 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::>(); + .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> } diff --git a/ir/analysis/has_vtable.rs b/ir/analysis/has_vtable.rs index 980a551..12b1fe0 100644 --- a/ir/analysis/has_vtable.rs +++ b/ir/analysis/has_vtable.rs @@ -164,7 +164,7 @@ impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> { TypeKind::TemplateAlias(t, _) | TypeKind::Alias(t) | TypeKind::ResolvedTypeRef(t) | - TypeKind::Reference(t) => { + TypeKind::Reference(t, _) => { trace!( " aliases and references forward to their inner type" ); diff --git a/ir/comp.rs b/ir/comp.rs index 89e77e1..1ff8961 100644 --- a/ir/comp.rs +++ b/ir/comp.rs @@ -4,6 +4,7 @@ use super::analysis::Sizedness; use super::annotations::Annotations; use super::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId}; use super::dot::DotAttributes; +use super::function::Visibility; use super::item::{IsOpaque, Item}; use super::layout::Layout; use super::template::TemplateParameters; @@ -72,6 +73,18 @@ impl MethodKind { } } +// The kind of C++ special member. +// TODO: We don't currently cover copy assignment or move assignment operator +// because libclang doesn't provide a way to query for them. +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum SpecialMemberKind { + DefaultConstructor, + CopyConstructor, + MoveConstructor, + Destructor, + AssignmentOperator, +} + /// A struct representing a C++ method, either static, normal, or virtual. #[derive(Debug)] pub(crate) struct Method { @@ -976,6 +989,10 @@ pub(crate) struct CompInfo { /// Whether this is a struct or a union. kind: CompKind, + /// The visibility of this struct or union if it was declared inside of + /// another type. Top-level types always have public visibility. + visibility: Visibility, + /// The members of this struct or union. fields: CompFields, @@ -1055,6 +1072,7 @@ impl CompInfo { pub(crate) fn new(kind: CompKind) -> Self { CompInfo { kind, + visibility: Visibility::Public, fields: CompFields::default(), template_params: vec![], methods: vec![], @@ -1166,6 +1184,11 @@ impl CompInfo { } } + /// Returns the visibility of the type. + pub fn visibility(&self) -> Visibility { + self.visibility + } + /// Returns whether we have a too large bitfield unit, in which case we may /// not be able to derive some of the things we should be able to normally /// derive. @@ -1255,6 +1278,7 @@ impl CompInfo { debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor); let mut ci = CompInfo::new(kind); + ci.visibility = Visibility::from(cursor.access_specifier()); ci.is_forward_declaration = location.map_or(true, |cur| match cur.kind() { CXCursor_ParmDecl => true, diff --git a/ir/context.rs b/ir/context.rs index a5c14a8..80e7f8d 100644 --- a/ir/context.rs +++ b/ir/context.rs @@ -1971,6 +1971,9 @@ If you encounter an error missing from this list, please file an issue or a PR!" CXType_Short => TypeKind::Int(IntKind::Short), CXType_UShort => TypeKind::Int(IntKind::UShort), CXType_WChar => TypeKind::Int(IntKind::WChar), + CXType_Char16 if self.options().use_distinct_char16_t => { + TypeKind::Int(IntKind::Char16) + } CXType_Char16 => TypeKind::Int(IntKind::U16), CXType_Char32 => TypeKind::Int(IntKind::U32), CXType_Long => TypeKind::Int(IntKind::Long), diff --git a/ir/enum_ty.rs b/ir/enum_ty.rs index 70cf0ea..a863340 100644 --- a/ir/enum_ty.rs +++ b/ir/enum_ty.rs @@ -2,6 +2,7 @@ use super::super::codegen::EnumVariation; use super::context::{BindgenContext, TypeId}; +use super::function::Visibility; use super::item::Item; use super::ty::{Type, TypeKind}; use crate::clang; @@ -32,6 +33,10 @@ pub(crate) struct Enum { /// The different variants, with explicit values. variants: Vec, + + /// The visibility of this enum if it was declared inside of + /// another type. Top-level types always have public visibility. + pub(crate) visibility: Visibility, } impl Enum { @@ -39,8 +44,13 @@ impl Enum { pub(crate) fn new( repr: Option, variants: Vec, + visibility: Visibility, ) -> Self { - Enum { repr, variants } + Enum { + repr, + variants, + visibility, + } } /// Get this enumeration's representation. @@ -56,6 +66,7 @@ impl Enum { /// Construct an enumeration from the given Clang type. pub(crate) fn from_ty( ty: &clang::Type, + visibility: Visibility, ctx: &mut BindgenContext, ) -> Result { use clang_sys::*; @@ -147,7 +158,7 @@ impl Enum { } CXChildVisit_Continue }); - Ok(Enum::new(repr, variants)) + Ok(Enum::new(repr, variants, visibility)) } fn is_matching_enum( diff --git a/ir/function.rs b/ir/function.rs index fab380e..d38c60e 100644 --- a/ir/function.rs +++ b/ir/function.rs @@ -1,6 +1,6 @@ //! Intermediate representation for C/C++ functions and methods. -use super::comp::MethodKind; +use super::comp::{MethodKind, SpecialMemberKind}; use super::context::{BindgenContext, TypeId}; use super::dot::DotAttributes; use super::item::Item; @@ -9,7 +9,9 @@ use super::ty::TypeKind; use crate::callbacks::{ItemInfo, ItemKind}; use crate::clang::{self, Attribute}; use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; -use clang_sys::{self, CXCallingConv}; +use clang_sys::{ + self, CXCallingConv, CX_CXXAccessSpecifier, CX_CXXPrivate, CX_CXXProtected, +}; use quote::TokenStreamExt; use std::io; @@ -70,6 +72,75 @@ pub(crate) enum Linkage { Internal, } +/// Visibility +#[derive(Debug, Clone, Copy)] +pub enum Visibility { + Public, + Protected, + Private, +} + +impl From for Visibility { + fn from(access_specifier: CX_CXXAccessSpecifier) -> Self { + if access_specifier == CX_CXXPrivate { + Visibility::Private + } else if access_specifier == CX_CXXProtected { + Visibility::Protected + } else { + Visibility::Public + } + } +} + +/// Autocxx specialized function information +#[derive(Debug)] +pub(crate) struct AutocxxFuncInfo { + /// C++ Special member kind, if applicable + special_member: Option, + /// Whether it is private + visibility: Visibility, + /// =delete + is_deleted: bool, + /// =default + is_defaulted: bool, +} + +impl AutocxxFuncInfo { + fn new( + special_member: Option, + visibility: Visibility, + is_deleted: bool, + is_defaulted: bool, + ) -> Self { + Self { + special_member, + visibility, + is_deleted, + is_defaulted, + } + } + + /// Get this function's C++ special member kind. + pub fn special_member(&self) -> Option { + self.special_member + } + + /// Whether it is private + pub fn visibility(&self) -> Visibility { + self.visibility + } + + /// Whether this is a function that's been deleted (=delete) + pub fn deleted_fn(&self) -> bool { + self.is_deleted + } + + /// Whether this is a function that's been deleted (=default) + pub fn defaulted_fn(&self) -> bool { + self.is_defaulted + } +} + /// A function declaration, with a signature, arguments, and argument names. /// /// The argument names vector must be the same length as the ones in the @@ -93,6 +164,9 @@ pub(crate) struct Function { /// The linkage of the function. linkage: Linkage, + + /// Autocxx extension information + autocxx: AutocxxFuncInfo, } impl Function { @@ -104,6 +178,7 @@ impl Function { signature: TypeId, kind: FunctionKind, linkage: Linkage, + autocxx: AutocxxFuncInfo, ) -> Self { Function { name, @@ -112,6 +187,7 @@ impl Function { signature, kind, linkage, + autocxx, } } @@ -144,6 +220,26 @@ impl Function { pub(crate) fn linkage(&self) -> Linkage { self.linkage } + + /// Get this function's C++ special member kind. + pub fn special_member(&self) -> Option { + self.autocxx.special_member() + } + + /// Whether it is private + pub fn visibility(&self) -> Visibility { + self.autocxx.visibility() + } + + /// Whether this is a function that's been deleted (=delete) + pub fn deleted_fn(&self) -> bool { + self.autocxx.deleted_fn() + } + + /// Whether this is a function that's been deleted (=default) + pub fn defaulted_fn(&self) -> bool { + self.autocxx.defaulted_fn() + } } impl DotAttributes for Function { @@ -422,15 +518,6 @@ impl FunctionSig { let spelling = cursor.spelling(); - // Don't parse operatorxx functions in C++ - let is_operator = |spelling: &str| { - spelling.starts_with("operator") && - !clang::is_valid_identifier(spelling) - }; - if is_operator(&spelling) { - return Err(ParseError::Continue); - } - // Constructors of non-type template parameter classes for some reason // include the template parameter in their name. Just skip them, since // we don't handle well non-type template parameters anyway. @@ -513,7 +600,10 @@ impl FunctionSig { let is_const = is_method && cursor.method_is_const(); let is_virtual = is_method && cursor.method_is_virtual(); let is_static = is_method && cursor.method_is_static(); - if !is_static && !is_virtual { + if !is_static && + (!is_virtual || + ctx.options().use_specific_virtual_function_receiver) + { let parent = cursor.semantic_parent(); let class = Item::parse(parent, None, ctx) .expect("Expected to parse the class"); @@ -537,7 +627,7 @@ impl FunctionSig { Item::builtin_type(TypeKind::Pointer(class), false, ctx); args.insert(0, (Some("this".into()), ptr)); } else if is_virtual { - let void = Item::builtin_type(TypeKind::Void, false, ctx); + let void = Item::builtin_type(TypeKind::Void, is_const, ctx); let ptr = Item::builtin_type(TypeKind::Pointer(void), false, ctx); args.insert(0, (Some("this".into()), ptr)); @@ -685,9 +775,7 @@ impl ClangSubItemParser for Function { return Err(ParseError::Continue); } - if cursor.access_specifier() == CX_CXXPrivate { - return Err(ParseError::Continue); - } + let visibility = Visibility::from(cursor.access_specifier()); let linkage = cursor.linkage(); let linkage = match linkage { @@ -707,10 +795,6 @@ impl ClangSubItemParser for Function { return Err(ParseError::Continue); } - if cursor.is_deleted_function() { - return Err(ParseError::Continue); - } - // We cannot handle `inline` functions that are not `static`. if context.options().wrap_static_fns && cursor.is_inlined_function() && @@ -749,7 +833,23 @@ impl ClangSubItemParser for Function { } assert!(!name.is_empty(), "Empty function name."); - let mangled_name = cursor_mangling(context, &cursor); + let operator_suffix = name.strip_prefix("operator"); + let special_member = if let Some(operator_suffix) = operator_suffix { + // We can't represent operatorxx functions as-is because + // they are not valid identifiers + if context.options().represent_cxx_operators { + let (new_suffix, special_member) = match operator_suffix { + "=" => ("equals", SpecialMemberKind::AssignmentOperator), + _ => return Err(ParseError::Continue), + }; + name = format!("operator_{}", new_suffix); + Some(special_member) + } else { + return Err(ParseError::Continue); + } + } else { + None + }; let link_name = context.options().last_callback(|callbacks| { callbacks.generated_link_name_override(ItemInfo { @@ -758,13 +858,36 @@ impl ClangSubItemParser for Function { }) }); + let mangled_name = cursor_mangling(context, &cursor); + + let special_member = special_member.or_else(|| { + if cursor.is_default_constructor() { + Some(SpecialMemberKind::DefaultConstructor) + } else if cursor.is_copy_constructor() { + Some(SpecialMemberKind::CopyConstructor) + } else if cursor.is_move_constructor() { + Some(SpecialMemberKind::MoveConstructor) + } else if cursor.kind() == clang_sys::CXCursor_Destructor { + Some(SpecialMemberKind::Destructor) + } else { + None + } + }); + + let autocxx_info = AutocxxFuncInfo::new( + special_member, + visibility, + cursor.is_deleted_function(), + cursor.is_defaulted_function(), + ); let function = Self::new( - name.clone(), + name, mangled_name, link_name, sig, kind, linkage, + autocxx_info, ); Ok(ParseResult::New(function, Some(cursor))) diff --git a/ir/int.rs b/ir/int.rs index 4251b37..ea2456e 100644 --- a/ir/int.rs +++ b/ir/int.rs @@ -54,9 +54,12 @@ pub enum IntKind { /// A 16-bit signed integer. I16, - /// Either a `char16_t` or a `wchar_t`. + /// A 16-bit integer, used only for enum size representation. U16, + /// Either a `char16_t` or a `wchar_t`. + Char16, + /// A 32-bit signed integer. I32, @@ -94,7 +97,7 @@ impl IntKind { // to know whether it is or not right now (unlike char, there's no // WChar_S / WChar_U). Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 | - WChar | U32 | U64 | U128 => false, + Char16 | WChar | U32 | U64 | U128 => false, SChar | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 | I128 => true, @@ -112,7 +115,7 @@ impl IntKind { use self::IntKind::*; Some(match *self { Bool | UChar | SChar | U8 | I8 | Char { .. } => 1, - U16 | I16 => 2, + U16 | I16 | Char16 => 2, U32 | I32 => 4, U64 | I64 => 8, I128 | U128 => 16, diff --git a/ir/item.rs b/ir/item.rs index a50d267..c35b2ac 100644 --- a/ir/item.rs +++ b/ir/item.rs @@ -823,6 +823,38 @@ impl Item { } } + /// Get this item's original C++ name, including any containing types, but without + /// the namespace name. For nested types, the C++ name differs from the Rust name, e.g. + /// a nested C++ type `A::B` would correspond to the Rust type `A_B`. + /// If the item or any of its containing types is anonymous, returns None. + pub fn original_name(&self, ctx: &BindgenContext) -> Option { + let target = ctx.resolve_item(self.name_target(ctx)); + + // Get item and all ancestors until the first enclosing namespace. + let ancestors: Vec<_> = target + .ancestors(ctx) + .map(|id| ctx.resolve_item(id)) + .take_while(|item| !item.is_module()) + .collect(); + + if ancestors.iter().any(|item| item.is_anon()) { + return None; + } + + let mut names: Vec<_> = ancestors + .iter() + .map(|item| { + let target = ctx.resolve_item(item.name_target(ctx)); + target.base_name(ctx) + }) + .filter(|name| !name.is_empty()) + .collect(); + + names.reverse(); + + Some(names.join("::")) + } + /// Get the canonical name without taking into account the replaces /// annotation. /// diff --git a/ir/layout.rs b/ir/layout.rs index ba944b0..17ca66e 100644 --- a/ir/layout.rs +++ b/ir/layout.rs @@ -8,13 +8,13 @@ use std::cmp; /// A type that represents the struct layout of a type. #[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub(crate) struct Layout { +pub struct Layout { /// The size (in bytes) of this layout. - pub(crate) size: usize, + pub size: usize, /// The alignment (in bytes) of this layout. - pub(crate) align: usize, + pub align: usize, /// Whether this layout's members are packed or not. - pub(crate) packed: bool, + pub packed: bool, } #[test] diff --git a/ir/template.rs b/ir/template.rs index 4dd8442..a1f8f5f 100644 --- a/ir/template.rs +++ b/ir/template.rs @@ -31,6 +31,7 @@ use super::context::{BindgenContext, ItemId, TypeId}; use super::item::{IsOpaque, Item, ItemAncestors}; use super::traversal::{EdgeKind, Trace, Tracer}; use crate::clang; +use itertools::{Either, Itertools}; /// Template declaration (and such declaration's template parameters) related /// methods. @@ -143,8 +144,9 @@ pub(crate) trait TemplateParameters: Sized { /// Get only the set of template parameters that this item uses. This is a /// subset of `all_template_params` and does not necessarily contain any of - /// `self_template_params`. - fn used_template_params(&self, ctx: &BindgenContext) -> Vec + /// `self_template_params`. If any are unused, true will be returned + /// in the second tuple element + fn used_template_params(&self, ctx: &BindgenContext) -> (Vec, bool) where Self: AsRef, { @@ -154,11 +156,18 @@ pub(crate) trait TemplateParameters: Sized { ); let id = *self.as_ref(); - ctx.resolve_item(id) + let (used, unused): (Vec<_>, Vec<_>) = ctx + .resolve_item(id) .all_template_params(ctx) .into_iter() - .filter(|p| ctx.uses_template_parameter(id, *p)) - .collect() + .partition_map(|p| { + if ctx.uses_template_parameter(id, p) { + Either::Left(p) + } else { + Either::Right(true) + } + }); + (used, !unused.is_empty()) } } diff --git a/ir/ty.rs b/ir/ty.rs index 8c505aa..5bf3841 100644 --- a/ir/ty.rs +++ b/ir/ty.rs @@ -14,6 +14,7 @@ use super::template::{ }; use super::traversal::{EdgeKind, Trace, Tracer}; use crate::clang::{self, Cursor}; +use crate::ir::function::Visibility; use crate::parse::{ParseError, ParseResult}; use std::borrow::Cow; use std::io; @@ -253,7 +254,9 @@ impl Type { ) -> Option> { let name_info = match *self.kind() { TypeKind::Pointer(inner) => Some((inner, Cow::Borrowed("ptr"))), - TypeKind::Reference(inner) => Some((inner, Cow::Borrowed("ref"))), + TypeKind::Reference(inner, _) => { + Some((inner, Cow::Borrowed("ref"))) + } TypeKind::Array(inner, length) => { Some((inner, format!("array{}", length).into())) } @@ -538,7 +541,7 @@ impl TemplateParameters for TypeKind { TypeKind::Enum(_) | TypeKind::Pointer(_) | TypeKind::BlockPointer(_) | - TypeKind::Reference(_) | + TypeKind::Reference(..) | TypeKind::UnresolvedTypeRef(..) | TypeKind::TypeParam | TypeKind::Alias(_) | @@ -616,7 +619,8 @@ pub(crate) enum TypeKind { BlockPointer(TypeId), /// A reference to a type, as in: int& foo(). - Reference(TypeId), + /// The bool represents whether it's rvalue. + Reference(TypeId, bool), /// An instantiation of an abstract template definition with a set of /// concrete template arguments. @@ -1044,14 +1048,23 @@ impl Type { } // XXX: RValueReference is most likely wrong, but I don't think we // can even add bindings for that, so huh. - CXType_RValueReference | CXType_LValueReference => { + CXType_LValueReference => { + let inner = Item::from_ty_or_ref( + ty.pointee_type().unwrap(), + location, + None, + ctx, + ); + TypeKind::Reference(inner, false) + } + CXType_RValueReference => { let inner = Item::from_ty_or_ref( ty.pointee_type().unwrap(), location, None, ctx, ); - TypeKind::Reference(inner) + TypeKind::Reference(inner, true) } // XXX DependentSizedArray is wrong CXType_VariableArray | CXType_DependentSizedArray => { @@ -1109,7 +1122,10 @@ impl Type { } } CXType_Enum => { - let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?"); + let visibility = + Visibility::from(cursor.access_specifier()); + let enum_ = Enum::from_ty(ty, visibility, ctx) + .expect("Not an enum?"); if !is_anonymous { let pretty_name = ty.spelling(); @@ -1222,7 +1238,7 @@ impl Trace for Type { } match *self.kind() { TypeKind::Pointer(inner) | - TypeKind::Reference(inner) | + TypeKind::Reference(inner, _) | TypeKind::Array(inner, _) | TypeKind::Vector(inner, _) | TypeKind::BlockPointer(inner) | diff --git a/lib.rs b/lib.rs index 482c1a3..e800136 100644 --- a/lib.rs +++ b/lib.rs @@ -1,5 +1,7 @@ //! Generate Rust bindings for C and C++ libraries. //! +//! This is a slightly forked version for use by `autocxx`. +//! //! Provide a C/C++ header file, receive Rust FFI code to call into C/C++ //! functions and use types defined in the header. //! @@ -1211,6 +1213,7 @@ fn get_target_dependent_env_var( /// When running inside a `build.rs` script, this can be used to make cargo invalidate the /// generated bindings whenever any of the files included from the header change: /// ``` +/// use autocxx_bindgen as bindgen; /// use bindgen::builder; /// let bindings = builder() /// .header("path/to/input/header") diff --git a/options/mod.rs b/options/mod.rs index c60da71..54b44eb 100644 --- a/options/mod.rs +++ b/options/mod.rs @@ -153,6 +153,61 @@ macro_rules! options { } options! { + /// Whether to specify the type of a virtual function receiver + use_specific_virtual_function_receiver: bool { + methods: { + /// Normally, virtual functions have void* as their 'this' type. + /// If this flag is enabled, override that behavior to indicate a + /// pointer of the specific type. + /// Disabled by default. + pub fn use_specific_virtual_function_receiver(mut self, doit: bool) -> Builder { + self.options.use_specific_virtual_function_receiver = doit; + self + } + }, + as_args: "--use-specific-virtual-function-receiver", + }, + + /// Whether we should emit C++ semantics attributes. + cpp_semantic_attributes: bool { + methods: { + /// If this is true, add attributes with details of underlying C++ semantics. + /// Disabled by default. + pub fn cpp_semantic_attributes(mut self, doit: bool) -> Builder { + self.options.cpp_semantic_attributes = doit; + self + } + }, + as_args: "--cpp-semantic-attributes", + }, + + /// Whether we should output information about C++ overloaded operators. + represent_cxx_operators: bool { + methods: { + /// If this is true, output existence of C++ overloaded operators. + /// At present, only operator= is noted. + /// Disabled by default. + pub fn represent_cxx_operators(mut self, doit: bool) -> Builder { + self.options.represent_cxx_operators = doit; + self + } + }, + as_args: "--represent-cxx-operators", + }, + + /// Whether we should distinguish between 'char16_t' and 'u16' + use_distinct_char16_t: bool { + methods: { + /// If this is true, denote 'char16_t' as a separate type from 'u16' + /// Disabled by default. + pub fn use_distinct_char16_t(mut self, doit: bool) -> Builder { + self.options.use_distinct_char16_t = doit; + self + } + }, + as_args: "--use-distinct-char16-t", + }, + /// Types that have been blocklisted and should not appear anywhere in the generated code. blocklisted_types: RegexSet { methods: { diff --git a/patches/autocxx.patch b/patches/autocxx.patch new file mode 100644 index 0000000..256b928 --- /dev/null +++ b/patches/autocxx.patch @@ -0,0 +1,2190 @@ +diff --git a/Android.bp b/Android.bp +index 0f0d867..af0cb35 100644 +--- a/Android.bp ++++ b/Android.bp +@@ -66,6 +66,7 @@ rust_library_host { + "libpeeking_take_while", + "libprettyplease", + "libproc_macro2", ++ "libitertools", + "libquote", + "libregex", + "librustc_hash", +diff --git a/clang.rs b/clang.rs +index 0060213..4f8de24 100644 +--- a/clang.rs ++++ b/clang.rs +@@ -833,6 +833,21 @@ impl Cursor { + unsafe { clang_isVirtualBase(self.x) != 0 } + } + ++ // Is this cursor's referent a default constructor? ++ pub fn is_default_constructor(&self) -> bool { ++ unsafe { clang_CXXConstructor_isDefaultConstructor(self.x) != 0 } ++ } ++ ++ // Is this cursor's referent a copy constructor? ++ pub fn is_copy_constructor(&self) -> bool { ++ unsafe { clang_CXXConstructor_isCopyConstructor(self.x) != 0 } ++ } ++ ++ // Is this cursor's referent a move constructor? ++ pub fn is_move_constructor(&self) -> bool { ++ unsafe { clang_CXXConstructor_isMoveConstructor(self.x) != 0 } ++ } ++ + /// Try to evaluate this cursor. + pub(crate) fn evaluate(&self) -> Option { + EvalResult::new(*self) +diff --git a/codegen/error.rs b/codegen/error.rs +index ead3496..f38a1c6 100644 +--- a/codegen/error.rs ++++ b/codegen/error.rs +@@ -11,6 +11,9 @@ pub(crate) enum Error { + /// definition that is too difficult for us to understand (like a partial + /// template specialization). + InstantiationOfOpaqueType, ++ ++ /// Type was a reference not a pointer, but we had nowhere to record that fact. ++ ReferenceButCouldNotRecord, + } + + impl fmt::Display for Error { +@@ -23,6 +26,9 @@ impl fmt::Display for Error { + "Instantiation of opaque template type or partial template \ + specialization" + } ++ Error::ReferenceButCouldNotRecord => { ++ "Type was a reference in a context where we only expected other types" ++ } + }) + } + } +diff --git a/codegen/helpers.rs b/codegen/helpers.rs +index 726fe75..113e93d 100644 +--- a/codegen/helpers.rs ++++ b/codegen/helpers.rs +@@ -1,7 +1,9 @@ + //! Helpers for code generation that don't need macro expansion. + +-use crate::ir::context::BindgenContext; ++use crate::ir::comp::SpecialMemberKind; ++use crate::ir::function::Visibility; + use crate::ir::layout::Layout; ++use crate::{ir::context::BindgenContext, BindgenOptions}; + use proc_macro2::{Ident, Span, TokenStream}; + use quote::TokenStreamExt; + +@@ -77,6 +79,173 @@ pub(crate) mod attributes { + } + } + ++pub trait CppSemanticAttributeCreator { ++ fn do_add(&mut self, ts: TokenStream); ++ fn is_enabled(&self) -> bool; ++ ++ fn add(&mut self, tokens: TokenStream) { ++ if self.is_enabled() { ++ self.do_add(quote! { ++ #[cpp_semantics(#tokens)] ++ }) ++ } ++ } ++ ++ fn add_ident(&mut self, desc: &str) { ++ if self.is_enabled() { ++ let id = Ident::new(desc, Span::call_site()); ++ self.add(quote! { #id }) ++ } ++ } ++ ++ fn special_member(&mut self, kind: SpecialMemberKind) { ++ let kind_str = match kind { ++ SpecialMemberKind::DefaultConstructor => "default_ctor", ++ SpecialMemberKind::CopyConstructor => "copy_ctor", ++ SpecialMemberKind::MoveConstructor => "move_ctor", ++ SpecialMemberKind::Destructor => "dtor", ++ SpecialMemberKind::AssignmentOperator => "assignment_operator", ++ }; ++ self.add(quote! { ++ special_member(#kind_str) ++ }) ++ } ++ ++ fn original_name(&mut self, name: &str) { ++ self.add(quote! { ++ original_name(#name) ++ }) ++ } ++ ++ fn ret_type_reference(&mut self) { ++ self.add_ident("ret_type_reference") ++ } ++ ++ fn ret_type_rvalue_reference(&mut self) { ++ self.add_ident("ret_type_rvalue_reference") ++ } ++ ++ fn arg_type_reference(&mut self, arg_name: &Ident) { ++ self.add(quote! { ++ arg_type_reference(#arg_name) ++ }) ++ } ++ ++ fn field_type_reference(&mut self) { ++ self.add_ident("reference") ++ } ++ ++ fn field_type_rvalue_reference(&mut self) { ++ self.add_ident("rvalue_reference") ++ } ++ ++ fn is_virtual(&mut self) { ++ self.add_ident("bindgen_virtual") ++ } ++ ++ fn arg_type_rvalue_reference(&mut self, arg_name: &Ident) { ++ self.add(quote! { ++ arg_type_rvalue_reference(#arg_name) ++ }) ++ } ++ ++ fn is_pure_virtual(&mut self) { ++ self.add_ident("pure_virtual") ++ } ++ ++ fn visibility(&mut self, visibility: Visibility) { ++ match visibility { ++ Visibility::Protected => self.add_ident("visibility_protected"), ++ Visibility::Private => self.add_ident("visibility_private"), ++ _ => {} ++ } ++ } ++ ++ fn incomprehensible_param_in_arg_or_return(&mut self) { ++ self.add_ident("incomprehensible_param_in_arg_or_return") ++ } ++ ++ fn discards_template_param(&mut self) { ++ self.add_ident("unused_template_param") ++ } ++ ++ fn deleted_fn(&mut self) { ++ self.add_ident("deleted") ++ } ++ ++ fn defaulted_fn(&mut self) { ++ self.add_ident("defaulted") ++ } ++ ++ fn layout(&mut self, layout: &Layout) { ++ let sz = ast_ty::int_expr(layout.size as i64); ++ let align = ast_ty::int_expr(layout.align as i64); ++ let packed = if layout.packed { ++ quote! { true } ++ } else { ++ quote! { false } ++ }; ++ self.add(quote! { ++ layout(#sz, #align, #packed) ++ }) ++ } ++} ++ ++pub struct CppSemanticAttributeAdder<'a> { ++ enabled: bool, ++ attrs: &'a mut Vec, ++} ++ ++impl<'a> CppSemanticAttributeAdder<'a> { ++ pub(crate) fn new( ++ opts: &BindgenOptions, ++ attrs: &'a mut Vec, ++ ) -> Self { ++ Self { ++ enabled: opts.cpp_semantic_attributes, ++ attrs, ++ } ++ } ++} ++ ++impl<'a> CppSemanticAttributeCreator for CppSemanticAttributeAdder<'a> { ++ fn do_add(&mut self, ts: TokenStream) { ++ self.attrs.push(ts) ++ } ++ ++ fn is_enabled(&self) -> bool { ++ self.enabled ++ } ++} ++ ++pub struct CppSemanticAttributeSingle { ++ enabled: bool, ++ attr: TokenStream, ++} ++ ++impl CppSemanticAttributeSingle { ++ pub(crate) fn new(opts: &BindgenOptions) -> Self { ++ Self { ++ enabled: opts.cpp_semantic_attributes, ++ attr: quote! {}, ++ } ++ } ++ ++ pub(crate) fn result(self) -> TokenStream { ++ self.attr ++ } ++} ++ ++impl CppSemanticAttributeCreator for CppSemanticAttributeSingle { ++ fn do_add(&mut self, ts: TokenStream) { ++ self.attr = ts; ++ } ++ ++ fn is_enabled(&self) -> bool { ++ self.enabled ++ } ++} ++ + /// Generates a proper type for a field or type with a given `Layout`, that is, + /// a type with the correct size and alignment restrictions. + pub(crate) fn blob(ctx: &BindgenContext, layout: Layout) -> TokenStream { +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 = Y; ++ // We don't want to note whether Y has unused template params, e.g. ++ // type X = Y ++ // 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 { ++ ) -> error::Result { + 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 { ++ ) -> error::Result { + 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; ++ ) -> error::Result; + } + + /// 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: &::Extra, +- ) -> error::Result; ++ ) -> error::Result; + } + + impl TryToRustTyOrOpaque for T +@@ -3682,10 +3776,10 @@ where + &self, + ctx: &BindgenContext, + extra: &E, +- ) -> error::Result { ++ ) -> error::Result { + 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: &::Extra, +- ) -> proc_macro2::TokenStream; ++ ) -> RustTy; + } + + impl 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 { ++ ) -> error::Result { + ctx.resolve_item((*self).into()).try_to_rust_ty(ctx, &()) + } + } +@@ -3785,7 +3875,7 @@ impl TryToRustTy for Item { + &self, + ctx: &BindgenContext, + _: &(), +- ) -> error::Result { ++ ) -> error::Result { + 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 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 { ++ 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 { ++ ) -> error::Result { + 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>) == + // 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 { ++ ) -> error::Result { + 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::>>()?; + ++ 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 { ++ ) -> error::Result { + // 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 { ++ ) -> (Vec, Vec) { + 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::>(); ++ .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> + } +diff --git a/ir/analysis/has_vtable.rs b/ir/analysis/has_vtable.rs +index 980a551..12b1fe0 100644 +--- a/ir/analysis/has_vtable.rs ++++ b/ir/analysis/has_vtable.rs +@@ -164,7 +164,7 @@ impl<'ctx> MonotoneFramework for HasVtableAnalysis<'ctx> { + TypeKind::TemplateAlias(t, _) | + TypeKind::Alias(t) | + TypeKind::ResolvedTypeRef(t) | +- TypeKind::Reference(t) => { ++ TypeKind::Reference(t, _) => { + trace!( + " aliases and references forward to their inner type" + ); +diff --git a/ir/comp.rs b/ir/comp.rs +index 89e77e1..1ff8961 100644 +--- a/ir/comp.rs ++++ b/ir/comp.rs +@@ -4,6 +4,7 @@ use super::analysis::Sizedness; + use super::annotations::Annotations; + use super::context::{BindgenContext, FunctionId, ItemId, TypeId, VarId}; + use super::dot::DotAttributes; ++use super::function::Visibility; + use super::item::{IsOpaque, Item}; + use super::layout::Layout; + use super::template::TemplateParameters; +@@ -72,6 +73,18 @@ impl MethodKind { + } + } + ++// The kind of C++ special member. ++// TODO: We don't currently cover copy assignment or move assignment operator ++// because libclang doesn't provide a way to query for them. ++#[derive(Debug, Copy, Clone, PartialEq)] ++pub enum SpecialMemberKind { ++ DefaultConstructor, ++ CopyConstructor, ++ MoveConstructor, ++ Destructor, ++ AssignmentOperator, ++} ++ + /// A struct representing a C++ method, either static, normal, or virtual. + #[derive(Debug)] + pub(crate) struct Method { +@@ -976,6 +989,10 @@ pub(crate) struct CompInfo { + /// Whether this is a struct or a union. + kind: CompKind, + ++ /// The visibility of this struct or union if it was declared inside of ++ /// another type. Top-level types always have public visibility. ++ visibility: Visibility, ++ + /// The members of this struct or union. + fields: CompFields, + +@@ -1055,6 +1072,7 @@ impl CompInfo { + pub(crate) fn new(kind: CompKind) -> Self { + CompInfo { + kind, ++ visibility: Visibility::Public, + fields: CompFields::default(), + template_params: vec![], + methods: vec![], +@@ -1166,6 +1184,11 @@ impl CompInfo { + } + } + ++ /// Returns the visibility of the type. ++ pub fn visibility(&self) -> Visibility { ++ self.visibility ++ } ++ + /// Returns whether we have a too large bitfield unit, in which case we may + /// not be able to derive some of the things we should be able to normally + /// derive. +@@ -1255,6 +1278,7 @@ impl CompInfo { + debug!("CompInfo::from_ty({:?}, {:?})", kind, cursor); + + let mut ci = CompInfo::new(kind); ++ ci.visibility = Visibility::from(cursor.access_specifier()); + ci.is_forward_declaration = + location.map_or(true, |cur| match cur.kind() { + CXCursor_ParmDecl => true, +diff --git a/ir/context.rs b/ir/context.rs +index a5c14a8..80e7f8d 100644 +--- a/ir/context.rs ++++ b/ir/context.rs +@@ -1971,6 +1971,9 @@ If you encounter an error missing from this list, please file an issue or a PR!" + CXType_Short => TypeKind::Int(IntKind::Short), + CXType_UShort => TypeKind::Int(IntKind::UShort), + CXType_WChar => TypeKind::Int(IntKind::WChar), ++ CXType_Char16 if self.options().use_distinct_char16_t => { ++ TypeKind::Int(IntKind::Char16) ++ } + CXType_Char16 => TypeKind::Int(IntKind::U16), + CXType_Char32 => TypeKind::Int(IntKind::U32), + CXType_Long => TypeKind::Int(IntKind::Long), +diff --git a/ir/enum_ty.rs b/ir/enum_ty.rs +index 70cf0ea..a863340 100644 +--- a/ir/enum_ty.rs ++++ b/ir/enum_ty.rs +@@ -2,6 +2,7 @@ + + use super::super::codegen::EnumVariation; + use super::context::{BindgenContext, TypeId}; ++use super::function::Visibility; + use super::item::Item; + use super::ty::{Type, TypeKind}; + use crate::clang; +@@ -32,6 +33,10 @@ pub(crate) struct Enum { + + /// The different variants, with explicit values. + variants: Vec, ++ ++ /// The visibility of this enum if it was declared inside of ++ /// another type. Top-level types always have public visibility. ++ pub(crate) visibility: Visibility, + } + + impl Enum { +@@ -39,8 +44,13 @@ impl Enum { + pub(crate) fn new( + repr: Option, + variants: Vec, ++ visibility: Visibility, + ) -> Self { +- Enum { repr, variants } ++ Enum { ++ repr, ++ variants, ++ visibility, ++ } + } + + /// Get this enumeration's representation. +@@ -56,6 +66,7 @@ impl Enum { + /// Construct an enumeration from the given Clang type. + pub(crate) fn from_ty( + ty: &clang::Type, ++ visibility: Visibility, + ctx: &mut BindgenContext, + ) -> Result { + use clang_sys::*; +@@ -147,7 +158,7 @@ impl Enum { + } + CXChildVisit_Continue + }); +- Ok(Enum::new(repr, variants)) ++ Ok(Enum::new(repr, variants, visibility)) + } + + fn is_matching_enum( +diff --git a/ir/function.rs b/ir/function.rs +index fab380e..d38c60e 100644 +--- a/ir/function.rs ++++ b/ir/function.rs +@@ -1,6 +1,6 @@ + //! Intermediate representation for C/C++ functions and methods. + +-use super::comp::MethodKind; ++use super::comp::{MethodKind, SpecialMemberKind}; + use super::context::{BindgenContext, TypeId}; + use super::dot::DotAttributes; + use super::item::Item; +@@ -9,7 +9,9 @@ use super::ty::TypeKind; + use crate::callbacks::{ItemInfo, ItemKind}; + use crate::clang::{self, Attribute}; + use crate::parse::{ClangSubItemParser, ParseError, ParseResult}; +-use clang_sys::{self, CXCallingConv}; ++use clang_sys::{ ++ self, CXCallingConv, CX_CXXAccessSpecifier, CX_CXXPrivate, CX_CXXProtected, ++}; + + use quote::TokenStreamExt; + use std::io; +@@ -70,6 +72,75 @@ pub(crate) enum Linkage { + Internal, + } + ++/// Visibility ++#[derive(Debug, Clone, Copy)] ++pub enum Visibility { ++ Public, ++ Protected, ++ Private, ++} ++ ++impl From for Visibility { ++ fn from(access_specifier: CX_CXXAccessSpecifier) -> Self { ++ if access_specifier == CX_CXXPrivate { ++ Visibility::Private ++ } else if access_specifier == CX_CXXProtected { ++ Visibility::Protected ++ } else { ++ Visibility::Public ++ } ++ } ++} ++ ++/// Autocxx specialized function information ++#[derive(Debug)] ++pub(crate) struct AutocxxFuncInfo { ++ /// C++ Special member kind, if applicable ++ special_member: Option, ++ /// Whether it is private ++ visibility: Visibility, ++ /// =delete ++ is_deleted: bool, ++ /// =default ++ is_defaulted: bool, ++} ++ ++impl AutocxxFuncInfo { ++ fn new( ++ special_member: Option, ++ visibility: Visibility, ++ is_deleted: bool, ++ is_defaulted: bool, ++ ) -> Self { ++ Self { ++ special_member, ++ visibility, ++ is_deleted, ++ is_defaulted, ++ } ++ } ++ ++ /// Get this function's C++ special member kind. ++ pub fn special_member(&self) -> Option { ++ self.special_member ++ } ++ ++ /// Whether it is private ++ pub fn visibility(&self) -> Visibility { ++ self.visibility ++ } ++ ++ /// Whether this is a function that's been deleted (=delete) ++ pub fn deleted_fn(&self) -> bool { ++ self.is_deleted ++ } ++ ++ /// Whether this is a function that's been deleted (=default) ++ pub fn defaulted_fn(&self) -> bool { ++ self.is_defaulted ++ } ++} ++ + /// A function declaration, with a signature, arguments, and argument names. + /// + /// The argument names vector must be the same length as the ones in the +@@ -93,6 +164,9 @@ pub(crate) struct Function { + + /// The linkage of the function. + linkage: Linkage, ++ ++ /// Autocxx extension information ++ autocxx: AutocxxFuncInfo, + } + + impl Function { +@@ -104,6 +178,7 @@ impl Function { + signature: TypeId, + kind: FunctionKind, + linkage: Linkage, ++ autocxx: AutocxxFuncInfo, + ) -> Self { + Function { + name, +@@ -112,6 +187,7 @@ impl Function { + signature, + kind, + linkage, ++ autocxx, + } + } + +@@ -144,6 +220,26 @@ impl Function { + pub(crate) fn linkage(&self) -> Linkage { + self.linkage + } ++ ++ /// Get this function's C++ special member kind. ++ pub fn special_member(&self) -> Option { ++ self.autocxx.special_member() ++ } ++ ++ /// Whether it is private ++ pub fn visibility(&self) -> Visibility { ++ self.autocxx.visibility() ++ } ++ ++ /// Whether this is a function that's been deleted (=delete) ++ pub fn deleted_fn(&self) -> bool { ++ self.autocxx.deleted_fn() ++ } ++ ++ /// Whether this is a function that's been deleted (=default) ++ pub fn defaulted_fn(&self) -> bool { ++ self.autocxx.defaulted_fn() ++ } + } + + impl DotAttributes for Function { +@@ -422,15 +518,6 @@ impl FunctionSig { + + let spelling = cursor.spelling(); + +- // Don't parse operatorxx functions in C++ +- let is_operator = |spelling: &str| { +- spelling.starts_with("operator") && +- !clang::is_valid_identifier(spelling) +- }; +- if is_operator(&spelling) { +- return Err(ParseError::Continue); +- } +- + // Constructors of non-type template parameter classes for some reason + // include the template parameter in their name. Just skip them, since + // we don't handle well non-type template parameters anyway. +@@ -513,7 +600,10 @@ impl FunctionSig { + let is_const = is_method && cursor.method_is_const(); + let is_virtual = is_method && cursor.method_is_virtual(); + let is_static = is_method && cursor.method_is_static(); +- if !is_static && !is_virtual { ++ if !is_static && ++ (!is_virtual || ++ ctx.options().use_specific_virtual_function_receiver) ++ { + let parent = cursor.semantic_parent(); + let class = Item::parse(parent, None, ctx) + .expect("Expected to parse the class"); +@@ -537,7 +627,7 @@ impl FunctionSig { + Item::builtin_type(TypeKind::Pointer(class), false, ctx); + args.insert(0, (Some("this".into()), ptr)); + } else if is_virtual { +- let void = Item::builtin_type(TypeKind::Void, false, ctx); ++ let void = Item::builtin_type(TypeKind::Void, is_const, ctx); + let ptr = + Item::builtin_type(TypeKind::Pointer(void), false, ctx); + args.insert(0, (Some("this".into()), ptr)); +@@ -685,9 +775,7 @@ impl ClangSubItemParser for Function { + return Err(ParseError::Continue); + } + +- if cursor.access_specifier() == CX_CXXPrivate { +- return Err(ParseError::Continue); +- } ++ let visibility = Visibility::from(cursor.access_specifier()); + + let linkage = cursor.linkage(); + let linkage = match linkage { +@@ -707,10 +795,6 @@ impl ClangSubItemParser for Function { + return Err(ParseError::Continue); + } + +- if cursor.is_deleted_function() { +- return Err(ParseError::Continue); +- } +- + // We cannot handle `inline` functions that are not `static`. + if context.options().wrap_static_fns && + cursor.is_inlined_function() && +@@ -749,7 +833,23 @@ impl ClangSubItemParser for Function { + } + assert!(!name.is_empty(), "Empty function name."); + +- let mangled_name = cursor_mangling(context, &cursor); ++ let operator_suffix = name.strip_prefix("operator"); ++ let special_member = if let Some(operator_suffix) = operator_suffix { ++ // We can't represent operatorxx functions as-is because ++ // they are not valid identifiers ++ if context.options().represent_cxx_operators { ++ let (new_suffix, special_member) = match operator_suffix { ++ "=" => ("equals", SpecialMemberKind::AssignmentOperator), ++ _ => return Err(ParseError::Continue), ++ }; ++ name = format!("operator_{}", new_suffix); ++ Some(special_member) ++ } else { ++ return Err(ParseError::Continue); ++ } ++ } else { ++ None ++ }; + + let link_name = context.options().last_callback(|callbacks| { + callbacks.generated_link_name_override(ItemInfo { +@@ -758,13 +858,36 @@ impl ClangSubItemParser for Function { + }) + }); + ++ let mangled_name = cursor_mangling(context, &cursor); ++ ++ let special_member = special_member.or_else(|| { ++ if cursor.is_default_constructor() { ++ Some(SpecialMemberKind::DefaultConstructor) ++ } else if cursor.is_copy_constructor() { ++ Some(SpecialMemberKind::CopyConstructor) ++ } else if cursor.is_move_constructor() { ++ Some(SpecialMemberKind::MoveConstructor) ++ } else if cursor.kind() == clang_sys::CXCursor_Destructor { ++ Some(SpecialMemberKind::Destructor) ++ } else { ++ None ++ } ++ }); ++ ++ let autocxx_info = AutocxxFuncInfo::new( ++ special_member, ++ visibility, ++ cursor.is_deleted_function(), ++ cursor.is_defaulted_function(), ++ ); + let function = Self::new( +- name.clone(), ++ name, + mangled_name, + link_name, + sig, + kind, + linkage, ++ autocxx_info, + ); + + Ok(ParseResult::New(function, Some(cursor))) +diff --git a/ir/int.rs b/ir/int.rs +index 4251b37..ea2456e 100644 +--- a/ir/int.rs ++++ b/ir/int.rs +@@ -54,9 +54,12 @@ pub enum IntKind { + /// A 16-bit signed integer. + I16, + +- /// Either a `char16_t` or a `wchar_t`. ++ /// A 16-bit integer, used only for enum size representation. + U16, + ++ /// Either a `char16_t` or a `wchar_t`. ++ Char16, ++ + /// A 32-bit signed integer. + I32, + +@@ -94,7 +97,7 @@ impl IntKind { + // to know whether it is or not right now (unlike char, there's no + // WChar_S / WChar_U). + Bool | UChar | UShort | UInt | ULong | ULongLong | U8 | U16 | +- WChar | U32 | U64 | U128 => false, ++ Char16 | WChar | U32 | U64 | U128 => false, + + SChar | Short | Int | Long | LongLong | I8 | I16 | I32 | I64 | + I128 => true, +@@ -112,7 +115,7 @@ impl IntKind { + use self::IntKind::*; + Some(match *self { + Bool | UChar | SChar | U8 | I8 | Char { .. } => 1, +- U16 | I16 => 2, ++ U16 | I16 | Char16 => 2, + U32 | I32 => 4, + U64 | I64 => 8, + I128 | U128 => 16, +diff --git a/ir/item.rs b/ir/item.rs +index a50d267..c35b2ac 100644 +--- a/ir/item.rs ++++ b/ir/item.rs +@@ -823,6 +823,38 @@ impl Item { + } + } + ++ /// Get this item's original C++ name, including any containing types, but without ++ /// the namespace name. For nested types, the C++ name differs from the Rust name, e.g. ++ /// a nested C++ type `A::B` would correspond to the Rust type `A_B`. ++ /// If the item or any of its containing types is anonymous, returns None. ++ pub fn original_name(&self, ctx: &BindgenContext) -> Option { ++ let target = ctx.resolve_item(self.name_target(ctx)); ++ ++ // Get item and all ancestors until the first enclosing namespace. ++ let ancestors: Vec<_> = target ++ .ancestors(ctx) ++ .map(|id| ctx.resolve_item(id)) ++ .take_while(|item| !item.is_module()) ++ .collect(); ++ ++ if ancestors.iter().any(|item| item.is_anon()) { ++ return None; ++ } ++ ++ let mut names: Vec<_> = ancestors ++ .iter() ++ .map(|item| { ++ let target = ctx.resolve_item(item.name_target(ctx)); ++ target.base_name(ctx) ++ }) ++ .filter(|name| !name.is_empty()) ++ .collect(); ++ ++ names.reverse(); ++ ++ Some(names.join("::")) ++ } ++ + /// Get the canonical name without taking into account the replaces + /// annotation. + /// +diff --git a/ir/layout.rs b/ir/layout.rs +index ba944b0..17ca66e 100644 +--- a/ir/layout.rs ++++ b/ir/layout.rs +@@ -8,13 +8,13 @@ use std::cmp; + + /// A type that represents the struct layout of a type. + #[derive(Debug, Clone, Copy, PartialEq, Eq)] +-pub(crate) struct Layout { ++pub struct Layout { + /// The size (in bytes) of this layout. +- pub(crate) size: usize, ++ pub size: usize, + /// The alignment (in bytes) of this layout. +- pub(crate) align: usize, ++ pub align: usize, + /// Whether this layout's members are packed or not. +- pub(crate) packed: bool, ++ pub packed: bool, + } + + #[test] +diff --git a/ir/template.rs b/ir/template.rs +index 4dd8442..a1f8f5f 100644 +--- a/ir/template.rs ++++ b/ir/template.rs +@@ -31,6 +31,7 @@ use super::context::{BindgenContext, ItemId, TypeId}; + use super::item::{IsOpaque, Item, ItemAncestors}; + use super::traversal::{EdgeKind, Trace, Tracer}; + use crate::clang; ++use itertools::{Either, Itertools}; + + /// Template declaration (and such declaration's template parameters) related + /// methods. +@@ -143,8 +144,9 @@ pub(crate) trait TemplateParameters: Sized { + + /// Get only the set of template parameters that this item uses. This is a + /// subset of `all_template_params` and does not necessarily contain any of +- /// `self_template_params`. +- fn used_template_params(&self, ctx: &BindgenContext) -> Vec ++ /// `self_template_params`. If any are unused, true will be returned ++ /// in the second tuple element ++ fn used_template_params(&self, ctx: &BindgenContext) -> (Vec, bool) + where + Self: AsRef, + { +@@ -154,11 +156,18 @@ pub(crate) trait TemplateParameters: Sized { + ); + + let id = *self.as_ref(); +- ctx.resolve_item(id) ++ let (used, unused): (Vec<_>, Vec<_>) = ctx ++ .resolve_item(id) + .all_template_params(ctx) + .into_iter() +- .filter(|p| ctx.uses_template_parameter(id, *p)) +- .collect() ++ .partition_map(|p| { ++ if ctx.uses_template_parameter(id, p) { ++ Either::Left(p) ++ } else { ++ Either::Right(true) ++ } ++ }); ++ (used, !unused.is_empty()) + } + } + +diff --git a/ir/ty.rs b/ir/ty.rs +index 8c505aa..5bf3841 100644 +--- a/ir/ty.rs ++++ b/ir/ty.rs +@@ -14,6 +14,7 @@ use super::template::{ + }; + use super::traversal::{EdgeKind, Trace, Tracer}; + use crate::clang::{self, Cursor}; ++use crate::ir::function::Visibility; + use crate::parse::{ParseError, ParseResult}; + use std::borrow::Cow; + use std::io; +@@ -253,7 +254,9 @@ impl Type { + ) -> Option> { + let name_info = match *self.kind() { + TypeKind::Pointer(inner) => Some((inner, Cow::Borrowed("ptr"))), +- TypeKind::Reference(inner) => Some((inner, Cow::Borrowed("ref"))), ++ TypeKind::Reference(inner, _) => { ++ Some((inner, Cow::Borrowed("ref"))) ++ } + TypeKind::Array(inner, length) => { + Some((inner, format!("array{}", length).into())) + } +@@ -538,7 +541,7 @@ impl TemplateParameters for TypeKind { + TypeKind::Enum(_) | + TypeKind::Pointer(_) | + TypeKind::BlockPointer(_) | +- TypeKind::Reference(_) | ++ TypeKind::Reference(..) | + TypeKind::UnresolvedTypeRef(..) | + TypeKind::TypeParam | + TypeKind::Alias(_) | +@@ -616,7 +619,8 @@ pub(crate) enum TypeKind { + BlockPointer(TypeId), + + /// A reference to a type, as in: int& foo(). +- Reference(TypeId), ++ /// The bool represents whether it's rvalue. ++ Reference(TypeId, bool), + + /// An instantiation of an abstract template definition with a set of + /// concrete template arguments. +@@ -1044,14 +1048,23 @@ impl Type { + } + // XXX: RValueReference is most likely wrong, but I don't think we + // can even add bindings for that, so huh. +- CXType_RValueReference | CXType_LValueReference => { ++ CXType_LValueReference => { ++ let inner = Item::from_ty_or_ref( ++ ty.pointee_type().unwrap(), ++ location, ++ None, ++ ctx, ++ ); ++ TypeKind::Reference(inner, false) ++ } ++ CXType_RValueReference => { + let inner = Item::from_ty_or_ref( + ty.pointee_type().unwrap(), + location, + None, + ctx, + ); +- TypeKind::Reference(inner) ++ TypeKind::Reference(inner, true) + } + // XXX DependentSizedArray is wrong + CXType_VariableArray | CXType_DependentSizedArray => { +@@ -1109,7 +1122,10 @@ impl Type { + } + } + CXType_Enum => { +- let enum_ = Enum::from_ty(ty, ctx).expect("Not an enum?"); ++ let visibility = ++ Visibility::from(cursor.access_specifier()); ++ let enum_ = Enum::from_ty(ty, visibility, ctx) ++ .expect("Not an enum?"); + + if !is_anonymous { + let pretty_name = ty.spelling(); +@@ -1222,7 +1238,7 @@ impl Trace for Type { + } + match *self.kind() { + TypeKind::Pointer(inner) | +- TypeKind::Reference(inner) | ++ TypeKind::Reference(inner, _) | + TypeKind::Array(inner, _) | + TypeKind::Vector(inner, _) | + TypeKind::BlockPointer(inner) | +diff --git a/lib.rs b/lib.rs +index 482c1a3..e800136 100644 +--- a/lib.rs ++++ b/lib.rs +@@ -1,5 +1,7 @@ + //! Generate Rust bindings for C and C++ libraries. + //! ++//! This is a slightly forked version for use by `autocxx`. ++//! + //! Provide a C/C++ header file, receive Rust FFI code to call into C/C++ + //! functions and use types defined in the header. + //! +@@ -1211,6 +1213,7 @@ fn get_target_dependent_env_var( + /// When running inside a `build.rs` script, this can be used to make cargo invalidate the + /// generated bindings whenever any of the files included from the header change: + /// ``` ++/// use autocxx_bindgen as bindgen; + /// use bindgen::builder; + /// let bindings = builder() + /// .header("path/to/input/header") +diff --git a/options/mod.rs b/options/mod.rs +index c60da71..54b44eb 100644 +--- a/options/mod.rs ++++ b/options/mod.rs +@@ -153,6 +153,61 @@ macro_rules! options { + } + + options! { ++ /// Whether to specify the type of a virtual function receiver ++ use_specific_virtual_function_receiver: bool { ++ methods: { ++ /// Normally, virtual functions have void* as their 'this' type. ++ /// If this flag is enabled, override that behavior to indicate a ++ /// pointer of the specific type. ++ /// Disabled by default. ++ pub fn use_specific_virtual_function_receiver(mut self, doit: bool) -> Builder { ++ self.options.use_specific_virtual_function_receiver = doit; ++ self ++ } ++ }, ++ as_args: "--use-specific-virtual-function-receiver", ++ }, ++ ++ /// Whether we should emit C++ semantics attributes. ++ cpp_semantic_attributes: bool { ++ methods: { ++ /// If this is true, add attributes with details of underlying C++ semantics. ++ /// Disabled by default. ++ pub fn cpp_semantic_attributes(mut self, doit: bool) -> Builder { ++ self.options.cpp_semantic_attributes = doit; ++ self ++ } ++ }, ++ as_args: "--cpp-semantic-attributes", ++ }, ++ ++ /// Whether we should output information about C++ overloaded operators. ++ represent_cxx_operators: bool { ++ methods: { ++ /// If this is true, output existence of C++ overloaded operators. ++ /// At present, only operator= is noted. ++ /// Disabled by default. ++ pub fn represent_cxx_operators(mut self, doit: bool) -> Builder { ++ self.options.represent_cxx_operators = doit; ++ self ++ } ++ }, ++ as_args: "--represent-cxx-operators", ++ }, ++ ++ /// Whether we should distinguish between 'char16_t' and 'u16' ++ use_distinct_char16_t: bool { ++ methods: { ++ /// If this is true, denote 'char16_t' as a separate type from 'u16' ++ /// Disabled by default. ++ pub fn use_distinct_char16_t(mut self, doit: bool) -> Builder { ++ self.options.use_distinct_char16_t = doit; ++ self ++ } ++ }, ++ as_args: "--use-distinct-char16-t", ++ }, ++ + /// Types that have been blocklisted and should not appear anywhere in the generated code. + blocklisted_types: RegexSet { + methods: { -- cgit v1.2.3