Skip to content

Commit 142b91c

Browse files
committed
Support dependent qualified names.
For a situation like this: struct InnerType { typedef int related_type; int foo; int foo2; }; template <typename ContainedType> class Container { public: typedef typename ContainedType::related_type content_ty; content_ty contents_; }; typedef Container<InnerType> Concrete; struct LaterContainingType { Concrete outer_contents; }; previously bindgen would have generated an opaque type. It now correctly recognizes that the contents_ field is of a new TypeKind::DependentQualifiedName and correctly identifies the right type to use when instantiating Concrete. The generated code looks like this: #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct InnerType { pub foo: ::std::os::raw::c_int, pub foo2: ::std::os::raw::c_int, } pub type InnerType_related_type = ::std::os::raw::c_int; pub trait __bindgen_has_inner_type_related_type { type related_type: std::fmt::Debug + Default + Copy + Clone; } impl __bindgen_has_inner_type_related_type for InnerType { type related_type = InnerType_related_type; } #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct Container<ContainedType: __bindgen_has_inner_type_related_type> { pub contents_: Container_content_ty<ContainedType>, pub _phantom_0: ::std::marker::PhantomData<::std::cell::UnsafeCell<ContainedType>>, } pub type Container_content_ty<ContainedType> = <ContainedType as __bindgen_has_inner_type_related_type>::related_type; pub type Concrete = Container<InnerType>; #[repr(C)] #[derive(Debug, Default, Copy, Clone)] pub struct LaterContainingType { pub outer_contents: Concrete, } Note the trait constructed to mark types which have an inner type. This trait is then used in the Rust definition of Container_content_ty. Such a trait is emitted only if it's actually used, to avoid too much verbosity. This is useful for types which are parameterized with a traits type. For example Chromium's base::StringPiece which is parameterized by an STL string type (e.g. std::string) and looks up the correct size of character to use by using a parameterized type: typedef typename STRING_TYPE::value_type value_type; (Of course, std::string and other string types have other reasons why they're difficult to work with from Rust, such as self-referential pointers, but that's another story). This change assumes all types involved derive the same traits: in the above example note that __bindgen_has_inner_type_related_type requires all traits be derived. It would be possible to be more nuanced here and move those trait bounds to the places where the trait is used (e.g. pub type Concrete = ... in the above example).
1 parent 5761a88 commit 142b91c

16 files changed

+559
-51
lines changed

src/clang.rs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,23 +1282,30 @@ impl Type {
12821282
/// typename T::Associated member;
12831283
/// };
12841284
/// ```
1285-
pub fn is_associated_type(&self) -> bool {
1285+
///
1286+
/// If so, returns the type name, e.g. 'member'
1287+
pub fn get_associated_type_name(&self) -> Option<String> {
12861288
// This is terrible :(
1287-
fn hacky_parse_associated_type<S: AsRef<str>>(spelling: S) -> bool {
1289+
fn hacky_parse_associated_type<S: AsRef<str>>(
1290+
spelling: S,
1291+
) -> Option<String> {
12881292
lazy_static! {
12891293
static ref ASSOC_TYPE_RE: regex::Regex = regex::Regex::new(
1290-
r"typename type\-parameter\-\d+\-\d+::.+"
1294+
r"typename type\-parameter\-\d+\-\d+::(.+)"
12911295
)
12921296
.unwrap();
12931297
}
1294-
ASSOC_TYPE_RE.is_match(spelling.as_ref())
1298+
ASSOC_TYPE_RE
1299+
.captures(spelling.as_ref())
1300+
.map(|caps| caps.get(1).unwrap().as_str().to_string())
12951301
}
12961302

1297-
self.kind() == CXType_Unexposed &&
1298-
(hacky_parse_associated_type(self.spelling()) ||
1299-
hacky_parse_associated_type(
1300-
self.canonical_type().spelling(),
1301-
))
1303+
if self.kind() != CXType_Unexposed {
1304+
return None;
1305+
}
1306+
hacky_parse_associated_type(self.spelling()).or_else(|| {
1307+
hacky_parse_associated_type(self.canonical_type().spelling())
1308+
})
13021309
}
13031310
}
13041311

src/codegen/impl_debug.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ impl<'a> ImplDebug<'a> for Item {
159159
TypeKind::ObjCInterface(..) |
160160
TypeKind::ObjCId |
161161
TypeKind::Comp(..) |
162+
TypeKind::DependentQualifiedType(..) |
162163
TypeKind::ObjCSel => debug_print(name, quote! { #name_ident }),
163164

164165
TypeKind::TemplateInstantiation(ref inst) => {

src/codegen/impl_partialeq.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ fn gen_field(
9393
TypeKind::Float(..) |
9494
TypeKind::Enum(..) |
9595
TypeKind::TypeParam |
96+
TypeKind::DependentQualifiedType(..) |
9697
TypeKind::UnresolvedTypeRef(..) |
9798
TypeKind::Reference(..) |
9899
TypeKind::ObjCInterface(..) |

src/codegen/mod.rs

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ struct CodegenResult<'a> {
231231
/// function name to the number of overloads we have already codegen'd for
232232
/// that name. This lets us give each overload a unique suffix.
233233
overload_counters: HashMap<String, u32>,
234+
235+
/// Used to record what traits we have generated for the names
236+
/// of inner types, such that we generate each trait exactly once.
237+
/// (The trait may be implemented by multiple types.)
238+
inner_type_traits_generated: HashSet<Ident>,
234239
}
235240

236241
impl<'a> CodegenResult<'a> {
@@ -248,6 +253,7 @@ impl<'a> CodegenResult<'a> {
248253
functions_seen: Default::default(),
249254
vars_seen: Default::default(),
250255
overload_counters: Default::default(),
256+
inner_type_traits_generated: Default::default(),
251257
}
252258
}
253259

@@ -393,6 +399,7 @@ impl AppendImplicitTemplateParams for proc_macro2::TokenStream {
393399
TypeKind::Complex(..) |
394400
TypeKind::Array(..) |
395401
TypeKind::TypeParam |
402+
TypeKind::DependentQualifiedType(..) |
396403
TypeKind::Opaque |
397404
TypeKind::Function(..) |
398405
TypeKind::Enum(..) |
@@ -758,6 +765,25 @@ impl CodeGenerator for Type {
758765
// it to BindgenContext::compute_allowlisted_and_codegen_items.
759766
return;
760767
}
768+
TypeKind::DependentQualifiedType(_, ref field_name) => {
769+
let shortname = ctx.rust_ident(&field_name);
770+
let traitname = ctx.inner_type_trait_ident(field_name);
771+
if result.inner_type_traits_generated.insert(traitname.clone())
772+
{
773+
let mut type_definition = quote! { #shortname };
774+
let derivable_traits = derives_of_item(item, ctx);
775+
append_associated_type_constraints(
776+
ctx,
777+
&derivable_traits,
778+
&mut type_definition,
779+
);
780+
result.push(quote! {
781+
pub trait #traitname {
782+
type #type_definition;
783+
}
784+
});
785+
}
786+
}
761787
TypeKind::TemplateInstantiation(ref inst) => {
762788
inst.codegen(ctx, result, item)
763789
}
@@ -1908,10 +1934,48 @@ impl CodeGenerator for CompInfo {
19081934

19091935
let mut generic_param_names = vec![];
19101936

1937+
let used_dependent_qualified_types =
1938+
item.used_dependent_qualified_types(ctx);
1939+
let mut dependent_qualified_types_by_param: HashMap<
1940+
crate::ir::context::TypeId,
1941+
Vec<&String>,
1942+
> = HashMap::default();
1943+
for ty_id in used_dependent_qualified_types {
1944+
let dependent_qualified_type = ctx.resolve_type(ty_id);
1945+
match dependent_qualified_type.kind() {
1946+
TypeKind::DependentQualifiedType(
1947+
tp_id,
1948+
associated_type_name,
1949+
) => {
1950+
dependent_qualified_types_by_param
1951+
.entry(*tp_id)
1952+
.or_default()
1953+
.push(associated_type_name);
1954+
}
1955+
_ => panic!(
1956+
"unexpected type kind for dependent qualified type type"
1957+
),
1958+
}
1959+
}
1960+
1961+
let mut where_constraints: std::collections::HashMap<
1962+
Ident,
1963+
Vec<Ident>,
1964+
> = std::collections::HashMap::new();
19111965
for (idx, ty) in item.used_template_params(ctx).iter().enumerate() {
19121966
let param = ctx.resolve_type(*ty);
19131967
let name = param.name().unwrap();
19141968
let ident = ctx.rust_ident(name);
1969+
if let Some(dependent_qualified_type_field_names) =
1970+
dependent_qualified_types_by_param.get(ty)
1971+
{
1972+
where_constraints.entry(ident.clone()).or_default().extend(
1973+
dependent_qualified_type_field_names.into_iter().map(
1974+
|field_name| ctx.inner_type_trait_ident(field_name),
1975+
),
1976+
);
1977+
}
1978+
19151979
generic_param_names.push(ident.clone());
19161980

19171981
let prefix = ctx.trait_prefix();
@@ -2013,8 +2077,28 @@ impl CodeGenerator for CompInfo {
20132077
}
20142078
};
20152079

2080+
let mut where_constraints_ts = quote! {};
2081+
if !where_constraints.is_empty() {
2082+
for (i, (k, traits)) in where_constraints.into_iter().enumerate() {
2083+
let prefix = if i == 0 {
2084+
quote! { where }
2085+
} else {
2086+
quote! { , }
2087+
};
2088+
where_constraints_ts.extend(quote! { #prefix #k });
2089+
for (j, v) in traits.into_iter().enumerate() {
2090+
let sep = if j == 0 {
2091+
quote! {:}
2092+
} else {
2093+
quote! {+}
2094+
};
2095+
where_constraints_ts.extend(quote! { #sep #v });
2096+
}
2097+
}
2098+
}
2099+
20162100
tokens.append_all(quote! {
2017-
#generics {
2101+
#generics #where_constraints_ts {
20182102
#( #fields )*
20192103
}
20202104
});
@@ -2028,6 +2112,26 @@ impl CodeGenerator for CompInfo {
20282112
let child_item = ctx.resolve_item(*ty);
20292113
// assert_eq!(child_item.parent_id(), item.id());
20302114
child_item.codegen(ctx, result, &());
2115+
2116+
if let Some(shortname) = child_item.expect_type().name() {
2117+
if !ctx.inner_type_used(shortname) {
2118+
continue;
2119+
}
2120+
let child_canonical_name = child_item.canonical_name(ctx);
2121+
let child_canonical_name =
2122+
ctx.rust_ident(&child_canonical_name);
2123+
2124+
let traitname = ctx.inner_type_trait_ident(&shortname);
2125+
let shortname = ctx.rust_ident(shortname);
2126+
let mut template_params = proc_macro2::TokenStream::new();
2127+
template_params
2128+
.append_implicit_template_params(ctx, child_item);
2129+
result.push(quote! {
2130+
impl #generics #traitname for #canonical_ident #generics {
2131+
type #shortname = #child_canonical_name #template_params;
2132+
}
2133+
});
2134+
}
20312135
}
20322136

20332137
// NOTE: Some unexposed attributes (like alignment attributes) may
@@ -2255,6 +2359,30 @@ impl CodeGenerator for CompInfo {
22552359
}
22562360
}
22572361

2362+
fn append_associated_type_constraints(
2363+
ctx: &BindgenContext,
2364+
derivable_traits: &DerivableTraits,
2365+
ts: &mut proc_macro2::TokenStream,
2366+
) {
2367+
let trait_bounds: Vec<&'static str> = derivable_traits.clone().into();
2368+
let mut done_first = false;
2369+
for id in trait_bounds.into_iter() {
2370+
let id = match id {
2371+
"Debug" => quote! { std::fmt::Debug },
2372+
_ => {
2373+
let id = ctx.rust_ident(id);
2374+
quote! { #id }
2375+
}
2376+
};
2377+
ts.append_all(if done_first {
2378+
quote! { + #id }
2379+
} else {
2380+
quote! { : #id }
2381+
});
2382+
done_first = true;
2383+
}
2384+
}
2385+
22582386
trait MethodCodegen {
22592387
fn codegen_method<'a>(
22602388
&self,
@@ -3643,6 +3771,15 @@ impl TryToRustTy for Type {
36433771
#ident
36443772
})
36453773
}
3774+
TypeKind::DependentQualifiedType(_, ref field_name) => {
3775+
let name = item.canonical_name(ctx);
3776+
let ident = ctx.rust_ident(&name);
3777+
let dependent_type_ident = ctx.rust_ident(&field_name);
3778+
let trait_id = ctx.inner_type_trait_ident(field_name);
3779+
Ok(quote! {
3780+
< #ident as #trait_id > :: #dependent_type_ident
3781+
})
3782+
}
36463783
TypeKind::ObjCSel => Ok(quote! {
36473784
objc::runtime::Sel
36483785
}),

src/ir/analysis/derive.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ fn consider_edge_default(kind: EdgeKind) -> bool {
9090
EdgeKind::VarType |
9191
EdgeKind::TemplateArgument |
9292
EdgeKind::TemplateDeclaration |
93+
EdgeKind::ContainedDependentQualifiedType |
94+
EdgeKind::DependentQualifiedTypeParam |
9395
EdgeKind::TemplateParameterDefinition => true,
9496

9597
EdgeKind::Constructor |
@@ -212,6 +214,7 @@ impl<'ctx> CannotDerive<'ctx> {
212214
TypeKind::Float(..) |
213215
TypeKind::Enum(..) |
214216
TypeKind::TypeParam |
217+
TypeKind::DependentQualifiedType(..) |
215218
TypeKind::UnresolvedTypeRef(..) |
216219
TypeKind::Reference(..) |
217220
TypeKind::ObjCInterface(..) |

src/ir/analysis/has_float.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ impl<'ctx> HasFloat<'ctx> {
4848
EdgeKind::VarType |
4949
EdgeKind::TemplateArgument |
5050
EdgeKind::TemplateDeclaration |
51+
EdgeKind::ContainedDependentQualifiedType |
52+
EdgeKind::DependentQualifiedTypeParam |
5153
EdgeKind::TemplateParameterDefinition => true,
5254

5355
EdgeKind::Constructor |
@@ -122,6 +124,7 @@ impl<'ctx> MonotoneFramework for HasFloat<'ctx> {
122124
TypeKind::Enum(..) |
123125
TypeKind::Reference(..) |
124126
TypeKind::TypeParam |
127+
TypeKind::DependentQualifiedType(..) |
125128
TypeKind::Opaque |
126129
TypeKind::Pointer(..) |
127130
TypeKind::UnresolvedTypeRef(..) |

src/ir/analysis/has_type_param_in_array.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ impl<'ctx> HasTypeParameterInArray<'ctx> {
5050
EdgeKind::VarType |
5151
EdgeKind::TemplateArgument |
5252
EdgeKind::TemplateDeclaration |
53+
EdgeKind::ContainedDependentQualifiedType |
54+
EdgeKind::DependentQualifiedTypeParam |
5355
EdgeKind::TemplateParameterDefinition => true,
5456

5557
EdgeKind::Constructor |
@@ -133,6 +135,7 @@ impl<'ctx> MonotoneFramework for HasTypeParameterInArray<'ctx> {
133135
TypeKind::Enum(..) |
134136
TypeKind::Reference(..) |
135137
TypeKind::TypeParam |
138+
TypeKind::DependentQualifiedType(..) |
136139
TypeKind::Opaque |
137140
TypeKind::Pointer(..) |
138141
TypeKind::UnresolvedTypeRef(..) |

src/ir/analysis/sizedness.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ impl<'ctx> MonotoneFramework for SizednessAnalysis<'ctx> {
239239
self.insert(id, SizednessResult::ZeroSized)
240240
}
241241

242-
TypeKind::TypeParam => {
242+
TypeKind::TypeParam | TypeKind::DependentQualifiedType(..) => {
243243
trace!(
244244
" type params sizedness depends on what they're \
245245
instantiated as"

src/ir/analysis/template_params.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,9 @@ impl<'ctx> UsedTemplateParameters<'ctx> {
195195
EdgeKind::TemplateDeclaration |
196196
EdgeKind::TemplateParameterDefinition => false,
197197

198+
EdgeKind::DependentQualifiedTypeParam |
199+
EdgeKind::ContainedDependentQualifiedType => true,
200+
198201
// Since we have to be careful about which edges we consider for
199202
// this analysis to be correct, we ignore generic edges. We also
200203
// avoid a `_` wild card to force authors of new edge kinds to
@@ -534,6 +537,10 @@ impl<'ctx> MonotoneFramework for UsedTemplateParameters<'ctx> {
534537
trace!(" named type, trivially uses itself");
535538
used_by_this_id.insert(id);
536539
}
540+
Some(&TypeKind::DependentQualifiedType(tp_id, ..)) => {
541+
used_by_this_id.insert(id);
542+
used_by_this_id.insert(tp_id.into());
543+
}
537544
// Template instantiations only use their template arguments if the
538545
// template definition uses the corresponding template parameter.
539546
Some(&TypeKind::TemplateInstantiation(ref inst)) => {

0 commit comments

Comments
 (0)