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