1 // SPDX-License-Identifier: Apache-2.0 OR MIT 2 3 use proc_macro2::TokenStream; 4 use quote::{format_ident, quote, ToTokens}; 5 use syn::{ 6 parse::{End, Nothing, Parse}, 7 parse_quote, parse_quote_spanned, 8 spanned::Spanned, 9 visit_mut::VisitMut, 10 Field, Fields, Generics, Ident, Item, PathSegment, Type, TypePath, Visibility, WhereClause, 11 }; 12 13 use crate::diagnostics::{DiagCtxt, ErrorGuaranteed}; 14 15 pub(crate) mod kw { 16 syn::custom_keyword!(PinnedDrop); 17 } 18 19 pub(crate) enum Args { 20 Nothing(Nothing), 21 #[allow(dead_code)] 22 PinnedDrop(kw::PinnedDrop), 23 } 24 25 impl Parse for Args { 26 fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> { 27 let lh = input.lookahead1(); 28 if lh.peek(End) { 29 input.parse().map(Self::Nothing) 30 } else if lh.peek(kw::PinnedDrop) { 31 input.parse().map(Self::PinnedDrop) 32 } else { 33 Err(lh.error()) 34 } 35 } 36 } 37 38 impl ToTokens for Args { 39 fn to_tokens(&self, tokens: &mut TokenStream) { 40 match self { 41 Self::Nothing(_) => (), 42 Self::PinnedDrop(kw) => kw.to_tokens(tokens), 43 } 44 } 45 } 46 47 struct FieldInfo<'a> { 48 field: &'a Field, 49 pinned: bool, 50 } 51 52 pub(crate) fn pin_data( 53 args: Args, 54 input: Item, 55 dcx: &mut DiagCtxt, 56 ) -> Result<TokenStream, ErrorGuaranteed> { 57 let mut struct_ = match input { 58 Item::Struct(struct_) => struct_, 59 Item::Enum(enum_) => { 60 return Err(dcx.error( 61 enum_.enum_token, 62 "`#[pin_data]` only supports structs for now", 63 )); 64 } 65 Item::Union(union) => { 66 return Err(dcx.error( 67 union.union_token, 68 "`#[pin_data]` only supports structs for now", 69 )); 70 } 71 rest => { 72 return Err(dcx.error( 73 rest, 74 "`#[pin_data]` can only be applied to struct, enum and union definitions", 75 )); 76 } 77 }; 78 79 // Handling cfg can gets very complicated, especially for tuple structs. Therefore, resolve all 80 // field cfgs first before continuing. 81 // 82 // We need to perform this after parsing so we can reliably detect field cfgs. 83 for (field_idx, field) in struct_.fields.iter_mut().enumerate() { 84 let cfg: Vec<_> = field 85 .attrs 86 .iter() 87 .filter(|a| a.path().is_ident("cfg")) 88 .map(|a| { 89 a.parse_args::<TokenStream>() 90 .expect("parse as token stream cannot fail") 91 }) 92 .collect(); 93 94 if cfg.is_empty() { 95 continue; 96 } 97 98 field.attrs.retain(|a| !a.path().is_ident("cfg")); 99 let cfg_true_struct = quote!(#struct_); 100 101 let punctuated = match &mut struct_.fields { 102 Fields::Named(fields) => &mut fields.named, 103 Fields::Unnamed(fields) => &mut fields.unnamed, 104 Fields::Unit => unreachable!(), 105 }; 106 *punctuated = std::mem::take(punctuated) 107 .into_pairs() 108 .enumerate() 109 .filter(|&(i, _)| i != field_idx) 110 .map(|(_, p)| p) 111 .collect(); 112 let cfg_false_struct = quote!(#struct_); 113 114 // Resolve one field at a time until we've got no more field cfgs. 115 // 116 // This is linear time because macro invocations with false cfg will not be expanded. 117 return Ok(quote!( 118 #[cfg(all(#(#cfg,)*))] 119 #[::pin_init::pin_data(#args)] 120 #cfg_true_struct 121 122 #[cfg(not(all(#(#cfg,)*)))] 123 #[::pin_init::pin_data(#args)] 124 #cfg_false_struct 125 )); 126 } 127 128 // The generics might contain the `Self` type. Since this macro will define a new type with the 129 // same generics and bounds, this poses a problem: `Self` will refer to the new type as opposed 130 // to this struct definition. Therefore we have to replace `Self` with the concrete name. 131 let mut replacer = { 132 let name = &struct_.ident; 133 let (_, ty_generics, _) = struct_.generics.split_for_impl(); 134 SelfReplacer(parse_quote!(#name #ty_generics)) 135 }; 136 replacer.visit_generics_mut(&mut struct_.generics); 137 replacer.visit_fields_mut(&mut struct_.fields); 138 139 let fields: Vec<FieldInfo<'_>> = struct_ 140 .fields 141 .iter_mut() 142 .map(|field| { 143 let len = field.attrs.len(); 144 field.attrs.retain(|a| !a.path().is_ident("pin")); 145 let pinned_count = len - field.attrs.len(); 146 if pinned_count > 1 { 147 dcx.error(&field, "#[pin] attribute specified more than once"); 148 } 149 150 assert!( 151 !field.attrs.iter().any(|a| a.path().is_ident("cfg")), 152 "cfgs should be all resolved at this point" 153 ); 154 155 FieldInfo { 156 field: &*field, 157 pinned: pinned_count != 0, 158 } 159 }) 160 .collect(); 161 162 for field in &fields { 163 let ident = field.field.ident.as_ref().unwrap(); 164 165 if !field.pinned && is_phantom_pinned(&field.field.ty) { 166 dcx.warn( 167 field.field, 168 format!( 169 "The field `{ident}` of type `PhantomPinned` only has an effect \ 170 if it has the `#[pin]` attribute", 171 ), 172 ); 173 } 174 } 175 176 let unpin_impl = generate_unpin_impl(&struct_.ident, &struct_.generics, &fields); 177 let drop_impl = generate_drop_impl(&struct_.ident, &struct_.generics, args); 178 let projections = 179 generate_projections(&struct_.vis, &struct_.ident, &struct_.generics, &fields); 180 let the_pin_data = 181 generate_the_pin_data(&struct_.vis, &struct_.ident, &struct_.generics, &fields); 182 183 Ok(quote! { 184 #struct_ 185 #projections 186 // We put the rest into this const item, because it then will not be accessible to anything 187 // outside. 188 const _: () = { 189 #the_pin_data 190 #unpin_impl 191 #drop_impl 192 }; 193 }) 194 } 195 196 fn is_phantom_pinned(ty: &Type) -> bool { 197 match ty { 198 Type::Path(TypePath { qself: None, path }) => { 199 // Cannot possibly refer to `PhantomPinned` (except alias, but that's on the user). 200 if path.segments.len() > 3 { 201 return false; 202 } 203 // If there is a `::`, then the path needs to be `::core::marker::PhantomPinned` or 204 // `::std::marker::PhantomPinned`. 205 if path.leading_colon.is_some() && path.segments.len() != 3 { 206 return false; 207 } 208 let expected: Vec<&[&str]> = vec![&["PhantomPinned"], &["marker"], &["core", "std"]]; 209 for (actual, expected) in path.segments.iter().rev().zip(expected) { 210 if !actual.arguments.is_empty() || expected.iter().all(|e| actual.ident != e) { 211 return false; 212 } 213 } 214 true 215 } 216 _ => false, 217 } 218 } 219 220 fn generate_unpin_impl( 221 ident: &Ident, 222 generics: &Generics, 223 fields: &[FieldInfo<'_>], 224 ) -> TokenStream { 225 let (_, ty_generics, _) = generics.split_for_impl(); 226 let mut generics_with_pin_lt = generics.clone(); 227 generics_with_pin_lt.params.insert(0, parse_quote!('__pin)); 228 generics_with_pin_lt.make_where_clause(); 229 let ( 230 impl_generics_with_pin_lt, 231 ty_generics_with_pin_lt, 232 Some(WhereClause { 233 where_token, 234 predicates, 235 }), 236 ) = generics_with_pin_lt.split_for_impl() 237 else { 238 unreachable!() 239 }; 240 let pinned_fields = fields.iter().filter(|f| f.pinned).map(|f| { 241 let ident = f.field.ident.as_ref().unwrap(); 242 let ty = &f.field.ty; 243 quote!( 244 #ident: #ty 245 ) 246 }); 247 quote! { 248 // This struct will be used for the unpin analysis. It is needed, because only structurally 249 // pinned fields are relevant whether the struct should implement `Unpin`. 250 #[allow( 251 dead_code, // The fields below are never used. 252 non_snake_case // The warning will be emitted on the struct definition. 253 )] 254 struct __Unpin #generics_with_pin_lt 255 #where_token 256 #predicates 257 { 258 __phantom_pin: ::pin_init::__internal::PhantomInvariantLifetime<'__pin>, 259 __phantom: ::pin_init::__internal::PhantomInvariant<#ident #ty_generics>, 260 #(#pinned_fields),* 261 } 262 263 #[doc(hidden)] 264 impl #impl_generics_with_pin_lt ::core::marker::Unpin for #ident #ty_generics 265 #where_token 266 __Unpin #ty_generics_with_pin_lt: ::core::marker::Unpin, 267 #predicates 268 {} 269 } 270 } 271 272 fn generate_drop_impl(ident: &Ident, generics: &Generics, args: Args) -> TokenStream { 273 let (impl_generics, ty_generics, whr) = generics.split_for_impl(); 274 let has_pinned_drop = matches!(args, Args::PinnedDrop(_)); 275 // We need to disallow normal `Drop` implementation, the exact behavior depends on whether 276 // `PinnedDrop` was specified in `args`. 277 if has_pinned_drop { 278 // When `PinnedDrop` was specified we just implement `Drop` and delegate. 279 quote! { 280 impl #impl_generics ::core::ops::Drop for #ident #ty_generics 281 #whr 282 { 283 fn drop(&mut self) { 284 // SAFETY: Since this is a destructor, `self` will not move after this function 285 // terminates, since it is inaccessible. 286 let pinned = unsafe { ::core::pin::Pin::new_unchecked(self) }; 287 // SAFETY: Since this is a drop function, we can create this token to call the 288 // pinned destructor of this type. 289 let token = unsafe { ::pin_init::__internal::OnlyCallFromDrop::new() }; 290 ::pin_init::PinnedDrop::drop(pinned, token); 291 } 292 } 293 } 294 } else { 295 // When no `PinnedDrop` was specified, then we have to prevent implementing drop. 296 quote! { 297 // We prevent this by creating a trait that will be implemented for all types implementing 298 // `Drop`. Additionally we will implement this trait for the struct leading to a conflict, 299 // if it also implements `Drop` 300 trait MustNotImplDrop {} 301 impl<T: ::core::ops::Drop + ?::core::marker::Sized> MustNotImplDrop for T {} 302 impl #impl_generics MustNotImplDrop for #ident #ty_generics 303 #whr 304 {} 305 // We also take care to prevent users from writing a useless `PinnedDrop` implementation. 306 // They might implement `PinnedDrop` correctly for the struct, but forget to give 307 // `PinnedDrop` as the parameter to `#[pin_data]`. 308 trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} 309 impl<T: ::pin_init::PinnedDrop + ?::core::marker::Sized> 310 UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} 311 impl #impl_generics 312 UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for #ident #ty_generics 313 #whr 314 {} 315 } 316 } 317 } 318 319 fn generate_projections( 320 vis: &Visibility, 321 ident: &Ident, 322 generics: &Generics, 323 fields: &[FieldInfo<'_>], 324 ) -> TokenStream { 325 let (impl_generics, ty_generics, _) = generics.split_for_impl(); 326 let mut generics_with_pin_lt = generics.clone(); 327 generics_with_pin_lt.params.insert(0, parse_quote!('__pin)); 328 let (_, ty_generics_with_pin_lt, whr) = generics_with_pin_lt.split_for_impl(); 329 let projection = format_ident!("{ident}Projection"); 330 let this = format_ident!("this"); 331 332 let (fields_decl, fields_proj): (Vec<_>, Vec<_>) = fields 333 .iter() 334 .map(|field| { 335 let Field { vis, ident, ty, .. } = &field.field; 336 337 let ident = ident 338 .as_ref() 339 .expect("only structs with named fields are supported"); 340 if field.pinned { 341 ( 342 quote!( 343 #vis #ident: ::core::pin::Pin<&'__pin mut #ty>, 344 ), 345 quote!( 346 // SAFETY: this field is structurally pinned. 347 #ident: unsafe { ::core::pin::Pin::new_unchecked(&mut #this.#ident) }, 348 ), 349 ) 350 } else { 351 ( 352 quote!( 353 #vis #ident: &'__pin mut #ty, 354 ), 355 quote!( 356 #ident: &mut #this.#ident, 357 ), 358 ) 359 } 360 }) 361 .collect(); 362 let structurally_pinned_fields_docs = fields 363 .iter() 364 .filter(|f| f.pinned) 365 .map(|f| format!(" - `{}`", f.field.ident.as_ref().unwrap())); 366 let not_structurally_pinned_fields_docs = fields 367 .iter() 368 .filter(|f| !f.pinned) 369 .map(|f| format!(" - `{}`", f.field.ident.as_ref().unwrap())); 370 let docs = format!(" Pin-projections of [`{ident}`]"); 371 quote! { 372 #[doc = #docs] 373 // Allow `non_snake_case` since the same warning will be emitted on 374 // the struct definition. 375 #[allow(dead_code, non_snake_case)] 376 #[doc(hidden)] 377 #vis struct #projection #generics_with_pin_lt 378 #whr 379 { 380 #(#fields_decl)* 381 ___pin_phantom_data: ::core::marker::PhantomData<&'__pin mut ()>, 382 } 383 384 impl #impl_generics #ident #ty_generics 385 #whr 386 { 387 /// Pin-projects all fields of `Self`. 388 /// 389 /// These fields are structurally pinned: 390 #(#[doc = #structurally_pinned_fields_docs])* 391 /// 392 /// These fields are **not** structurally pinned: 393 #(#[doc = #not_structurally_pinned_fields_docs])* 394 #[inline] 395 #vis fn project<'__pin>( 396 self: ::core::pin::Pin<&'__pin mut Self>, 397 ) -> #projection #ty_generics_with_pin_lt { 398 // SAFETY: we only give access to `&mut` for fields not structurally pinned. 399 let #this = unsafe { ::core::pin::Pin::get_unchecked_mut(self) }; 400 #projection { 401 #(#fields_proj)* 402 ___pin_phantom_data: ::core::marker::PhantomData, 403 } 404 } 405 } 406 } 407 } 408 409 fn generate_the_pin_data( 410 vis: &Visibility, 411 struct_name: &Ident, 412 generics: &Generics, 413 fields: &[FieldInfo<'_>], 414 ) -> TokenStream { 415 let (impl_generics, ty_generics, whr) = generics.split_for_impl(); 416 417 // For every field, we create an initializing projection function according to its projection 418 // type. If a field is structurally pinned, we create a `Slot` with `Pinned` which must be 419 // initialized via `PinInit`; if it is not structurally pinned, then we create a `Slot` with 420 // `Unpinned` which allows initialization via `Init`. 421 let field_accessors = fields 422 .iter() 423 .map(|f| { 424 let Field { vis, ident, ty, .. } = f.field; 425 426 let field_name = ident 427 .as_ref() 428 .expect("only structs with named fields are supported"); 429 let pin_marker = if f.pinned { 430 quote!(Pinned) 431 } else { 432 quote!(Unpinned) 433 }; 434 quote! { 435 /// # Safety 436 /// 437 /// - `slot` is valid and properly aligned. 438 /// - `(*slot).#field_name` is properly aligned. 439 /// - `(*slot).#field_name` points to uninitialized and exclusively accessed 440 /// memory. 441 // Allow `non_snake_case` since the same warning will be emitted on 442 // the struct definition. 443 #[allow(non_snake_case)] 444 #[inline(always)] 445 #vis unsafe fn #field_name( 446 self, 447 slot: *mut #struct_name #ty_generics, 448 ) -> ::pin_init::__internal::Slot<::pin_init::__internal::#pin_marker, #ty> { 449 // SAFETY: 450 // - If `#pin_marker` is `Pinned`, the corresponding field is structurally 451 // pinned. 452 // - Other safety requirements follows the safety requirement. 453 unsafe { ::pin_init::__internal::Slot::new(&raw mut (*slot).#field_name) } 454 } 455 } 456 }) 457 .collect::<TokenStream>(); 458 quote! { 459 // We declare this struct which will host all of the projection function for our type. It 460 // will be invariant over all generic parameters which are inherited from the struct. 461 #[doc(hidden)] 462 #vis struct __ThePinData #generics 463 #whr 464 { 465 __phantom: ::pin_init::__internal::PhantomInvariant<#struct_name #ty_generics>, 466 } 467 468 impl #impl_generics ::core::clone::Clone for __ThePinData #ty_generics 469 #whr 470 { 471 #[inline] 472 fn clone(&self) -> Self { *self } 473 } 474 475 impl #impl_generics ::core::marker::Copy for __ThePinData #ty_generics 476 #whr 477 {} 478 479 #[allow(dead_code)] // Some functions might never be used and private. 480 impl #impl_generics __ThePinData #ty_generics 481 #whr 482 { 483 /// Type inference helper function. 484 #[inline(always)] 485 #vis fn __make_closure<__F, __E>(self, f: __F) -> __F 486 where 487 __F: FnOnce(*mut #struct_name #ty_generics) -> 488 ::core::result::Result<::pin_init::__internal::InitOk, __E>, 489 { 490 f 491 } 492 493 #field_accessors 494 } 495 496 // SAFETY: We have added the correct projection functions above to `__ThePinData` and 497 // we also use the least restrictive generics possible. 498 unsafe impl #impl_generics ::pin_init::__internal::HasPinData for #struct_name #ty_generics 499 #whr 500 { 501 type PinData = __ThePinData #ty_generics; 502 503 #[inline] 504 unsafe fn __pin_data() -> Self::PinData { 505 __ThePinData { __phantom: ::pin_init::__internal::PhantomInvariant::new() } 506 } 507 } 508 } 509 } 510 511 struct SelfReplacer(PathSegment); 512 513 impl VisitMut for SelfReplacer { 514 fn visit_path_mut(&mut self, i: &mut syn::Path) { 515 if i.is_ident("Self") { 516 let span = i.span(); 517 let seg = &self.0; 518 *i = parse_quote_spanned!(span=> #seg); 519 } else { 520 syn::visit_mut::visit_path_mut(self, i); 521 } 522 } 523 524 fn visit_path_segment_mut(&mut self, seg: &mut PathSegment) { 525 if seg.ident == "Self" { 526 let span = seg.span(); 527 let this = &self.0; 528 *seg = parse_quote_spanned!(span=> #this); 529 } else { 530 syn::visit_mut::visit_path_segment_mut(self, seg); 531 } 532 } 533 534 fn visit_item_mut(&mut self, _: &mut Item) { 535 // Do not descend into items, since items reset/change what `Self` refers to. 536 } 537 } 538