1
1
#![ feature(
2
- proc_macro_diagnostic, // Used for warnings
3
2
proc_macro_tracked_env, // Used for `DEBUG_DERIVE`
4
3
) ]
5
4
extern crate proc_macro;
@@ -117,6 +116,7 @@ struct TypeAttrs {
117
116
is_copy : bool ,
118
117
nop_trace : bool ,
119
118
gc_lifetime : Option < Lifetime > ,
119
+ collector_id : Option < Ident > ,
120
120
ignore_params : HashSet < Ident > ,
121
121
ignored_lifetimes : HashSet < Lifetime >
122
122
}
@@ -143,6 +143,7 @@ impl Default for TypeAttrs {
143
143
is_copy : false ,
144
144
nop_trace : false ,
145
145
gc_lifetime : None ,
146
+ collector_id : None ,
146
147
ignore_params : Default :: default ( ) ,
147
148
ignored_lifetimes : Default :: default ( ) ,
148
149
}
@@ -211,6 +212,32 @@ impl Parse for TypeAttrs {
211
212
}
212
213
} ;
213
214
result. gc_lifetime = Some ( lifetime) ;
215
+ } else if meta. path ( ) . is_ident ( "collector_id" ) {
216
+ if result. collector_id . is_some ( ) {
217
+ return Err ( Error :: new (
218
+ meta. span ( ) ,
219
+ "Duplicate flags: #[zerogc(collector_id)]"
220
+ ) )
221
+ }
222
+ fn get_ident_meta ( meta : & NestedMeta ) -> Option < & Ident > {
223
+ match * meta {
224
+ NestedMeta :: Meta ( Meta :: Path ( ref p) ) => p. get_ident ( ) ,
225
+ _ => None
226
+ }
227
+ }
228
+ let ident = match meta {
229
+ Meta :: List ( ref l) if l. nested . len ( ) == 1
230
+ && get_ident_meta ( & l. nested [ 0 ] ) . is_some ( ) => {
231
+ get_ident_meta ( & l. nested [ 0 ] ) . unwrap ( )
232
+ }
233
+ _ => {
234
+ return Err ( Error :: new (
235
+ meta. span ( ) ,
236
+ "Malformed attribute for #[zerogc(collector_id)]"
237
+ ) )
238
+ }
239
+ } ;
240
+ result. collector_id = Some ( ident. clone ( ) ) ;
214
241
} else if meta. path ( ) . is_ident ( "ignore_params" ) {
215
242
if !result. ignore_params . is_empty ( ) {
216
243
return Err ( Error :: new (
@@ -250,7 +277,7 @@ impl Parse for TypeAttrs {
250
277
}
251
278
}
252
279
} else if meta. path ( ) . is_ident ( "ignore_lifetimes" ) {
253
- if !result. ignore_params . is_empty ( ) {
280
+ if !result. ignored_lifetimes . is_empty ( ) {
254
281
return Err ( Error :: new (
255
282
meta. span ( ) ,
256
283
"Duplicate flags: #[zerogc(ignore_lifetimes)]"
@@ -505,7 +532,13 @@ fn impl_erase_nop(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream
505
532
}
506
533
let mut impl_generics = generics. clone ( ) ;
507
534
impl_generics. params . push ( GenericParam :: Lifetime ( parse_quote ! ( ' min) ) ) ;
508
- impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( S : :: zerogc:: CollectorId ) ) ) ;
535
+ let collector_id = match info. config . collector_id {
536
+ Some ( ref id) => id. clone ( ) ,
537
+ None => {
538
+ impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( Id : :: zerogc:: CollectorId ) ) ) ;
539
+ parse_quote ! ( Id )
540
+ }
541
+ } ;
509
542
// Require that `Self: NullTrace`
510
543
impl_generics. make_where_clause ( ) . predicates . push ( WherePredicate :: Type ( PredicateType {
511
544
lifetimes : None ,
@@ -515,14 +548,8 @@ fn impl_erase_nop(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream
515
548
} ) ) ;
516
549
let ( _, ty_generics, _) = generics. split_for_impl ( ) ;
517
550
let ( impl_generics, _, where_clause) = impl_generics. split_for_impl ( ) ;
518
- :: proc_macro:: Diagnostic :: spanned (
519
- :: proc_macro:: Span :: call_site ( ) ,
520
- :: proc_macro:: Level :: Note ,
521
- // We know this is safe because we know that `Self: NullTrace`
522
- "derive(GcRebrand) is safe for NullTrace, unlike standard implementation"
523
- ) . emit ( ) ;
524
551
Ok ( quote ! {
525
- unsafe impl #impl_generics :: zerogc:: GcErase <' min, S >
552
+ unsafe impl #impl_generics :: zerogc:: GcErase <' min, #collector_id >
526
553
for #name #ty_generics #where_clause {
527
554
// We can pass-through because we are NullTrace
528
555
type Erased = Self ;
@@ -534,15 +561,19 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
534
561
let mut generics: Generics = target. generics . clone ( ) ;
535
562
let mut rewritten_params = Vec :: new ( ) ;
536
563
let mut rewritten_restrictions = Vec :: new ( ) ;
564
+ let collector_id = match info. config . collector_id {
565
+ Some ( ref id) => id. clone ( ) ,
566
+ None => parse_quote ! ( Id )
567
+ } ;
537
568
for param in & mut generics. params {
538
569
let rewritten_param: GenericArgument ;
539
570
match param {
540
571
GenericParam :: Type ( ref mut type_param) => {
541
572
let original_bounds = type_param. bounds . iter ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
542
- type_param. bounds . push ( parse_quote ! ( :: zerogc:: GcErase <' min, S >) ) ;
573
+ type_param. bounds . push ( parse_quote ! ( :: zerogc:: GcErase <' min, #collector_id >) ) ;
543
574
type_param. bounds . push ( parse_quote ! ( ' min) ) ;
544
575
let param_name = & type_param. ident ;
545
- let rewritten_type: Type = parse_quote ! ( <#param_name as :: zerogc:: GcErase <' min, S >>:: Erased ) ;
576
+ let rewritten_type: Type = parse_quote ! ( <#param_name as :: zerogc:: GcErase <' min, #collector_id >>:: Erased ) ;
546
577
rewritten_restrictions. push ( WherePredicate :: Type ( PredicateType {
547
578
lifetimes : None ,
548
579
bounded_ty : rewritten_type. clone ( ) ,
@@ -569,21 +600,44 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
569
600
}
570
601
rewritten_params. push ( rewritten_param) ;
571
602
}
603
+ let mut field_types = Vec :: new ( ) ;
604
+ match target. data {
605
+ Data :: Struct ( ref s) => {
606
+ for f in & s. fields {
607
+ field_types. push ( f. ty . clone ( ) ) ;
608
+ }
609
+ } ,
610
+ Data :: Enum ( ref e) => {
611
+ for variant in & e. variants {
612
+ for f in & variant. fields {
613
+ field_types. push ( f. ty . clone ( ) ) ;
614
+ }
615
+ }
616
+ } ,
617
+ Data :: Union ( _) => {
618
+ return Err ( Error :: new ( target. ident . span ( ) , "Unable to derive(GcErase) for unions" ) )
619
+ }
620
+ }
572
621
let mut impl_generics = generics. clone ( ) ;
573
622
impl_generics. params . push ( GenericParam :: Lifetime ( parse_quote ! ( ' min) ) ) ;
574
- impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( S : :: zerogc:: CollectorId ) ) ) ;
623
+ if info. config . collector_id . is_none ( ) {
624
+ impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( Id : :: zerogc:: CollectorId ) ) ) ;
625
+ }
575
626
impl_generics. make_where_clause ( ) . predicates . extend ( rewritten_restrictions) ;
576
627
let ( _, ty_generics, _) = generics. split_for_impl ( ) ;
577
628
let ( impl_generics, _, where_clause) = impl_generics. split_for_impl ( ) ;
578
- :: proc_macro:: Diagnostic :: spanned (
579
- :: proc_macro:: Span :: call_site ( ) ,
580
- :: proc_macro:: Level :: Warning ,
581
- "derive(GcErase) doesn't currently verify the correctness of its fields"
582
- ) . emit ( ) ;
629
+ let assert_erase = field_types. iter ( ) . map ( |field_type| {
630
+ let span = field_type. span ( ) ;
631
+ quote_spanned ! ( span => <#field_type as :: zerogc:: GcErase <' min, #collector_id>>:: assert_erase( ) ; )
632
+ } ) . collect :: < Vec < _ > > ( ) ;
583
633
Ok ( quote ! {
584
- unsafe impl #impl_generics :: zerogc:: GcErase <' min, S >
634
+ unsafe impl #impl_generics :: zerogc:: GcErase <' min, #collector_id >
585
635
for #name #ty_generics #where_clause {
586
636
type Erased = #name:: <#( #rewritten_params) , * >;
637
+
638
+ fn assert_erase( ) {
639
+ #( #assert_erase) *
640
+ }
587
641
}
588
642
} )
589
643
}
@@ -620,7 +674,13 @@ fn impl_rebrand_nop(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStre
620
674
}
621
675
let mut impl_generics = generics. clone ( ) ;
622
676
impl_generics. params . push ( GenericParam :: Lifetime ( parse_quote ! ( ' new_gc) ) ) ;
623
- impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( S : :: zerogc:: CollectorId ) ) ) ;
677
+ let collector_id = match info. config . collector_id {
678
+ Some ( ref id) => id. clone ( ) ,
679
+ None => {
680
+ impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( Id : :: zerogc:: CollectorId ) ) ) ;
681
+ parse_quote ! ( Id )
682
+ }
683
+ } ;
624
684
// Require that `Self: NullTrace`
625
685
impl_generics. make_where_clause ( ) . predicates . push ( WherePredicate :: Type ( PredicateType {
626
686
lifetimes : None ,
@@ -630,14 +690,8 @@ fn impl_rebrand_nop(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStre
630
690
} ) ) ;
631
691
let ( _, ty_generics, _) = generics. split_for_impl ( ) ;
632
692
let ( impl_generics, _, where_clause) = impl_generics. split_for_impl ( ) ;
633
- :: proc_macro:: Diagnostic :: spanned (
634
- :: proc_macro:: Span :: call_site ( ) ,
635
- :: proc_macro:: Level :: Note ,
636
- // We know this is safe because we know that `Self: NullTrace`
637
- "derive(GcRebrand) is safe for NullTrace, unlike standard implementation"
638
- ) . emit ( ) ;
639
693
Ok ( quote ! {
640
- unsafe impl #impl_generics :: zerogc:: GcRebrand <' new_gc, S >
694
+ unsafe impl #impl_generics :: zerogc:: GcRebrand <' new_gc, #collector_id >
641
695
for #name #ty_generics #where_clause {
642
696
// We can pass-through because we are NullTrace
643
697
type Branded = Self ;
@@ -649,14 +703,18 @@ fn impl_rebrand(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream,
649
703
let mut generics: Generics = target. generics . clone ( ) ;
650
704
let mut rewritten_params = Vec :: new ( ) ;
651
705
let mut rewritten_restrictions = Vec :: new ( ) ;
706
+ let collector_id = match info. config . collector_id {
707
+ Some ( ref id) => id. clone ( ) ,
708
+ None => parse_quote ! ( Id )
709
+ } ;
652
710
for param in & mut generics. params {
653
711
let rewritten_param: GenericArgument ;
654
712
match param {
655
713
GenericParam :: Type ( ref mut type_param) => {
656
714
let original_bounds = type_param. bounds . iter ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
657
- type_param. bounds . push ( parse_quote ! ( :: zerogc:: GcRebrand <' new_gc, S >) ) ;
715
+ type_param. bounds . push ( parse_quote ! ( :: zerogc:: GcRebrand <' new_gc, #collector_id >) ) ;
658
716
let param_name = & type_param. ident ;
659
- let rewritten_type: Type = parse_quote ! ( <#param_name as :: zerogc:: GcRebrand <' new_gc, S >>:: Branded ) ;
717
+ let rewritten_type: Type = parse_quote ! ( <#param_name as :: zerogc:: GcRebrand <' new_gc, #collector_id >>:: Branded ) ;
660
718
rewritten_restrictions. push ( WherePredicate :: Type ( PredicateType {
661
719
lifetimes : None ,
662
720
bounded_ty : rewritten_type. clone ( ) ,
@@ -683,29 +741,52 @@ fn impl_rebrand(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream,
683
741
}
684
742
rewritten_params. push ( rewritten_param) ;
685
743
}
744
+ let mut field_types = Vec :: new ( ) ;
745
+ match target. data {
746
+ Data :: Struct ( ref s) => {
747
+ for f in & s. fields {
748
+ field_types. push ( f. ty . clone ( ) ) ;
749
+ }
750
+ } ,
751
+ Data :: Enum ( ref e) => {
752
+ for variant in & e. variants {
753
+ for f in & variant. fields {
754
+ field_types. push ( f. ty . clone ( ) ) ;
755
+ }
756
+ }
757
+ } ,
758
+ Data :: Union ( _) => {
759
+ return Err ( Error :: new ( target. ident . span ( ) , "Unable to derive(GcErase) for unions" ) )
760
+ }
761
+ }
686
762
let mut impl_generics = generics. clone ( ) ;
687
763
impl_generics. params . push ( GenericParam :: Lifetime ( parse_quote ! ( ' new_gc) ) ) ;
688
- impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( S : :: zerogc:: CollectorId ) ) ) ;
764
+ if info. config . collector_id . is_none ( ) {
765
+ impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( Id : :: zerogc:: CollectorId ) ) ) ;
766
+ }
767
+ let assert_rebrand = field_types. iter ( ) . map ( |field_type| {
768
+ let span = field_type. span ( ) ;
769
+ quote_spanned ! ( span => <#field_type as :: zerogc:: GcRebrand <' new_gc, #collector_id>>:: assert_rebrand( ) ; )
770
+ } ) . collect :: < Vec < _ > > ( ) ;
689
771
impl_generics. make_where_clause ( ) . predicates . extend ( rewritten_restrictions) ;
690
772
let ( _, ty_generics, _) = generics. split_for_impl ( ) ;
691
773
let ( impl_generics, _, where_clause) = impl_generics. split_for_impl ( ) ;
692
- :: proc_macro:: Diagnostic :: spanned (
693
- :: proc_macro:: Span :: call_site ( ) ,
694
- :: proc_macro:: Level :: Warning ,
695
- "derive(GcRebrand) doesn't currently verify the correctness of its fields"
696
- ) . emit ( ) ;
697
774
Ok ( quote ! {
698
- unsafe impl #impl_generics :: zerogc:: GcRebrand <' new_gc, S >
775
+ unsafe impl #impl_generics :: zerogc:: GcRebrand <' new_gc, #collector_id >
699
776
for #name #ty_generics #where_clause {
700
777
type Branded = #name:: <#( #rewritten_params) , * >;
778
+
779
+ fn assert_rebrand( ) {
780
+ #( #assert_rebrand) *
781
+ }
701
782
}
702
783
} )
703
784
}
704
785
fn impl_trace ( target : & DeriveInput , info : & GcTypeInfo ) -> Result < TokenStream , Error > {
705
786
let name = & target. ident ;
706
787
let generics = add_trait_bounds_except (
707
788
& target. generics , parse_quote ! ( zerogc:: Trace ) ,
708
- & info. config . ignore_params
789
+ & info. config . ignore_params , None
709
790
) ?;
710
791
let ( impl_generics, ty_generics, where_clause) = generics. split_for_impl ( ) ;
711
792
let field_types: Vec < & Type > ;
@@ -787,9 +868,17 @@ fn impl_trace(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
787
868
}
788
869
fn impl_gc_safe ( target : & DeriveInput , info : & GcTypeInfo ) -> Result < TokenStream , Error > {
789
870
let name = & target. ident ;
871
+ let collector_id = & info. config . collector_id ;
790
872
let generics = add_trait_bounds_except (
791
873
& target. generics , parse_quote ! ( zerogc:: GcSafe ) ,
792
- & info. config . ignore_params
874
+ & info. config . ignore_params ,
875
+ Some ( & mut |other : & Ident | {
876
+ if let Some ( ref collector_id) = * collector_id {
877
+ other == collector_id // -> ignore collector_id for GcSafe
878
+ } else {
879
+ false
880
+ }
881
+ } )
793
882
) ?;
794
883
let ( impl_generics, ty_generics, where_clause) = generics. split_for_impl ( ) ;
795
884
let field_types: Vec < & Type > = match target. data {
@@ -859,7 +948,7 @@ fn impl_nop_trace(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream
859
948
let name = & target. ident ;
860
949
let generics = add_trait_bounds_except (
861
950
& target. generics , parse_quote ! ( zerogc:: Trace ) ,
862
- & info. config . ignore_params
951
+ & info. config . ignore_params , None
863
952
) ?;
864
953
let ( impl_generics, ty_generics, where_clause) = generics. split_for_impl ( ) ;
865
954
let field_types: Vec < & Type > ;
@@ -914,12 +1003,18 @@ fn impl_nop_trace(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream
914
1003
915
1004
fn add_trait_bounds_except (
916
1005
generics : & Generics , bound : TypeParamBound ,
917
- ignored_params : & HashSet < Ident >
1006
+ ignored_params : & HashSet < Ident > ,
1007
+ mut extra_ignore : Option < & mut dyn FnMut ( & Ident ) -> bool >
918
1008
) -> Result < Generics , Error > {
919
1009
let mut actually_ignored_args = HashSet :: < Ident > :: new ( ) ;
920
1010
let generics = add_trait_bounds (
921
1011
& generics, bound,
922
1012
& mut |param : & TypeParam | {
1013
+ if let Some ( ref mut extra) = extra_ignore {
1014
+ if extra ( & param. ident ) {
1015
+ return true ; // ignore (but don't add to set)
1016
+ }
1017
+ }
923
1018
if ignored_params. contains ( & param. ident ) {
924
1019
actually_ignored_args. insert ( param. ident . clone ( ) ) ;
925
1020
true
0 commit comments