@@ -97,6 +97,7 @@ impl Parse for GcFieldAttrs {
97
97
98
98
struct GcTypeAttrs {
99
99
is_copy : bool ,
100
+ nop_trace : bool ,
100
101
ignore_params : HashSet < Ident >
101
102
}
102
103
impl GcTypeAttrs {
@@ -114,6 +115,7 @@ impl Default for GcTypeAttrs {
114
115
fn default ( ) -> Self {
115
116
GcTypeAttrs {
116
117
is_copy : false ,
118
+ nop_trace : false ,
117
119
ignore_params : HashSet :: new ( )
118
120
}
119
121
}
@@ -139,6 +141,20 @@ impl Parse for GcTypeAttrs {
139
141
) )
140
142
}
141
143
result. is_copy = true ;
144
+ } else if meta. path ( ) . is_ident ( "nop_trace" ) {
145
+ if !matches ! ( meta, Meta :: Path ( _) ) {
146
+ return Err ( Error :: new (
147
+ meta. span ( ) ,
148
+ "Malformed attribute for #[zerogc(nop_trace)]"
149
+ ) )
150
+ }
151
+ if result. nop_trace {
152
+ return Err ( Error :: new (
153
+ meta. span ( ) ,
154
+ "Duplicate flags: #[zerogc(nop_trace)]"
155
+ ) )
156
+ }
157
+ result. nop_trace = true ;
142
158
} else if meta. path ( ) . is_ident ( "ignore_params" ) {
143
159
if !result. ignore_params . is_empty ( ) {
144
160
return Err ( Error :: new (
@@ -193,30 +209,32 @@ impl Parse for GcTypeAttrs {
193
209
#[ proc_macro_derive( Trace , attributes( zerogc) ) ]
194
210
pub fn derive_trace ( input : proc_macro:: TokenStream ) -> proc_macro:: TokenStream {
195
211
let input = parse_macro_input ! ( input as DeriveInput ) ;
196
- let attrs = match GcTypeAttrs :: find ( & * input. attrs ) {
197
- Ok ( attrs) => attrs,
198
- Err ( e) => return e. to_compile_error ( ) . into ( )
212
+ let res = From :: from ( impl_derive_trace ( & input)
213
+ . unwrap_or_else ( |e| e. to_compile_error ( ) ) ) ;
214
+ debug_derive (
215
+ "derive(Trace)" ,
216
+ & format_args ! ( "#[derive(Trace) for {}" , input. ident) ,
217
+ & res
218
+ ) ;
219
+ res
220
+ }
221
+
222
+ fn impl_derive_trace ( input : & DeriveInput ) -> Result < TokenStream , syn:: Error > {
223
+ let attrs = GcTypeAttrs :: find ( & * input. attrs ) ?;
224
+ let trace_impl = if attrs. nop_trace {
225
+ impl_nop_trace ( & input, & attrs) ?
226
+ } else {
227
+ impl_trace ( & input, & attrs) ?
199
228
} ;
200
- let trace_impl = impl_trace ( & input, & attrs)
201
- . unwrap_or_else ( |e| e. to_compile_error ( ) ) ;
202
- let brand_impl = impl_brand ( & input)
203
- . unwrap_or_else ( |e| e. to_compile_error ( ) ) ;
204
- let gc_safe_impl = impl_gc_safe ( & input, & attrs)
205
- . unwrap_or_else ( |e| e. to_compile_error ( ) ) ;
206
- let extra_impls = impl_extras ( & input)
207
- . unwrap_or_else ( |e| e. to_compile_error ( ) ) ;
208
- let t = From :: from ( quote ! {
229
+ let brand_impl = impl_brand ( & input) ?;
230
+ let gc_safe_impl = impl_gc_safe ( & input, & attrs) ?;
231
+ let extra_impls = impl_extras ( & input) ?;
232
+ Ok ( quote ! {
209
233
#trace_impl
210
234
#brand_impl
211
235
#gc_safe_impl
212
236
#extra_impls
213
- } ) ;
214
- debug_derive (
215
- "derive(Trace)" ,
216
- & format_args ! ( "#[derive(Trace) for {}" , input. ident) ,
217
- & t
218
- ) ;
219
- t
237
+ } )
220
238
}
221
239
222
240
fn trace_fields ( fields : & Fields , access_ref : & mut dyn FnMut ( Member ) -> TokenStream ) -> TokenStream {
@@ -550,6 +568,62 @@ fn impl_gc_safe(target: &DeriveInput, attrs: &GcTypeAttrs) -> Result<TokenStream
550
568
} )
551
569
}
552
570
571
+
572
+ fn impl_nop_trace ( target : & DeriveInput , attrs : & GcTypeAttrs ) -> Result < TokenStream , Error > {
573
+ let name = & target. ident ;
574
+ let generics = add_trait_bounds_except (
575
+ & target. generics , parse_quote ! ( zerogc:: Trace ) ,
576
+ & attrs. ignore_params
577
+ ) ?;
578
+ let ( impl_generics, ty_generics, where_clause) = generics. split_for_impl ( ) ;
579
+ let field_types: Vec < & Type > ;
580
+ match target. data {
581
+ Data :: Struct ( ref data) => {
582
+ field_types = data. fields . iter ( ) . map ( |f| & f. ty ) . collect ( ) ;
583
+ } ,
584
+ Data :: Enum ( ref data) => {
585
+ field_types = data. variants . iter ( )
586
+ . flat_map ( |var| var. fields . iter ( ) . map ( |f| & f. ty ) )
587
+ . collect ( ) ;
588
+ } ,
589
+ Data :: Union ( _) => {
590
+ return Err ( Error :: new (
591
+ name. span ( ) ,
592
+ "Unions can't #[derive(Trace)]"
593
+ ) ) ;
594
+ } ,
595
+ }
596
+ let const_assertions = field_types. iter ( )
597
+ . map ( |& t| {
598
+ let ty_span = t. span ( ) ;
599
+ quote_spanned ! { ty_span =>
600
+ #[ allow( clippy:: eq_op) ]
601
+ const _: [ ( ) ; 0 - !{
602
+ const ASSERT : bool = !<#t as Trace >:: NEEDS_TRACE ;
603
+ ASSERT
604
+ } as usize ] = [ ] ;
605
+ }
606
+ } ) . collect :: < Vec < _ > > ( ) ;
607
+ Ok ( quote ! {
608
+ #( #const_assertions) *
609
+ unsafe impl #impl_generics :: zerogc:: Trace for #name #ty_generics #where_clause {
610
+ const NEEDS_TRACE : bool = false ;
611
+
612
+ #[ inline( always) ] // NOP
613
+ fn visit<V : :: zerogc:: GcVisitor >( & mut self , #[ allow( unused) ] visitor: & mut V ) -> Result <( ) , V :: Err > {
614
+ Ok ( ( ) )
615
+ }
616
+ }
617
+ unsafe impl #impl_generics :: zerogc:: TraceImmutable for #name #ty_generics #where_clause {
618
+ #[ inline( always) ] // NOP
619
+ fn visit_immutable<V : :: zerogc:: GcVisitor >( & self , #[ allow( unused) ] visitor: & mut V ) -> Result <( ) , V :: Err > {
620
+ Ok ( ( ) )
621
+ }
622
+ }
623
+ unsafe impl #impl_generics :: zerogc:: NullTrace for #name #ty_generics #where_clause { }
624
+ } )
625
+ }
626
+
553
627
fn add_trait_bounds_except (
554
628
generics : & Generics , bound : TypeParamBound ,
555
629
ignored_params : & HashSet < Ident >
0 commit comments