summaryrefslogtreecommitdiffstats
path: root/third_party/rust/pin-project-internal/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /third_party/rust/pin-project-internal/src
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/pin-project-internal/src')
-rw-r--r--third_party/rust/pin-project-internal/src/lib.rs584
-rw-r--r--third_party/rust/pin-project-internal/src/pin_project/args.rs254
-rw-r--r--third_party/rust/pin-project-internal/src/pin_project/attribute.rs65
-rw-r--r--third_party/rust/pin-project-internal/src/pin_project/derive.rs1127
-rw-r--r--third_party/rust/pin-project-internal/src/pin_project/mod.rs17
-rw-r--r--third_party/rust/pin-project-internal/src/pinned_drop.rs226
-rw-r--r--third_party/rust/pin-project-internal/src/utils.rs402
7 files changed, 2675 insertions, 0 deletions
diff --git a/third_party/rust/pin-project-internal/src/lib.rs b/third_party/rust/pin-project-internal/src/lib.rs
new file mode 100644
index 0000000000..07683c417e
--- /dev/null
+++ b/third_party/rust/pin-project-internal/src/lib.rs
@@ -0,0 +1,584 @@
+//! Implementation detail of the `pin-project` crate. - **do not use directly**
+
+#![doc(test(
+ no_crate_inject,
+ attr(
+ deny(warnings, rust_2018_idioms, single_use_lifetimes),
+ allow(dead_code, unused_variables)
+ )
+))]
+#![forbid(unsafe_code)]
+#![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
+#![warn(clippy::pedantic)]
+#![allow(
+ clippy::needless_doctest_main,
+ clippy::similar_names,
+ clippy::single_match_else,
+ clippy::too_many_lines,
+ clippy::unnested_or_patterns
+)]
+
+// older compilers require explicit `extern crate`.
+#[allow(unused_extern_crates)]
+extern crate proc_macro;
+
+#[macro_use]
+mod utils;
+
+mod pin_project;
+mod pinned_drop;
+
+use proc_macro::TokenStream;
+
+/// An attribute that creates projection types covering all the fields of
+/// struct or enum.
+///
+/// This attribute creates projection types according to the following rules:
+///
+/// - For the fields that use `#[pin]` attribute, create the pinned reference to
+/// the field.
+/// - For the other fields, create a normal reference to the field.
+///
+/// And the following methods are implemented on the original type:
+///
+/// ```rust
+/// # use std::pin::Pin;
+/// # type Projection<'a> = &'a ();
+/// # type ProjectionRef<'a> = &'a ();
+/// # trait Dox {
+/// fn project(self: Pin<&mut Self>) -> Projection<'_>;
+/// fn project_ref(self: Pin<&Self>) -> ProjectionRef<'_>;
+/// # }
+/// ```
+///
+/// By passing an argument with the same name as the method to the attribute,
+/// you can name the projection type returned from the method. This allows you
+/// to use pattern matching on the projected types.
+///
+/// ```rust
+/// # use pin_project::pin_project;
+/// # use std::pin::Pin;
+/// #[pin_project(project = EnumProj)]
+/// enum Enum<T> {
+/// Variant(#[pin] T),
+/// }
+///
+/// impl<T> Enum<T> {
+/// fn method(self: Pin<&mut Self>) {
+/// let this: EnumProj<'_, T> = self.project();
+/// match this {
+/// EnumProj::Variant(x) => {
+/// let _: Pin<&mut T> = x;
+/// }
+/// }
+/// }
+/// }
+/// ```
+///
+/// Note that the projection types returned by `project` and `project_ref` have
+/// an additional lifetime at the beginning of generics.
+///
+/// ```text
+/// let this: EnumProj<'_, T> = self.project();
+/// ^^
+/// ```
+///
+/// The visibility of the projected types and projection methods is based on the
+/// original type. However, if the visibility of the original type is `pub`, the
+/// visibility of the projected types and the projection methods is downgraded
+/// to `pub(crate)`.
+///
+/// # Safety
+///
+/// This attribute is completely safe. In the absence of other `unsafe` code
+/// *that you write*, it is impossible to cause [undefined
+/// behavior][undefined-behavior] with this attribute.
+///
+/// This is accomplished by enforcing the four requirements for pin projection
+/// stated in [the Rust documentation][pin-projection]:
+///
+/// 1. The struct must only be [`Unpin`] if all the structural fields are
+/// [`Unpin`].
+///
+/// To enforce this, this attribute will automatically generate an [`Unpin`]
+/// implementation for you, which will require that all structurally pinned
+/// fields be [`Unpin`].
+///
+/// If you attempt to provide an [`Unpin`] impl, the blanket impl will then
+/// apply to your type, causing a compile-time error due to the conflict with
+/// the second impl.
+///
+/// If you wish to provide a manual [`Unpin`] impl, you can do so via the
+/// [`UnsafeUnpin`][unsafe-unpin] argument.
+///
+/// 2. The destructor of the struct must not move structural fields out of its
+/// argument.
+///
+/// To enforce this, this attribute will generate code like this:
+///
+/// ```rust
+/// struct MyStruct {}
+/// trait MyStructMustNotImplDrop {}
+/// # #[allow(unknown_lints, drop_bounds)]
+/// impl<T: Drop> MyStructMustNotImplDrop for T {}
+/// impl MyStructMustNotImplDrop for MyStruct {}
+/// ```
+///
+/// If you attempt to provide an [`Drop`] impl, the blanket impl will then
+/// apply to your type, causing a compile-time error due to the conflict with
+/// the second impl.
+///
+/// If you wish to provide a custom [`Drop`] impl, you can annotate an impl
+/// with [`#[pinned_drop]`][pinned-drop]. This impl takes a pinned version of
+/// your struct - that is, [`Pin`]`<&mut MyStruct>` where `MyStruct` is the
+/// type of your struct.
+///
+/// You can call `.project()` on this type as usual, along with any other
+/// methods you have defined. Because your code is never provided with
+/// a `&mut MyStruct`, it is impossible to move out of pin-projectable
+/// fields in safe code in your destructor.
+///
+/// 3. You must make sure that you uphold the [`Drop`
+/// guarantee][drop-guarantee]: once your struct is pinned, the memory that
+/// contains the content is not overwritten or deallocated without calling
+/// the content's destructors.
+///
+/// Safe code doesn't need to worry about this - the only way to violate
+/// this requirement is to manually deallocate memory (which is `unsafe`),
+/// or to overwrite a field with something else.
+/// Because your custom destructor takes [`Pin`]`<&mut MyStruct>`, it's
+/// impossible to obtain a mutable reference to a pin-projected field in safe
+/// code.
+///
+/// 4. You must not offer any other operations that could lead to data being
+/// moved out of the structural fields when your type is pinned.
+///
+/// As with requirement 3, it is impossible for safe code to violate this.
+/// This crate ensures that safe code can never obtain a mutable reference to
+/// `#[pin]` fields, which prevents you from ever moving out of them in safe
+/// code.
+///
+/// Pin projections are also incompatible with [`#[repr(packed)]`][repr-packed]
+/// types. Attempting to use this attribute on a `#[repr(packed)]` type results
+/// in a compile-time error.
+///
+/// # Examples
+///
+/// `#[pin_project]` can be used on structs and enums.
+///
+/// ```rust
+/// use std::pin::Pin;
+///
+/// use pin_project::pin_project;
+///
+/// #[pin_project]
+/// struct Struct<T, U> {
+/// #[pin]
+/// pinned: T,
+/// unpinned: U,
+/// }
+///
+/// impl<T, U> Struct<T, U> {
+/// fn method(self: Pin<&mut Self>) {
+/// let this = self.project();
+/// let _: Pin<&mut T> = this.pinned;
+/// let _: &mut U = this.unpinned;
+/// }
+/// }
+/// ```
+///
+/// ```rust
+/// use std::pin::Pin;
+///
+/// use pin_project::pin_project;
+///
+/// #[pin_project]
+/// struct TupleStruct<T, U>(#[pin] T, U);
+///
+/// impl<T, U> TupleStruct<T, U> {
+/// fn method(self: Pin<&mut Self>) {
+/// let this = self.project();
+/// let _: Pin<&mut T> = this.0;
+/// let _: &mut U = this.1;
+/// }
+/// }
+/// ```
+///
+/// To use `#[pin_project]` on enums, you need to name the projection type
+/// returned from the method.
+///
+/// ```rust
+/// use std::pin::Pin;
+///
+/// use pin_project::pin_project;
+///
+/// #[pin_project(project = EnumProj)]
+/// enum Enum<T, U> {
+/// Tuple(#[pin] T),
+/// Struct { field: U },
+/// Unit,
+/// }
+///
+/// impl<T, U> Enum<T, U> {
+/// fn method(self: Pin<&mut Self>) {
+/// match self.project() {
+/// EnumProj::Tuple(x) => {
+/// let _: Pin<&mut T> = x;
+/// }
+/// EnumProj::Struct { field } => {
+/// let _: &mut U = field;
+/// }
+/// EnumProj::Unit => {}
+/// }
+/// }
+/// }
+/// ```
+///
+/// When `#[pin_project]` is used on enums, only named projection types and
+/// methods are generated because there is no way to access variants of
+/// projected types without naming it.
+/// For example, in the above example, only the `project` method is generated,
+/// and the `project_ref` method is not generated.
+/// (When `#[pin_project]` is used on structs, both methods are always generated.)
+///
+/// ```rust,compile_fail,E0599
+/// # use pin_project::pin_project;
+/// # use std::pin::Pin;
+/// #
+/// # #[pin_project(project = EnumProj)]
+/// # enum Enum<T, U> {
+/// # Tuple(#[pin] T),
+/// # Struct { field: U },
+/// # Unit,
+/// # }
+/// #
+/// impl<T, U> Enum<T, U> {
+/// fn call_project_ref(self: Pin<&Self>) {
+/// let _this = self.project_ref();
+/// //~^ ERROR no method named `project_ref` found for struct `Pin<&Enum<T, U>>` in the current scope
+/// }
+/// }
+/// ```
+///
+/// If you want to call `.project()` multiple times or later use the
+/// original [`Pin`] type, it needs to use [`.as_mut()`][`Pin::as_mut`] to avoid
+/// consuming the [`Pin`].
+///
+/// ```rust
+/// use std::pin::Pin;
+///
+/// use pin_project::pin_project;
+///
+/// #[pin_project]
+/// struct Struct<T> {
+/// #[pin]
+/// field: T,
+/// }
+///
+/// impl<T> Struct<T> {
+/// fn call_project_twice(mut self: Pin<&mut Self>) {
+/// // `project` consumes `self`, so reborrow the `Pin<&mut Self>` via `as_mut`.
+/// self.as_mut().project();
+/// self.as_mut().project();
+/// }
+/// }
+/// ```
+///
+/// # `!Unpin`
+///
+/// If you want to ensure that [`Unpin`] is not implemented, use the `!Unpin`
+/// argument to `#[pin_project]`.
+///
+/// ```rust
+/// use pin_project::pin_project;
+///
+/// #[pin_project(!Unpin)]
+/// struct Struct<T> {
+/// field: T,
+/// }
+/// ```
+///
+/// This is equivalent to using `#[pin]` attribute for the [`PhantomPinned`]
+/// field.
+///
+/// ```rust
+/// use std::marker::PhantomPinned;
+///
+/// use pin_project::pin_project;
+///
+/// #[pin_project]
+/// struct Struct<T> {
+/// field: T,
+/// #[pin] // <------ This `#[pin]` is required to make `Struct` to `!Unpin`.
+/// _pin: PhantomPinned,
+/// }
+/// ```
+///
+/// Note that using [`PhantomPinned`] without `#[pin]` attribute has no effect.
+///
+/// # `UnsafeUnpin`
+///
+/// If you want to implement [`Unpin`] manually, you must use the `UnsafeUnpin`
+/// argument to `#[pin_project]`.
+///
+/// ```rust
+/// use pin_project::{pin_project, UnsafeUnpin};
+///
+/// #[pin_project(UnsafeUnpin)]
+/// struct Struct<T, U> {
+/// #[pin]
+/// pinned: T,
+/// unpinned: U,
+/// }
+///
+/// unsafe impl<T: Unpin, U> UnsafeUnpin for Struct<T, U> {}
+/// ```
+///
+/// Note the usage of the unsafe [`UnsafeUnpin`] trait, instead of the usual
+/// [`Unpin`] trait. [`UnsafeUnpin`] behaves exactly like [`Unpin`], except that
+/// is unsafe to implement. This unsafety comes from the fact that pin
+/// projections are being used. If you implement [`UnsafeUnpin`], you must
+/// ensure that it is only implemented when all pin-projected fields implement
+/// [`Unpin`].
+///
+/// See [`UnsafeUnpin`] trait for more details.
+///
+/// # `#[pinned_drop]`
+///
+/// In order to correctly implement pin projections, a type's [`Drop`] impl must
+/// not move out of any structurally pinned fields. Unfortunately,
+/// [`Drop::drop`] takes `&mut Self`, not [`Pin`]`<&mut Self>`.
+///
+/// To ensure that this requirement is upheld, the `#[pin_project]` attribute
+/// will provide a [`Drop`] impl for you. This [`Drop`] impl will delegate to
+/// an impl block annotated with `#[pinned_drop]` if you use the `PinnedDrop`
+/// argument to `#[pin_project]`.
+///
+/// This impl block acts just like a normal [`Drop`] impl,
+/// except for the following two:
+///
+/// - `drop` method takes [`Pin`]`<&mut Self>`
+/// - Name of the trait is `PinnedDrop`.
+///
+/// ```rust
+/// # use std::pin::Pin;
+/// pub trait PinnedDrop {
+/// fn drop(self: Pin<&mut Self>);
+/// }
+/// ```
+///
+/// `#[pin_project]` implements the actual [`Drop`] trait via `PinnedDrop` you
+/// implemented. To drop a type that implements `PinnedDrop`, use the [`drop`]
+/// function just like dropping a type that directly implements [`Drop`].
+///
+/// In particular, it will never be called more than once, just like
+/// [`Drop::drop`].
+///
+/// For example:
+///
+/// ```rust
+/// use std::{fmt::Debug, pin::Pin};
+///
+/// use pin_project::{pin_project, pinned_drop};
+///
+/// #[pin_project(PinnedDrop)]
+/// struct PrintOnDrop<T: Debug, U: Debug> {
+/// #[pin]
+/// pinned_field: T,
+/// unpin_field: U,
+/// }
+///
+/// #[pinned_drop]
+/// impl<T: Debug, U: Debug> PinnedDrop for PrintOnDrop<T, U> {
+/// fn drop(self: Pin<&mut Self>) {
+/// println!("Dropping pinned field: {:?}", self.pinned_field);
+/// println!("Dropping unpin field: {:?}", self.unpin_field);
+/// }
+/// }
+///
+/// fn main() {
+/// let _x = PrintOnDrop { pinned_field: true, unpin_field: 40 };
+/// }
+/// ```
+///
+/// See also [`#[pinned_drop]`][macro@pinned_drop] attribute.
+///
+/// # `project_replace` method
+///
+/// In addition to the `project` and `project_ref` methods which are always
+/// provided when you use the `#[pin_project]` attribute, there is a third
+/// method, `project_replace` which can be useful in some situations. It is
+/// equivalent to [`Pin::set`], except that the unpinned fields are moved and
+/// returned, instead of being dropped in-place.
+///
+/// ```rust
+/// # use std::pin::Pin;
+/// # type ProjectionOwned = ();
+/// # trait Dox {
+/// fn project_replace(self: Pin<&mut Self>, other: Self) -> ProjectionOwned;
+/// # }
+/// ```
+///
+/// The `ProjectionOwned` type is identical to the `Self` type, except that
+/// all pinned fields have been replaced by equivalent [`PhantomData`] types.
+///
+/// This method is opt-in, because it is only supported for [`Sized`] types, and
+/// because it is incompatible with the [`#[pinned_drop]`][pinned-drop]
+/// attribute described above. It can be enabled by using
+/// `#[pin_project(project_replace)]`.
+///
+/// For example:
+///
+/// ```rust
+/// use std::{marker::PhantomData, pin::Pin};
+///
+/// use pin_project::pin_project;
+///
+/// #[pin_project(project_replace)]
+/// struct Struct<T, U> {
+/// #[pin]
+/// pinned_field: T,
+/// unpinned_field: U,
+/// }
+///
+/// impl<T, U> Struct<T, U> {
+/// fn method(self: Pin<&mut Self>, other: Self) {
+/// let this = self.project_replace(other);
+/// let _: U = this.unpinned_field;
+/// let _: PhantomData<T> = this.pinned_field;
+/// }
+/// }
+/// ```
+///
+/// By passing the value to the `project_replace` argument, you can name the
+/// returned type of the `project_replace` method. This is necessary whenever
+/// destructuring the return type of the `project_replace` method, and work in exactly
+/// the same way as the `project` and `project_ref` arguments.
+///
+/// ```rust
+/// use pin_project::pin_project;
+///
+/// #[pin_project(project_replace = EnumProjOwn)]
+/// enum Enum<T, U> {
+/// A {
+/// #[pin]
+/// pinned_field: T,
+/// unpinned_field: U,
+/// },
+/// B,
+/// }
+///
+/// let mut x = Box::pin(Enum::A { pinned_field: 42, unpinned_field: "hello" });
+///
+/// match x.as_mut().project_replace(Enum::B) {
+/// EnumProjOwn::A { unpinned_field, .. } => assert_eq!(unpinned_field, "hello"),
+/// EnumProjOwn::B => unreachable!(),
+/// }
+/// ```
+///
+/// [`PhantomData`]: core::marker::PhantomData
+/// [`PhantomPinned`]: core::marker::PhantomPinned
+/// [`Pin::as_mut`]: core::pin::Pin::as_mut
+/// [`Pin::set`]: core::pin::Pin::set
+/// [`Pin`]: core::pin::Pin
+/// [`UnsafeUnpin`]: https://docs.rs/pin-project/1/pin_project/trait.UnsafeUnpin.html
+/// [drop-guarantee]: core::pin#drop-guarantee
+/// [pin-projection]: core::pin#projections-and-structural-pinning
+/// [pinned-drop]: macro@pin_project#pinned_drop
+/// [repr-packed]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprpacked
+/// [undefined-behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html
+/// [unsafe-unpin]: macro@pin_project#unsafeunpin
+#[proc_macro_attribute]
+pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream {
+ pin_project::attribute(&args.into(), input.into()).into()
+}
+
+/// An attribute used for custom implementations of [`Drop`].
+///
+/// This attribute is used in conjunction with the `PinnedDrop` argument to
+/// the [`#[pin_project]`][macro@pin_project] attribute.
+///
+/// The impl block annotated with this attribute acts just like a normal
+/// [`Drop`] impl, except for the following two:
+///
+/// - `drop` method takes [`Pin`]`<&mut Self>`
+/// - Name of the trait is `PinnedDrop`.
+///
+/// ```rust
+/// # use std::pin::Pin;
+/// pub trait PinnedDrop {
+/// fn drop(self: Pin<&mut Self>);
+/// }
+/// ```
+///
+/// `#[pin_project]` implements the actual [`Drop`] trait via `PinnedDrop` you
+/// implemented. To drop a type that implements `PinnedDrop`, use the [`drop`]
+/// function just like dropping a type that directly implements [`Drop`].
+///
+/// In particular, it will never be called more than once, just like
+/// [`Drop::drop`].
+///
+/// # Examples
+///
+/// ```rust
+/// use std::pin::Pin;
+///
+/// use pin_project::{pin_project, pinned_drop};
+///
+/// #[pin_project(PinnedDrop)]
+/// struct PrintOnDrop {
+/// #[pin]
+/// field: u8,
+/// }
+///
+/// #[pinned_drop]
+/// impl PinnedDrop for PrintOnDrop {
+/// fn drop(self: Pin<&mut Self>) {
+/// println!("Dropping: {}", self.field);
+/// }
+/// }
+///
+/// fn main() {
+/// let _x = PrintOnDrop { field: 50 };
+/// }
+/// ```
+///
+/// See also ["pinned-drop" section of `#[pin_project]` attribute][pinned-drop].
+///
+/// # Why `#[pinned_drop]` attribute is needed?
+///
+/// Implementing `PinnedDrop::drop` is safe, but calling it is not safe.
+/// This is because destructors can be called multiple times in safe code and
+/// [double dropping is unsound][rust-lang/rust#62360].
+///
+/// Ideally, it would be desirable to be able to forbid manual calls in
+/// the same way as [`Drop::drop`], but the library cannot do it. So, by using
+/// macros and replacing them with private traits like the following,
+/// this crate prevent users from calling `PinnedDrop::drop` in safe code.
+///
+/// ```rust
+/// # use std::pin::Pin;
+/// pub trait PinnedDrop {
+/// unsafe fn drop(self: Pin<&mut Self>);
+/// }
+/// ```
+///
+/// This allows implementing [`Drop`] safely using `#[pinned_drop]`.
+/// Also by using the [`drop`] function just like dropping a type that directly
+/// implements [`Drop`], can drop safely a type that implements `PinnedDrop`.
+///
+/// [rust-lang/rust#62360]: https://github.com/rust-lang/rust/pull/62360
+/// [`Pin`]: core::pin::Pin
+/// [pinned-drop]: macro@pin_project#pinned_drop
+#[proc_macro_attribute]
+pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
+ let input = syn::parse_macro_input!(input);
+ pinned_drop::attribute(&args.into(), input).into()
+}
+
+// Not public API.
+#[doc(hidden)]
+#[proc_macro_derive(__PinProjectInternalDerive, attributes(pin))]
+pub fn __pin_project_internal_derive(input: TokenStream) -> TokenStream {
+ pin_project::derive(input.into()).into()
+}
diff --git a/third_party/rust/pin-project-internal/src/pin_project/args.rs b/third_party/rust/pin-project-internal/src/pin_project/args.rs
new file mode 100644
index 0000000000..d0d4f362f5
--- /dev/null
+++ b/third_party/rust/pin-project-internal/src/pin_project/args.rs
@@ -0,0 +1,254 @@
+use proc_macro2::{Span, TokenStream};
+use quote::quote;
+use syn::{
+ parse::{Parse, ParseStream},
+ spanned::Spanned,
+ Attribute, Error, Ident, Result, Token,
+};
+
+use super::PIN;
+use crate::utils::{ParseBufferExt, SliceExt};
+
+pub(super) fn parse_args(attrs: &[Attribute]) -> Result<Args> {
+ // `(__private(<args>))` -> `<args>`
+ struct Input(Option<TokenStream>);
+
+ impl Parse for Input {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ Ok(Self((|| {
+ let content = input.parenthesized().ok()?;
+ let private = content.parse::<Ident>().ok()?;
+ if private == "__private" {
+ content.parenthesized().ok()?.parse::<TokenStream>().ok()
+ } else {
+ None
+ }
+ })()))
+ }
+ }
+
+ if let Some(attr) = attrs.find("pin_project") {
+ bail!(attr, "duplicate #[pin_project] attribute");
+ }
+
+ let mut attrs = attrs.iter().filter(|attr| attr.path.is_ident(PIN));
+
+ let prev = if let Some(attr) = attrs.next() {
+ (attr, syn::parse2::<Input>(attr.tokens.clone()).unwrap().0)
+ } else {
+ // This only fails if another macro removes `#[pin]`.
+ bail!(TokenStream::new(), "#[pin_project] attribute has been removed");
+ };
+
+ if let Some(attr) = attrs.next() {
+ let (prev_attr, prev_res) = &prev;
+ // As the `#[pin]` attribute generated by `#[pin_project]`
+ // has the same span as `#[pin_project]`, it is possible
+ // that a useless error message will be generated.
+ // So, use the span of `prev_attr` if it is not a valid attribute.
+ let res = syn::parse2::<Input>(attr.tokens.clone()).unwrap().0;
+ let span = match (prev_res, res) {
+ (Some(_), _) => attr,
+ (None, _) => prev_attr,
+ };
+ bail!(span, "duplicate #[pin] attribute");
+ }
+ // This `unwrap` only fails if another macro removes `#[pin]` and inserts own `#[pin]`.
+ syn::parse2(prev.1.unwrap())
+}
+
+pub(super) struct Args {
+ /// `PinnedDrop` argument.
+ pub(super) pinned_drop: Option<Span>,
+ /// `UnsafeUnpin` or `!Unpin` argument.
+ pub(super) unpin_impl: UnpinImpl,
+ /// `project = <ident>` argument.
+ pub(super) project: Option<Ident>,
+ /// `project_ref = <ident>` argument.
+ pub(super) project_ref: Option<Ident>,
+ /// `project_replace [= <ident>]` argument.
+ pub(super) project_replace: ProjReplace,
+}
+
+impl Parse for Args {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ mod kw {
+ syn::custom_keyword!(Unpin);
+ }
+
+ /// Parses `= <value>` in `<name> = <value>` and returns value and span of name-value pair.
+ fn parse_value(
+ input: ParseStream<'_>,
+ name: &Ident,
+ has_prev: bool,
+ ) -> Result<(Ident, TokenStream)> {
+ if input.is_empty() {
+ bail!(name, "expected `{0} = <identifier>`, found `{0}`", name);
+ }
+ let eq_token: Token![=] = input.parse()?;
+ if input.is_empty() {
+ let span = quote!(#name #eq_token);
+ bail!(span, "expected `{0} = <identifier>`, found `{0} =`", name);
+ }
+ let value: Ident = input.parse()?;
+ let span = quote!(#name #value);
+ if has_prev {
+ bail!(span, "duplicate `{}` argument", name);
+ }
+ Ok((value, span))
+ }
+
+ let mut pinned_drop = None;
+ let mut unsafe_unpin = None;
+ let mut not_unpin = None;
+ let mut project = None;
+ let mut project_ref = None;
+ let mut project_replace_value = None;
+ let mut project_replace_span = None;
+
+ while !input.is_empty() {
+ if input.peek(Token![!]) {
+ let bang: Token![!] = input.parse()?;
+ if input.is_empty() {
+ bail!(bang, "expected `!Unpin`, found `!`");
+ }
+ let unpin: kw::Unpin = input.parse()?;
+ let span = quote!(#bang #unpin);
+ if not_unpin.replace(span.span()).is_some() {
+ bail!(span, "duplicate `!Unpin` argument");
+ }
+ } else {
+ let token = input.parse::<Ident>()?;
+ match &*token.to_string() {
+ "PinnedDrop" => {
+ if pinned_drop.replace(token.span()).is_some() {
+ bail!(token, "duplicate `PinnedDrop` argument");
+ }
+ }
+ "UnsafeUnpin" => {
+ if unsafe_unpin.replace(token.span()).is_some() {
+ bail!(token, "duplicate `UnsafeUnpin` argument");
+ }
+ }
+ "project" => {
+ project = Some(parse_value(input, &token, project.is_some())?.0);
+ }
+ "project_ref" => {
+ project_ref = Some(parse_value(input, &token, project_ref.is_some())?.0);
+ }
+ "project_replace" => {
+ if input.peek(Token![=]) {
+ let (value, span) =
+ parse_value(input, &token, project_replace_span.is_some())?;
+ project_replace_value = Some(value);
+ project_replace_span = Some(span.span());
+ } else if project_replace_span.is_some() {
+ bail!(token, "duplicate `project_replace` argument");
+ } else {
+ project_replace_span = Some(token.span());
+ }
+ }
+ "Replace" => {
+ bail!(
+ token,
+ "`Replace` argument was removed, use `project_replace` argument instead"
+ );
+ }
+ _ => bail!(token, "unexpected argument: {}", token),
+ }
+ }
+
+ if input.is_empty() {
+ break;
+ }
+ let _: Token![,] = input.parse()?;
+ }
+
+ if project.is_some() || project_ref.is_some() {
+ if project == project_ref {
+ bail!(
+ project_ref,
+ "name `{}` is already specified by `project` argument",
+ project_ref.as_ref().unwrap()
+ );
+ }
+ if let Some(ident) = &project_replace_value {
+ if project == project_replace_value {
+ bail!(ident, "name `{}` is already specified by `project` argument", ident);
+ } else if project_ref == project_replace_value {
+ bail!(ident, "name `{}` is already specified by `project_ref` argument", ident);
+ }
+ }
+ }
+
+ if let Some(span) = pinned_drop {
+ if project_replace_span.is_some() {
+ return Err(Error::new(
+ span,
+ "arguments `PinnedDrop` and `project_replace` are mutually exclusive",
+ ));
+ }
+ }
+ let project_replace = match (project_replace_span, project_replace_value) {
+ (None, _) => ProjReplace::None,
+ (Some(span), Some(ident)) => ProjReplace::Named { ident, span },
+ (Some(span), None) => ProjReplace::Unnamed { span },
+ };
+ let unpin_impl = match (unsafe_unpin, not_unpin) {
+ (None, None) => UnpinImpl::Default,
+ (Some(span), None) => UnpinImpl::Unsafe(span),
+ (None, Some(span)) => UnpinImpl::Negative(span),
+ (Some(span), Some(_)) => {
+ return Err(Error::new(
+ span,
+ "arguments `UnsafeUnpin` and `!Unpin` are mutually exclusive",
+ ));
+ }
+ };
+
+ Ok(Self { pinned_drop, unpin_impl, project, project_ref, project_replace })
+ }
+}
+
+/// `UnsafeUnpin` or `!Unpin` argument.
+#[derive(Clone, Copy)]
+pub(super) enum UnpinImpl {
+ Default,
+ /// `UnsafeUnpin`.
+ Unsafe(Span),
+ /// `!Unpin`.
+ Negative(Span),
+}
+
+/// `project_replace [= <ident>]` argument.
+pub(super) enum ProjReplace {
+ None,
+ /// `project_replace`.
+ Unnamed {
+ span: Span,
+ },
+ /// `project_replace = <ident>`.
+ #[allow(dead_code)] // false positive that fixed in Rust 1.38
+ Named {
+ span: Span,
+ ident: Ident,
+ },
+}
+
+impl ProjReplace {
+ /// Return the span of this argument.
+ pub(super) fn span(&self) -> Option<Span> {
+ match self {
+ Self::None => None,
+ Self::Named { span, .. } | Self::Unnamed { span, .. } => Some(*span),
+ }
+ }
+
+ pub(super) fn ident(&self) -> Option<&Ident> {
+ if let Self::Named { ident, .. } = self {
+ Some(ident)
+ } else {
+ None
+ }
+ }
+}
diff --git a/third_party/rust/pin-project-internal/src/pin_project/attribute.rs b/third_party/rust/pin-project-internal/src/pin_project/attribute.rs
new file mode 100644
index 0000000000..7adfc07d59
--- /dev/null
+++ b/third_party/rust/pin-project-internal/src/pin_project/attribute.rs
@@ -0,0 +1,65 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+use syn::{
+ parse::{Parse, ParseStream},
+ Attribute, Result, Token, Visibility,
+};
+
+use super::PIN;
+use crate::utils::SliceExt;
+
+// To generate the correct `Unpin` implementation and the projection methods,
+// we need to collect the types of the pinned fields.
+// However, since proc-macro-attribute is applied before `cfg` and `cfg_attr`
+// on fields, we cannot be collecting field types properly at this timing.
+// So instead of generating the `Unpin` implementation and the projection
+// methods here, delegate their processing to proc-macro-derive.
+//
+// At this stage, only attributes are parsed and the following attributes are
+// added to the attributes of the item.
+// - `#[derive(InternalDerive)]` - An internal helper macro that does the above
+// processing.
+// - `#[pin(__private(#args))]` - Pass the argument of `#[pin_project]` to
+// proc-macro-derive (`InternalDerive`).
+
+pub(super) fn parse_attribute(args: &TokenStream, input: TokenStream) -> Result<TokenStream> {
+ let Input { attrs, body } = syn::parse2(input)?;
+
+ Ok(quote! {
+ #(#attrs)*
+ #[derive(::pin_project::__private::__PinProjectInternalDerive)]
+ // Use `__private` to prevent users from trying to control `InternalDerive`
+ // manually. `__private` does not guarantee compatibility between patch
+ // versions, so it should be sufficient for this purpose in most cases.
+ #[pin(__private(#args))]
+ #body
+ })
+}
+
+#[allow(dead_code)] // false positive that fixed in Rust 1.39
+struct Input {
+ attrs: Vec<Attribute>,
+ body: TokenStream,
+}
+
+impl Parse for Input {
+ fn parse(input: ParseStream<'_>) -> Result<Self> {
+ let attrs = input.call(Attribute::parse_outer)?;
+
+ let ahead = input.fork();
+ let _vis: Visibility = ahead.parse()?;
+ if !ahead.peek(Token![struct]) && !ahead.peek(Token![enum]) {
+ // If we check this only on proc-macro-derive, it may generate unhelpful error
+ // messages. So it is preferable to be able to detect it here.
+ bail!(
+ input.parse::<TokenStream>()?,
+ "#[pin_project] attribute may only be used on structs or enums"
+ );
+ } else if let Some(attr) = attrs.find(PIN) {
+ bail!(attr, "#[pin] attribute may only be used on fields of structs or variants");
+ } else if let Some(attr) = attrs.find("pin_project") {
+ bail!(attr, "duplicate #[pin_project] attribute");
+ }
+ Ok(Self { attrs, body: input.parse()? })
+ }
+}
diff --git a/third_party/rust/pin-project-internal/src/pin_project/derive.rs b/third_party/rust/pin-project-internal/src/pin_project/derive.rs
new file mode 100644
index 0000000000..fd2375dc3b
--- /dev/null
+++ b/third_party/rust/pin-project-internal/src/pin_project/derive.rs
@@ -0,0 +1,1127 @@
+use proc_macro2::{Delimiter, Group, Span, TokenStream};
+use quote::{format_ident, quote, quote_spanned, ToTokens};
+use syn::{
+ parse_quote, token, visit_mut::VisitMut, Attribute, Data, DataEnum, DeriveInput, Error, Field,
+ Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index, Lifetime, LifetimeDef, Meta,
+ MetaList, MetaNameValue, NestedMeta, Result, Token, Type, Variant, Visibility, WhereClause,
+};
+
+use super::{
+ args::{parse_args, Args, ProjReplace, UnpinImpl},
+ PIN,
+};
+use crate::utils::{
+ determine_lifetime_name, determine_visibility, insert_lifetime_and_bound, ReplaceReceiver,
+ SliceExt, Variants,
+};
+
+pub(super) fn parse_derive(input: TokenStream) -> Result<TokenStream> {
+ let mut input: DeriveInput = syn::parse2(input)?;
+
+ let mut cx;
+ let mut generate = GenerateTokens::default();
+
+ let ident = &input.ident;
+ let ty_generics = input.generics.split_for_impl().1;
+ let self_ty = parse_quote!(#ident #ty_generics);
+ let mut visitor = ReplaceReceiver(&self_ty);
+ visitor.visit_generics_mut(&mut input.generics);
+ visitor.visit_data_mut(&mut input.data);
+
+ match &input.data {
+ Data::Struct(data) => {
+ cx = Context::new(&input.attrs, &input.vis, ident, &mut input.generics, Struct)?;
+ parse_struct(&mut cx, &data.fields, &mut generate)?;
+ }
+ Data::Enum(data) => {
+ cx = Context::new(&input.attrs, &input.vis, ident, &mut input.generics, Enum)?;
+ parse_enum(&mut cx, data, &mut generate)?;
+ }
+ Data::Union(_) => {
+ bail!(input, "#[pin_project] attribute may only be used on structs or enums");
+ }
+ }
+
+ Ok(generate.into_tokens(&cx))
+}
+
+#[derive(Default)]
+struct GenerateTokens {
+ exposed: TokenStream,
+ scoped: TokenStream,
+}
+
+impl GenerateTokens {
+ fn extend(&mut self, expose: bool, tokens: TokenStream) {
+ if expose {
+ self.exposed.extend(tokens);
+ } else {
+ self.scoped.extend(tokens);
+ }
+ }
+
+ fn into_tokens(self, cx: &Context<'_>) -> TokenStream {
+ let mut tokens = self.exposed;
+ let scoped = self.scoped;
+
+ let unpin_impl = make_unpin_impl(cx);
+ let drop_impl = make_drop_impl(cx);
+ let allowed_lints = global_allowed_lints();
+
+ tokens.extend(quote! {
+ // All items except projected types are generated inside a `const` scope.
+ // This makes it impossible for user code to refer to these types.
+ // However, this prevents Rustdoc from displaying docs for any
+ // of our types. In particular, users cannot see the
+ // automatically generated `Unpin` impl for the '__UnpinStruct' types
+ //
+ // Previously, we provided a flag to correctly document the
+ // automatically generated `Unpin` impl by using def-site hygiene,
+ // but it is now removed.
+ //
+ // Refs:
+ // - https://github.com/rust-lang/rust/issues/63281
+ // - https://github.com/taiki-e/pin-project/pull/53#issuecomment-525906867
+ // - https://github.com/taiki-e/pin-project/pull/70
+ #allowed_lints
+ #[allow(unused_qualifications)]
+ #[allow(clippy::semicolon_if_nothing_returned)]
+ #[allow(clippy::use_self)]
+ #[allow(clippy::used_underscore_binding)]
+ const _: () = {
+ #[allow(unused_extern_crates)]
+ extern crate pin_project as _pin_project;
+ #scoped
+ #unpin_impl
+ #drop_impl
+ };
+ });
+ tokens
+ }
+}
+
+/// Returns attributes that should be applied to all generated code.
+fn global_allowed_lints() -> TokenStream {
+ quote! {
+ #[allow(box_pointers)] // This lint warns use of the `Box` type.
+ #[allow(deprecated)]
+ #[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993
+ #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
+ #[allow(unreachable_pub)] // This lint warns `pub` field in private struct.
+ #[allow(unused_tuple_struct_fields)]
+ // This lint warns of `clippy::*` generated by external macros.
+ // We allow this lint for compatibility with older compilers.
+ #[allow(clippy::unknown_clippy_lints)]
+ #[allow(clippy::pattern_type_mismatch)]
+ #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct.
+ #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326
+ }
+}
+
+/// Returns attributes used on projected types.
+fn proj_allowed_lints(cx: &Context<'_>) -> (TokenStream, TokenStream, TokenStream) {
+ let large_enum_variant = if cx.kind == Enum {
+ Some(quote! {
+ #[allow(variant_size_differences)]
+ #[allow(clippy::large_enum_variant)]
+ })
+ } else {
+ None
+ };
+ let global_allowed_lints = global_allowed_lints();
+ let proj_mut_allowed_lints = if cx.project { Some(&global_allowed_lints) } else { None };
+ let proj_mut = quote! {
+ #proj_mut_allowed_lints
+ #[allow(dead_code)] // This lint warns unused fields/variants.
+ #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
+ };
+ let proj_ref_allowed_lints = if cx.project_ref { Some(&global_allowed_lints) } else { None };
+ let proj_ref = quote! {
+ #proj_ref_allowed_lints
+ #[allow(dead_code)] // This lint warns unused fields/variants.
+ #[allow(clippy::ref_option_ref)] // This lint warns `&Option<&<ty>>`.
+ };
+ let proj_own_allowed_lints =
+ if cx.project_replace.ident().is_some() { Some(&global_allowed_lints) } else { None };
+ let proj_own = quote! {
+ #proj_own_allowed_lints
+ #[allow(dead_code)] // This lint warns unused fields/variants.
+ #large_enum_variant
+ };
+ (proj_mut, proj_ref, proj_own)
+}
+
+struct Context<'a> {
+ /// The original type.
+ orig: OriginalType<'a>,
+ /// The projected types.
+ proj: ProjectedType,
+ /// Types of the pinned fields.
+ pinned_fields: Vec<&'a Type>,
+ /// Kind of the original type: struct or enum
+ kind: TypeKind,
+
+ /// `PinnedDrop` argument.
+ pinned_drop: Option<Span>,
+ /// `UnsafeUnpin` or `!Unpin` argument.
+ unpin_impl: UnpinImpl,
+ /// `project` argument.
+ project: bool,
+ /// `project_ref` argument.
+ project_ref: bool,
+ /// `project_replace [= <ident>]` argument.
+ project_replace: ProjReplace,
+}
+
+impl<'a> Context<'a> {
+ fn new(
+ attrs: &'a [Attribute],
+ vis: &'a Visibility,
+ ident: &'a Ident,
+ generics: &'a mut Generics,
+ kind: TypeKind,
+ ) -> Result<Self> {
+ let Args { pinned_drop, unpin_impl, project, project_ref, project_replace } =
+ parse_args(attrs)?;
+
+ if let Some(name) = [project.as_ref(), project_ref.as_ref(), project_replace.ident()]
+ .iter()
+ .filter_map(Option::as_ref)
+ .find(|name| **name == ident)
+ {
+ bail!(name, "name `{}` is the same as the original type name", name);
+ }
+
+ let mut lifetime_name = String::from("'pin");
+ determine_lifetime_name(&mut lifetime_name, generics);
+ let lifetime = Lifetime::new(&lifetime_name, Span::call_site());
+
+ let ty_generics = generics.split_for_impl().1;
+ let ty_generics_as_generics = parse_quote!(#ty_generics);
+ let mut proj_generics = generics.clone();
+ let pred = insert_lifetime_and_bound(
+ &mut proj_generics,
+ lifetime.clone(),
+ &ty_generics_as_generics,
+ ident,
+ );
+ let mut where_clause = generics.make_where_clause().clone();
+ where_clause.predicates.push(pred);
+
+ let own_ident = project_replace
+ .ident()
+ .cloned()
+ .unwrap_or_else(|| format_ident!("__{}ProjectionOwned", ident));
+
+ Ok(Self {
+ kind,
+ pinned_drop,
+ unpin_impl,
+ project: project.is_some(),
+ project_ref: project_ref.is_some(),
+ project_replace,
+ proj: ProjectedType {
+ vis: determine_visibility(vis),
+ mut_ident: project.unwrap_or_else(|| format_ident!("__{}Projection", ident)),
+ ref_ident: project_ref.unwrap_or_else(|| format_ident!("__{}ProjectionRef", ident)),
+ own_ident,
+ lifetime,
+ generics: proj_generics,
+ where_clause,
+ },
+ orig: OriginalType { attrs, vis, ident, generics },
+ pinned_fields: Vec::new(),
+ })
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq)]
+enum TypeKind {
+ Enum,
+ Struct,
+}
+
+use TypeKind::{Enum, Struct};
+
+struct OriginalType<'a> {
+ /// Attributes of the original type.
+ attrs: &'a [Attribute],
+ /// Visibility of the original type.
+ vis: &'a Visibility,
+ /// Name of the original type.
+ ident: &'a Ident,
+ /// Generics of the original type.
+ generics: &'a Generics,
+}
+
+struct ProjectedType {
+ /// Visibility of the projected types.
+ vis: Visibility,
+ /// Name of the projected type returned by `project` method.
+ mut_ident: Ident,
+ /// Name of the projected type returned by `project_ref` method.
+ ref_ident: Ident,
+ /// Name of the projected type returned by `project_replace` method.
+ own_ident: Ident,
+ /// Lifetime on the generated projected types.
+ lifetime: Lifetime,
+ /// Generics of the projected types.
+ generics: Generics,
+ /// `where` clause of the projected types. This has an additional
+ /// bound generated by `insert_lifetime_and_bound`
+ where_clause: WhereClause,
+}
+
+struct ProjectedVariants {
+ proj_variants: TokenStream,
+ proj_ref_variants: TokenStream,
+ proj_own_variants: TokenStream,
+ proj_arms: TokenStream,
+ proj_ref_arms: TokenStream,
+ proj_own_arms: TokenStream,
+}
+
+#[derive(Default)]
+struct ProjectedFields {
+ proj_pat: TokenStream,
+ proj_body: TokenStream,
+ proj_own_body: TokenStream,
+ proj_fields: TokenStream,
+ proj_ref_fields: TokenStream,
+ proj_own_fields: TokenStream,
+}
+
+fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> {
+ if fields.is_empty() {
+ let msg = "#[pin_project] attribute may not be used on structs with zero fields";
+ if let Fields::Unit = fields {
+ bail!(ident, msg)
+ }
+ bail!(fields, msg)
+ }
+ Ok(())
+}
+
+fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> {
+ if variants.is_empty() {
+ return Err(Error::new(
+ brace_token.span,
+ "#[pin_project] attribute may not be used on enums without variants",
+ ));
+ }
+ let has_field = variants.iter().try_fold(false, |has_field, v| {
+ if let Some((_, e)) = &v.discriminant {
+ bail!(e, "#[pin_project] attribute may not be used on enums with discriminants");
+ } else if let Some(attr) = v.attrs.find(PIN) {
+ bail!(attr, "#[pin] attribute may only be used on fields of structs or variants");
+ } else if v.fields.is_empty() {
+ Ok(has_field)
+ } else {
+ Ok(true)
+ }
+ })?;
+ if has_field {
+ Ok(())
+ } else {
+ bail!(variants, "#[pin_project] attribute may not be used on enums with zero fields");
+ }
+}
+
+fn parse_struct<'a>(
+ cx: &mut Context<'a>,
+ fields: &'a Fields,
+ generate: &mut GenerateTokens,
+) -> Result<()> {
+ // Do this first for a better error message.
+ let packed_check = ensure_not_packed(&cx.orig, Some(fields))?;
+
+ validate_struct(cx.orig.ident, fields)?;
+
+ let ProjectedFields {
+ proj_pat,
+ proj_body,
+ proj_fields,
+ proj_ref_fields,
+ proj_own_fields,
+ proj_own_body,
+ } = match fields {
+ Fields::Named(_) => visit_fields(cx, None, fields, Delimiter::Brace)?,
+ Fields::Unnamed(_) => visit_fields(cx, None, fields, Delimiter::Parenthesis)?,
+ Fields::Unit => unreachable!(),
+ };
+
+ let proj_ident = &cx.proj.mut_ident;
+ let proj_ref_ident = &cx.proj.ref_ident;
+ let proj_own_ident = &cx.proj.own_ident;
+ let vis = &cx.proj.vis;
+ let mut orig_generics = cx.orig.generics.clone();
+ let orig_where_clause = orig_generics.where_clause.take();
+ let proj_generics = &cx.proj.generics;
+ let proj_where_clause = &cx.proj.where_clause;
+
+ // For tuple structs, we need to generate `(T1, T2) where Foo: Bar`
+ // For non-tuple structs, we need to generate `where Foo: Bar { field1: T }`
+ let (where_clause_fields, where_clause_ref_fields, where_clause_own_fields) = match fields {
+ Fields::Named(_) => (
+ quote!(#proj_where_clause #proj_fields),
+ quote!(#proj_where_clause #proj_ref_fields),
+ quote!(#orig_where_clause #proj_own_fields),
+ ),
+ Fields::Unnamed(_) => (
+ quote!(#proj_fields #proj_where_clause;),
+ quote!(#proj_ref_fields #proj_where_clause;),
+ quote!(#proj_own_fields #orig_where_clause;),
+ ),
+ Fields::Unit => unreachable!(),
+ };
+
+ let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx);
+ generate.extend(cx.project, quote! {
+ #proj_attrs
+ #vis struct #proj_ident #proj_generics #where_clause_fields
+ });
+ generate.extend(cx.project_ref, quote! {
+ #proj_ref_attrs
+ #vis struct #proj_ref_ident #proj_generics #where_clause_ref_fields
+ });
+ if cx.project_replace.span().is_some() {
+ generate.extend(cx.project_replace.ident().is_some(), quote! {
+ #proj_own_attrs
+ #vis struct #proj_own_ident #orig_generics #where_clause_own_fields
+ });
+ }
+
+ let proj_mut_body = quote! {
+ let Self #proj_pat = self.get_unchecked_mut();
+ #proj_ident #proj_body
+ };
+ let proj_ref_body = quote! {
+ let Self #proj_pat = self.get_ref();
+ #proj_ref_ident #proj_body
+ };
+ let proj_own_body = quote! {
+ let Self #proj_pat = &mut *__self_ptr;
+ #proj_own_body
+ };
+ generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body));
+
+ generate.extend(false, packed_check);
+ Ok(())
+}
+
+fn parse_enum<'a>(
+ cx: &mut Context<'a>,
+ DataEnum { brace_token, variants, .. }: &'a DataEnum,
+ generate: &mut GenerateTokens,
+) -> Result<()> {
+ if let ProjReplace::Unnamed { span } = &cx.project_replace {
+ return Err(Error::new(
+ *span,
+ "`project_replace` argument requires a value when used on enums",
+ ));
+ }
+
+ // #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
+ // However, we should not rely on the behavior of rustc that rejects this.
+ // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
+ //
+ // Do this first for a better error message.
+ ensure_not_packed(&cx.orig, None)?;
+
+ validate_enum(*brace_token, variants)?;
+
+ let ProjectedVariants {
+ proj_variants,
+ proj_ref_variants,
+ proj_own_variants,
+ proj_arms,
+ proj_ref_arms,
+ proj_own_arms,
+ } = visit_variants(cx, variants)?;
+
+ let proj_ident = &cx.proj.mut_ident;
+ let proj_ref_ident = &cx.proj.ref_ident;
+ let proj_own_ident = &cx.proj.own_ident;
+ let vis = &cx.proj.vis;
+ let mut orig_generics = cx.orig.generics.clone();
+ let orig_where_clause = orig_generics.where_clause.take();
+ let proj_generics = &cx.proj.generics;
+ let proj_where_clause = &cx.proj.where_clause;
+
+ let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx);
+ if cx.project {
+ generate.extend(true, quote! {
+ #proj_attrs
+ #vis enum #proj_ident #proj_generics #proj_where_clause {
+ #proj_variants
+ }
+ });
+ }
+ if cx.project_ref {
+ generate.extend(true, quote! {
+ #proj_ref_attrs
+ #vis enum #proj_ref_ident #proj_generics #proj_where_clause {
+ #proj_ref_variants
+ }
+ });
+ }
+ if cx.project_replace.ident().is_some() {
+ generate.extend(true, quote! {
+ #proj_own_attrs
+ #vis enum #proj_own_ident #orig_generics #orig_where_clause {
+ #proj_own_variants
+ }
+ });
+ }
+
+ let proj_mut_body = quote! {
+ match self.get_unchecked_mut() {
+ #proj_arms
+ }
+ };
+ let proj_ref_body = quote! {
+ match self.get_ref() {
+ #proj_ref_arms
+ }
+ };
+ let proj_own_body = quote! {
+ match &mut *__self_ptr {
+ #proj_own_arms
+ }
+ };
+ generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body));
+
+ Ok(())
+}
+
+fn visit_variants<'a>(cx: &mut Context<'a>, variants: &'a Variants) -> Result<ProjectedVariants> {
+ let mut proj_variants = TokenStream::new();
+ let mut proj_ref_variants = TokenStream::new();
+ let mut proj_own_variants = TokenStream::new();
+ let mut proj_arms = TokenStream::new();
+ let mut proj_ref_arms = TokenStream::new();
+ let mut proj_own_arms = TokenStream::new();
+
+ for Variant { ident, fields, .. } in variants {
+ let ProjectedFields {
+ proj_pat,
+ proj_body,
+ proj_fields,
+ proj_ref_fields,
+ proj_own_fields,
+ proj_own_body,
+ } = match fields {
+ Fields::Named(_) => visit_fields(cx, Some(ident), fields, Delimiter::Brace)?,
+ Fields::Unnamed(_) => visit_fields(cx, Some(ident), fields, Delimiter::Parenthesis)?,
+ Fields::Unit => ProjectedFields {
+ proj_own_body: proj_own_body(cx, Some(ident), None, &[]),
+ ..Default::default()
+ },
+ };
+
+ let proj_ident = &cx.proj.mut_ident;
+ let proj_ref_ident = &cx.proj.ref_ident;
+ proj_variants.extend(quote! {
+ #ident #proj_fields,
+ });
+ proj_ref_variants.extend(quote! {
+ #ident #proj_ref_fields,
+ });
+ proj_own_variants.extend(quote! {
+ #ident #proj_own_fields,
+ });
+ proj_arms.extend(quote! {
+ Self::#ident #proj_pat => #proj_ident::#ident #proj_body,
+ });
+ proj_ref_arms.extend(quote! {
+ Self::#ident #proj_pat => #proj_ref_ident::#ident #proj_body,
+ });
+ proj_own_arms.extend(quote! {
+ Self::#ident #proj_pat => { #proj_own_body }
+ });
+ }
+
+ Ok(ProjectedVariants {
+ proj_variants,
+ proj_ref_variants,
+ proj_own_variants,
+ proj_arms,
+ proj_ref_arms,
+ proj_own_arms,
+ })
+}
+
+fn visit_fields<'a>(
+ cx: &mut Context<'a>,
+ variant_ident: Option<&Ident>,
+ fields: &'a Fields,
+ delim: Delimiter,
+) -> Result<ProjectedFields> {
+ fn surround(delim: Delimiter, tokens: TokenStream) -> TokenStream {
+ Group::new(delim, tokens).into_token_stream()
+ }
+
+ let mut proj_pat = TokenStream::new();
+ let mut proj_body = TokenStream::new();
+ let mut proj_fields = TokenStream::new();
+ let mut proj_ref_fields = TokenStream::new();
+ let mut proj_own_fields = TokenStream::new();
+ let mut proj_move = TokenStream::new();
+ let mut pinned_bindings = Vec::with_capacity(fields.len());
+
+ for (i, Field { attrs, vis, ident, colon_token, ty }) in fields.iter().enumerate() {
+ let binding = ident.clone().unwrap_or_else(|| format_ident!("_{}", i));
+ proj_pat.extend(quote!(#binding,));
+ let lifetime = &cx.proj.lifetime;
+ if attrs.position_exact(PIN)?.is_some() {
+ proj_fields.extend(quote! {
+ #vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime mut (#ty)>,
+ });
+ proj_ref_fields.extend(quote! {
+ #vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime (#ty)>,
+ });
+ proj_own_fields.extend(quote! {
+ #vis #ident #colon_token ::pin_project::__private::PhantomData<#ty>,
+ });
+ proj_body.extend(quote! {
+ #ident #colon_token _pin_project::__private::Pin::new_unchecked(#binding),
+ });
+ proj_move.extend(quote! {
+ #ident #colon_token _pin_project::__private::PhantomData,
+ });
+
+ cx.pinned_fields.push(ty);
+ pinned_bindings.push(binding);
+ } else {
+ proj_fields.extend(quote! {
+ #vis #ident #colon_token &#lifetime mut (#ty),
+ });
+ proj_ref_fields.extend(quote! {
+ #vis #ident #colon_token &#lifetime (#ty),
+ });
+ proj_own_fields.extend(quote! {
+ #vis #ident #colon_token #ty,
+ });
+ proj_body.extend(quote! {
+ #binding,
+ });
+ proj_move.extend(quote! {
+ #ident #colon_token _pin_project::__private::ptr::read(#binding),
+ });
+ }
+ }
+
+ let proj_pat = surround(delim, proj_pat);
+ let proj_body = surround(delim, proj_body);
+ let proj_fields = surround(delim, proj_fields);
+ let proj_ref_fields = surround(delim, proj_ref_fields);
+ let proj_own_fields = surround(delim, proj_own_fields);
+
+ let proj_move = Group::new(delim, proj_move);
+ let proj_own_body = proj_own_body(cx, variant_ident, Some(&proj_move), &pinned_bindings);
+
+ Ok(ProjectedFields {
+ proj_pat,
+ proj_body,
+ proj_own_body,
+ proj_fields,
+ proj_ref_fields,
+ proj_own_fields,
+ })
+}
+
+/// Generates the processing that `project_replace` does for the struct or each variant.
+///
+/// Note: `pinned_fields` must be in declaration order.
+fn proj_own_body(
+ cx: &Context<'_>,
+ variant_ident: Option<&Ident>,
+ proj_move: Option<&Group>,
+ pinned_fields: &[Ident],
+) -> TokenStream {
+ let ident = &cx.proj.own_ident;
+ let proj_own = match variant_ident {
+ Some(variant_ident) => quote!(#ident::#variant_ident),
+ None => quote!(#ident),
+ };
+
+ // The fields of the struct and the active enum variant are dropped
+ // in declaration order.
+ // Refs: https://doc.rust-lang.org/reference/destructors.html
+ let pinned_fields = pinned_fields.iter().rev();
+
+ quote! {
+ // First, extract all the unpinned fields.
+ let __result = #proj_own #proj_move;
+
+ // Now create guards to drop all the pinned fields.
+ //
+ // Due to a compiler bug (https://github.com/rust-lang/rust/issues/47949)
+ // this must be in its own scope, or else `__result` will not be dropped
+ // if any of the destructors panic.
+ {
+ #(
+ let __guard = _pin_project::__private::UnsafeDropInPlaceGuard::new(#pinned_fields);
+ )*
+ }
+
+ // Finally, return the result.
+ __result
+ }
+}
+
+/// Creates `Unpin` implementation for the original type.
+///
+/// The kind of `Unpin` impl generated depends on `unpin_impl` field:
+/// - `UnpinImpl::Unsafe` - Implements `Unpin` via `UnsafeUnpin` impl.
+/// - `UnpinImpl::Negative` - Generates `Unpin` impl with bounds that will never be true.
+/// - `UnpinImpl::Default` - Generates `Unpin` impl that requires `Unpin` for all pinned fields.
+fn make_unpin_impl(cx: &Context<'_>) -> TokenStream {
+ match cx.unpin_impl {
+ UnpinImpl::Unsafe(span) => {
+ let mut proj_generics = cx.proj.generics.clone();
+ let orig_ident = cx.orig.ident;
+ let lifetime = &cx.proj.lifetime;
+
+ // Make the error message highlight `UnsafeUnpin` argument.
+ proj_generics.make_where_clause().predicates.push(parse_quote_spanned! { span =>
+ _pin_project::__private::Wrapper<#lifetime, Self>: _pin_project::UnsafeUnpin
+ });
+
+ let (impl_generics, _, where_clause) = proj_generics.split_for_impl();
+ let ty_generics = cx.orig.generics.split_for_impl().1;
+
+ quote_spanned! { span =>
+ impl #impl_generics _pin_project::__private::Unpin for #orig_ident #ty_generics
+ #where_clause
+ {
+ }
+ }
+ }
+ UnpinImpl::Negative(span) => {
+ let mut proj_generics = cx.proj.generics.clone();
+ let orig_ident = cx.orig.ident;
+ let lifetime = &cx.proj.lifetime;
+
+ proj_generics.make_where_clause().predicates.push(parse_quote! {
+ _pin_project::__private::Wrapper<
+ #lifetime, _pin_project::__private::PhantomPinned
+ >: _pin_project::__private::Unpin
+ });
+
+ let (proj_impl_generics, _, proj_where_clause) = proj_generics.split_for_impl();
+ let ty_generics = cx.orig.generics.split_for_impl().1;
+
+ // For interoperability with `forbid(unsafe_code)`, `unsafe` token should be
+ // call-site span.
+ let unsafety = <Token![unsafe]>::default();
+ quote_spanned! { span =>
+ impl #proj_impl_generics _pin_project::__private::Unpin
+ for #orig_ident #ty_generics
+ #proj_where_clause
+ {
+ }
+
+ // Generate a dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it.
+ //
+ // To ensure that users don't accidentally write a non-functional `UnsafeUnpin`
+ // impls, we emit one ourselves. If the user ends up writing an `UnsafeUnpin`
+ // impl, they'll get a "conflicting implementations of trait" error when
+ // coherence checks are run.
+ #[doc(hidden)]
+ #unsafety impl #proj_impl_generics _pin_project::UnsafeUnpin
+ for #orig_ident #ty_generics
+ #proj_where_clause
+ {
+ }
+ }
+ }
+ UnpinImpl::Default => {
+ let mut full_where_clause = cx.orig.generics.where_clause.clone().unwrap();
+
+ // Generate a field in our new struct for every
+ // pinned field in the original type.
+ let fields = cx.pinned_fields.iter().enumerate().map(|(i, ty)| {
+ let field_ident = format_ident!("__field{}", i);
+ quote!(#field_ident: #ty)
+ });
+
+ // We could try to determine the subset of type parameters
+ // and lifetimes that are actually used by the pinned fields
+ // (as opposed to those only used by unpinned fields).
+ // However, this would be tricky and error-prone, since
+ // it's possible for users to create types that would alias
+ // with generic parameters (e.g. 'struct T').
+ //
+ // Instead, we generate a use of every single type parameter
+ // and lifetime used in the original struct. For type parameters,
+ // we generate code like this:
+ //
+ // ```rust
+ // struct AlwaysUnpin<T: ?Sized>(PhantomData<T>) {}
+ // impl<T: ?Sized> Unpin for AlwaysUnpin<T> {}
+ //
+ // ...
+ // _field: AlwaysUnpin<(A, B, C)>
+ // ```
+ //
+ // This ensures that any unused type parameters
+ // don't end up with `Unpin` bounds.
+ let lifetime_fields = cx.orig.generics.lifetimes().enumerate().map(
+ |(i, LifetimeDef { lifetime, .. })| {
+ let field_ident = format_ident!("__lifetime{}", i);
+ quote!(#field_ident: &#lifetime ())
+ },
+ );
+
+ let orig_ident = cx.orig.ident;
+ let struct_ident = format_ident!("__{}", orig_ident);
+ let vis = cx.orig.vis;
+ let lifetime = &cx.proj.lifetime;
+ let type_params = cx.orig.generics.type_params().map(|t| &t.ident);
+ let proj_generics = &cx.proj.generics;
+ let (proj_impl_generics, proj_ty_generics, _) = proj_generics.split_for_impl();
+ let (_, ty_generics, where_clause) = cx.orig.generics.split_for_impl();
+
+ full_where_clause.predicates.push(parse_quote! {
+ #struct_ident #proj_ty_generics: _pin_project::__private::Unpin
+ });
+
+ quote! {
+ // This needs to have the same visibility as the original type,
+ // due to the limitations of the 'public in private' error.
+ //
+ // Our goal is to implement the public trait `Unpin` for
+ // a potentially public user type. Because of this, rust
+ // requires that any types mentioned in the where clause of
+ // our `Unpin` impl also be public. This means that our generated
+ // `__UnpinStruct` type must also be public.
+ // However, we ensure that the user can never actually reference
+ // this 'public' type by creating this type in the inside of `const`.
+ #[allow(missing_debug_implementations)]
+ #vis struct #struct_ident #proj_generics #where_clause {
+ __pin_project_use_generics: _pin_project::__private::AlwaysUnpin<
+ #lifetime, (#(_pin_project::__private::PhantomData<#type_params>),*)
+ >,
+
+ #(#fields,)*
+ #(#lifetime_fields,)*
+ }
+
+ impl #proj_impl_generics _pin_project::__private::Unpin
+ for #orig_ident #ty_generics
+ #full_where_clause
+ {
+ }
+
+ // Generate a dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it.
+ //
+ // To ensure that users don't accidentally write a non-functional `UnsafeUnpin`
+ // impls, we emit one ourselves. If the user ends up writing an `UnsafeUnpin`
+ // impl, they'll get a "conflicting implementations of trait" error when
+ // coherence checks are run.
+ #[doc(hidden)]
+ unsafe impl #proj_impl_generics _pin_project::UnsafeUnpin
+ for #orig_ident #ty_generics
+ #full_where_clause
+ {
+ }
+ }
+ }
+ }
+}
+
+/// Creates `Drop` implementation for the original type.
+///
+/// The kind of `Drop` impl generated depends on `pinned_drop` field:
+/// - `Some` - implements `Drop` via `PinnedDrop` impl.
+/// - `None` - generates code that ensures that `Drop` trait is not implemented,
+/// instead of generating `Drop` impl.
+fn make_drop_impl(cx: &Context<'_>) -> TokenStream {
+ let ident = cx.orig.ident;
+ let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl();
+
+ if let Some(span) = cx.pinned_drop {
+ // For interoperability with `forbid(unsafe_code)`, `unsafe` token should be
+ // call-site span.
+ let unsafety = <Token![unsafe]>::default();
+ quote_spanned! { span =>
+ impl #impl_generics _pin_project::__private::Drop for #ident #ty_generics
+ #where_clause
+ {
+ fn drop(&mut self) {
+ #unsafety {
+ // Safety - we're in 'drop', so we know that 'self' will
+ // never move again.
+ let __pinned_self = _pin_project::__private::Pin::new_unchecked(self);
+ // We call `pinned_drop` only once. Since `PinnedDrop::drop`
+ // is an unsafe method and a private API, it is never called again in safe
+ // code *unless the user uses a maliciously crafted macro*.
+ _pin_project::__private::PinnedDrop::drop(__pinned_self);
+ }
+ }
+ }
+ }
+ } else {
+ // If the user does not provide a `PinnedDrop` impl,
+ // we need to ensure that they don't provide a `Drop` impl of their
+ // own.
+ // Based on https://github.com/upsuper/assert-impl/blob/f503255b292ab0ba8d085b657f4065403cfa46eb/src/lib.rs#L80-L87
+ //
+ // We create a new identifier for each struct, so that the traits
+ // for different types do not conflict with each other.
+ //
+ // Another approach would be to provide an empty Drop impl,
+ // which would conflict with a user-provided Drop impl.
+ // However, this would trigger the compiler's special handling
+ // of Drop types (e.g. fields cannot be moved out of a Drop type).
+ // This approach prevents the creation of needless Drop impls,
+ // giving users more flexibility.
+ let trait_ident = format_ident!("{}MustNotImplDrop", ident);
+
+ quote! {
+ // There are two possible cases:
+ // 1. The user type does not implement Drop. In this case,
+ // the first blanked impl will not apply to it. This code
+ // will compile, as there is only one impl of MustNotImplDrop for the user type
+ // 2. The user type does impl Drop. This will make the blanket impl applicable,
+ // which will then conflict with the explicit MustNotImplDrop impl below.
+ // This will result in a compilation error, which is exactly what we want.
+ trait #trait_ident {}
+ #[allow(clippy::drop_bounds, drop_bounds)]
+ impl<T: _pin_project::__private::Drop> #trait_ident for T {}
+ impl #impl_generics #trait_ident for #ident #ty_generics #where_clause {}
+
+ // Generate a dummy impl of `PinnedDrop`, to ensure that the user cannot implement it.
+ // Since the user did not pass `PinnedDrop` to `#[pin_project]`, any `PinnedDrop`
+ // impl will not actually be called. Unfortunately, we can't detect this situation
+ // directly from either the `#[pin_project]` or `#[pinned_drop]` attributes, since
+ // we don't know what other attributes/impl may exist.
+ //
+ // To ensure that users don't accidentally write a non-functional `PinnedDrop`
+ // impls, we emit one ourselves. If the user ends up writing a `PinnedDrop` impl,
+ // they'll get a "conflicting implementations of trait" error when coherence
+ // checks are run.
+ #[doc(hidden)]
+ impl #impl_generics _pin_project::__private::PinnedDrop for #ident #ty_generics
+ #where_clause
+ {
+ unsafe fn drop(self: _pin_project::__private::Pin<&mut Self>) {}
+ }
+ }
+ }
+}
+
+/// Creates an implementation of the projection methods.
+///
+/// On structs, both the `project` and `project_ref` methods are always generated,
+/// and the `project_replace` method is only generated if `ProjReplace::span` is `Some`.
+///
+/// On enums, only methods that the returned projected type is named will be generated.
+fn make_proj_impl(
+ cx: &Context<'_>,
+ proj_body: &TokenStream,
+ proj_ref_body: &TokenStream,
+ proj_own_body: &TokenStream,
+) -> TokenStream {
+ let vis = &cx.proj.vis;
+ let lifetime = &cx.proj.lifetime;
+ let orig_ident = cx.orig.ident;
+ let proj_ident = &cx.proj.mut_ident;
+ let proj_ref_ident = &cx.proj.ref_ident;
+ let proj_own_ident = &cx.proj.own_ident;
+
+ let orig_ty_generics = cx.orig.generics.split_for_impl().1;
+ let proj_ty_generics = cx.proj.generics.split_for_impl().1;
+ let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl();
+ // TODO: For enums and project_replace, dead_code warnings should not be
+ // allowed because methods are not generated unless explicitly specified.
+ // However, there is currently no good way to allow warnings for generated
+ // code, so we allow warnings for all methods for now.
+ let allow_dead_code = quote! { #[allow(dead_code)] };
+
+ let mut project = Some(quote! {
+ #allow_dead_code
+ #vis fn project<#lifetime>(
+ self: _pin_project::__private::Pin<&#lifetime mut Self>,
+ ) -> #proj_ident #proj_ty_generics {
+ unsafe {
+ #proj_body
+ }
+ }
+ });
+ let mut project_ref = Some(quote! {
+ #allow_dead_code
+ #[allow(clippy::missing_const_for_fn)]
+ #vis fn project_ref<#lifetime>(
+ self: _pin_project::__private::Pin<&#lifetime Self>,
+ ) -> #proj_ref_ident #proj_ty_generics {
+ unsafe {
+ #proj_ref_body
+ }
+ }
+ });
+ let mut project_replace = cx.project_replace.span().map(|span| {
+ // It is enough to only set the span of the signature.
+ let sig = quote_spanned! { span =>
+ #allow_dead_code
+ #vis fn project_replace(
+ self: _pin_project::__private::Pin<&mut Self>,
+ __replacement: Self,
+ ) -> #proj_own_ident #orig_ty_generics
+ };
+ quote! {
+ #sig {
+ unsafe {
+ let __self_ptr: *mut Self = self.get_unchecked_mut();
+
+ // Destructors will run in reverse order, so next create a guard to overwrite
+ // `self` with the replacement value without calling destructors.
+ let __guard = _pin_project::__private::UnsafeOverwriteGuard::new(
+ __self_ptr,
+ __replacement,
+ );
+
+ #proj_own_body
+ }
+ }
+ }
+ });
+
+ if cx.kind == Enum {
+ if !cx.project {
+ project = None;
+ }
+ if !cx.project_ref {
+ project_ref = None;
+ }
+ if cx.project_replace.ident().is_none() {
+ project_replace = None;
+ }
+ }
+
+ quote! {
+ impl #impl_generics #orig_ident #ty_generics #where_clause {
+ #project
+ #project_ref
+ #project_replace
+ }
+ }
+}
+
+/// Checks that the `[repr(packed)]` attribute is not included.
+///
+/// This currently does two checks:
+/// - Checks the attributes of structs to ensure there is no `[repr(packed)]`.
+/// - Generates a function that borrows fields without an unsafe block and
+/// forbidding `unaligned_references` lint.
+fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result<TokenStream> {
+ for meta in orig.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
+ if let Meta::List(list) = meta {
+ if list.path.is_ident("repr") {
+ for repr in list.nested.iter() {
+ match repr {
+ NestedMeta::Meta(Meta::Path(path))
+ | NestedMeta::Meta(Meta::List(MetaList { path, .. }))
+ | NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, .. })) => {
+ if path.is_ident("packed") {
+ let msg = if fields.is_none() {
+ // #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
+ // However, we should not rely on the behavior of rustc that rejects this.
+ // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
+ "#[repr(packed)] attribute should be applied to a struct or union"
+ } else if let NestedMeta::Meta(Meta::NameValue(..)) = repr {
+ // #[repr(packed = "")] is not valid format of #[repr(packed)] and will be
+ // rejected by rustc.
+ // However, we should not rely on the behavior of rustc that rejects this.
+ // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
+ "#[repr(packed)] attribute should not be name-value pair"
+ } else {
+ "#[pin_project] attribute may not be used on #[repr(packed)] types"
+ };
+ bail!(repr, msg);
+ }
+ }
+ NestedMeta::Lit(..) => {}
+ }
+ }
+ }
+ }
+ }
+
+ let fields = match fields {
+ Some(fields) => fields,
+ None => return Ok(TokenStream::new()),
+ };
+
+ // Workaround for https://github.com/taiki-e/pin-project/issues/32
+ // Through the tricky use of proc macros, it's possible to bypass
+ // the above check for the `repr` attribute.
+ // To ensure that it's impossible to use pin projections on a `#[repr(packed)]`
+ // struct, we generate code like this:
+ //
+ // ```rust
+ // #[forbid(unaligned_references)]
+ // fn assert_not_repr_packed(val: &MyStruct) {
+ // let _field1 = &val.field1;
+ // let _field2 = &val.field2;
+ // ...
+ // let _fieldn = &val.fieldn;
+ // }
+ // ```
+ //
+ // Taking a reference to a packed field is UB, and applying
+ // `#[forbid(unaligned_references)]` makes sure that doing this is a hard error.
+ //
+ // If the struct ends up having `#[repr(packed)]` applied somehow,
+ // this will generate an (unfriendly) error message. Under all reasonable
+ // circumstances, we'll detect the `#[repr(packed)]` attribute, and generate
+ // a much nicer error above.
+ //
+ // There is one exception: If the type of a struct field has an alignment of 1
+ // (e.g. u8), it is always safe to take a reference to it, even if the struct
+ // is `#[repr(packed)]`. If the struct is composed entirely of types of
+ // alignment 1, our generated method will not trigger an error if the
+ // struct is `#[repr(packed)]`.
+ //
+ // Fortunately, this should have no observable consequence - `#[repr(packed)]`
+ // is essentially a no-op on such a type. Nevertheless, we include a test
+ // to ensure that the compiler doesn't ever try to copy the fields on
+ // such a struct when trying to drop it - which is reason we prevent
+ // `#[repr(packed)]` in the first place.
+ //
+ // See also https://github.com/taiki-e/pin-project/pull/34.
+ //
+ // Note:
+ // - Lint-based tricks aren't perfect, but they're much better than nothing:
+ // https://github.com/taiki-e/pin-project-lite/issues/26
+ //
+ // - Enable both unaligned_references and safe_packed_borrows lints
+ // because unaligned_references lint does not exist in older compilers:
+ // https://github.com/taiki-e/pin-project-lite/pull/55
+ // https://github.com/rust-lang/rust/pull/82525
+ let mut field_refs = vec![];
+ match fields {
+ Fields::Named(FieldsNamed { named, .. }) => {
+ for Field { ident, .. } in named {
+ field_refs.push(quote!(&this.#ident));
+ }
+ }
+ Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => {
+ for (index, _) in unnamed.iter().enumerate() {
+ let index = Index::from(index);
+ field_refs.push(quote!(&this.#index));
+ }
+ }
+ Fields::Unit => {}
+ }
+
+ let (impl_generics, ty_generics, where_clause) = orig.generics.split_for_impl();
+ let ident = orig.ident;
+ Ok(quote! {
+ #[forbid(unaligned_references, safe_packed_borrows)]
+ fn __assert_not_repr_packed #impl_generics (this: &#ident #ty_generics) #where_clause {
+ #(let _ = #field_refs;)*
+ }
+ })
+}
diff --git a/third_party/rust/pin-project-internal/src/pin_project/mod.rs b/third_party/rust/pin-project-internal/src/pin_project/mod.rs
new file mode 100644
index 0000000000..2dce78f37f
--- /dev/null
+++ b/third_party/rust/pin-project-internal/src/pin_project/mod.rs
@@ -0,0 +1,17 @@
+mod args;
+mod attribute;
+mod derive;
+
+use proc_macro2::TokenStream;
+use syn::Error;
+
+/// The annotation for pinned type.
+const PIN: &str = "pin";
+
+pub(crate) fn attribute(args: &TokenStream, input: TokenStream) -> TokenStream {
+ attribute::parse_attribute(args, input).unwrap_or_else(Error::into_compile_error)
+}
+
+pub(crate) fn derive(input: TokenStream) -> TokenStream {
+ derive::parse_derive(input).unwrap_or_else(Error::into_compile_error)
+}
diff --git a/third_party/rust/pin-project-internal/src/pinned_drop.rs b/third_party/rust/pin-project-internal/src/pinned_drop.rs
new file mode 100644
index 0000000000..912989dd41
--- /dev/null
+++ b/third_party/rust/pin-project-internal/src/pinned_drop.rs
@@ -0,0 +1,226 @@
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote, ToTokens};
+use syn::{
+ parse_quote, spanned::Spanned, visit_mut::VisitMut, Error, FnArg, GenericArgument, ImplItem,
+ ItemImpl, Pat, PatIdent, Path, PathArguments, Result, ReturnType, Signature, Token, Type,
+ TypePath, TypeReference,
+};
+
+use crate::utils::{parse_as_empty, prepend_underscore_to_self, ReplaceReceiver, SliceExt};
+
+pub(crate) fn attribute(args: &TokenStream, mut input: ItemImpl) -> TokenStream {
+ let res = (|| -> Result<()> {
+ parse_as_empty(args)?;
+ validate_impl(&input)?;
+ expand_impl(&mut input);
+ Ok(())
+ })();
+
+ if let Err(e) = res {
+ let mut tokens = e.to_compile_error();
+ if let Type::Path(self_ty) = &*input.self_ty {
+ let (impl_generics, _, where_clause) = input.generics.split_for_impl();
+
+ // Generate a dummy impl of `PinnedDrop`.
+ // In many cases, `#[pinned_drop] impl` is declared after `#[pin_project]`.
+ // Therefore, if `pinned_drop` compile fails, you will also get an error
+ // about `PinnedDrop` not being implemented.
+ // This can be prevented to some extent by generating a dummy
+ // `PinnedDrop` implementation.
+ // We already know that we will get a compile error, so this won't
+ // accidentally compile successfully.
+ //
+ // However, if `input.self_ty` is not Type::Path, there is a high possibility that
+ // the type does not exist (since #[pin_project] can only be used on struct/enum
+ // definitions), so do not generate a dummy impl.
+ tokens.extend(quote! {
+ impl #impl_generics ::pin_project::__private::PinnedDrop for #self_ty
+ #where_clause
+ {
+ unsafe fn drop(self: ::pin_project::__private::Pin<&mut Self>) {}
+ }
+ });
+ }
+ tokens
+ } else {
+ input.into_token_stream()
+ }
+}
+
+/// Validates the signature of given `PinnedDrop` impl.
+fn validate_impl(item: &ItemImpl) -> Result<()> {
+ const INVALID_ITEM: &str =
+ "#[pinned_drop] may only be used on implementation for the `PinnedDrop` trait";
+
+ if let Some(attr) = item.attrs.find("pinned_drop") {
+ bail!(attr, "duplicate #[pinned_drop] attribute");
+ }
+
+ if let Some((_, path, _)) = &item.trait_ {
+ if !path.is_ident("PinnedDrop") {
+ bail!(path, INVALID_ITEM);
+ }
+ } else {
+ bail!(item.self_ty, INVALID_ITEM);
+ }
+
+ if item.unsafety.is_some() {
+ bail!(item.unsafety, "implementing the trait `PinnedDrop` is not unsafe");
+ }
+ if item.items.is_empty() {
+ bail!(item, "not all trait items implemented, missing: `drop`");
+ }
+
+ match &*item.self_ty {
+ Type::Path(_) => {}
+ ty => {
+ bail!(ty, "implementing the trait `PinnedDrop` on this type is unsupported");
+ }
+ }
+
+ item.items.iter().enumerate().try_for_each(|(i, item)| match item {
+ ImplItem::Const(item) => {
+ bail!(item, "const `{}` is not a member of trait `PinnedDrop`", item.ident)
+ }
+ ImplItem::Type(item) => {
+ bail!(item, "type `{}` is not a member of trait `PinnedDrop`", item.ident)
+ }
+ ImplItem::Method(method) => {
+ validate_sig(&method.sig)?;
+ if i == 0 {
+ Ok(())
+ } else {
+ bail!(method, "duplicate definitions with name `drop`")
+ }
+ }
+ _ => unreachable!("unexpected ImplItem"),
+ })
+}
+
+/// Validates the signature of given `PinnedDrop::drop` method.
+///
+/// The correct signature is: `(mut) self: (<path>::)Pin<&mut Self>`
+fn validate_sig(sig: &Signature) -> Result<()> {
+ fn get_ty_path(ty: &Type) -> Option<&Path> {
+ if let Type::Path(TypePath { qself: None, path }) = ty {
+ Some(path)
+ } else {
+ None
+ }
+ }
+
+ const INVALID_ARGUMENT: &str = "method `drop` must take an argument `self: Pin<&mut Self>`";
+
+ if sig.ident != "drop" {
+ bail!(sig.ident, "method `{}` is not a member of trait `PinnedDrop", sig.ident,);
+ }
+
+ if let ReturnType::Type(_, ty) = &sig.output {
+ match &**ty {
+ Type::Tuple(ty) if ty.elems.is_empty() => {}
+ _ => bail!(ty, "method `drop` must return the unit type"),
+ }
+ }
+
+ match sig.inputs.len() {
+ 1 => {}
+ 0 => return Err(Error::new(sig.paren_token.span, INVALID_ARGUMENT)),
+ _ => bail!(sig.inputs, INVALID_ARGUMENT),
+ }
+
+ if let Some(FnArg::Typed(arg)) = sig.receiver() {
+ // (mut) self: <path>
+ if let Some(path) = get_ty_path(&arg.ty) {
+ let ty = path.segments.last().unwrap();
+ if let PathArguments::AngleBracketed(args) = &ty.arguments {
+ // (mut) self: (<path>::)<ty><&mut <elem>..>
+ if let Some(GenericArgument::Type(Type::Reference(TypeReference {
+ mutability: Some(_),
+ elem,
+ ..
+ }))) = args.args.first()
+ {
+ // (mut) self: (<path>::)Pin<&mut Self>
+ if args.args.len() == 1
+ && ty.ident == "Pin"
+ && get_ty_path(elem).map_or(false, |path| path.is_ident("Self"))
+ {
+ if sig.unsafety.is_some() {
+ bail!(sig.unsafety, "implementing the method `drop` is not unsafe");
+ }
+ return Ok(());
+ }
+ }
+ }
+ }
+ }
+
+ bail!(sig.inputs[0], INVALID_ARGUMENT)
+}
+
+// from:
+//
+// fn drop(self: Pin<&mut Self>) {
+// // ...
+// }
+//
+// into:
+//
+// unsafe fn drop(self: Pin<&mut Self>) {
+// fn __drop_inner<T>(__self: Pin<&mut Foo<'_, T>>) {
+// fn __drop_inner() {}
+// // ...
+// }
+// __drop_inner(self);
+// }
+//
+fn expand_impl(item: &mut ItemImpl) {
+ fn get_arg_pat(arg: &mut FnArg) -> Option<&mut PatIdent> {
+ if let FnArg::Typed(arg) = arg {
+ if let Pat::Ident(ident) = &mut *arg.pat {
+ return Some(ident);
+ }
+ }
+ None
+ }
+
+ // `PinnedDrop` is a private trait and should not appear in docs.
+ item.attrs.push(parse_quote!(#[doc(hidden)]));
+
+ let path = &mut item.trait_.as_mut().unwrap().1;
+ *path = parse_quote_spanned! { path.span() =>
+ ::pin_project::__private::PinnedDrop
+ };
+
+ let method =
+ if let ImplItem::Method(method) = &mut item.items[0] { method } else { unreachable!() };
+
+ // `fn drop(mut self: Pin<&mut Self>)` -> `fn __drop_inner<T>(mut __self: Pin<&mut Receiver>)`
+ let drop_inner = {
+ let mut drop_inner = method.clone();
+ let ident = format_ident!("__drop_inner");
+ // Add a dummy `__drop_inner` function to prevent users call outer `__drop_inner`.
+ drop_inner.block.stmts.insert(0, parse_quote!(fn #ident() {}));
+ drop_inner.sig.ident = ident;
+ drop_inner.sig.generics = item.generics.clone();
+ let self_pat = get_arg_pat(&mut drop_inner.sig.inputs[0]).unwrap();
+ prepend_underscore_to_self(&mut self_pat.ident);
+ let self_ty = if let Type::Path(ty) = &*item.self_ty { ty } else { unreachable!() };
+ let mut visitor = ReplaceReceiver(self_ty);
+ visitor.visit_signature_mut(&mut drop_inner.sig);
+ visitor.visit_block_mut(&mut drop_inner.block);
+ drop_inner
+ };
+
+ // `fn drop(mut self: Pin<&mut Self>)` -> `unsafe fn drop(self: Pin<&mut Self>)`
+ method.sig.unsafety = Some(<Token![unsafe]>::default());
+ let self_pat = get_arg_pat(&mut method.sig.inputs[0]).unwrap();
+ self_pat.mutability = None;
+ let self_token = &self_pat.ident;
+
+ method.block.stmts = parse_quote! {
+ #[allow(clippy::needless_pass_by_value)] // This lint does not warn the receiver.
+ #drop_inner
+ __drop_inner(#self_token);
+ };
+}
diff --git a/third_party/rust/pin-project-internal/src/utils.rs b/third_party/rust/pin-project-internal/src/utils.rs
new file mode 100644
index 0000000000..27373efbae
--- /dev/null
+++ b/third_party/rust/pin-project-internal/src/utils.rs
@@ -0,0 +1,402 @@
+use std::{iter::FromIterator, mem};
+
+use proc_macro2::{Group, Spacing, Span, TokenStream, TokenTree};
+use quote::{quote, quote_spanned, ToTokens};
+use syn::{
+ parse::{Parse, ParseBuffer, ParseStream},
+ parse_quote,
+ punctuated::Punctuated,
+ token,
+ visit_mut::{self, VisitMut},
+ Attribute, ExprPath, ExprStruct, Generics, Ident, Item, Lifetime, LifetimeDef, Macro, PatPath,
+ PatStruct, PatTupleStruct, Path, PathArguments, PredicateType, QSelf, Result, Token, Type,
+ TypeParamBound, TypePath, Variant, Visibility, WherePredicate,
+};
+
+pub(crate) type Variants = Punctuated<Variant, Token![,]>;
+
+macro_rules! format_err {
+ ($span:expr, $msg:expr $(,)?) => {
+ syn::Error::new_spanned(&$span as &dyn quote::ToTokens, &$msg as &dyn std::fmt::Display)
+ };
+ ($span:expr, $($tt:tt)*) => {
+ format_err!($span, format!($($tt)*))
+ };
+}
+
+macro_rules! bail {
+ ($($tt:tt)*) => {
+ return Err(format_err!($($tt)*))
+ };
+}
+
+macro_rules! parse_quote_spanned {
+ ($span:expr => $($tt:tt)*) => {
+ syn::parse2(quote::quote_spanned!($span => $($tt)*)).unwrap_or_else(|e| panic!("{}", e))
+ };
+}
+
+/// Determines the lifetime names. Ensure it doesn't overlap with any existing
+/// lifetime names.
+pub(crate) fn determine_lifetime_name(lifetime_name: &mut String, generics: &mut Generics) {
+ struct CollectLifetimes(Vec<String>);
+
+ impl VisitMut for CollectLifetimes {
+ fn visit_lifetime_def_mut(&mut self, def: &mut LifetimeDef) {
+ self.0.push(def.lifetime.to_string());
+ }
+ }
+
+ debug_assert!(lifetime_name.starts_with('\''));
+
+ let mut lifetimes = CollectLifetimes(Vec::new());
+ lifetimes.visit_generics_mut(generics);
+
+ while lifetimes.0.iter().any(|name| name.starts_with(&**lifetime_name)) {
+ lifetime_name.push('_');
+ }
+}
+
+/// Like `insert_lifetime`, but also generates a bound of the form
+/// `OriginalType<A, B>: 'lifetime`. Used when generating the definition
+/// of a projection type
+pub(crate) fn insert_lifetime_and_bound(
+ generics: &mut Generics,
+ lifetime: Lifetime,
+ orig_generics: &Generics,
+ orig_ident: &Ident,
+) -> WherePredicate {
+ insert_lifetime(generics, lifetime.clone());
+
+ let orig_type: Type = parse_quote!(#orig_ident #orig_generics);
+ let mut punct = Punctuated::new();
+ punct.push(TypeParamBound::Lifetime(lifetime));
+
+ WherePredicate::Type(PredicateType {
+ lifetimes: None,
+ bounded_ty: orig_type,
+ colon_token: <Token![:]>::default(),
+ bounds: punct,
+ })
+}
+
+/// Inserts a `lifetime` at position `0` of `generics.params`.
+pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) {
+ generics.lt_token.get_or_insert_with(<Token![<]>::default);
+ generics.gt_token.get_or_insert_with(<Token![>]>::default);
+ generics.params.insert(0, LifetimeDef::new(lifetime).into());
+}
+
+/// Determines the visibility of the projected types and projection methods.
+///
+/// If given visibility is `pub`, returned visibility is `pub(crate)`.
+/// Otherwise, returned visibility is the same as given visibility.
+pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility {
+ if let Visibility::Public(token) = vis {
+ parse_quote_spanned!(token.pub_token.span => pub(crate))
+ } else {
+ vis.clone()
+ }
+}
+
+/// Checks if `tokens` is an empty `TokenStream`.
+///
+/// This is almost equivalent to `syn::parse2::<Nothing>()`, but produces
+/// a better error message and does not require ownership of `tokens`.
+pub(crate) fn parse_as_empty(tokens: &TokenStream) -> Result<()> {
+ if tokens.is_empty() {
+ Ok(())
+ } else {
+ bail!(tokens, "unexpected token: `{}`", tokens)
+ }
+}
+
+pub(crate) fn respan<T>(node: &T, span: Span) -> T
+where
+ T: ToTokens + Parse,
+{
+ let tokens = node.to_token_stream();
+ let respanned = respan_tokens(tokens, span);
+ syn::parse2(respanned).unwrap()
+}
+
+fn respan_tokens(tokens: TokenStream, span: Span) -> TokenStream {
+ tokens
+ .into_iter()
+ .map(|mut token| {
+ token.set_span(span);
+ token
+ })
+ .collect()
+}
+
+// =================================================================================================
+// extension traits
+
+pub(crate) trait SliceExt {
+ fn position_exact(&self, ident: &str) -> Result<Option<usize>>;
+ fn find(&self, ident: &str) -> Option<&Attribute>;
+}
+
+impl SliceExt for [Attribute] {
+ /// # Errors
+ ///
+ /// - There are multiple specified attributes.
+ /// - The `Attribute::tokens` field of the specified attribute is not empty.
+ fn position_exact(&self, ident: &str) -> Result<Option<usize>> {
+ self.iter()
+ .try_fold((0, None), |(i, mut prev), attr| {
+ if attr.path.is_ident(ident) {
+ if prev.replace(i).is_some() {
+ bail!(attr, "duplicate #[{}] attribute", ident);
+ }
+ parse_as_empty(&attr.tokens)?;
+ }
+ Ok((i + 1, prev))
+ })
+ .map(|(_, pos)| pos)
+ }
+
+ fn find(&self, ident: &str) -> Option<&Attribute> {
+ self.iter().position(|attr| attr.path.is_ident(ident)).map(|i| &self[i])
+ }
+}
+
+pub(crate) trait ParseBufferExt<'a> {
+ fn parenthesized(self) -> Result<ParseBuffer<'a>>;
+}
+
+impl<'a> ParseBufferExt<'a> for ParseStream<'a> {
+ fn parenthesized(self) -> Result<ParseBuffer<'a>> {
+ let content;
+ let _: token::Paren = syn::parenthesized!(content in self);
+ Ok(content)
+ }
+}
+
+impl<'a> ParseBufferExt<'a> for ParseBuffer<'a> {
+ fn parenthesized(self) -> Result<ParseBuffer<'a>> {
+ let content;
+ let _: token::Paren = syn::parenthesized!(content in self);
+ Ok(content)
+ }
+}
+
+// =================================================================================================
+// visitors
+
+// Replace `self`/`Self` with `__self`/`self_ty`.
+// Based on:
+// - https://github.com/dtolnay/async-trait/blob/0.1.35/src/receiver.rs
+// - https://github.com/dtolnay/async-trait/commit/6029cbf375c562ca98fa5748e9d950a8ff93b0e7
+
+pub(crate) struct ReplaceReceiver<'a>(pub(crate) &'a TypePath);
+
+impl ReplaceReceiver<'_> {
+ fn self_ty(&self, span: Span) -> TypePath {
+ respan(self.0, span)
+ }
+
+ fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
+ if path.leading_colon.is_some() {
+ return;
+ }
+
+ let first = &path.segments[0];
+ if first.ident != "Self" || !first.arguments.is_empty() {
+ return;
+ }
+
+ if path.segments.len() == 1 {
+ self.self_to_expr_path(path);
+ return;
+ }
+
+ let span = first.ident.span();
+ *qself = Some(QSelf {
+ lt_token: Token![<](span),
+ ty: Box::new(self.self_ty(span).into()),
+ position: 0,
+ as_token: None,
+ gt_token: Token![>](span),
+ });
+
+ path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap());
+
+ let segments = mem::replace(&mut path.segments, Punctuated::new());
+ path.segments = segments.into_pairs().skip(1).collect();
+ }
+
+ fn self_to_expr_path(&self, path: &mut Path) {
+ if path.leading_colon.is_some() {
+ return;
+ }
+
+ let first = &path.segments[0];
+ if first.ident != "Self" || !first.arguments.is_empty() {
+ return;
+ }
+
+ let self_ty = self.self_ty(first.ident.span());
+ let variant = mem::replace(path, self_ty.path);
+ for segment in &mut path.segments {
+ if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
+ if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
+ bracketed.colon2_token = Some(<Token![::]>::default());
+ }
+ }
+ }
+ if variant.segments.len() > 1 {
+ path.segments.push_punct(<Token![::]>::default());
+ path.segments.extend(variant.segments.into_pairs().skip(1));
+ }
+ }
+
+ fn visit_token_stream(&self, tokens: &mut TokenStream) -> bool {
+ let mut out = Vec::new();
+ let mut modified = false;
+ let mut iter = tokens.clone().into_iter().peekable();
+ while let Some(tt) = iter.next() {
+ match tt {
+ TokenTree::Ident(mut ident) => {
+ modified |= prepend_underscore_to_self(&mut ident);
+ if ident == "Self" {
+ modified = true;
+ let self_ty = self.self_ty(ident.span());
+ match iter.peek() {
+ Some(TokenTree::Punct(p))
+ if p.as_char() == ':' && p.spacing() == Spacing::Joint =>
+ {
+ let next = iter.next().unwrap();
+ match iter.peek() {
+ Some(TokenTree::Punct(p)) if p.as_char() == ':' => {
+ let span = ident.span();
+ out.extend(quote_spanned!(span=> <#self_ty>));
+ }
+ _ => out.extend(quote!(#self_ty)),
+ }
+ out.push(next);
+ }
+ _ => out.extend(quote!(#self_ty)),
+ }
+ } else {
+ out.push(TokenTree::Ident(ident));
+ }
+ }
+ TokenTree::Group(group) => {
+ let mut content = group.stream();
+ modified |= self.visit_token_stream(&mut content);
+ let mut new = Group::new(group.delimiter(), content);
+ new.set_span(group.span());
+ out.push(TokenTree::Group(new));
+ }
+ other => out.push(other),
+ }
+ }
+ if modified {
+ *tokens = TokenStream::from_iter(out);
+ }
+ modified
+ }
+}
+
+impl VisitMut for ReplaceReceiver<'_> {
+ // `Self` -> `Receiver`
+ fn visit_type_mut(&mut self, ty: &mut Type) {
+ if let Type::Path(node) = ty {
+ if node.qself.is_none() && node.path.is_ident("Self") {
+ *ty = self.self_ty(node.path.segments[0].ident.span()).into();
+ } else {
+ self.visit_type_path_mut(node);
+ }
+ } else {
+ visit_mut::visit_type_mut(self, ty);
+ }
+ }
+
+ // `Self::Assoc` -> `<Receiver>::Assoc`
+ fn visit_type_path_mut(&mut self, ty: &mut TypePath) {
+ if ty.qself.is_none() {
+ self.self_to_qself(&mut ty.qself, &mut ty.path);
+ }
+ visit_mut::visit_type_path_mut(self, ty);
+ }
+
+ // `Self::method` -> `<Receiver>::method`
+ fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) {
+ if expr.qself.is_none() {
+ self.self_to_qself(&mut expr.qself, &mut expr.path);
+ }
+ visit_mut::visit_expr_path_mut(self, expr);
+ }
+
+ fn visit_expr_struct_mut(&mut self, expr: &mut ExprStruct) {
+ self.self_to_expr_path(&mut expr.path);
+ visit_mut::visit_expr_struct_mut(self, expr);
+ }
+
+ fn visit_pat_path_mut(&mut self, pat: &mut PatPath) {
+ if pat.qself.is_none() {
+ self.self_to_qself(&mut pat.qself, &mut pat.path);
+ }
+ visit_mut::visit_pat_path_mut(self, pat);
+ }
+
+ fn visit_pat_struct_mut(&mut self, pat: &mut PatStruct) {
+ self.self_to_expr_path(&mut pat.path);
+ visit_mut::visit_pat_struct_mut(self, pat);
+ }
+
+ fn visit_pat_tuple_struct_mut(&mut self, pat: &mut PatTupleStruct) {
+ self.self_to_expr_path(&mut pat.path);
+ visit_mut::visit_pat_tuple_struct_mut(self, pat);
+ }
+
+ fn visit_path_mut(&mut self, path: &mut Path) {
+ if path.segments.len() == 1 {
+ // Replace `self`, but not `self::function`.
+ prepend_underscore_to_self(&mut path.segments[0].ident);
+ }
+ for segment in &mut path.segments {
+ self.visit_path_arguments_mut(&mut segment.arguments);
+ }
+ }
+
+ fn visit_item_mut(&mut self, item: &mut Item) {
+ match item {
+ // Visit `macro_rules!` because locally defined macros can refer to `self`.
+ Item::Macro(item) if item.mac.path.is_ident("macro_rules") => {
+ self.visit_macro_mut(&mut item.mac);
+ }
+ // Otherwise, do not recurse into nested items.
+ _ => {}
+ }
+ }
+
+ fn visit_macro_mut(&mut self, mac: &mut Macro) {
+ // We can't tell in general whether `self` inside a macro invocation
+ // refers to the self in the argument list or a different self
+ // introduced within the macro. Heuristic: if the macro input contains
+ // `fn`, then `self` is more likely to refer to something other than the
+ // outer function's self argument.
+ if !contains_fn(mac.tokens.clone()) {
+ self.visit_token_stream(&mut mac.tokens);
+ }
+ }
+}
+
+fn contains_fn(tokens: TokenStream) -> bool {
+ tokens.into_iter().any(|tt| match tt {
+ TokenTree::Ident(ident) => ident == "fn",
+ TokenTree::Group(group) => contains_fn(group.stream()),
+ _ => false,
+ })
+}
+
+pub(crate) fn prepend_underscore_to_self(ident: &mut Ident) -> bool {
+ let modified = ident == "self";
+ if modified {
+ *ident = Ident::new("__self", ident.span());
+ }
+ modified
+}