From 4f3cea4992b7bbc9ab7dbb256bf965cdc8a0042b Mon Sep 17 00:00:00 2001 From: Ethan Smith Date: Thu, 26 Mar 2026 14:24:29 -0700 Subject: [PATCH] Integrate trait impls into template specialization logic. Trait impls predate the logic around emitting template specializations, and so had special case logic to emit in the right location. Now that we have actual logic for placing template specializations correctly in bindings, we don't need the special case logic. This revealed an issue around template specialization where trait impls can, understandably, produce specializations of `Result`/`Option`. I think a simpler hiearchy of `handle trait impls` -> `handle result/option specializations` would suffice, but I opted to use a fixpoint of specializations instead so that such issues do not continue to arise in the future. It is absolutely debatable if this is warranted. PiperOrigin-RevId: 890047063 --- .../database/code_snippet.rs | 28 +- .../generate_template_specialization.rs | 166 ++++++++- cc_bindings_from_rs/generate_bindings/lib.rs | 271 ++++---------- .../test/traits/for_cc_type/trait_cc_api.h | 2 + .../test/traits/generic_traits_cc_api.h | 60 +-- .../trait_definition_cc_api.h | 22 +- .../in_dependent_crate/trait_impl_cc_api.h | 22 +- .../test/traits/traits_cc_api.h | 344 +++++++++--------- .../test/traits/traits_cc_api_impl.rs | 72 ++-- examples/rust/trait/example_generated.h | 32 +- 10 files changed, 555 insertions(+), 464 deletions(-) diff --git a/cc_bindings_from_rs/generate_bindings/database/code_snippet.rs b/cc_bindings_from_rs/generate_bindings/database/code_snippet.rs index aa5b1b74f..73e521329 100644 --- a/cc_bindings_from_rs/generate_bindings/database/code_snippet.rs +++ b/cc_bindings_from_rs/generate_bindings/database/code_snippet.rs @@ -81,6 +81,24 @@ pub struct CcPrerequisites<'tcx> { #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub enum TemplateSpecialization<'tcx> { RsStdEnum(RsStdEnumTemplateSpecialization<'tcx>), + TraitImpl(TraitImplTemplateSpecialization), +} + +#[derive(Clone, Debug)] +pub struct TraitImplTemplateSpecialization { + pub self_ty_cc_name: TokenStream, + pub trait_impl: DefId, +} +impl PartialEq for TraitImplTemplateSpecialization { + fn eq(&self, other: &Self) -> bool { + self.trait_impl == other.trait_impl + } +} +impl Eq for TraitImplTemplateSpecialization {} +impl Hash for TraitImplTemplateSpecialization { + fn hash(&self, state: &mut H) { + self.trait_impl.hash(state); + } } #[derive(Clone, Debug)] @@ -92,11 +110,19 @@ pub struct RsStdEnumTemplateSpecializationCore<'tcx> { pub tag_type_cc: CcSnippet<'tcx>, } -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct RsStdEnumTemplateSpecialization<'tcx> { pub core: RsStdEnumTemplateSpecializationCore<'tcx>, pub kind: TemplateSpecializationKind<'tcx>, } +impl std::fmt::Debug for RsStdEnumTemplateSpecialization<'_> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("RsStdEnumTemplateSpecialization") + .field("core", &self.core.self_ty_rs) + .field("kind", &self.kind) + .finish() + } +} impl PartialEq for RsStdEnumTemplateSpecialization<'_> { fn eq(&self, other: &Self) -> bool { diff --git a/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs b/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs index 16eda77bd..eeb5d5382 100644 --- a/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs +++ b/cc_bindings_from_rs/generate_bindings/generate_template_specialization.rs @@ -3,12 +3,16 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception use crate::generate_function_thunk::replace_all_regions_with_static; -use crate::generate_struct_and_union::{generate_relocating_ctor, scalar_value_to_string}; -use arc_anyhow::Result; +use crate::generate_struct_and_union::{ + generate_associated_item, generate_relocating_ctor, has_type_or_const_vars, + scalar_value_to_string, +}; +use crate::generate_unsupported_def; +use arc_anyhow::{Error, Result}; use code_gen_utils::{escape_non_identifier_chars, CcInclude}; use database::code_snippet::{ ApiSnippets, CcPrerequisites, CcSnippet, FormattedTy, RsStdEnumTemplateSpecialization, - RsStdEnumTemplateSpecializationCore, TemplateSpecialization, + RsStdEnumTemplateSpecializationCore, TemplateSpecialization, TraitImplTemplateSpecialization, }; use database::{BindingsGenerator, TypeLocation}; use error_report::anyhow; @@ -19,6 +23,8 @@ use quote::{format_ident, quote}; use rustc_abi::VariantIdx; use rustc_middle::ty::layout::PrimitiveExt; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_span::def_id::DefId; +use std::collections::HashSet; use std::rc::Rc; fn is_cpp_movable<'tcx>(db: &BindingsGenerator<'tcx>, ty: Ty<'tcx>) -> bool { @@ -1142,6 +1148,155 @@ impl<'tcx> TemplateSpecializationExt<'tcx> for RsStdEnumTemplateSpecialization<' } } +/// Collect trait implementations and map them to `TemplateSpecialization::TraitImpl`. +pub(crate) fn collect_trait_impls<'a, 'tcx>( + db: &'a BindingsGenerator<'tcx>, +) -> impl Iterator> + use<'a, 'tcx> { + let tcx = db.tcx(); + let supported_traits: Vec = db.supported_traits().iter().copied().collect(); + // TyCtxt makes it easy to get all the implementations of a trait, but there isn't an easy way + // to say give me all the trait implementations for this type. This is by design. The compiler + // lazily determines conformance to traits as needed for types and never computes every trait + // for a type in a single data structure. + // + // We, however, want every implementation for a supported type, so we can emit bindings to them. + // We achieve this by walking every supported trait, walking every implementation of that trait, + // and paring down to the implementations that receive bindings. + // + // A serendipitous side effect of this approach is that our implementations are emitted as a + // single list containing just implementations. We want to emit all of our implementations in a + // separate portion of our header from the rest of our bindings. Our impls become template + // specializaitons, which are required to be in an enclosing namespace of the template they + // specialize. This prevents them from living in the same namespace as our other bindings, as + // they may implement a trait that is not enclosed by that namespace. + supported_traits.into_iter().flat_map(move |trait_def_id| { + use rustc_middle::ty::fast_reject::SimplifiedType; + tcx.trait_impls_of(trait_def_id) + .non_blanket_impls() + .into_iter() + .filter_map(move |(simple_ty, impl_def_ids)| match simple_ty { + SimplifiedType::Adt(did) => { + // Only bind implementations for supported ADTs. + let canonical_name = db.symbol_canonical_name(*did)?; + // We explicitly want to allow ADTs that specify cpp_type. + // These are typically C++ types that have generated Rust bindings. + if canonical_name.unqualified.cpp_type.is_none() + && db.adt_needs_bindings(*did).is_err() + { + return None; + } + let crate_name = tcx.crate_name(did.krate); + // TODO: b/391443811 - Add support for implementations of stdlib types once + // we have headers that can be included for those types. + if ["std", "core", "alloc"].contains(&crate_name.as_str()) { + return None; + } + let adt_cc_name = canonical_name.format_for_cc(db).ok()?; + Some((adt_cc_name, impl_def_ids)) + } + // TODO: b/457803426 - Support trait implementations for non-adt types. + _ => None, + }) + .flat_map(move |(adt_cc_name, impl_def_ids)| { + impl_def_ids + .iter() + .copied() + // TODO: b/458768435 - This is technically suboptimal. We could instead only + // query for the impls from this crate, but the logic is complicated by + // supporting LOCAL_CRATE. Revisit once we've migrated to rmetas. + .filter(|impl_def_id| impl_def_id.krate == db.source_crate_num()) + .map(move |impl_def_id| { + TemplateSpecialization::TraitImpl(TraitImplTemplateSpecialization { + self_ty_cc_name: adt_cc_name.clone(), + trait_impl: impl_def_id, + }) + }) + }) + }) +} + +fn generate_trait_impl_specialization<'tcx>( + db: &BindingsGenerator<'tcx>, + trait_impl: &TraitImplTemplateSpecialization, +) -> std::result::Result, (DefId, Error)> { + let tcx = db.tcx(); + let impl_def_id = trait_impl.trait_impl; + let trait_header = tcx.impl_trait_header(impl_def_id); + #[rustversion::before(2025-10-17)] + let trait_header = trait_header.expect("Trait impl should have a trait header"); + let trait_ref = trait_header.trait_ref.instantiate_identity(); + let trait_def_id = trait_ref.def_id; + + let canonical_trait_name = db.symbol_canonical_name(trait_def_id).expect( + "symbol_canonical_name was unexpectedly called on a trait without a canonical name", + ); + let trait_name = canonical_trait_name.format_for_cc(db).map_err(|err| (impl_def_id, err))?; + + let mut prereqs = CcPrerequisites::default(); + let trait_args: Vec<_> = trait_ref + .args + .iter() + // Skip self type. + .skip(1) + .filter_map(|arg| arg.as_type()) + .map(|arg| { + if arg.flags().contains(has_type_or_const_vars()) { + return Err((impl_def_id, anyhow!("Implementation of traits must specify all types to receive bindings."))); + } + if arg.walk().any(|arg| arg.as_type().is_some_and(|ty| ty.is_ptr_sized_integral())) { + return Err(( + impl_def_id, + anyhow!( + "b/491106325 - isize and usize types are not yet supported as trait type arguments." + ), + )); + } + db.format_ty_for_cc(arg, TypeLocation::Other) + .map(|snippet| snippet.into_tokens(&mut prereqs)) + .map_err(|err| (impl_def_id, err)) + }) + .collect::, _>>()?; + + let type_args = if trait_args.is_empty() { + quote! {} + } else { + quote! { <#(#trait_args),*> } + }; + + let trait_name_with_args = quote! { #trait_name #type_args }; + + prereqs.depend_on_def(db, trait_def_id).map_err(|err| (impl_def_id, err))?; + + let mut member_function_names = HashSet::new(); + let assoc_items: ApiSnippets = tcx + .associated_items(impl_def_id) + .in_definition_order() + .flat_map(|assoc_item| generate_associated_item(db, assoc_item, &mut member_function_names)) + .collect(); + + let main_api = assoc_items.main_api.into_tokens(&mut prereqs); + prereqs.includes.insert(db.support_header("rs_std/traits.h")); + + let self_ty_cc_name = &trait_impl.self_ty_cc_name; + Ok(ApiSnippets { + main_api: CcSnippet { + tokens: quote! { + __NEWLINE__ + template<> + struct rs_std::impl<#self_ty_cc_name, #trait_name_with_args> { + static constexpr bool kIsImplemented = true; + + #main_api + }; + __NEWLINE__ + }, + prereqs, + }, + cc_details: assoc_items.cc_details, + rs_details: assoc_items.rs_details, + }) +} + /// Generate a template specialization. pub fn generate_template_specialization<'tcx>( db: &BindingsGenerator<'tcx>, @@ -1149,6 +1304,11 @@ pub fn generate_template_specialization<'tcx>( ) -> ApiSnippets<'tcx> { let mut snippets = match &specialization { TemplateSpecialization::RsStdEnum(rs_std_enum) => rs_std_enum.clone().api_snippets(db), + TemplateSpecialization::TraitImpl(trait_impl) => { + generate_trait_impl_specialization(db, trait_impl).unwrap_or_else(|(def_id, err)| { + generate_unsupported_def(db, def_id, err).into_main_api() + }) + } }; // Because we reuse logic from generate_struct_and_union here, we will add our `self_ty` as a template specialization of it's own specialization creating a depedency cycle. // We break that loop manually here to avoid that. diff --git a/cc_bindings_from_rs/generate_bindings/lib.rs b/cc_bindings_from_rs/generate_bindings/lib.rs index 0b80a4cca..7fcdce3df 100644 --- a/cc_bindings_from_rs/generate_bindings/lib.rs +++ b/cc_bindings_from_rs/generate_bindings/lib.rs @@ -34,13 +34,13 @@ use crate::generate_function::{generate_function, must_use_attr_of}; use crate::generate_function_thunk::{generate_trait_thunks, TraitThunks}; use crate::generate_struct_and_union::{ adt_needs_bindings, cpp_enum_cpp_underlying_type, from_trait_impls_by_argument, generate_adt, - generate_adt_core, generate_associated_item, has_type_or_const_vars, scalar_value_to_string, + generate_adt_core, scalar_value_to_string, }; +use crate::generate_template_specialization::collect_trait_impls; use arc_anyhow::{Context, Error, Result}; use code_gen_utils::{format_cc_includes, CcConstQualifier, CcInclude, NamespaceQualifier}; use database::code_snippet::{ - ApiSnippets, CcPrerequisites, CcSnippet, ExternCDecl, RsSnippet, - RsStdEnumTemplateSpecialization, RsStdEnumTemplateSpecializationCore, TemplateSpecialization, + ApiSnippets, CcPrerequisites, CcSnippet, ExternCDecl, RsSnippet, TemplateSpecialization, }; use database::{ AdtCoreBindings, ExportedPath, FineGrainedFeature, FullyQualifiedName, NoMoveOrAssign, @@ -1707,152 +1707,62 @@ struct FormattedItem<'tcx> { aliases: Vec, } -/// Generate bindings to supported trait implementations. An implementation is supported if both -/// its trait and implementing type receive bindings. -fn generate_trait_impls<'a, 'tcx>( - db: &'a BindingsGenerator<'tcx>, -) -> impl Iterator> + use<'a, 'tcx> { - let tcx = db.tcx(); - let supported_traits: Vec = db.supported_traits().iter().copied().collect(); - // TyCtxt makes it easy to get all the implementations of a trait, but there isn't an easy way - // to say give me all the trait implementations for this type. This is by design. The compiler - // lazily determines conformance to traits as needed for types and never computes every trait - // for a type in a single data structure. - // - // We, however, want every implementation for a supported type, so we can emit bindings to them. - // We achieve this by walking every supported trait, walking every implementation of that trait, - // and paring down to the implementations that receive bindings. - // - // A serendipitous side effect of this approach is that our implementations are emitted as a - // single list containing just implementations. We want to emit all of our implementations in a - // separate portion of our header from the rest of our bindings. Our impls become template - // specializaitons, which are required to be in an enclosing namespace of the template they - // specialize. This prevents them from living in the same namespace as our other bindings, as - // they may implement a trait that is not enclosed by that namespace. - supported_traits - .into_iter() - .flat_map(move |trait_def_id| { - use rustc_middle::ty::fast_reject::SimplifiedType; - tcx.trait_impls_of(trait_def_id) - .non_blanket_impls() - .into_iter() - .filter_map(move |(simple_ty, impl_def_ids)| match simple_ty { - SimplifiedType::Adt(did) => { - // Only bind implementations for supported ADTs. - let canonical_name = db.symbol_canonical_name(*did)?; - // We explicitly want to allow ADTs that specify cpp_type. - // These are typically C++ types that have generated Rust bindings. - if canonical_name.unqualified.cpp_type.is_none() - && db.adt_needs_bindings(*did).is_err() { - return None; - } - let crate_name = tcx.crate_name(did.krate); - // TODO: b/391443811 - Add support for implementations of stdlib types once - // we have headers that can be included for those types. - if ["std", "core", "alloc"].contains(&crate_name.as_str()) { - return None; - } - let adt_cc_name = canonical_name.format_for_cc(db).ok()?; - Some((adt_cc_name, trait_def_id, impl_def_ids)) - } - // TODO: b/457803426 - Support trait implementations for non-adt types. - _ => None, - }) - .flat_map(move |(adt_cc_name, trait_def_id, impl_def_ids)| { - impl_def_ids - .iter() - .copied() - // TODO: b/458768435 - This is technically suboptimal. We could instead only - // query for the impls from this crate, but the logic is complicated by - // supporting LOCAL_CRATE. Revisit once we've migrated to rmetas. - .filter(|impl_def_id| impl_def_id.krate == db.source_crate_num()) - .map(move |impl_def_id| (adt_cc_name.clone(), trait_def_id, impl_def_id)) - }) - }) - .map( - move |(adt_cc_name, trait_def_id, impl_def_id)| -> Result { - let trait_header = tcx.impl_trait_header(impl_def_id); - #[rustversion::before(2025-10-17)] - let trait_header = trait_header.expect("Trait impl should have a trait header"); - let trait_ref = trait_header.trait_ref.instantiate_identity(); - - let canonical_name = db.symbol_canonical_name(trait_def_id).expect( - "symbol_canonical_name was unexpectedly called on a trait without a canonical name", - ); - let trait_name = - canonical_name.format_for_cc(db).map_err(|err| (impl_def_id, err))?; +struct GeneratedSpecializations<'tcx> { + specializations: HashMap, CcSnippet<'tcx>>, + impls_cc_details: Vec, +} - let mut prereqs = CcPrerequisites::default(); - let trait_args: Vec<_> = trait_ref - .args - .iter() - // Skip self type. - .skip(1) - .filter_map(|arg| arg.as_type()) - .map(|arg| { - if arg.flags().contains(has_type_or_const_vars()) { - return Err((impl_def_id, anyhow!("Implementation of traits must specify all types to receive bindings."))); - } - if arg.walk().any(|arg| arg.as_type().is_some_and(|ty| ty.is_ptr_sized_integral())) { - return Err(( - impl_def_id, - anyhow!( - "b/491106325 - isize and usize types are not yet supported as trait type arguments." - ), - )); - } - db.format_ty_for_cc(arg, TypeLocation::Other) - .map(|snippet| snippet.into_tokens(&mut prereqs)) - .map_err(|err| (impl_def_id, err)) - }) - .collect::, _>>()?; +/// Generates template specializations for a given worklist, and transitively discovers +/// any specializations required by the generated specializations. +fn generate_specializations_fixpoint<'tcx>( + db: &BindingsGenerator<'tcx>, + mut worklist: Vec>, + cc_details_prereqs: &mut CcPrerequisites<'tcx>, + extern_c_decls: &mut BTreeSet, + cc_api_impl: &mut TokenStream, +) -> GeneratedSpecializations<'tcx> { + let mut seen = HashSet::new(); + let mut specializations = HashMap::new(); + let mut impls_cc_details = Vec::new(); + + while !worklist.is_empty() { + // Sort to ensure deterministic processing. + worklist.sort_unstable_by(|a, b| template_specialization_cmp(db.tcx(), a, b)); + + let mut next_worklist = Vec::new(); + for spec in worklist { + if seen.contains(&spec) { + continue; + } - let type_args = if trait_args.is_empty() { - quote! {} - } else { - quote! { <#(#trait_args),*> } - }; + let snippets = generate_template_specialization::generate_template_specialization( + db, + spec.clone(), + ); + seen.insert(spec.clone()); - let trait_name_with_args = quote! { #trait_name #type_args }; + // Collect specializations required by the main_api. + for new_spec in snippets.main_api.prereqs.template_specializations.iter() { + if !seen.contains(new_spec) { + next_worklist.push(new_spec.clone()); + } + } - prereqs.depend_on_def(db, trait_def_id).map_err(|err| (impl_def_id, err))?; + impls_cc_details.push(snippets.cc_details.into_tokens(cc_details_prereqs)); + // Collect any transitive specializations discovered in cc_details. + for new_spec in std::mem::take(&mut cc_details_prereqs.template_specializations) { + if !seen.contains(&new_spec) { + next_worklist.push(new_spec); + } + } - let mut member_function_names = HashSet::new(); - let assoc_items: ApiSnippets = tcx - .associated_items(impl_def_id) - .in_definition_order() - .flat_map(|assoc_item| { - generate_associated_item(db, assoc_item, &mut member_function_names) - }) - .collect(); - - let main_api = assoc_items.main_api.into_tokens(&mut prereqs); - prereqs.includes.insert(db.support_header("rs_std/traits.h")); - - Ok(ApiSnippets { - main_api: CcSnippet { - tokens: quote! { - __NEWLINE__ - template<> - struct rs_std::impl<#adt_cc_name, #trait_name_with_args> { - static constexpr bool kIsImplemented = true; - - #main_api - }; - __NEWLINE__ - }, - prereqs, - }, - cc_details: assoc_items.cc_details, - rs_details: assoc_items.rs_details, - }) - }, - ) - .map(|results_snippets| { - results_snippets.unwrap_or_else(|(def_id, err)| { - generate_unsupported_def(db, def_id, err).into_main_api() - }) - }) + cc_api_impl.extend(snippets.rs_details.into_tokens(extern_c_decls)); + specializations.insert(spec, snippets.main_api); + } + worklist = next_worklist; + } + + GeneratedSpecializations { specializations, impls_cc_details } } fn formatted_items_in_crate<'tcx>( @@ -1894,16 +1804,14 @@ fn template_specialization_cmp<'tcx>( right: &TemplateSpecialization<'tcx>, ) -> std::cmp::Ordering { match (left, right) { - ( - TemplateSpecialization::RsStdEnum(RsStdEnumTemplateSpecialization { - core: RsStdEnumTemplateSpecializationCore { self_ty_rs: left_ty, .. }, - .. - }), - TemplateSpecialization::RsStdEnum(RsStdEnumTemplateSpecialization { - core: RsStdEnumTemplateSpecializationCore { self_ty_rs: right_ty, .. }, - .. - }), - ) => left_ty.sort_string(tcx).cmp(&right_ty.sort_string(tcx)), + (TemplateSpecialization::RsStdEnum(left), TemplateSpecialization::RsStdEnum(right)) => { + left.core.self_ty_rs.sort_string(tcx).cmp(&right.core.self_ty_rs.sort_string(tcx)) + } + (TemplateSpecialization::TraitImpl(left), TemplateSpecialization::TraitImpl(right)) => { + stable_def_id_cmp(tcx, left.trait_impl, right.trait_impl) + } + (TemplateSpecialization::RsStdEnum(_), _) => Ordering::Less, + (_, TemplateSpecialization::RsStdEnum(_)) => Ordering::Greater, } } @@ -1962,48 +1870,23 @@ fn generate_crate(db: &BindingsGenerator) -> Result { cc_api_impl.extend(api_snippets.rs_details.into_tokens(&mut extern_c_decls)); } - // Because trait implementations are template specialization, they can't live in the top-level - // namespace generated for our other definitions. Template specializations must live in an - // enclosing namespace of the template they specialize. For this reason, we put our specializations in the top level namespace. The remainder of our implementation code, should be handled like normal. - // We append our cc_details and rs_details here, so that they get processed like normal, but save our main_api to be specially placed in the top level namespace. - let mut impls_cc_details = vec![]; - let impls = generate_trait_impls(db) - .map(|snippets| { - impls_cc_details.push(snippets.cc_details.clone().into_tokens(&mut cc_details_prereqs)); - cc_api_impl.extend(snippets.rs_details.clone().into_tokens(&mut extern_c_decls)); - snippets.main_api.clone().into_tokens(&mut cc_details_prereqs) - }) - .collect::>(); - let impls_tokens = if impls.is_empty() { - // Exclude leading newline for an empty impls list. - quote! {} - } else { - quote! { - __NEWLINE__ - #(#impls)__NEWLINE__* - } - }; - - let mut specializations = std::mem::take(&mut cc_details_prereqs.template_specializations); - specializations.extend( - main_apis.values().flat_map(|api| api.prereqs.template_specializations.iter()).cloned(), - ); - - let mut specializations: HashMap = specializations + let worklist: Vec<_> = std::mem::take(&mut cc_details_prereqs.template_specializations) .into_iter() - // We sort here, so our details are added in a consistent order. - .sorted_unstable_by(|a, b| template_specialization_cmp(db.tcx(), a, b)) - .map(|spec| { - let snippets = generate_template_specialization::generate_template_specialization( - db, - spec.clone(), - ); - impls_cc_details.push(snippets.cc_details.clone().into_tokens(&mut cc_details_prereqs)); - cc_api_impl.extend(snippets.rs_details.clone().into_tokens(&mut extern_c_decls)); - (spec, snippets.main_api) - }) + .chain( + main_apis.values().flat_map(|api| api.prereqs.template_specializations.iter()).cloned(), + ) + .chain(collect_trait_impls(db)) .collect(); + let GeneratedSpecializations { mut specializations, impls_cc_details } = + generate_specializations_fixpoint( + db, + worklist, + &mut cc_details_prereqs, + &mut extern_c_decls, + &mut cc_api_impl, + ); + // Find the order of `main_apis` that 1) meets the requirements of // `CcPrerequisites::defs` and 2) makes a best effort attempt to keep the // `main_apis` in the same order as the source order of the Rust APIs. @@ -2044,6 +1927,7 @@ fn generate_crate(db: &BindingsGenerator) -> Result { .template_specializations .iter() .cloned() + //.filter(|spec| specializations.contains_key(spec)) .map(Node::Specialization), ); predecessors.map(move |predecessor| toposort::Dependency { @@ -2162,7 +2046,6 @@ fn generate_crate(db: &BindingsGenerator) -> Result { __NEWLINE__ __NEWLINE__ #ordered_cc __NEWLINE__ - #impls_tokens #(#impls_cc_details)__NEWLINE__* __NEWLINE__ } diff --git a/cc_bindings_from_rs/test/traits/for_cc_type/trait_cc_api.h b/cc_bindings_from_rs/test/traits/for_cc_type/trait_cc_api.h index 7f3de953b..4c73899ec 100644 --- a/cc_bindings_from_rs/test/traits/for_cc_type/trait_cc_api.h +++ b/cc_bindings_from_rs/test/traits/for_cc_type/trait_cc_api.h @@ -41,6 +41,8 @@ struct rs_std::impl { static std::int32_t get_value(CcType const& self); }; +namespace trait {} + namespace trait { namespace __crubit_internal { extern "C" std::int32_t __crubit_thunk_Trait_uget_uvalue(CcType const&); diff --git a/cc_bindings_from_rs/test/traits/generic_traits_cc_api.h b/cc_bindings_from_rs/test/traits/generic_traits_cc_api.h index 84a1e1542..cade5e1a2 100644 --- a/cc_bindings_from_rs/test/traits/generic_traits_cc_api.h +++ b/cc_bindings_from_rs/test/traits/generic_traits_cc_api.h @@ -118,6 +118,38 @@ struct CRUBIT_INTERNAL_RUST_TYPE( using impl = rs_std::impl>; }; +} // namespace generic_traits + +// Error generating bindings for `>` defined at +// cc_bindings_from_rs/test/traits/generic_traits.rs;l=42: +// The following Rust type is not supported yet: U + +template <> +struct rs_std::impl<::generic_traits::StructGeneric, + ::generic_traits::TraitWithGeneric> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/generic_traits.rs;l=21 + static std::int32_t foo(::generic_traits::StructGeneric const& self, + std::int32_t t); +}; + +template <> +struct rs_std::impl< + ::generic_traits::StructGeneric, + ::generic_traits::TraitWithTwoGenerics> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/generic_traits.rs;l=32 + static std::int32_t bar(::generic_traits::StructGeneric const& self, + std::int32_t t, std::int32_t u); +}; + +namespace generic_traits { + static_assert( sizeof(AnotherStruct) == 4, "Verify that ADT layout didn't change since this header got generated"); @@ -158,34 +190,6 @@ inline void StructGeneric::__crubit_field_offset_assertions() { } } // namespace generic_traits -template <> -struct rs_std::impl<::generic_traits::StructGeneric, - ::generic_traits::TraitWithGeneric> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/generic_traits.rs;l=21 - static std::int32_t foo(::generic_traits::StructGeneric const& self, - std::int32_t t); -}; - -template <> -struct rs_std::impl< - ::generic_traits::StructGeneric, - ::generic_traits::TraitWithTwoGenerics> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/generic_traits.rs;l=32 - static std::int32_t bar(::generic_traits::StructGeneric const& self, - std::int32_t t, std::int32_t u); -}; - -// Error generating bindings for `>` defined at -// cc_bindings_from_rs/test/traits/generic_traits.rs;l=42: -// The following Rust type is not supported yet: U - namespace generic_traits { namespace __crubit_internal { extern "C" std::int32_t __crubit_thunk_TraitWithGeneric_ufoo( diff --git a/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition_cc_api.h b/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition_cc_api.h index afc3565e1..2758899a9 100644 --- a/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition_cc_api.h +++ b/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition_cc_api.h @@ -65,6 +65,19 @@ struct CRUBIT_INTERNAL_RUST_TYPE(":: trait_definition_golden :: MyTrait") using impl = rs_std::impl; }; +} // namespace trait_definition + +template <> +struct rs_std::impl<::trait_definition::MyStruct, ::trait_definition::MyTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition.rs;l=14 + static std::int32_t do_something(::trait_definition::MyStruct const& self); +}; + +namespace trait_definition { + static_assert( sizeof(MyStruct) == 4, "Verify that ADT layout didn't change since this header got generated"); @@ -81,15 +94,6 @@ inline void MyStruct::__crubit_field_offset_assertions() { } } // namespace trait_definition -template <> -struct rs_std::impl<::trait_definition::MyStruct, ::trait_definition::MyTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/in_dependent_crate/trait_definition.rs;l=14 - static std::int32_t do_something(::trait_definition::MyStruct const& self); -}; - namespace trait_definition { namespace __crubit_internal { extern "C" std::int32_t __crubit_thunk_MyTrait_udo_usomething( diff --git a/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl_cc_api.h b/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl_cc_api.h index b77fe8238..f38e6ffc0 100644 --- a/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl_cc_api.h +++ b/cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl_cc_api.h @@ -97,6 +97,19 @@ NotImplemented final { static void __crubit_field_offset_assertions(); }; +} // namespace trait_impl + +template <> +struct rs_std::impl<::trait_impl::MyStruct, ::trait_definition::MyTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl.rs;l=18 + static std::int32_t do_something(::trait_impl::MyStruct const& self); +}; + +namespace trait_impl { + static_assert( sizeof(MyStruct) == 4, "Verify that ADT layout didn't change since this header got generated"); @@ -136,15 +149,6 @@ inline void NotImplemented::__crubit_field_offset_assertions() { } } // namespace trait_impl -template <> -struct rs_std::impl<::trait_impl::MyStruct, ::trait_definition::MyTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/in_dependent_crate/trait_impl.rs;l=18 - static std::int32_t do_something(::trait_impl::MyStruct const& self); -}; - namespace trait_impl { namespace __crubit_internal { extern "C" std::int32_t __crubit_thunk_MyTrait_udo_usomething( diff --git a/cc_bindings_from_rs/test/traits/traits_cc_api.h b/cc_bindings_from_rs/test/traits/traits_cc_api.h index 5ff4d95e5..2830f2949 100644 --- a/cc_bindings_from_rs/test/traits/traits_cc_api.h +++ b/cc_bindings_from_rs/test/traits/traits_cc_api.h @@ -282,6 +282,129 @@ struct CRUBIT_INTERNAL_RUST_TYPE(":: traits_golden :: TraitWithAssociatedConst") using impl = rs_std::impl; }; +} // namespace traits + +template <> +struct rs_std::impl<::traits::AssociatedTypeStruct, + ::traits::AssociatedTypeTrait> { + static constexpr bool kIsImplemented = true; + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=148 + using MyAssocType CRUBIT_INTERNAL_RUST_TYPE( + "::MyAssocType") = std::int32_t; + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=149 + static std::int32_t get_my_assoc_type( + ::traits::AssociatedTypeStruct const& self); + + // Error generating bindings for `::UnsupportedAssocType` defined at + // cc_bindings_from_rs/test/traits/traits.rs;l=154: + // Definition `std::string::String` comes from the `alloc` crate, but no + // `--crate-header` was specified for this crate + + // Error generating bindings for `::get_unsupported_assoc_type` defined at + // cc_bindings_from_rs/test/traits/traits.rs;l=155: + // Error formatting function return type `std::string::String`: Definition + // `std::string::String` comes from the `alloc` crate, but no `--crate-header` + // was specified for this crate +}; + +template <> +struct rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=95 + static std::int32_t const& $a + trait_do_something(::traits::LifetimeStruct const& self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=99 + static std::int32_t const& $(__anon1) + function_do_something(::traits::LifetimeStruct const& self); +}; + +template <> +struct rs_std::impl<::traits::MyStruct, ::traits::DifferentTraitSameName> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=79 + static std::int32_t do_something(::traits::MyStruct const& self); +}; + +template <> +struct rs_std::impl<::traits::MyStruct, ::traits::MyTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=57 + static std::int32_t do_something(::traits::MyStruct const& self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=61 + static std::int32_t consume_self(::traits::MyStruct self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=65 + static ::traits::MyStruct const& $(__anon1) + return_self(::traits::MyStruct const& self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=69 + static std::int32_t no_self(); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=73 + static std::tuple take_and_return_other_types( + ::traits::MyStruct const& self, ::traits::Foo x); +}; + +template <> +struct rs_std::impl<::traits::MyStruct2, ::traits::MyTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=110 + static std::int32_t do_something(::traits::MyStruct2 const& self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=114 + static std::int32_t consume_self(::traits::MyStruct2 self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=118 + static ::traits::MyStruct2 const& $(__anon1) + return_self(::traits::MyStruct2 const& self); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=122 + static std::int32_t no_self(); + + // Generated from: + // cc_bindings_from_rs/test/traits/traits.rs;l=126 + static std::tuple take_and_return_other_types( + ::traits::MyStruct2 const& self, ::traits::Foo x); +}; + +template <> +struct rs_std::impl<::traits::StructWithAssociatedConst, + ::traits::TraitWithAssociatedConst> { + static constexpr bool kIsImplemented = true; + static constexpr std::int32_t CONST_INT = INT32_C(10); + + // Error generating bindings for `::CONST_STRUCT` defined at + // cc_bindings_from_rs/test/traits/traits.rs;l=174: + // Unsupported constant type: traits_golden::StructWithAssociatedConst +}; + +namespace traits { + static_assert( sizeof(AssociatedTypeStruct) == 32, "Verify that ADT layout didn't change since this header got generated"); @@ -450,124 +573,60 @@ inline void StructWithAssociatedConst::__crubit_field_offset_assertions() { } } // namespace traits -template <> -struct rs_std::impl<::traits::MyStruct, ::traits::MyTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=57 - static std::int32_t do_something(::traits::MyStruct const& self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=61 - static std::int32_t consume_self(::traits::MyStruct self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=65 - static ::traits::MyStruct const& $(__anon1) - return_self(::traits::MyStruct const& self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=69 - static std::int32_t no_self(); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=73 - static std::tuple take_and_return_other_types( - ::traits::MyStruct const& self, ::traits::Foo x); -}; - -template <> -struct rs_std::impl<::traits::MyStruct2, ::traits::MyTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=110 - static std::int32_t do_something(::traits::MyStruct2 const& self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=114 - static std::int32_t consume_self(::traits::MyStruct2 self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=118 - static ::traits::MyStruct2 const& $(__anon1) - return_self(::traits::MyStruct2 const& self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=122 - static std::int32_t no_self(); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=126 - static std::tuple take_and_return_other_types( - ::traits::MyStruct2 const& self, ::traits::Foo x); -}; - -template <> -struct rs_std::impl<::traits::MyStruct, ::traits::DifferentTraitSameName> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=79 - static std::int32_t do_something(::traits::MyStruct const& self); -}; - -template <> -struct rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=95 - static std::int32_t const& $a - trait_do_something(::traits::LifetimeStruct const& self); - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=99 - static std::int32_t const& $(__anon1) - function_do_something(::traits::LifetimeStruct const& self); -}; - -template <> -struct rs_std::impl<::traits::AssociatedTypeStruct, - ::traits::AssociatedTypeTrait> { - static constexpr bool kIsImplemented = true; - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=148 - using MyAssocType CRUBIT_INTERNAL_RUST_TYPE( - "::MyAssocType") = std::int32_t; - - // Generated from: - // cc_bindings_from_rs/test/traits/traits.rs;l=149 - static std::int32_t get_my_assoc_type( - ::traits::AssociatedTypeStruct const& self); - - // Error generating bindings for `::UnsupportedAssocType` defined at - // cc_bindings_from_rs/test/traits/traits.rs;l=154: - // Definition `std::string::String` comes from the `alloc` crate, but no - // `--crate-header` was specified for this crate +namespace traits { +namespace __crubit_internal { +extern "C" std::int32_t +__crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype( + ::traits::AssociatedTypeStruct const&); +} +} // namespace traits +inline std::int32_t +rs_std::impl<::traits::AssociatedTypeStruct, ::traits::AssociatedTypeTrait>:: + get_my_assoc_type(::traits::AssociatedTypeStruct const& self) { + return traits::__crubit_internal:: + __crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype(self); +} - // Error generating bindings for `::get_unsupported_assoc_type` defined at - // cc_bindings_from_rs/test/traits/traits.rs;l=155: - // Error formatting function return type `std::string::String`: Definition - // `std::string::String` comes from the `alloc` crate, but no `--crate-header` - // was specified for this crate -}; +namespace traits { +namespace __crubit_internal { +extern "C" std::int32_t const& $a +__crubit_thunk_LifetimeTrait_utrait_udo_usomething( + ::traits::LifetimeStruct const&); +} +} // namespace traits +inline std::int32_t const& $a +rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait>:: + trait_do_something(::traits::LifetimeStruct const& self) { + return traits::__crubit_internal:: + __crubit_thunk_LifetimeTrait_utrait_udo_usomething(self); +} -template <> -struct rs_std::impl<::traits::StructWithAssociatedConst, - ::traits::TraitWithAssociatedConst> { - static constexpr bool kIsImplemented = true; - static constexpr std::int32_t CONST_INT = INT32_C(10); +namespace traits { +namespace __crubit_internal { +extern "C" std::int32_t const& $(__anon1) + __crubit_thunk_LifetimeTrait_ufunction_udo_usomething( + ::traits::LifetimeStruct const&); +} +} // namespace traits +inline std::int32_t const& $( + __anon1) rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait>:: + function_do_something(::traits::LifetimeStruct const& self) { + return traits::__crubit_internal:: + __crubit_thunk_LifetimeTrait_ufunction_udo_usomething(self); +} - // Error generating bindings for `::CONST_STRUCT` defined at - // cc_bindings_from_rs/test/traits/traits.rs;l=174: - // Unsupported constant type: traits_golden::StructWithAssociatedConst -}; +namespace traits { +namespace __crubit_internal { +extern "C" std::int32_t __crubit_thunk_DifferentTraitSameName_udo_usomething( + ::traits::MyStruct const&); +} +} // namespace traits +inline std::int32_t rs_std:: + impl<::traits::MyStruct, ::traits::DifferentTraitSameName>::do_something( + ::traits::MyStruct const& self) { + return traits::__crubit_internal:: + __crubit_thunk_DifferentTraitSameName_udo_usomething(self); +} namespace traits { namespace __crubit_internal { @@ -705,60 +764,5 @@ inline std::tuple rs_std:: return std::make_tuple(*__return_value_0_storage, *__return_value_1_storage); } -namespace traits { -namespace __crubit_internal { -extern "C" std::int32_t __crubit_thunk_DifferentTraitSameName_udo_usomething( - ::traits::MyStruct const&); -} -} // namespace traits -inline std::int32_t rs_std:: - impl<::traits::MyStruct, ::traits::DifferentTraitSameName>::do_something( - ::traits::MyStruct const& self) { - return traits::__crubit_internal:: - __crubit_thunk_DifferentTraitSameName_udo_usomething(self); -} - -namespace traits { -namespace __crubit_internal { -extern "C" std::int32_t const& $a -__crubit_thunk_LifetimeTrait_utrait_udo_usomething( - ::traits::LifetimeStruct const&); -} -} // namespace traits -inline std::int32_t const& $a -rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait>:: - trait_do_something(::traits::LifetimeStruct const& self) { - return traits::__crubit_internal:: - __crubit_thunk_LifetimeTrait_utrait_udo_usomething(self); -} - -namespace traits { -namespace __crubit_internal { -extern "C" std::int32_t const& $(__anon1) - __crubit_thunk_LifetimeTrait_ufunction_udo_usomething( - ::traits::LifetimeStruct const&); -} -} // namespace traits -inline std::int32_t const& $( - __anon1) rs_std::impl<::traits::LifetimeStruct, ::traits::LifetimeTrait>:: - function_do_something(::traits::LifetimeStruct const& self) { - return traits::__crubit_internal:: - __crubit_thunk_LifetimeTrait_ufunction_udo_usomething(self); -} - -namespace traits { -namespace __crubit_internal { -extern "C" std::int32_t -__crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype( - ::traits::AssociatedTypeStruct const&); -} -} // namespace traits -inline std::int32_t -rs_std::impl<::traits::AssociatedTypeStruct, ::traits::AssociatedTypeTrait>:: - get_my_assoc_type(::traits::AssociatedTypeStruct const& self) { - return traits::__crubit_internal:: - __crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype(self); -} - #pragma clang diagnostic pop #endif // THIRD_PARTY_CRUBIT_CC_BINDINGS_FROM_RS_TEST_TRAITS_TRAITS_GOLDEN diff --git a/cc_bindings_from_rs/test/traits/traits_cc_api_impl.rs b/cc_bindings_from_rs/test/traits/traits_cc_api_impl.rs index aebe846e9..e130337de 100644 --- a/cc_bindings_from_rs/test/traits/traits_cc_api_impl.rs +++ b/cc_bindings_from_rs/test/traits/traits_cc_api_impl.rs @@ -103,6 +103,42 @@ unsafe extern "C" fn __crubit_thunk_default(__ret_ptr: *mut core::ffi::c_void) - } const _: () = assert!(::core::mem::offset_of!(::traits_golden::StructWithAssociatedConst, x) == 0); #[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype( + __self: &'static ::traits_golden::AssociatedTypeStruct, +) -> i32 { + unsafe { + <::traits_golden::AssociatedTypeStruct as::traits_golden::AssociatedTypeTrait>::get_my_assoc_type(__self) + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_LifetimeTrait_utrait_udo_usomething( + __self: &'static ::traits_golden::LifetimeStruct<'static>, +) -> &'static i32 { + unsafe { + <::traits_golden::LifetimeStruct as ::traits_golden::LifetimeTrait>::trait_do_something( + __self, + ) + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_LifetimeTrait_ufunction_udo_usomething( + __self: &'static ::traits_golden::LifetimeStruct<'static>, +) -> &'static i32 { + unsafe { + <::traits_golden::LifetimeStruct as ::traits_golden::LifetimeTrait>::function_do_something( + __self, + ) + } +} +#[unsafe(no_mangle)] +unsafe extern "C" fn __crubit_thunk_DifferentTraitSameName_udo_usomething( + __self: &'static ::traits_golden::MyStruct, +) -> i32 { + unsafe { + <::traits_golden::MyStruct as ::traits_golden::DifferentTraitSameName>::do_something(__self) + } +} +#[unsafe(no_mangle)] unsafe extern "C" fn __crubit_thunk_MyTrait_udo_usomething( __self: &'static ::traits_golden::MyStruct, ) -> i32 { @@ -188,39 +224,3 @@ unsafe extern "C" fn __crubit_thunk_MyTrait_utake_uand_ureturn_uother_utypes( (__ret_ptr_1 as *mut i32).write(__rs_return_value_1); } } -#[unsafe(no_mangle)] -unsafe extern "C" fn __crubit_thunk_DifferentTraitSameName_udo_usomething( - __self: &'static ::traits_golden::MyStruct, -) -> i32 { - unsafe { - <::traits_golden::MyStruct as ::traits_golden::DifferentTraitSameName>::do_something(__self) - } -} -#[unsafe(no_mangle)] -unsafe extern "C" fn __crubit_thunk_LifetimeTrait_utrait_udo_usomething( - __self: &'static ::traits_golden::LifetimeStruct<'static>, -) -> &'static i32 { - unsafe { - <::traits_golden::LifetimeStruct as ::traits_golden::LifetimeTrait>::trait_do_something( - __self, - ) - } -} -#[unsafe(no_mangle)] -unsafe extern "C" fn __crubit_thunk_LifetimeTrait_ufunction_udo_usomething( - __self: &'static ::traits_golden::LifetimeStruct<'static>, -) -> &'static i32 { - unsafe { - <::traits_golden::LifetimeStruct as ::traits_golden::LifetimeTrait>::function_do_something( - __self, - ) - } -} -#[unsafe(no_mangle)] -unsafe extern "C" fn __crubit_thunk_AssociatedTypeTrait_uget_umy_uassoc_utype( - __self: &'static ::traits_golden::AssociatedTypeStruct, -) -> i32 { - unsafe { - <::traits_golden::AssociatedTypeStruct as::traits_golden::AssociatedTypeTrait>::get_my_assoc_type(__self) - } -} diff --git a/examples/rust/trait/example_generated.h b/examples/rust/trait/example_generated.h index c955a7de1..1a3e08aae 100644 --- a/examples/rust/trait/example_generated.h +++ b/examples/rust/trait/example_generated.h @@ -69,6 +69,24 @@ struct CRUBIT_INTERNAL_RUST_TYPE(":: example_crate_golden :: MyTrait") MyTrait { using impl = rs_std::impl; }; +} // namespace example_crate + +template <> +struct rs_std::impl<::example_crate::MyStruct, ::example_crate::MyTrait> { + static constexpr bool kIsImplemented = true; + + // Generated from: + // examples/rust/trait/example.rs;l=23 + static std::int32_t add_with(::example_crate::MyStruct const& self, + std::int32_t y); + + // Generated from: + // examples/rust/trait/example.rs;l=27 + static rs_std::StrRef describe(::example_crate::MyStruct const& self); +}; + +namespace example_crate { + static_assert( sizeof(MyStruct) == 4, "Verify that ADT layout didn't change since this header got generated"); @@ -103,20 +121,6 @@ inline void MyStruct::__crubit_field_offset_assertions() { } } // namespace example_crate -template <> -struct rs_std::impl<::example_crate::MyStruct, ::example_crate::MyTrait> { - static constexpr bool kIsImplemented = true; - - // Generated from: - // examples/rust/trait/example.rs;l=23 - static std::int32_t add_with(::example_crate::MyStruct const& self, - std::int32_t y); - - // Generated from: - // examples/rust/trait/example.rs;l=27 - static rs_std::StrRef describe(::example_crate::MyStruct const& self); -}; - namespace example_crate { namespace __crubit_internal { extern "C" std::int32_t __crubit_thunk_MyTrait_uadd_uwith(