@@ -30,7 +30,7 @@ use crate::{
30
30
} ;
31
31
use proc_macro2:: { Span , TokenStream as TokenStream2 , TokenTree } ;
32
32
use quote:: quote;
33
- use syn:: { parse:: Parser , ItemType } ;
33
+ use syn:: { parse:: Parser , Field , GenericParam , Generics , ItemStruct } ;
34
34
use syn:: {
35
35
parse_quote, Attribute , FnArg , ForeignItem , ForeignItemFn , GenericArgument , Ident , Item ,
36
36
ItemForeignMod , ItemMod , Pat , PathArguments , PathSegment , ReturnType , Type , TypePath , TypePtr ,
@@ -262,26 +262,13 @@ impl<'a> BridgeConversion<'a> {
262
262
Item :: Struct ( mut s) => {
263
263
let tyname = TypeName :: new ( & ns, & s. ident . to_string ( ) ) ;
264
264
let should_be_pod = self . byvalue_checker . is_pod ( & tyname) ;
265
- self . generate_type_alias ( tyname, should_be_pod) ?;
265
+ if !Self :: generics_contentful ( & s. generics ) {
266
+ // cxx::bridge can't cope with type aliases to generic
267
+ // types at the moment.
268
+ self . generate_type_alias ( tyname, should_be_pod) ?;
269
+ }
266
270
if !should_be_pod {
267
- // See cxx's opaque::Opaque for rationale for this type... in
268
- // short, it's to avoid being Send/Sync.
269
- s. fields = syn:: Fields :: Named ( parse_quote ! {
270
- {
271
- do_not_attempt_to_allocate_nonpod_types: [ * const u8 ; 0 ] ,
272
- }
273
- } ) ;
274
- // Thanks to dtolnay@ for this explanation of why the following
275
- // is needed:
276
- // If the real alignment of the C++ type is smaller and a reference
277
- // is returned from C++ to Rust, mere existence of an insufficiently
278
- // aligned reference in Rust causes UB even if never dereferenced
279
- // by Rust code
280
- // (see https://doc.rust-lang.org/1.47.0/reference/behavior-considered-undefined.html).
281
- // Rustc can use least-significant bits of the reference for other storage.
282
- s. attrs = vec ! [ parse_quote!(
283
- #[ repr( C , packed) ]
284
- ) ] ;
271
+ Self :: make_non_pod ( & mut s) ;
285
272
}
286
273
output_items. push ( Item :: Struct ( s) ) ;
287
274
}
@@ -319,7 +306,7 @@ impl<'a> BridgeConversion<'a> {
319
306
self . all_items . push ( item) ;
320
307
}
321
308
Item :: Type ( ity) => {
322
- if Self :: should_ignore_item_type ( & ity) {
309
+ if Self :: generics_contentful ( & ity. generics ) {
323
310
// Ignore this for now. Sometimes bindgen generates such things
324
311
// without an actual need to do so.
325
312
continue ;
@@ -349,10 +336,51 @@ impl<'a> BridgeConversion<'a> {
349
336
Ok ( ( ) )
350
337
}
351
338
352
- fn should_ignore_item_type ( ity : & ItemType ) -> bool {
353
- ity. generics . lifetimes ( ) . next ( ) . is_some ( )
354
- || ity. generics . const_params ( ) . next ( ) . is_some ( )
355
- || ity. generics . type_params ( ) . next ( ) . is_some ( )
339
+ fn make_non_pod ( s : & mut ItemStruct ) {
340
+ // Thanks to dtolnay@ for this explanation of why the following
341
+ // is needed:
342
+ // If the real alignment of the C++ type is smaller and a reference
343
+ // is returned from C++ to Rust, mere existence of an insufficiently
344
+ // aligned reference in Rust causes UB even if never dereferenced
345
+ // by Rust code
346
+ // (see https://doc.rust-lang.org/1.47.0/reference/behavior-considered-undefined.html).
347
+ // Rustc can use least-significant bits of the reference for other storage.
348
+ s. attrs = vec ! [ parse_quote!(
349
+ #[ repr( C , packed) ]
350
+ ) ] ;
351
+ // Now fill in fields. Usually, we just want a single field
352
+ // but if this is a generic type we need to faff a bit.
353
+ let generic_type_fields =
354
+ s. generics
355
+ . params
356
+ . iter ( )
357
+ . enumerate ( )
358
+ . filter_map ( |( counter, gp) | match gp {
359
+ GenericParam :: Type ( gpt) => {
360
+ let id = & gpt. ident ;
361
+ let field_name = make_ident ( & format ! ( "_phantom_{}" , counter) ) ;
362
+ let toks = quote ! {
363
+ #field_name: :: std:: marker:: PhantomData <:: std:: cell:: UnsafeCell < #id >>
364
+ } ;
365
+ let parser = Field :: parse_named;
366
+ Some ( parser. parse2 ( toks) . unwrap ( ) )
367
+ }
368
+ _ => None ,
369
+ } ) ;
370
+ // See cxx's opaque::Opaque for rationale for this type... in
371
+ // short, it's to avoid being Send/Sync.
372
+ s. fields = syn:: Fields :: Named ( parse_quote ! {
373
+ {
374
+ do_not_attempt_to_allocate_nonpod_types: [ * const u8 ; 0 ] ,
375
+ #( #generic_type_fields) , *
376
+ }
377
+ } ) ;
378
+ }
379
+
380
+ fn generics_contentful ( generics : & Generics ) -> bool {
381
+ generics. lifetimes ( ) . next ( ) . is_some ( )
382
+ || generics. const_params ( ) . next ( ) . is_some ( )
383
+ || generics. type_params ( ) . next ( ) . is_some ( )
356
384
}
357
385
358
386
fn analyze_typedef_target ( ty : & Type ) -> TypedefTarget {
@@ -381,7 +409,7 @@ impl<'a> BridgeConversion<'a> {
381
409
. byvalue_checker
382
410
. ingest_pod_type ( TypeName :: new ( & ns, & e. ident . to_string ( ) ) ) ,
383
411
Item :: Type ( ity) => {
384
- if Self :: should_ignore_item_type ( & ity) {
412
+ if Self :: generics_contentful ( & ity. generics ) {
385
413
// Ignore this for now. Sometimes bindgen generates such things
386
414
// without an actual need to do so.
387
415
continue ;
0 commit comments