1 | use proc_macro2::{Delimiter, Group, Span, TokenStream}; |
2 | use quote::{format_ident, quote, quote_spanned, ToTokens}; |
3 | use syn::{ |
4 | parse_quote, punctuated::Punctuated, token, visit_mut::VisitMut, Attribute, Data, DataEnum, |
5 | DeriveInput, Error, Field, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index, |
6 | Lifetime, LifetimeParam, Meta, Result, Token, Type, Variant, Visibility, WhereClause, |
7 | }; |
8 | |
9 | use super::{ |
10 | args::{parse_args, Args, ProjReplace, UnpinImpl}, |
11 | PIN, |
12 | }; |
13 | use crate::utils::{ |
14 | determine_lifetime_name, determine_visibility, insert_lifetime_and_bound, ReplaceReceiver, |
15 | SliceExt, Variants, |
16 | }; |
17 | |
18 | pub(super) fn parse_derive(input: TokenStream) -> Result<TokenStream> { |
19 | let mut input: DeriveInput = syn::parse2(input)?; |
20 | |
21 | let mut cx; |
22 | let mut generate = GenerateTokens::default(); |
23 | |
24 | let ident = &input.ident; |
25 | let ty_generics = input.generics.split_for_impl().1; |
26 | let self_ty = parse_quote!(#ident #ty_generics); |
27 | let mut visitor = ReplaceReceiver(&self_ty); |
28 | visitor.visit_generics_mut(&mut input.generics); |
29 | visitor.visit_data_mut(&mut input.data); |
30 | |
31 | match &input.data { |
32 | Data::Struct(data) => { |
33 | cx = Context::new(&input.attrs, &input.vis, ident, &mut input.generics, Struct)?; |
34 | parse_struct(&mut cx, &data.fields, &mut generate)?; |
35 | } |
36 | Data::Enum(data) => { |
37 | cx = Context::new(&input.attrs, &input.vis, ident, &mut input.generics, Enum)?; |
38 | parse_enum(&mut cx, data, &mut generate)?; |
39 | } |
40 | Data::Union(_) => { |
41 | bail!(input, "#[pin_project] attribute may only be used on structs or enums" ); |
42 | } |
43 | } |
44 | |
45 | Ok(generate.into_tokens(&cx)) |
46 | } |
47 | |
48 | #[derive(Default)] |
49 | struct GenerateTokens { |
50 | exposed: TokenStream, |
51 | scoped: TokenStream, |
52 | } |
53 | |
54 | impl GenerateTokens { |
55 | fn extend(&mut self, expose: bool, tokens: TokenStream) { |
56 | if expose { |
57 | self.exposed.extend(tokens); |
58 | } else { |
59 | self.scoped.extend(tokens); |
60 | } |
61 | } |
62 | |
63 | fn into_tokens(self, cx: &Context<'_>) -> TokenStream { |
64 | let mut tokens = self.exposed; |
65 | let scoped = self.scoped; |
66 | |
67 | let unpin_impl = make_unpin_impl(cx); |
68 | let drop_impl = make_drop_impl(cx); |
69 | let allowed_lints = global_allowed_lints(); |
70 | |
71 | tokens.extend(quote! { |
72 | // All items except projected types are generated inside a `const` scope. |
73 | // This makes it impossible for user code to refer to these types. |
74 | // However, this prevents Rustdoc from displaying docs for any |
75 | // of our types. In particular, users cannot see the |
76 | // automatically generated `Unpin` impl for the '__UnpinStruct' types |
77 | // |
78 | // Previously, we provided a flag to correctly document the |
79 | // automatically generated `Unpin` impl by using def-site hygiene, |
80 | // but it is now removed. |
81 | // |
82 | // Refs: |
83 | // - https://github.com/rust-lang/rust/issues/63281 |
84 | // - https://github.com/taiki-e/pin-project/pull/53#issuecomment-525906867 |
85 | // - https://github.com/taiki-e/pin-project/pull/70 |
86 | #allowed_lints |
87 | #[allow(unused_qualifications)] |
88 | #[allow(clippy::semicolon_if_nothing_returned)] |
89 | #[allow(clippy::use_self)] |
90 | #[allow(clippy::used_underscore_binding)] |
91 | const _: () = { |
92 | #[allow(unused_extern_crates)] |
93 | extern crate pin_project as _pin_project; |
94 | #scoped |
95 | #unpin_impl |
96 | #drop_impl |
97 | }; |
98 | }); |
99 | tokens |
100 | } |
101 | } |
102 | |
103 | /// Returns attributes that should be applied to all generated code. |
104 | fn global_allowed_lints() -> TokenStream { |
105 | quote! { |
106 | #[allow(box_pointers)] // This lint warns use of the `Box` type. |
107 | #[allow(deprecated)] |
108 | #[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993 |
109 | #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 |
110 | #[allow(unreachable_pub)] // This lint warns `pub` field in private struct. |
111 | #[allow(unused_tuple_struct_fields)] |
112 | // This lint warns of `clippy::*` generated by external macros. |
113 | // We allow this lint for compatibility with older compilers. |
114 | #[allow(clippy::unknown_clippy_lints)] |
115 | #[allow(clippy::pattern_type_mismatch)] |
116 | #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. |
117 | #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 |
118 | } |
119 | } |
120 | |
121 | /// Returns attributes used on projected types. |
122 | fn proj_allowed_lints(cx: &Context<'_>) -> (TokenStream, TokenStream, TokenStream) { |
123 | let large_enum_variant = if cx.kind == Enum { |
124 | Some(quote! { |
125 | #[allow(variant_size_differences)] |
126 | #[allow(clippy::large_enum_variant)] |
127 | }) |
128 | } else { |
129 | None |
130 | }; |
131 | let global_allowed_lints = global_allowed_lints(); |
132 | let proj_mut_allowed_lints = if cx.project { Some(&global_allowed_lints) } else { None }; |
133 | let proj_mut = quote! { |
134 | #proj_mut_allowed_lints |
135 | #[allow(dead_code)] // This lint warns unused fields/variants. |
136 | #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. |
137 | }; |
138 | let proj_ref_allowed_lints = if cx.project_ref { Some(&global_allowed_lints) } else { None }; |
139 | let proj_ref = quote! { |
140 | #proj_ref_allowed_lints |
141 | #[allow(dead_code)] // This lint warns unused fields/variants. |
142 | #[allow(clippy::ref_option_ref)] // This lint warns `&Option<&<ty>>`. |
143 | }; |
144 | let proj_own_allowed_lints = |
145 | if cx.project_replace.ident().is_some() { Some(&global_allowed_lints) } else { None }; |
146 | let proj_own = quote! { |
147 | #proj_own_allowed_lints |
148 | #[allow(dead_code)] // This lint warns unused fields/variants. |
149 | #large_enum_variant |
150 | }; |
151 | (proj_mut, proj_ref, proj_own) |
152 | } |
153 | |
154 | struct Context<'a> { |
155 | /// The original type. |
156 | orig: OriginalType<'a>, |
157 | /// The projected types. |
158 | proj: ProjectedType, |
159 | /// Types of the pinned fields. |
160 | pinned_fields: Vec<&'a Type>, |
161 | /// Kind of the original type: struct or enum |
162 | kind: TypeKind, |
163 | |
164 | /// `PinnedDrop` argument. |
165 | pinned_drop: Option<Span>, |
166 | /// `UnsafeUnpin` or `!Unpin` argument. |
167 | unpin_impl: UnpinImpl, |
168 | /// `project` argument. |
169 | project: bool, |
170 | /// `project_ref` argument. |
171 | project_ref: bool, |
172 | /// `project_replace [= <ident>]` argument. |
173 | project_replace: ProjReplace, |
174 | } |
175 | |
176 | impl<'a> Context<'a> { |
177 | fn new( |
178 | attrs: &'a [Attribute], |
179 | vis: &'a Visibility, |
180 | ident: &'a Ident, |
181 | generics: &'a mut Generics, |
182 | kind: TypeKind, |
183 | ) -> Result<Self> { |
184 | let Args { pinned_drop, unpin_impl, project, project_ref, project_replace } = |
185 | parse_args(attrs)?; |
186 | |
187 | if let Some(name) = [project.as_ref(), project_ref.as_ref(), project_replace.ident()] |
188 | .iter() |
189 | .filter_map(Option::as_ref) |
190 | .find(|name| **name == ident) |
191 | { |
192 | bail!(name, "name `{}` is the same as the original type name" , name); |
193 | } |
194 | |
195 | let mut lifetime_name = String::from("'pin" ); |
196 | determine_lifetime_name(&mut lifetime_name, generics); |
197 | let lifetime = Lifetime::new(&lifetime_name, Span::call_site()); |
198 | |
199 | let ty_generics = generics.split_for_impl().1; |
200 | let ty_generics_as_generics = parse_quote!(#ty_generics); |
201 | let mut proj_generics = generics.clone(); |
202 | let pred = insert_lifetime_and_bound( |
203 | &mut proj_generics, |
204 | lifetime.clone(), |
205 | &ty_generics_as_generics, |
206 | ident, |
207 | ); |
208 | let mut where_clause = generics.make_where_clause().clone(); |
209 | where_clause.predicates.push(pred); |
210 | |
211 | let own_ident = project_replace |
212 | .ident() |
213 | .cloned() |
214 | .unwrap_or_else(|| format_ident!("__{}ProjectionOwned" , ident)); |
215 | |
216 | Ok(Self { |
217 | kind, |
218 | pinned_drop, |
219 | unpin_impl, |
220 | project: project.is_some(), |
221 | project_ref: project_ref.is_some(), |
222 | project_replace, |
223 | proj: ProjectedType { |
224 | vis: determine_visibility(vis), |
225 | mut_ident: project.unwrap_or_else(|| format_ident!("__{}Projection" , ident)), |
226 | ref_ident: project_ref.unwrap_or_else(|| format_ident!("__{}ProjectionRef" , ident)), |
227 | own_ident, |
228 | lifetime, |
229 | generics: proj_generics, |
230 | where_clause, |
231 | }, |
232 | orig: OriginalType { attrs, vis, ident, generics }, |
233 | pinned_fields: Vec::new(), |
234 | }) |
235 | } |
236 | } |
237 | |
238 | #[derive(Copy, Clone, PartialEq)] |
239 | enum TypeKind { |
240 | Enum, |
241 | Struct, |
242 | } |
243 | |
244 | use TypeKind::{Enum, Struct}; |
245 | |
246 | struct OriginalType<'a> { |
247 | /// Attributes of the original type. |
248 | attrs: &'a [Attribute], |
249 | /// Visibility of the original type. |
250 | vis: &'a Visibility, |
251 | /// Name of the original type. |
252 | ident: &'a Ident, |
253 | /// Generics of the original type. |
254 | generics: &'a Generics, |
255 | } |
256 | |
257 | struct ProjectedType { |
258 | /// Visibility of the projected types. |
259 | vis: Visibility, |
260 | /// Name of the projected type returned by `project` method. |
261 | mut_ident: Ident, |
262 | /// Name of the projected type returned by `project_ref` method. |
263 | ref_ident: Ident, |
264 | /// Name of the projected type returned by `project_replace` method. |
265 | own_ident: Ident, |
266 | /// Lifetime on the generated projected types. |
267 | lifetime: Lifetime, |
268 | /// Generics of the projected types. |
269 | generics: Generics, |
270 | /// `where` clause of the projected types. This has an additional |
271 | /// bound generated by `insert_lifetime_and_bound` |
272 | where_clause: WhereClause, |
273 | } |
274 | |
275 | struct ProjectedVariants { |
276 | proj_variants: TokenStream, |
277 | proj_ref_variants: TokenStream, |
278 | proj_own_variants: TokenStream, |
279 | proj_arms: TokenStream, |
280 | proj_ref_arms: TokenStream, |
281 | proj_own_arms: TokenStream, |
282 | } |
283 | |
284 | #[derive(Default)] |
285 | struct ProjectedFields { |
286 | proj_pat: TokenStream, |
287 | proj_body: TokenStream, |
288 | proj_own_body: TokenStream, |
289 | proj_fields: TokenStream, |
290 | proj_ref_fields: TokenStream, |
291 | proj_own_fields: TokenStream, |
292 | } |
293 | |
294 | fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> { |
295 | if fields.is_empty() { |
296 | let msg = "#[pin_project] attribute may not be used on structs with zero fields" ; |
297 | if let Fields::Unit = fields { |
298 | bail!(ident, msg) |
299 | } |
300 | bail!(fields, msg) |
301 | } |
302 | Ok(()) |
303 | } |
304 | |
305 | fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> { |
306 | if variants.is_empty() { |
307 | return Err(Error::new( |
308 | brace_token.span.join(), |
309 | "#[pin_project] attribute may not be used on enums without variants" , |
310 | )); |
311 | } |
312 | let has_field = variants.iter().try_fold(false, |has_field, v| { |
313 | if let Some((_, e)) = &v.discriminant { |
314 | bail!(e, "#[pin_project] attribute may not be used on enums with discriminants" ); |
315 | } else if let Some(attr) = v.attrs.find(PIN) { |
316 | bail!(attr, "#[pin] attribute may only be used on fields of structs or variants" ); |
317 | } else if v.fields.is_empty() { |
318 | Ok(has_field) |
319 | } else { |
320 | Ok(true) |
321 | } |
322 | })?; |
323 | if has_field { |
324 | Ok(()) |
325 | } else { |
326 | bail!(variants, "#[pin_project] attribute may not be used on enums with zero fields" ); |
327 | } |
328 | } |
329 | |
330 | fn parse_struct<'a>( |
331 | cx: &mut Context<'a>, |
332 | fields: &'a Fields, |
333 | generate: &mut GenerateTokens, |
334 | ) -> Result<()> { |
335 | // Do this first for a better error message. |
336 | let packed_check = ensure_not_packed(&cx.orig, Some(fields))?; |
337 | |
338 | validate_struct(cx.orig.ident, fields)?; |
339 | |
340 | let ProjectedFields { |
341 | proj_pat, |
342 | proj_body, |
343 | proj_fields, |
344 | proj_ref_fields, |
345 | proj_own_fields, |
346 | proj_own_body, |
347 | } = match fields { |
348 | Fields::Named(_) => visit_fields(cx, None, fields, Delimiter::Brace)?, |
349 | Fields::Unnamed(_) => visit_fields(cx, None, fields, Delimiter::Parenthesis)?, |
350 | Fields::Unit => unreachable!(), |
351 | }; |
352 | |
353 | let proj_ident = &cx.proj.mut_ident; |
354 | let proj_ref_ident = &cx.proj.ref_ident; |
355 | let proj_own_ident = &cx.proj.own_ident; |
356 | let vis = &cx.proj.vis; |
357 | let mut orig_generics = cx.orig.generics.clone(); |
358 | let orig_where_clause = orig_generics.where_clause.take(); |
359 | let proj_generics = &cx.proj.generics; |
360 | let proj_where_clause = &cx.proj.where_clause; |
361 | |
362 | // For tuple structs, we need to generate `(T1, T2) where Foo: Bar` |
363 | // For non-tuple structs, we need to generate `where Foo: Bar { field1: T }` |
364 | let (where_clause_fields, where_clause_ref_fields, where_clause_own_fields) = match fields { |
365 | Fields::Named(_) => ( |
366 | quote!(#proj_where_clause #proj_fields), |
367 | quote!(#proj_where_clause #proj_ref_fields), |
368 | quote!(#orig_where_clause #proj_own_fields), |
369 | ), |
370 | Fields::Unnamed(_) => ( |
371 | quote!(#proj_fields #proj_where_clause;), |
372 | quote!(#proj_ref_fields #proj_where_clause;), |
373 | quote!(#proj_own_fields #orig_where_clause;), |
374 | ), |
375 | Fields::Unit => unreachable!(), |
376 | }; |
377 | |
378 | let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx); |
379 | generate.extend(cx.project, quote! { |
380 | #proj_attrs |
381 | #vis struct #proj_ident #proj_generics #where_clause_fields |
382 | }); |
383 | generate.extend(cx.project_ref, quote! { |
384 | #proj_ref_attrs |
385 | #vis struct #proj_ref_ident #proj_generics #where_clause_ref_fields |
386 | }); |
387 | if cx.project_replace.span().is_some() { |
388 | generate.extend(cx.project_replace.ident().is_some(), quote! { |
389 | #proj_own_attrs |
390 | #vis struct #proj_own_ident #orig_generics #where_clause_own_fields |
391 | }); |
392 | } |
393 | |
394 | let proj_mut_body = quote! { |
395 | let Self #proj_pat = self.get_unchecked_mut(); |
396 | #proj_ident #proj_body |
397 | }; |
398 | let proj_ref_body = quote! { |
399 | let Self #proj_pat = self.get_ref(); |
400 | #proj_ref_ident #proj_body |
401 | }; |
402 | let proj_own_body = quote! { |
403 | let Self #proj_pat = &mut *__self_ptr; |
404 | #proj_own_body |
405 | }; |
406 | generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body)); |
407 | |
408 | generate.extend(false, packed_check); |
409 | Ok(()) |
410 | } |
411 | |
412 | fn parse_enum<'a>( |
413 | cx: &mut Context<'a>, |
414 | DataEnum { brace_token, variants, .. }: &'a DataEnum, |
415 | generate: &mut GenerateTokens, |
416 | ) -> Result<()> { |
417 | if let ProjReplace::Unnamed { span } = &cx.project_replace { |
418 | return Err(Error::new( |
419 | *span, |
420 | "`project_replace` argument requires a value when used on enums" , |
421 | )); |
422 | } |
423 | |
424 | // #[repr(packed)] cannot be apply on enums and will be rejected by rustc. |
425 | // However, we should not rely on the behavior of rustc that rejects this. |
426 | // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001 |
427 | // |
428 | // Do this first for a better error message. |
429 | ensure_not_packed(&cx.orig, None)?; |
430 | |
431 | validate_enum(*brace_token, variants)?; |
432 | |
433 | let ProjectedVariants { |
434 | proj_variants, |
435 | proj_ref_variants, |
436 | proj_own_variants, |
437 | proj_arms, |
438 | proj_ref_arms, |
439 | proj_own_arms, |
440 | } = visit_variants(cx, variants)?; |
441 | |
442 | let proj_ident = &cx.proj.mut_ident; |
443 | let proj_ref_ident = &cx.proj.ref_ident; |
444 | let proj_own_ident = &cx.proj.own_ident; |
445 | let vis = &cx.proj.vis; |
446 | let mut orig_generics = cx.orig.generics.clone(); |
447 | let orig_where_clause = orig_generics.where_clause.take(); |
448 | let proj_generics = &cx.proj.generics; |
449 | let proj_where_clause = &cx.proj.where_clause; |
450 | |
451 | let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx); |
452 | if cx.project { |
453 | generate.extend(true, quote! { |
454 | #proj_attrs |
455 | #vis enum #proj_ident #proj_generics #proj_where_clause { |
456 | #proj_variants |
457 | } |
458 | }); |
459 | } |
460 | if cx.project_ref { |
461 | generate.extend(true, quote! { |
462 | #proj_ref_attrs |
463 | #vis enum #proj_ref_ident #proj_generics #proj_where_clause { |
464 | #proj_ref_variants |
465 | } |
466 | }); |
467 | } |
468 | if cx.project_replace.ident().is_some() { |
469 | generate.extend(true, quote! { |
470 | #proj_own_attrs |
471 | #vis enum #proj_own_ident #orig_generics #orig_where_clause { |
472 | #proj_own_variants |
473 | } |
474 | }); |
475 | } |
476 | |
477 | let proj_mut_body = quote! { |
478 | match self.get_unchecked_mut() { |
479 | #proj_arms |
480 | } |
481 | }; |
482 | let proj_ref_body = quote! { |
483 | match self.get_ref() { |
484 | #proj_ref_arms |
485 | } |
486 | }; |
487 | let proj_own_body = quote! { |
488 | match &mut *__self_ptr { |
489 | #proj_own_arms |
490 | } |
491 | }; |
492 | generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body)); |
493 | |
494 | Ok(()) |
495 | } |
496 | |
497 | fn visit_variants<'a>(cx: &mut Context<'a>, variants: &'a Variants) -> Result<ProjectedVariants> { |
498 | let mut proj_variants = TokenStream::new(); |
499 | let mut proj_ref_variants = TokenStream::new(); |
500 | let mut proj_own_variants = TokenStream::new(); |
501 | let mut proj_arms = TokenStream::new(); |
502 | let mut proj_ref_arms = TokenStream::new(); |
503 | let mut proj_own_arms = TokenStream::new(); |
504 | |
505 | for Variant { ident, fields, .. } in variants { |
506 | let ProjectedFields { |
507 | proj_pat, |
508 | proj_body, |
509 | proj_fields, |
510 | proj_ref_fields, |
511 | proj_own_fields, |
512 | proj_own_body, |
513 | } = match fields { |
514 | Fields::Named(_) => visit_fields(cx, Some(ident), fields, Delimiter::Brace)?, |
515 | Fields::Unnamed(_) => visit_fields(cx, Some(ident), fields, Delimiter::Parenthesis)?, |
516 | Fields::Unit => ProjectedFields { |
517 | proj_own_body: proj_own_body(cx, Some(ident), None, &[]), |
518 | ..Default::default() |
519 | }, |
520 | }; |
521 | |
522 | let proj_ident = &cx.proj.mut_ident; |
523 | let proj_ref_ident = &cx.proj.ref_ident; |
524 | proj_variants.extend(quote! { |
525 | #ident #proj_fields, |
526 | }); |
527 | proj_ref_variants.extend(quote! { |
528 | #ident #proj_ref_fields, |
529 | }); |
530 | proj_own_variants.extend(quote! { |
531 | #ident #proj_own_fields, |
532 | }); |
533 | proj_arms.extend(quote! { |
534 | Self::#ident #proj_pat => #proj_ident::#ident #proj_body, |
535 | }); |
536 | proj_ref_arms.extend(quote! { |
537 | Self::#ident #proj_pat => #proj_ref_ident::#ident #proj_body, |
538 | }); |
539 | proj_own_arms.extend(quote! { |
540 | Self::#ident #proj_pat => { #proj_own_body } |
541 | }); |
542 | } |
543 | |
544 | Ok(ProjectedVariants { |
545 | proj_variants, |
546 | proj_ref_variants, |
547 | proj_own_variants, |
548 | proj_arms, |
549 | proj_ref_arms, |
550 | proj_own_arms, |
551 | }) |
552 | } |
553 | |
554 | fn visit_fields<'a>( |
555 | cx: &mut Context<'a>, |
556 | variant_ident: Option<&Ident>, |
557 | fields: &'a Fields, |
558 | delim: Delimiter, |
559 | ) -> Result<ProjectedFields> { |
560 | fn surround(delim: Delimiter, tokens: TokenStream) -> TokenStream { |
561 | Group::new(delim, tokens).into_token_stream() |
562 | } |
563 | |
564 | let mut proj_pat = TokenStream::new(); |
565 | let mut proj_body = TokenStream::new(); |
566 | let mut proj_fields = TokenStream::new(); |
567 | let mut proj_ref_fields = TokenStream::new(); |
568 | let mut proj_own_fields = TokenStream::new(); |
569 | let mut proj_move = TokenStream::new(); |
570 | let mut pinned_bindings = Vec::with_capacity(fields.len()); |
571 | |
572 | for (i, Field { attrs, vis, ident, colon_token, ty, mutability: _ }) in |
573 | fields.iter().enumerate() |
574 | { |
575 | let binding = ident.clone().unwrap_or_else(|| format_ident!("_{}" , i)); |
576 | proj_pat.extend(quote!(#binding,)); |
577 | let lifetime = &cx.proj.lifetime; |
578 | if attrs.position_exact(PIN)?.is_some() { |
579 | proj_fields.extend(quote! { |
580 | #vis #ident #colon_token ::pin_project::__private::Pin<lifetime mut (#ty)>, |
581 | }); |
582 | proj_ref_fields.extend(quote! { |
583 | #vis #ident #colon_token ::pin_project::__private::Pin<lifetime (#ty)>, |
584 | }); |
585 | proj_own_fields.extend(quote! { |
586 | #vis #ident #colon_token ::pin_project::__private::PhantomData<#ty>, |
587 | }); |
588 | proj_body.extend(quote! { |
589 | #ident #colon_token _pin_project::__private::Pin::new_unchecked(#binding), |
590 | }); |
591 | proj_move.extend(quote! { |
592 | #ident #colon_token _pin_project::__private::PhantomData, |
593 | }); |
594 | |
595 | cx.pinned_fields.push(ty); |
596 | pinned_bindings.push(binding); |
597 | } else { |
598 | proj_fields.extend(quote! { |
599 | #vis #ident #colon_token lifetime mut (#ty), |
600 | }); |
601 | proj_ref_fields.extend(quote! { |
602 | #vis #ident #colon_token lifetime (#ty), |
603 | }); |
604 | proj_own_fields.extend(quote! { |
605 | #vis #ident #colon_token #ty, |
606 | }); |
607 | proj_body.extend(quote! { |
608 | #binding, |
609 | }); |
610 | proj_move.extend(quote! { |
611 | #ident #colon_token _pin_project::__private::ptr::read(#binding), |
612 | }); |
613 | } |
614 | } |
615 | |
616 | let proj_pat = surround(delim, proj_pat); |
617 | let proj_body = surround(delim, proj_body); |
618 | let proj_fields = surround(delim, proj_fields); |
619 | let proj_ref_fields = surround(delim, proj_ref_fields); |
620 | let proj_own_fields = surround(delim, proj_own_fields); |
621 | |
622 | let proj_move = Group::new(delim, proj_move); |
623 | let proj_own_body = proj_own_body(cx, variant_ident, Some(&proj_move), &pinned_bindings); |
624 | |
625 | Ok(ProjectedFields { |
626 | proj_pat, |
627 | proj_body, |
628 | proj_own_body, |
629 | proj_fields, |
630 | proj_ref_fields, |
631 | proj_own_fields, |
632 | }) |
633 | } |
634 | |
635 | /// Generates the processing that `project_replace` does for the struct or each variant. |
636 | /// |
637 | /// Note: `pinned_fields` must be in declaration order. |
638 | fn proj_own_body( |
639 | cx: &Context<'_>, |
640 | variant_ident: Option<&Ident>, |
641 | proj_move: Option<&Group>, |
642 | pinned_fields: &[Ident], |
643 | ) -> TokenStream { |
644 | let ident = &cx.proj.own_ident; |
645 | let proj_own = match variant_ident { |
646 | Some(variant_ident) => quote!(#ident::#variant_ident), |
647 | None => quote!(#ident), |
648 | }; |
649 | |
650 | // The fields of the struct and the active enum variant are dropped |
651 | // in declaration order. |
652 | // Refs: https://doc.rust-lang.org/reference/destructors.html |
653 | let pinned_fields = pinned_fields.iter().rev(); |
654 | |
655 | quote! { |
656 | // First, extract all the unpinned fields. |
657 | let __result = #proj_own #proj_move; |
658 | |
659 | // Now create guards to drop all the pinned fields. |
660 | // |
661 | // Due to a compiler bug (https://github.com/rust-lang/rust/issues/47949) |
662 | // this must be in its own scope, or else `__result` will not be dropped |
663 | // if any of the destructors panic. |
664 | { |
665 | #( |
666 | let __guard = _pin_project::__private::UnsafeDropInPlaceGuard::new(#pinned_fields); |
667 | )* |
668 | } |
669 | |
670 | // Finally, return the result. |
671 | __result |
672 | } |
673 | } |
674 | |
675 | /// Creates `Unpin` implementation for the original type. |
676 | /// |
677 | /// The kind of `Unpin` impl generated depends on `unpin_impl` field: |
678 | /// - `UnpinImpl::Unsafe` - Implements `Unpin` via `UnsafeUnpin` impl. |
679 | /// - `UnpinImpl::Negative` - Generates `Unpin` impl with bounds that will never be true. |
680 | /// - `UnpinImpl::Default` - Generates `Unpin` impl that requires `Unpin` for all pinned fields. |
681 | fn make_unpin_impl(cx: &Context<'_>) -> TokenStream { |
682 | match cx.unpin_impl { |
683 | UnpinImpl::Unsafe(span) => { |
684 | let mut proj_generics = cx.proj.generics.clone(); |
685 | let orig_ident = cx.orig.ident; |
686 | let lifetime = &cx.proj.lifetime; |
687 | |
688 | // Make the error message highlight `UnsafeUnpin` argument. |
689 | proj_generics.make_where_clause().predicates.push(parse_quote_spanned! { span => |
690 | _pin_project::__private::Wrapper<#lifetime, Self>: _pin_project::UnsafeUnpin |
691 | }); |
692 | |
693 | let (impl_generics, _, where_clause) = proj_generics.split_for_impl(); |
694 | let ty_generics = cx.orig.generics.split_for_impl().1; |
695 | |
696 | quote_spanned! { span => |
697 | impl #impl_generics _pin_project::__private::Unpin for #orig_ident #ty_generics |
698 | #where_clause |
699 | { |
700 | } |
701 | } |
702 | } |
703 | UnpinImpl::Negative(span) => { |
704 | let mut proj_generics = cx.proj.generics.clone(); |
705 | let orig_ident = cx.orig.ident; |
706 | let lifetime = &cx.proj.lifetime; |
707 | |
708 | proj_generics.make_where_clause().predicates.push(parse_quote! { |
709 | _pin_project::__private::Wrapper< |
710 | #lifetime, _pin_project::__private::PhantomPinned |
711 | >: _pin_project::__private::Unpin |
712 | }); |
713 | |
714 | let (proj_impl_generics, _, proj_where_clause) = proj_generics.split_for_impl(); |
715 | let ty_generics = cx.orig.generics.split_for_impl().1; |
716 | |
717 | // For interoperability with `forbid(unsafe_code)`, `unsafe` token should be |
718 | // call-site span. |
719 | let unsafety = <Token![unsafe]>::default(); |
720 | quote_spanned! { span => |
721 | #[doc(hidden)] |
722 | impl #proj_impl_generics _pin_project::__private::Unpin |
723 | for #orig_ident #ty_generics |
724 | #proj_where_clause |
725 | { |
726 | } |
727 | |
728 | // Generate a dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it. |
729 | // |
730 | // To ensure that users don't accidentally write a non-functional `UnsafeUnpin` |
731 | // impls, we emit one ourselves. If the user ends up writing an `UnsafeUnpin` |
732 | // impl, they'll get a "conflicting implementations of trait" error when |
733 | // coherence checks are run. |
734 | #[doc(hidden)] |
735 | #unsafety impl #proj_impl_generics _pin_project::UnsafeUnpin |
736 | for #orig_ident #ty_generics |
737 | #proj_where_clause |
738 | { |
739 | } |
740 | } |
741 | } |
742 | UnpinImpl::Default => { |
743 | let mut full_where_clause = cx.orig.generics.where_clause.clone().unwrap(); |
744 | |
745 | // Generate a field in our new struct for every |
746 | // pinned field in the original type. |
747 | let fields = cx.pinned_fields.iter().enumerate().map(|(i, ty)| { |
748 | let field_ident = format_ident!("__field{}" , i); |
749 | quote!(#field_ident: #ty) |
750 | }); |
751 | |
752 | // We could try to determine the subset of type parameters |
753 | // and lifetimes that are actually used by the pinned fields |
754 | // (as opposed to those only used by unpinned fields). |
755 | // However, this would be tricky and error-prone, since |
756 | // it's possible for users to create types that would alias |
757 | // with generic parameters (e.g. 'struct T'). |
758 | // |
759 | // Instead, we generate a use of every single type parameter |
760 | // and lifetime used in the original struct. For type parameters, |
761 | // we generate code like this: |
762 | // |
763 | // ```rust |
764 | // struct AlwaysUnpin<T: ?Sized>(PhantomData<T>) {} |
765 | // impl<T: ?Sized> Unpin for AlwaysUnpin<T> {} |
766 | // |
767 | // ... |
768 | // _field: AlwaysUnpin<(A, B, C)> |
769 | // ``` |
770 | // |
771 | // This ensures that any unused type parameters |
772 | // don't end up with `Unpin` bounds. |
773 | let lifetime_fields = cx.orig.generics.lifetimes().enumerate().map( |
774 | |(i, LifetimeParam { lifetime, .. })| { |
775 | let field_ident = format_ident!("__lifetime{}" , i); |
776 | quote!(#field_ident: lifetime ()) |
777 | }, |
778 | ); |
779 | |
780 | let orig_ident = cx.orig.ident; |
781 | let struct_ident = format_ident!("__{}" , orig_ident); |
782 | let vis = cx.orig.vis; |
783 | let lifetime = &cx.proj.lifetime; |
784 | let type_params = cx.orig.generics.type_params().map(|t| &t.ident); |
785 | let proj_generics = &cx.proj.generics; |
786 | let (proj_impl_generics, proj_ty_generics, _) = proj_generics.split_for_impl(); |
787 | let (_, ty_generics, where_clause) = cx.orig.generics.split_for_impl(); |
788 | |
789 | full_where_clause.predicates.push(parse_quote! { |
790 | #struct_ident #proj_ty_generics: _pin_project::__private::Unpin |
791 | }); |
792 | |
793 | quote! { |
794 | // This needs to have the same visibility as the original type, |
795 | // due to the limitations of the 'public in private' error. |
796 | // |
797 | // Our goal is to implement the public trait `Unpin` for |
798 | // a potentially public user type. Because of this, rust |
799 | // requires that any types mentioned in the where clause of |
800 | // our `Unpin` impl also be public. This means that our generated |
801 | // `__UnpinStruct` type must also be public. |
802 | // However, we ensure that the user can never actually reference |
803 | // this 'public' type by creating this type in the inside of `const`. |
804 | #[allow(missing_debug_implementations)] |
805 | #vis struct #struct_ident #proj_generics #where_clause { |
806 | __pin_project_use_generics: _pin_project::__private::AlwaysUnpin< |
807 | #lifetime, (#(_pin_project::__private::PhantomData<#type_params>),*) |
808 | >, |
809 | |
810 | #(#fields,)* |
811 | #(#lifetime_fields,)* |
812 | } |
813 | |
814 | impl #proj_impl_generics _pin_project::__private::Unpin |
815 | for #orig_ident #ty_generics |
816 | #full_where_clause |
817 | { |
818 | } |
819 | |
820 | // Generate a dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it. |
821 | // |
822 | // To ensure that users don't accidentally write a non-functional `UnsafeUnpin` |
823 | // impls, we emit one ourselves. If the user ends up writing an `UnsafeUnpin` |
824 | // impl, they'll get a "conflicting implementations of trait" error when |
825 | // coherence checks are run. |
826 | #[doc(hidden)] |
827 | unsafe impl #proj_impl_generics _pin_project::UnsafeUnpin |
828 | for #orig_ident #ty_generics |
829 | #full_where_clause |
830 | { |
831 | } |
832 | } |
833 | } |
834 | } |
835 | } |
836 | |
837 | /// Creates `Drop` implementation for the original type. |
838 | /// |
839 | /// The kind of `Drop` impl generated depends on `pinned_drop` field: |
840 | /// - `Some` - implements `Drop` via `PinnedDrop` impl. |
841 | /// - `None` - generates code that ensures that `Drop` trait is not implemented, |
842 | /// instead of generating `Drop` impl. |
843 | fn make_drop_impl(cx: &Context<'_>) -> TokenStream { |
844 | let ident = cx.orig.ident; |
845 | let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl(); |
846 | |
847 | if let Some(span) = cx.pinned_drop { |
848 | // For interoperability with `forbid(unsafe_code)`, `unsafe` token should be |
849 | // call-site span. |
850 | let unsafety = <Token![unsafe]>::default(); |
851 | quote_spanned! { span => |
852 | impl #impl_generics _pin_project::__private::Drop for #ident #ty_generics |
853 | #where_clause |
854 | { |
855 | fn drop(&mut self) { |
856 | #unsafety { |
857 | // Safety - we're in 'drop', so we know that 'self' will |
858 | // never move again. |
859 | let __pinned_self = _pin_project::__private::Pin::new_unchecked(self); |
860 | // We call `pinned_drop` only once. Since `PinnedDrop::drop` |
861 | // is an unsafe method and a private API, it is never called again in safe |
862 | // code *unless the user uses a maliciously crafted macro*. |
863 | _pin_project::__private::PinnedDrop::drop(__pinned_self); |
864 | } |
865 | } |
866 | } |
867 | } |
868 | } else { |
869 | // If the user does not provide a `PinnedDrop` impl, |
870 | // we need to ensure that they don't provide a `Drop` impl of their |
871 | // own. |
872 | // Based on https://github.com/upsuper/assert-impl/blob/f503255b292ab0ba8d085b657f4065403cfa46eb/src/lib.rs#L80-L87 |
873 | // |
874 | // We create a new identifier for each struct, so that the traits |
875 | // for different types do not conflict with each other. |
876 | // |
877 | // Another approach would be to provide an empty Drop impl, |
878 | // which would conflict with a user-provided Drop impl. |
879 | // However, this would trigger the compiler's special handling |
880 | // of Drop types (e.g. fields cannot be moved out of a Drop type). |
881 | // This approach prevents the creation of needless Drop impls, |
882 | // giving users more flexibility. |
883 | let trait_ident = format_ident!("{}MustNotImplDrop" , ident); |
884 | |
885 | quote! { |
886 | // There are two possible cases: |
887 | // 1. The user type does not implement Drop. In this case, |
888 | // the first blanked impl will not apply to it. This code |
889 | // will compile, as there is only one impl of MustNotImplDrop for the user type |
890 | // 2. The user type does impl Drop. This will make the blanket impl applicable, |
891 | // which will then conflict with the explicit MustNotImplDrop impl below. |
892 | // This will result in a compilation error, which is exactly what we want. |
893 | trait #trait_ident {} |
894 | #[allow(clippy::drop_bounds, drop_bounds)] |
895 | impl<T: _pin_project::__private::Drop> #trait_ident for T {} |
896 | impl #impl_generics #trait_ident for #ident #ty_generics #where_clause {} |
897 | |
898 | // Generate a dummy impl of `PinnedDrop`, to ensure that the user cannot implement it. |
899 | // Since the user did not pass `PinnedDrop` to `#[pin_project]`, any `PinnedDrop` |
900 | // impl will not actually be called. Unfortunately, we can't detect this situation |
901 | // directly from either the `#[pin_project]` or `#[pinned_drop]` attributes, since |
902 | // we don't know what other attributes/impl may exist. |
903 | // |
904 | // To ensure that users don't accidentally write a non-functional `PinnedDrop` |
905 | // impls, we emit one ourselves. If the user ends up writing a `PinnedDrop` impl, |
906 | // they'll get a "conflicting implementations of trait" error when coherence |
907 | // checks are run. |
908 | #[doc(hidden)] |
909 | impl #impl_generics _pin_project::__private::PinnedDrop for #ident #ty_generics |
910 | #where_clause |
911 | { |
912 | unsafe fn drop(self: _pin_project::__private::Pin<&mut Self>) {} |
913 | } |
914 | } |
915 | } |
916 | } |
917 | |
918 | /// Creates an implementation of the projection methods. |
919 | /// |
920 | /// On structs, both the `project` and `project_ref` methods are always generated, |
921 | /// and the `project_replace` method is only generated if `ProjReplace::span` is `Some`. |
922 | /// |
923 | /// On enums, only methods that the returned projected type is named will be generated. |
924 | fn make_proj_impl( |
925 | cx: &Context<'_>, |
926 | proj_body: &TokenStream, |
927 | proj_ref_body: &TokenStream, |
928 | proj_own_body: &TokenStream, |
929 | ) -> TokenStream { |
930 | let vis = &cx.proj.vis; |
931 | let lifetime = &cx.proj.lifetime; |
932 | let orig_ident = cx.orig.ident; |
933 | let proj_ident = &cx.proj.mut_ident; |
934 | let proj_ref_ident = &cx.proj.ref_ident; |
935 | let proj_own_ident = &cx.proj.own_ident; |
936 | |
937 | let orig_ty_generics = cx.orig.generics.split_for_impl().1; |
938 | let proj_ty_generics = cx.proj.generics.split_for_impl().1; |
939 | let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl(); |
940 | // TODO: For enums and project_replace, dead_code warnings should not be |
941 | // allowed because methods are not generated unless explicitly specified. |
942 | // However, there is currently no good way to allow warnings for generated |
943 | // code, so we allow warnings for all methods for now. |
944 | let allow_dead_code = quote! { #[allow(dead_code)] }; |
945 | |
946 | let mut project = Some(quote! { |
947 | #allow_dead_code |
948 | #[inline] |
949 | #vis fn project<#lifetime>( |
950 | self: _pin_project::__private::Pin<lifetime mut Self>, |
951 | ) -> #proj_ident #proj_ty_generics { |
952 | unsafe { |
953 | #proj_body |
954 | } |
955 | } |
956 | }); |
957 | let mut project_ref = Some(quote! { |
958 | #allow_dead_code |
959 | #[allow(clippy::missing_const_for_fn)] |
960 | #[inline] |
961 | #vis fn project_ref<#lifetime>( |
962 | self: _pin_project::__private::Pin<lifetime Self>, |
963 | ) -> #proj_ref_ident #proj_ty_generics { |
964 | unsafe { |
965 | #proj_ref_body |
966 | } |
967 | } |
968 | }); |
969 | let mut project_replace = cx.project_replace.span().map(|span| { |
970 | // It is enough to only set the span of the signature. |
971 | let sig = quote_spanned! { span => |
972 | #allow_dead_code |
973 | #[inline] |
974 | #vis fn project_replace( |
975 | self: _pin_project::__private::Pin<&mut Self>, |
976 | __replacement: Self, |
977 | ) -> #proj_own_ident #orig_ty_generics |
978 | }; |
979 | quote! { |
980 | #sig { |
981 | unsafe { |
982 | let __self_ptr: *mut Self = self.get_unchecked_mut(); |
983 | |
984 | // Destructors will run in reverse order, so next create a guard to overwrite |
985 | // `self` with the replacement value without calling destructors. |
986 | let __guard = _pin_project::__private::UnsafeOverwriteGuard::new( |
987 | __self_ptr, |
988 | __replacement, |
989 | ); |
990 | |
991 | #proj_own_body |
992 | } |
993 | } |
994 | } |
995 | }); |
996 | |
997 | if cx.kind == Enum { |
998 | if !cx.project { |
999 | project = None; |
1000 | } |
1001 | if !cx.project_ref { |
1002 | project_ref = None; |
1003 | } |
1004 | if cx.project_replace.ident().is_none() { |
1005 | project_replace = None; |
1006 | } |
1007 | } |
1008 | |
1009 | quote! { |
1010 | impl #impl_generics #orig_ident #ty_generics #where_clause { |
1011 | #project |
1012 | #project_ref |
1013 | #project_replace |
1014 | } |
1015 | } |
1016 | } |
1017 | |
1018 | /// Checks that the `[repr(packed)]` attribute is not included. |
1019 | /// |
1020 | /// This currently does two checks: |
1021 | /// - Checks the attributes of structs to ensure there is no `[repr(packed)]`. |
1022 | /// - Generates a function that borrows fields without an unsafe block and |
1023 | /// forbidding `unaligned_references` lint. |
1024 | fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result<TokenStream> { |
1025 | for attr in orig.attrs { |
1026 | if let Meta::List(ref list) = attr.meta { |
1027 | if list.path.is_ident("repr" ) { |
1028 | for repr in list.parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)? { |
1029 | if repr.path().is_ident("packed" ) { |
1030 | let msg = if fields.is_none() { |
1031 | // #[repr(packed)] cannot be apply on enums and will be rejected by rustc. |
1032 | // However, we should not rely on the behavior of rustc that rejects this. |
1033 | // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001 |
1034 | "#[repr(packed)] attribute should be applied to a struct or union" |
1035 | } else if repr.require_name_value().is_ok() { |
1036 | // #[repr(packed = "")] is not valid format of #[repr(packed)] and will be |
1037 | // rejected by rustc. |
1038 | // However, we should not rely on the behavior of rustc that rejects this. |
1039 | // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001 |
1040 | "#[repr(packed)] attribute should not be name-value pair" |
1041 | } else { |
1042 | "#[pin_project] attribute may not be used on #[repr(packed)] types" |
1043 | }; |
1044 | bail!(repr, msg); |
1045 | } |
1046 | } |
1047 | } |
1048 | } |
1049 | } |
1050 | |
1051 | let fields = match fields { |
1052 | Some(fields) => fields, |
1053 | None => return Ok(TokenStream::new()), |
1054 | }; |
1055 | |
1056 | // Workaround for https://github.com/taiki-e/pin-project/issues/32 |
1057 | // Through the tricky use of proc macros, it's possible to bypass |
1058 | // the above check for the `repr` attribute. |
1059 | // To ensure that it's impossible to use pin projections on a `#[repr(packed)]` |
1060 | // struct, we generate code like this: |
1061 | // |
1062 | // ```rust |
1063 | // #[forbid(unaligned_references)] |
1064 | // fn assert_not_repr_packed(val: &MyStruct) { |
1065 | // let _field_1 = &val.field_1; |
1066 | // let _field_2 = &val.field_2; |
1067 | // ... |
1068 | // let _field_n = &val.field_n; |
1069 | // } |
1070 | // ``` |
1071 | // |
1072 | // Taking a reference to a packed field is UB, and applying |
1073 | // `#[forbid(unaligned_references)]` makes sure that doing this is a hard error. |
1074 | // |
1075 | // If the struct ends up having `#[repr(packed)]` applied somehow, |
1076 | // this will generate an (unfriendly) error message. Under all reasonable |
1077 | // circumstances, we'll detect the `#[repr(packed)]` attribute, and generate |
1078 | // a much nicer error above. |
1079 | // |
1080 | // There is one exception: If the type of a struct field has an alignment of 1 |
1081 | // (e.g. u8), it is always safe to take a reference to it, even if the struct |
1082 | // is `#[repr(packed)]`. If the struct is composed entirely of types of |
1083 | // alignment 1, our generated method will not trigger an error if the |
1084 | // struct is `#[repr(packed)]`. |
1085 | // |
1086 | // Fortunately, this should have no observable consequence - `#[repr(packed)]` |
1087 | // is essentially a no-op on such a type. Nevertheless, we include a test |
1088 | // to ensure that the compiler doesn't ever try to copy the fields on |
1089 | // such a struct when trying to drop it - which is reason we prevent |
1090 | // `#[repr(packed)]` in the first place. |
1091 | // |
1092 | // See also https://github.com/taiki-e/pin-project/pull/34. |
1093 | // |
1094 | // Note: |
1095 | // - Lint-based tricks aren't perfect, but they're much better than nothing: |
1096 | // https://github.com/taiki-e/pin-project-lite/issues/26 |
1097 | // |
1098 | // - Enable both unaligned_references and safe_packed_borrows lints |
1099 | // because unaligned_references lint does not exist in older compilers: |
1100 | // https://github.com/taiki-e/pin-project-lite/pull/55 |
1101 | // https://github.com/rust-lang/rust/pull/82525 |
1102 | let mut field_refs = vec![]; |
1103 | match fields { |
1104 | Fields::Named(FieldsNamed { named, .. }) => { |
1105 | for Field { ident, .. } in named { |
1106 | field_refs.push(quote!(&this.#ident)); |
1107 | } |
1108 | } |
1109 | Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => { |
1110 | for (index, _) in unnamed.iter().enumerate() { |
1111 | let index = Index::from(index); |
1112 | field_refs.push(quote!(&this.#index)); |
1113 | } |
1114 | } |
1115 | Fields::Unit => {} |
1116 | } |
1117 | |
1118 | let (impl_generics, ty_generics, where_clause) = orig.generics.split_for_impl(); |
1119 | let ident = orig.ident; |
1120 | Ok(quote! { |
1121 | #[forbid(unaligned_references, safe_packed_borrows)] |
1122 | fn __assert_not_repr_packed #impl_generics (this: ident #ty_generics) #where_clause { |
1123 | #(let _ = #field_refs;)* |
1124 | } |
1125 | }) |
1126 | } |
1127 | |