5
5
extern crate proc_macro;
6
6
7
7
use quote:: { quote, quote_spanned} ;
8
- use syn:: { parse_macro_input, parenthesized, parse_quote, DeriveInput , Data , Error , Generics , GenericParam , TypeParamBound , Fields , Member , Index , Type , GenericArgument , Attribute , PathArguments , Meta , TypeParam , WherePredicate , PredicateType , Token , Lifetime , NestedMeta , Lit , PredicateLifetime } ;
8
+ use syn:: { parse_macro_input, parenthesized, parse_quote, DeriveInput , Data , Error , Generics , GenericParam , TypeParamBound , Fields , Member , Index , Type , GenericArgument , Attribute , PathArguments , Meta , TypeParam , WherePredicate , PredicateType , Token , Lifetime , NestedMeta , Lit } ;
9
9
use proc_macro2:: { Ident , TokenStream , Span } ;
10
10
use syn:: spanned:: Spanned ;
11
11
use syn:: parse:: { ParseStream , Parse } ;
@@ -328,8 +328,16 @@ fn impl_derive_trace(input: &DeriveInput) -> Result<TokenStream, syn::Error> {
328
328
} else {
329
329
impl_trace ( & input, & info) ?
330
330
} ;
331
- let rebrand_impl = impl_rebrand ( & input, & info) ?;
332
- let erase_impl = impl_erase ( & input, & info) ?;
331
+ let rebrand_impl = if info. config . nop_trace {
332
+ impl_rebrand_nop ( & input, & info) ?
333
+ } else {
334
+ impl_rebrand ( & input, & info) ?
335
+ } ;
336
+ let erase_impl = if info. config . nop_trace {
337
+ impl_erase_nop ( & input, & info) ?
338
+ } else {
339
+ impl_erase ( & input, & info) ?
340
+ } ;
333
341
let gc_safe_impl = impl_gc_safe ( & input, & info) ?;
334
342
let extra_impls = impl_extras ( & input, & info) ?;
335
343
Ok ( quote ! {
@@ -465,6 +473,62 @@ fn impl_extras(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, E
465
473
} )
466
474
}
467
475
476
+
477
+ fn impl_erase_nop ( target : & DeriveInput , info : & GcTypeInfo ) -> Result < TokenStream , Error > {
478
+ let name = & target. ident ;
479
+ let mut generics: Generics = target. generics . clone ( ) ;
480
+ for param in & mut generics. params {
481
+ match param {
482
+ GenericParam :: Type ( ref mut type_param) => {
483
+ // Require all params are NullTrace
484
+ type_param. bounds . push ( parse_quote ! ( :: zerogc:: NullTrace ) ) ;
485
+ } ,
486
+ GenericParam :: Lifetime ( ref mut l) => {
487
+ if l. lifetime == info. config . gc_lifetime ( ) {
488
+ assert ! ( !info. config. ignored_lifetimes. contains( & l. lifetime) ) ;
489
+ return Err ( Error :: new (
490
+ l. lifetime . span ( ) ,
491
+ "Unexpected GC lifetime: Expected #[zerogc(nop_trace)] during #[derive(GcErase)]"
492
+ ) )
493
+ } else if info. config . ignored_lifetimes . contains ( & l. lifetime ) {
494
+ // Explicitly ignored is okay, as long as it outlives the `'min`
495
+ l. bounds . push ( parse_quote ! ( ' min) ) ;
496
+ } else {
497
+ return Err ( Error :: new (
498
+ l. span ( ) ,
499
+ "Lifetime must be explicitly ignored"
500
+ ) )
501
+ }
502
+ } ,
503
+ GenericParam :: Const ( _) => { }
504
+ }
505
+ }
506
+ let mut impl_generics = generics. clone ( ) ;
507
+ impl_generics. params . push ( GenericParam :: Lifetime ( parse_quote ! ( ' min) ) ) ;
508
+ impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( S : :: zerogc:: CollectorId ) ) ) ;
509
+ // Require that `Self: NullTrace`
510
+ impl_generics. make_where_clause ( ) . predicates . push ( WherePredicate :: Type ( PredicateType {
511
+ lifetimes : None ,
512
+ bounded_ty : parse_quote ! ( Self ) ,
513
+ bounds : parse_quote ! ( :: zerogc:: NullTrace ) ,
514
+ colon_token : Default :: default ( )
515
+ } ) ) ;
516
+ let ( _, ty_generics, _) = generics. split_for_impl ( ) ;
517
+ 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
+ Ok ( quote ! {
525
+ unsafe impl #impl_generics :: zerogc:: GcErase <' min, S >
526
+ for #name #ty_generics #where_clause {
527
+ // We can pass-through because we are NullTrace
528
+ type Erased = Self ;
529
+ }
530
+ } )
531
+ }
468
532
fn impl_erase ( target : & DeriveInput , info : & GcTypeInfo ) -> Result < TokenStream , Error > {
469
533
let name = & target. ident ;
470
534
let mut generics: Generics = target. generics . clone ( ) ;
@@ -475,10 +539,10 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
475
539
match param {
476
540
GenericParam :: Type ( ref mut type_param) => {
477
541
let original_bounds = type_param. bounds . iter ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
478
- type_param. bounds . push ( parse_quote ! ( :: zerogc:: GcErase <' max , S >) ) ;
479
- type_param. bounds . push ( parse_quote ! ( ' max ) ) ;
542
+ type_param. bounds . push ( parse_quote ! ( :: zerogc:: GcErase <' min , S >) ) ;
543
+ type_param. bounds . push ( parse_quote ! ( ' min ) ) ;
480
544
let param_name = & type_param. ident ;
481
- let rewritten_type: Type = parse_quote ! ( <#param_name as :: zerogc:: GcErase <' max , S >>:: Erased ) ;
545
+ let rewritten_type: Type = parse_quote ! ( <#param_name as :: zerogc:: GcErase <' min , S >>:: Erased ) ;
482
546
rewritten_restrictions. push ( WherePredicate :: Type ( PredicateType {
483
547
lifetimes : None ,
484
548
bounded_ty : rewritten_type. clone ( ) ,
@@ -491,19 +555,11 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
491
555
if l. lifetime == info. config . gc_lifetime ( ) {
492
556
rewritten_param = parse_quote ! ( ' static ) ;
493
557
assert ! ( !info. config. ignored_lifetimes. contains( & l. lifetime) ) ;
494
- } else if info. config . ignored_lifetimes . contains ( & l. lifetime ) {
495
- let lt = l. lifetime . clone ( ) ;
496
- rewritten_restrictions. push ( WherePredicate :: Lifetime ( PredicateLifetime {
497
- lifetime : parse_quote ! ( ' max) ,
498
- colon_token : Default :: default ( ) ,
499
- bounds : parse_quote ! ( #lt)
500
- } ) ) ;
501
- rewritten_param = GenericArgument :: Lifetime ( lt) ;
502
558
} else {
503
559
return Err ( Error :: new (
504
560
l. span ( ) ,
505
- "Unable to handle lifetime "
506
- ) ) ;
561
+ "Unless Self: NullTrace, derive(GcErase) is currently unable to handle lifetimes "
562
+ ) )
507
563
}
508
564
} ,
509
565
GenericParam :: Const ( ref param) => {
@@ -514,7 +570,7 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
514
570
rewritten_params. push ( rewritten_param) ;
515
571
}
516
572
let mut impl_generics = generics. clone ( ) ;
517
- impl_generics. params . push ( GenericParam :: Lifetime ( parse_quote ! ( ' max ) ) ) ;
573
+ impl_generics. params . push ( GenericParam :: Lifetime ( parse_quote ! ( ' min ) ) ) ;
518
574
impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( S : :: zerogc:: CollectorId ) ) ) ;
519
575
impl_generics. make_where_clause ( ) . predicates . extend ( rewritten_restrictions) ;
520
576
let ( _, ty_generics, _) = generics. split_for_impl ( ) ;
@@ -525,13 +581,69 @@ fn impl_erase(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream, Er
525
581
"derive(GcErase) doesn't currently verify the correctness of its fields"
526
582
) . emit ( ) ;
527
583
Ok ( quote ! {
528
- unsafe impl #impl_generics :: zerogc:: GcErase <' max , S >
584
+ unsafe impl #impl_generics :: zerogc:: GcErase <' min , S >
529
585
for #name #ty_generics #where_clause {
530
586
type Erased = #name:: <#( #rewritten_params) , * >;
531
587
}
532
588
} )
533
589
}
534
590
591
+
592
+ fn impl_rebrand_nop ( target : & DeriveInput , info : & GcTypeInfo ) -> Result < TokenStream , Error > {
593
+ let name = & target. ident ;
594
+ let mut generics: Generics = target. generics . clone ( ) ;
595
+ for param in & mut generics. params {
596
+ match param {
597
+ GenericParam :: Type ( ref mut type_param) => {
598
+ // Require all params are NullTrace
599
+ type_param. bounds . push ( parse_quote ! ( :: zerogc:: NullTrace ) ) ;
600
+ } ,
601
+ GenericParam :: Lifetime ( ref mut l) => {
602
+ if l. lifetime == info. config . gc_lifetime ( ) {
603
+ assert ! ( !info. config. ignored_lifetimes. contains( & l. lifetime) ) ;
604
+ return Err ( Error :: new (
605
+ l. lifetime . span ( ) ,
606
+ "Unexpected GC lifetime: Expected #[zerogc(nop_trace)] during #[derive(GcRebrand)]"
607
+ ) )
608
+ } else if info. config . ignored_lifetimes . contains ( & l. lifetime ) {
609
+ // Explicitly ignored is okay, as long as it outlives the `'new_gc`
610
+ l. bounds . push ( parse_quote ! ( ' new_gc) ) ;
611
+ } else {
612
+ return Err ( Error :: new (
613
+ l. span ( ) ,
614
+ "Lifetime must be explicitly ignored"
615
+ ) )
616
+ }
617
+ } ,
618
+ GenericParam :: Const ( _) => { }
619
+ }
620
+ }
621
+ let mut impl_generics = generics. clone ( ) ;
622
+ impl_generics. params . push ( GenericParam :: Lifetime ( parse_quote ! ( ' new_gc) ) ) ;
623
+ impl_generics. params . push ( GenericParam :: Type ( parse_quote ! ( S : :: zerogc:: CollectorId ) ) ) ;
624
+ // Require that `Self: NullTrace`
625
+ impl_generics. make_where_clause ( ) . predicates . push ( WherePredicate :: Type ( PredicateType {
626
+ lifetimes : None ,
627
+ bounded_ty : parse_quote ! ( Self ) ,
628
+ bounds : parse_quote ! ( :: zerogc:: NullTrace ) ,
629
+ colon_token : Default :: default ( )
630
+ } ) ) ;
631
+ let ( _, ty_generics, _) = generics. split_for_impl ( ) ;
632
+ 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
+ Ok ( quote ! {
640
+ unsafe impl #impl_generics :: zerogc:: GcRebrand <' new_gc, S >
641
+ for #name #ty_generics #where_clause {
642
+ // We can pass-through because we are NullTrace
643
+ type Branded = Self ;
644
+ }
645
+ } )
646
+ }
535
647
fn impl_rebrand ( target : & DeriveInput , info : & GcTypeInfo ) -> Result < TokenStream , Error > {
536
648
let name = & target. ident ;
537
649
let mut generics: Generics = target. generics . clone ( ) ;
@@ -557,13 +669,11 @@ fn impl_rebrand(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream,
557
669
if l. lifetime == info. config . gc_lifetime ( ) {
558
670
rewritten_param = parse_quote ! ( ' new_gc) ;
559
671
assert ! ( !info. config. ignored_lifetimes. contains( & l. lifetime) ) ;
560
- } else if info. config . ignored_lifetimes . contains ( & l. lifetime ) {
561
- rewritten_param = GenericArgument :: Lifetime ( l. lifetime . clone ( ) ) ;
562
672
} else {
563
673
return Err ( Error :: new (
564
674
l. span ( ) ,
565
- "Unable to handle lifetime "
566
- ) ) ;
675
+ "Unless Self: NullTrace, derive(GcRebrand) is currently unable to handle lifetimes "
676
+ ) )
567
677
}
568
678
} ,
569
679
GenericParam :: Const ( ref param) => {
@@ -769,6 +879,7 @@ fn impl_nop_trace(target: &DeriveInput, info: &GcTypeInfo) -> Result<TokenStream
769
879
) ) ;
770
880
} ,
771
881
}
882
+ // TODO: We should have some sort of const-assertion for this....
772
883
let trace_assertions = field_types. iter ( )
773
884
. map ( |& t| {
774
885
let ty_span = t. span ( ) ;
0 commit comments