From 57651373b18d01821f9a66c48a018e012d662311 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Mon, 18 May 2020 21:05:52 +0900 Subject: [PATCH] Allow naming the projected types --- examples/enum-default-expanded.rs | 15 +- examples/enum-default.rs | 2 +- pin-project-internal/src/lib.rs | 48 ++++-- .../src/pin_project/derive.rs | 77 +++++++-- .../tests/expand/naming-enum.expanded.rs | 155 ++++++++++++++++++ tests/expand/tests/expand/naming-enum.rs | 14 ++ .../tests/expand/naming-struct.expanded.rs | 104 ++++++++++++ tests/expand/tests/expand/naming-struct.rs | 10 ++ .../expand/naming-tuple_struct.expanded.rs | 86 ++++++++++ .../tests/expand/naming-tuple_struct.rs | 6 + tests/pin_project.rs | 45 ++--- tests/ui/pin_project/conflict-naming.rs | 6 + tests/ui/pin_project/conflict-naming.stderr | 21 +++ tests/ui/pin_project/invalid.rs | 30 ++++ tests/ui/pin_project/invalid.stderr | 150 ++++++++++++----- tests/ui/pin_project/visibility.rs | 30 ++++ tests/ui/pin_project/visibility.stderr | 40 +++++ 17 files changed, 744 insertions(+), 95 deletions(-) create mode 100644 tests/expand/tests/expand/naming-enum.expanded.rs create mode 100644 tests/expand/tests/expand/naming-enum.rs create mode 100644 tests/expand/tests/expand/naming-struct.expanded.rs create mode 100644 tests/expand/tests/expand/naming-struct.rs create mode 100644 tests/expand/tests/expand/naming-tuple_struct.expanded.rs create mode 100644 tests/expand/tests/expand/naming-tuple_struct.rs create mode 100644 tests/ui/pin_project/conflict-naming.rs create mode 100644 tests/ui/pin_project/conflict-naming.stderr diff --git a/examples/enum-default-expanded.rs b/examples/enum-default-expanded.rs index 036c01fa..845645a7 100644 --- a/examples/enum-default-expanded.rs +++ b/examples/enum-default-expanded.rs @@ -5,7 +5,7 @@ // // use pin_project::pin_project; // -// #[pin_project] +// #[pin_project(project = EnumProj)] // enum Enum { // Pinned(#[pin] T), // Unpinned(U), @@ -24,11 +24,10 @@ enum Enum { Unpinned(U), } -#[doc(hidden)] #[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] -enum __EnumProjection<'pin, T, U> +enum EnumProj<'pin, T, U> where Enum: 'pin, { @@ -53,13 +52,13 @@ const __SCOPE_Enum: () = { impl Enum { fn project<'pin>( self: ::pin_project::__reexport::pin::Pin<&'pin mut Self>, - ) -> __EnumProjection<'pin, T, U> { + ) -> EnumProj<'pin, T, U> { unsafe { match self.get_unchecked_mut() { - Enum::Pinned(_0) => __EnumProjection::Pinned( - ::pin_project::__reexport::pin::Pin::new_unchecked(_0), - ), - Enum::Unpinned(_0) => __EnumProjection::Unpinned(_0), + Enum::Pinned(_0) => { + EnumProj::Pinned(::pin_project::__reexport::pin::Pin::new_unchecked(_0)) + } + Enum::Unpinned(_0) => EnumProj::Unpinned(_0), } } } diff --git a/examples/enum-default.rs b/examples/enum-default.rs index ab5a4bc2..bd3f2e63 100644 --- a/examples/enum-default.rs +++ b/examples/enum-default.rs @@ -4,7 +4,7 @@ use pin_project::pin_project; -#[pin_project] +#[pin_project(project = EnumProj)] enum Enum { Pinned(#[pin] T), Unpinned(U), diff --git a/pin-project-internal/src/lib.rs b/pin-project-internal/src/lib.rs index a302d054..a6aecafe 100644 --- a/pin-project-internal/src/lib.rs +++ b/pin-project-internal/src/lib.rs @@ -50,6 +50,27 @@ use crate::utils::{Immutable, Mutable, Owned}; /// # } /// ``` /// +/// By passing an argument with the same name as the method to the attribute, +/// you can name the projection type returned from the method: +/// +/// ```rust +/// use pin_project::pin_project; +/// use std::pin::Pin; +/// +/// #[pin_project(project = EnumProj)] +/// enum Enum { +/// Variant(#[pin] T), +/// } +/// +/// fn func(x: Pin<&mut Enum>) { +/// match x.project() { +/// EnumProj::Variant(y) => { +/// let _: Pin<&mut T> = y; +/// } +/// } +/// } +/// ``` +/// /// The visibility of the projected type and projection method is based on the original type. /// However, if the visibility of the original type is `pub`, the visibility of the projected type /// and the projection method is downgraded to `pub(crate)`. @@ -67,7 +88,7 @@ use crate::utils::{Immutable, Mutable, Owned}; /// 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 wish to provide an manual [`Unpin`] impl, you can do so via the -/// `UnsafeUnpin` argument. +/// [`UnsafeUnpin`][unsafe-unpin] argument. /// /// 2. The destructor of the struct must not move structural fields out of its argument. /// @@ -84,8 +105,8 @@ use crate::utils::{Immutable, Mutable, Owned}; /// 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 a function -/// with [`#[pinned_drop]`][pinned-drop]. This function takes a pinned version of your struct - +/// 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 @@ -184,17 +205,14 @@ use crate::utils::{Immutable, Mutable, Owned}; /// /// [Enums](https://doc.rust-lang.org/reference/items/enumerations.html): /// -/// `#[pin_project]` supports enums, but to use it, you need to use with the -/// [`project`] attribute. -/// -/// The attribute at the expression position is not stable, so you need to use -/// a dummy [`project`] attribute for the function. +/// `#[pin_project]` supports enums, but to use it, you need to name the +/// projection type returned from the method or to use with the [`project`] attribute. /// /// ```rust -/// use pin_project::{pin_project, project}; +/// use pin_project::pin_project; /// use std::pin::Pin; /// -/// #[pin_project] +/// #[pin_project(project = EnumProj)] /// enum Enum { /// Tuple(#[pin] T), /// Struct { field: U }, @@ -202,17 +220,15 @@ use crate::utils::{Immutable, Mutable, Owned}; /// } /// /// impl Enum { -/// #[project] // Nightly does not need a dummy attribute to the function. /// fn method(self: Pin<&mut Self>) { -/// #[project] /// match self.project() { -/// Enum::Tuple(x) => { +/// EnumProj::Tuple(x) => { /// let _: Pin<&mut T> = x; /// } -/// Enum::Struct { field } => { +/// EnumProj::Struct { field } => { /// let _: &mut U = field; /// } -/// Enum::Unit => {} +/// EnumProj::Unit => {} /// } /// } /// } @@ -410,7 +426,7 @@ use crate::utils::{Immutable, Mutable, Owned}; /// [repr-packed]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprpacked /// [pin-projection]: https://doc.rust-lang.org/nightly/std/pin/index.html#projections-and-structural-pinning /// [undefined-behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html -/// [unsafe-unpin]: ./attr.pin_project.html#pinned_drop +/// [unsafe-unpin]: ./attr.pin_project.html#unsafeunpin #[proc_macro_attribute] pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream { pin_project::attribute(&args.into(), input.into()).into() diff --git a/pin-project-internal/src/pin_project/derive.rs b/pin-project-internal/src/pin_project/derive.rs index f8040227..25e9623d 100644 --- a/pin-project-internal/src/pin_project/derive.rs +++ b/pin-project-internal/src/pin_project/derive.rs @@ -110,6 +110,12 @@ struct Args { replace: Option, /// `UnsafeUnpin` or `!Unpin` argument. unpin_impl: UnpinImpl, + /// `project = `. + project: Option, + /// `project_ref = `. + project_ref: Option, + /// `project_replace = `. + project_replace: Option, } const DUPLICATE_PIN: &str = "duplicate #[pin] attribute"; @@ -187,6 +193,9 @@ impl Parse for Args { let mut replace = None; let mut unsafe_unpin = None; let mut not_unpin = None; + let mut project = None; + let mut project_ref = None; + let mut project_replace: Option<(Span, Ident)> = None; while !input.is_empty() { if input.peek(token::Bang) { let t: token::Bang = input.parse()?; @@ -201,6 +210,18 @@ impl Parse for Args { "PinnedDrop" => update(&mut pinned_drop, token.span(), &token)?, "Replace" => update(&mut replace, token.span(), &token)?, "UnsafeUnpin" => update(&mut unsafe_unpin, token.span(), &token)?, + "project" => { + let _: token::Eq = input.parse()?; + update(&mut project, input.parse()?, &token)?; + } + "project_ref" => { + let _: token::Eq = input.parse()?; + update(&mut project_ref, input.parse()?, &token)?; + } + "project_replace" => { + let _: token::Eq = input.parse()?; + update(&mut project_replace, (token.span(), input.parse()?), &token)?; + } _ => return Err(error!(token, "unexpected argument: {}", token)), } } @@ -228,7 +249,21 @@ impl Parse for Args { (None, Some(span)) => UnpinImpl::Negative(span.span), }; - Ok(Self { pinned_drop, replace, unpin_impl }) + if let (Some((span, _)), None) = (&project_replace, replace) { + Err(Error::new( + *span, + "`project_replace` argument can only be used together with `Replace` argument", + )) + } else { + Ok(Self { + pinned_drop, + replace, + unpin_impl, + project, + project_ref, + project_replace: project_replace.map(|(_, i)| i), + }) + } } } @@ -294,6 +329,12 @@ struct Context<'a> { replace: Option, /// `UnsafeUnpin` or `!Unpin` argument. unpin_impl: UnpinImpl, + /// `project` argument. + project: bool, + /// `project_ref` argument. + project_ref: bool, + /// `project_replace` argument. + project_replace: bool, } #[derive(Clone, Copy)] @@ -312,7 +353,8 @@ impl<'a> Context<'a> { ident: &'a Ident, generics: &'a mut Generics, ) -> Result { - let Args { pinned_drop, replace, unpin_impl } = Args::get(attrs)?; + let Args { pinned_drop, unpin_impl, replace, project, project_ref, project_replace } = + Args::get(attrs)?; let ty_generics = generics.split_for_impl().1; let self_ty = syn::parse_quote!(#ident #ty_generics); @@ -339,11 +381,14 @@ impl<'a> Context<'a> { pinned_drop, replace, unpin_impl, + project: project.is_some(), + project_ref: project_ref.is_some(), + project_replace: project_replace.is_some(), proj: ProjectedType { vis: determine_visibility(vis), - mut_ident: Mutable.proj_ident(ident), - ref_ident: Immutable.proj_ident(ident), - own_ident: Owned.proj_ident(ident), + mut_ident: project.unwrap_or_else(|| Mutable.proj_ident(ident)), + ref_ident: project_ref.unwrap_or_else(|| Immutable.proj_ident(ident)), + own_ident: project_replace.unwrap_or_else(|| Owned.proj_ident(ident)), lifetime, generics: proj_generics, where_clause, @@ -398,13 +443,18 @@ impl<'a> Context<'a> { Fields::Unit => unreachable!(), }; + // If the user gave it a name, it should appear in the document. + let doc_attr = quote!(#[doc(hidden)]); + let doc_proj = if self.project { None } else { Some(&doc_attr) }; + let doc_proj_ref = if self.project_ref { None } else { Some(&doc_attr) }; + let doc_proj_own = if self.project_replace { None } else { Some(&doc_attr) }; let mut proj_items = quote! { - #[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document. + #doc_proj #[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 #vis struct #proj_ident #proj_generics #where_clause_fields - #[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document. + #doc_proj_ref #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 #vis struct #proj_ref_ident #proj_generics #where_clause_ref_fields @@ -412,7 +462,7 @@ impl<'a> Context<'a> { if self.replace.is_some() { // Currently, using quote_spanned here does not seem to have any effect on the diagnostics. proj_items.extend(quote! { - #[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document. + #doc_proj_own #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 #vis struct #proj_own_ident #orig_generics #where_clause_own_fields @@ -482,15 +532,20 @@ impl<'a> Context<'a> { let proj_generics = &self.proj.generics; let where_clause = &self.proj.where_clause; + // If the user gave it a name, it should appear in the document. + let doc_attr = quote!(#[doc(hidden)]); + let doc_proj = if self.project { None } else { Some(&doc_attr) }; + let doc_proj_ref = if self.project_ref { None } else { Some(&doc_attr) }; + let doc_proj_own = if self.project_replace { None } else { Some(&doc_attr) }; let mut proj_items = quote! { - #[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document. + #doc_proj #[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 #vis enum #proj_ident #proj_generics #where_clause { #proj_variants } - #[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document. + #doc_proj_ref #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 #vis enum #proj_ref_ident #proj_generics #where_clause { @@ -500,7 +555,7 @@ impl<'a> Context<'a> { if self.replace.is_some() { // Currently, using quote_spanned here does not seem to have any effect on the diagnostics. proj_items.extend(quote! { - #[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document. + #doc_proj_own #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 #vis enum #proj_own_ident #orig_generics #orig_where_clause { diff --git a/tests/expand/tests/expand/naming-enum.expanded.rs b/tests/expand/tests/expand/naming-enum.expanded.rs new file mode 100644 index 00000000..15d91048 --- /dev/null +++ b/tests/expand/tests/expand/naming-enum.expanded.rs @@ -0,0 +1,155 @@ +use pin_project::pin_project; +# [ pin ( __private ( Replace , project = Proj , project_ref = ProjRef , project_replace = ProjOwn ) ) ] +enum Enum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), + Unit, +} +#[allow(clippy::mut_mut)] +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +enum Proj<'pin, T, U> +where + Enum: 'pin, +{ + Struct { + pinned: ::pin_project::__reexport::pin::Pin<&'pin mut (T)>, + unpinned: &'pin mut (U), + }, + Tuple( + ::pin_project::__reexport::pin::Pin<&'pin mut (T)>, + &'pin mut (U), + ), + Unit, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +enum ProjRef<'pin, T, U> +where + Enum: 'pin, +{ + Struct { + pinned: ::pin_project::__reexport::pin::Pin<&'pin (T)>, + unpinned: &'pin (U), + }, + Tuple(::pin_project::__reexport::pin::Pin<&'pin (T)>, &'pin (U)), + Unit, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +enum ProjOwn { + Struct { + pinned: ::pin_project::__reexport::marker::PhantomData, + unpinned: U, + }, + Tuple(::pin_project::__reexport::marker::PhantomData, U), + Unit, +} +#[doc(hidden)] +#[allow(non_upper_case_globals)] +#[allow(single_use_lifetimes)] +const __SCOPE_Enum: () = { + impl Enum { + fn project<'pin>( + self: ::pin_project::__reexport::pin::Pin<&'pin mut Self>, + ) -> Proj<'pin, T, U> { + unsafe { + match self.get_unchecked_mut() { + Enum::Struct { pinned, unpinned } => Proj::Struct { + pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned), + unpinned, + }, + Enum::Tuple(_0, _1) => { + Proj::Tuple(::pin_project::__reexport::pin::Pin::new_unchecked(_0), _1) + } + Enum::Unit => Proj::Unit, + } + } + } + fn project_ref<'pin>( + self: ::pin_project::__reexport::pin::Pin<&'pin Self>, + ) -> ProjRef<'pin, T, U> { + unsafe { + match self.get_ref() { + Enum::Struct { pinned, unpinned } => ProjRef::Struct { + pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned), + unpinned, + }, + Enum::Tuple(_0, _1) => { + ProjRef::Tuple(::pin_project::__reexport::pin::Pin::new_unchecked(_0), _1) + } + Enum::Unit => ProjRef::Unit, + } + } + } + fn project_replace( + self: ::pin_project::__reexport::pin::Pin<&mut Self>, + __replacement: Self, + ) -> ProjOwn { + unsafe { + let __self_ptr: *mut Self = self.get_unchecked_mut(); + match &mut *__self_ptr { + Enum::Struct { pinned, unpinned } => { + let __result = ProjOwn::Struct { + pinned: ::pin_project::__reexport::marker::PhantomData, + unpinned: ::pin_project::__reexport::ptr::read(unpinned), + }; + let __guard = ::pin_project::__private::UnsafeOverwriteGuard { + target: __self_ptr, + value: ::pin_project::__reexport::mem::ManuallyDrop::new(__replacement), + }; + { + let __guard = ::pin_project::__private::UnsafeDropInPlaceGuard(pinned); + } + __result + } + Enum::Tuple(_0, _1) => { + let __result = ProjOwn::Tuple( + ::pin_project::__reexport::marker::PhantomData, + ::pin_project::__reexport::ptr::read(_1), + ); + let __guard = ::pin_project::__private::UnsafeOverwriteGuard { + target: __self_ptr, + value: ::pin_project::__reexport::mem::ManuallyDrop::new(__replacement), + }; + { + let __guard = ::pin_project::__private::UnsafeDropInPlaceGuard(_0); + } + __result + } + Enum::Unit => { + let __result = ProjOwn::Unit; + let __guard = ::pin_project::__private::UnsafeOverwriteGuard { + target: __self_ptr, + value: ::pin_project::__reexport::mem::ManuallyDrop::new(__replacement), + }; + {} + __result + } + } + } + } + } + struct __Enum<'pin, T, U> { + __pin_project_use_generics: ::pin_project::__private::AlwaysUnpin<'pin, (T, U)>, + __field0: T, + __field1: T, + } + impl<'pin, T, U> ::pin_project::__reexport::marker::Unpin for Enum where + __Enum<'pin, T, U>: ::pin_project::__reexport::marker::Unpin + { + } + unsafe impl ::pin_project::UnsafeUnpin for Enum {} + trait EnumMustNotImplDrop {} + #[allow(clippy::drop_bounds)] + impl EnumMustNotImplDrop for T {} + impl EnumMustNotImplDrop for Enum {} + impl ::pin_project::__private::PinnedDrop for Enum { + unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {} + } +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-enum.rs b/tests/expand/tests/expand/naming-enum.rs new file mode 100644 index 00000000..92270f9b --- /dev/null +++ b/tests/expand/tests/expand/naming-enum.rs @@ -0,0 +1,14 @@ +use pin_project::pin_project; + +#[pin_project(Replace, project = Proj, project_ref = ProjRef, project_replace = ProjOwn)] +enum Enum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), + Unit, +} + +fn main() {} diff --git a/tests/expand/tests/expand/naming-struct.expanded.rs b/tests/expand/tests/expand/naming-struct.expanded.rs new file mode 100644 index 00000000..cd56559c --- /dev/null +++ b/tests/expand/tests/expand/naming-struct.expanded.rs @@ -0,0 +1,104 @@ +use pin_project::pin_project; +# [ pin ( __private ( Replace , project = Proj , project_ref = ProjRef , project_replace = ProjOwn ) ) ] +struct Struct { + #[pin] + pinned: T, + unpinned: U, +} +#[allow(clippy::mut_mut)] +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +struct Proj<'pin, T, U> +where + Struct: 'pin, +{ + pinned: ::pin_project::__reexport::pin::Pin<&'pin mut (T)>, + unpinned: &'pin mut (U), +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +struct ProjRef<'pin, T, U> +where + Struct: 'pin, +{ + pinned: ::pin_project::__reexport::pin::Pin<&'pin (T)>, + unpinned: &'pin (U), +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +struct ProjOwn { + pinned: ::pin_project::__reexport::marker::PhantomData, + unpinned: U, +} +#[doc(hidden)] +#[allow(non_upper_case_globals)] +#[allow(single_use_lifetimes)] +const __SCOPE_Struct: () = { + impl Struct { + fn project<'pin>( + self: ::pin_project::__reexport::pin::Pin<&'pin mut Self>, + ) -> Proj<'pin, T, U> { + unsafe { + let Self { pinned, unpinned } = self.get_unchecked_mut(); + Proj { + pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned), + unpinned, + } + } + } + fn project_ref<'pin>( + self: ::pin_project::__reexport::pin::Pin<&'pin Self>, + ) -> ProjRef<'pin, T, U> { + unsafe { + let Self { pinned, unpinned } = self.get_ref(); + ProjRef { + pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned), + unpinned, + } + } + } + fn project_replace( + self: ::pin_project::__reexport::pin::Pin<&mut Self>, + __replacement: Self, + ) -> ProjOwn { + unsafe { + let __self_ptr: *mut Self = self.get_unchecked_mut(); + let Self { pinned, unpinned } = &mut *__self_ptr; + let __result = ProjOwn { + pinned: ::pin_project::__reexport::marker::PhantomData, + unpinned: ::pin_project::__reexport::ptr::read(unpinned), + }; + let __guard = ::pin_project::__private::UnsafeOverwriteGuard { + target: __self_ptr, + value: ::pin_project::__reexport::mem::ManuallyDrop::new(__replacement), + }; + { + let __guard = ::pin_project::__private::UnsafeDropInPlaceGuard(pinned); + } + __result + } + } + } + struct __Struct<'pin, T, U> { + __pin_project_use_generics: ::pin_project::__private::AlwaysUnpin<'pin, (T, U)>, + __field0: T, + } + impl<'pin, T, U> ::pin_project::__reexport::marker::Unpin for Struct where + __Struct<'pin, T, U>: ::pin_project::__reexport::marker::Unpin + { + } + unsafe impl ::pin_project::UnsafeUnpin for Struct {} + trait StructMustNotImplDrop {} + #[allow(clippy::drop_bounds)] + impl StructMustNotImplDrop for T {} + impl StructMustNotImplDrop for Struct {} + impl ::pin_project::__private::PinnedDrop for Struct { + unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {} + } + #[deny(safe_packed_borrows)] + fn __assert_not_repr_packed(val: &Struct) { + &val.pinned; + &val.unpinned; + } +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-struct.rs b/tests/expand/tests/expand/naming-struct.rs new file mode 100644 index 00000000..043cc4ff --- /dev/null +++ b/tests/expand/tests/expand/naming-struct.rs @@ -0,0 +1,10 @@ +use pin_project::pin_project; + +#[pin_project(Replace, project = Proj, project_ref = ProjRef, project_replace = ProjOwn)] +struct Struct { + #[pin] + pinned: T, + unpinned: U, +} + +fn main() {} diff --git a/tests/expand/tests/expand/naming-tuple_struct.expanded.rs b/tests/expand/tests/expand/naming-tuple_struct.expanded.rs new file mode 100644 index 00000000..420c1e2e --- /dev/null +++ b/tests/expand/tests/expand/naming-tuple_struct.expanded.rs @@ -0,0 +1,86 @@ +use pin_project::pin_project; +# [ pin ( __private ( Replace , project = Proj , project_ref = ProjRef , project_replace = ProjOwn ) ) ] +struct TupleStruct(#[pin] T, U); +#[allow(clippy::mut_mut)] +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +struct Proj<'pin, T, U>( + ::pin_project::__reexport::pin::Pin<&'pin mut (T)>, + &'pin mut (U), +) +where + TupleStruct: 'pin; +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +struct ProjRef<'pin, T, U>(::pin_project::__reexport::pin::Pin<&'pin (T)>, &'pin (U)) +where + TupleStruct: 'pin; +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +struct ProjOwn(::pin_project::__reexport::marker::PhantomData, U); +#[doc(hidden)] +#[allow(non_upper_case_globals)] +#[allow(single_use_lifetimes)] +const __SCOPE_TupleStruct: () = { + impl TupleStruct { + fn project<'pin>( + self: ::pin_project::__reexport::pin::Pin<&'pin mut Self>, + ) -> Proj<'pin, T, U> { + unsafe { + let Self(_0, _1) = self.get_unchecked_mut(); + Proj(::pin_project::__reexport::pin::Pin::new_unchecked(_0), _1) + } + } + fn project_ref<'pin>( + self: ::pin_project::__reexport::pin::Pin<&'pin Self>, + ) -> ProjRef<'pin, T, U> { + unsafe { + let Self(_0, _1) = self.get_ref(); + ProjRef(::pin_project::__reexport::pin::Pin::new_unchecked(_0), _1) + } + } + fn project_replace( + self: ::pin_project::__reexport::pin::Pin<&mut Self>, + __replacement: Self, + ) -> ProjOwn { + unsafe { + let __self_ptr: *mut Self = self.get_unchecked_mut(); + let Self(_0, _1) = &mut *__self_ptr; + let __result = ProjOwn( + ::pin_project::__reexport::marker::PhantomData, + ::pin_project::__reexport::ptr::read(_1), + ); + let __guard = ::pin_project::__private::UnsafeOverwriteGuard { + target: __self_ptr, + value: ::pin_project::__reexport::mem::ManuallyDrop::new(__replacement), + }; + { + let __guard = ::pin_project::__private::UnsafeDropInPlaceGuard(_0); + } + __result + } + } + } + struct __TupleStruct<'pin, T, U> { + __pin_project_use_generics: ::pin_project::__private::AlwaysUnpin<'pin, (T, U)>, + __field0: T, + } + impl<'pin, T, U> ::pin_project::__reexport::marker::Unpin for TupleStruct where + __TupleStruct<'pin, T, U>: ::pin_project::__reexport::marker::Unpin + { + } + unsafe impl ::pin_project::UnsafeUnpin for TupleStruct {} + trait TupleStructMustNotImplDrop {} + #[allow(clippy::drop_bounds)] + impl TupleStructMustNotImplDrop for T {} + impl TupleStructMustNotImplDrop for TupleStruct {} + impl ::pin_project::__private::PinnedDrop for TupleStruct { + unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {} + } + #[deny(safe_packed_borrows)] + fn __assert_not_repr_packed(val: &TupleStruct) { + &val.0; + &val.1; + } +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-tuple_struct.rs b/tests/expand/tests/expand/naming-tuple_struct.rs new file mode 100644 index 00000000..5fdffdf9 --- /dev/null +++ b/tests/expand/tests/expand/naming-tuple_struct.rs @@ -0,0 +1,6 @@ +use pin_project::pin_project; + +#[pin_project(Replace, project = Proj, project_ref = ProjRef, project_replace = ProjOwn)] +struct TupleStruct(#[pin] T, U); + +fn main() {} diff --git a/tests/pin_project.rs b/tests/pin_project.rs index c84ca4b7..72bcd152 100644 --- a/tests/pin_project.rs +++ b/tests/pin_project.rs @@ -9,7 +9,12 @@ use pin_project::{pin_project, pinned_drop, UnsafeUnpin}; #[test] fn projection() { - #[pin_project(Replace)] + #[pin_project( + Replace, + project = StructProj, + project_ref = StructProjRef, + project_replace = StructProjOwn, + )] struct Struct { #[pin] field1: T, @@ -31,16 +36,16 @@ fn projection() { let mut s = Struct { field1: 1, field2: 2 }; - let __StructProjection { field1, field2 } = Pin::new(&mut s).project(); + let StructProj { field1, field2 } = Pin::new(&mut s).project(); let _: Pin<&mut i32> = field1; let _: &mut i32 = field2; - let __StructProjectionRef { field1, field2 } = Pin::new(&s).project_ref(); + let StructProjRef { field1, field2 } = Pin::new(&s).project_ref(); let _: Pin<&i32> = field1; let _: &i32 = field2; let mut s = Pin::new(&mut s); - let __StructProjectionOwned { field1, field2 } = + let StructProjOwn { field1, field2 } = s.as_mut().project_replace(Struct { field1: 3, field2: 4 }); let _: PhantomData = field1; let _: i32 = field2; @@ -60,7 +65,7 @@ fn projection() { let y: &mut i32 = s.1; assert_eq!(*y, 2); - #[pin_project(Replace)] + #[pin_project(Replace, project = EnumProj)] #[derive(Eq, PartialEq, Debug)] enum Enum { Variant1(#[pin] A, B), @@ -77,18 +82,18 @@ fn projection() { let e = e_orig.as_mut().project(); match e { - __EnumProjection::Variant1(x, y) => { + EnumProj::Variant1(x, y) => { let x: Pin<&mut i32> = x; assert_eq!(*x, 1); let y: &mut i32 = y; assert_eq!(*y, 2); } - __EnumProjection::Variant2 { field1, field2 } => { + EnumProj::Variant2 { field1, field2 } => { let _x: Pin<&mut i32> = field1; let _y: &mut i32 = field2; } - __EnumProjection::None => {} + EnumProj::None => {} } assert_eq!(Pin::into_ref(e_orig).get_ref(), &Enum::Variant1(1, 2)); @@ -97,21 +102,21 @@ fn projection() { let mut e = Pin::new(&mut e).project(); match &mut e { - __EnumProjection::Variant1(x, y) => { + EnumProj::Variant1(x, y) => { let _x: &mut Pin<&mut i32> = x; let _y: &mut &mut i32 = y; } - __EnumProjection::Variant2 { field1, field2 } => { + EnumProj::Variant2 { field1, field2 } => { let x: &mut Pin<&mut i32> = field1; assert_eq!(**x, 3); let y: &mut &mut i32 = field2; assert_eq!(**y, 4); } - __EnumProjection::None => {} + EnumProj::None => {} } - if let __EnumProjection::Variant2 { field1, field2 } = e { + if let EnumProj::Variant2 { field1, field2 } = e { let x: Pin<&mut i32> = field1; assert_eq!(*x, 3); @@ -122,7 +127,7 @@ fn projection() { #[test] fn enum_project_set() { - #[pin_project(Replace)] + #[pin_project(Replace, project = EnumProj)] #[derive(Eq, PartialEq, Debug)] enum Enum { Variant1(#[pin] u8), @@ -134,7 +139,7 @@ fn enum_project_set() { let e_proj = e_orig.as_mut().project(); match e_proj { - __EnumProjection::Variant1(val) => { + EnumProj::Variant1(val) => { let new_e = Enum::Variant2(val.as_ref().get_ref() == &25); e_orig.set(new_e); } @@ -409,7 +414,7 @@ fn lifetime_project() { unpinned: U, } - #[pin_project(Replace)] + #[pin_project(Replace, project = EnumProj, project_ref = EnumProjRef)] enum Enum { Variant { #[pin] @@ -439,12 +444,12 @@ fn lifetime_project() { impl Enum { fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> { match self.project_ref() { - __EnumProjectionRef::Variant { pinned, .. } => pinned, + EnumProjRef::Variant { pinned, .. } => pinned, } } fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> { match self.project() { - __EnumProjection::Variant { pinned, .. } => pinned, + EnumProj::Variant { pinned, .. } => pinned, } } } @@ -467,7 +472,7 @@ fn lifetime_project_elided() { unpinned: U, } - #[pin_project(Replace)] + #[pin_project(Replace, project = EnumProj, project_ref = EnumProjRef)] enum Enum { Variant { #[pin] @@ -497,12 +502,12 @@ fn lifetime_project_elided() { impl Enum { fn get_pin_ref(self: Pin<&Self>) -> Pin<&T> { match self.project_ref() { - __EnumProjectionRef::Variant { pinned, .. } => pinned, + EnumProjRef::Variant { pinned, .. } => pinned, } } fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { match self.project() { - __EnumProjection::Variant { pinned, .. } => pinned, + EnumProj::Variant { pinned, .. } => pinned, } } } diff --git a/tests/ui/pin_project/conflict-naming.rs b/tests/ui/pin_project/conflict-naming.rs new file mode 100644 index 00000000..1cb50b44 --- /dev/null +++ b/tests/ui/pin_project/conflict-naming.rs @@ -0,0 +1,6 @@ +use pin_project::pin_project; + +#[pin_project(project = A, project_ref = A)] //~ ERROR E0428,E0308 +struct Struct(#[pin] ()); + +fn main() {} diff --git a/tests/ui/pin_project/conflict-naming.stderr b/tests/ui/pin_project/conflict-naming.stderr new file mode 100644 index 00000000..bbac1eb9 --- /dev/null +++ b/tests/ui/pin_project/conflict-naming.stderr @@ -0,0 +1,21 @@ +error[E0428]: the name `A` is defined multiple times + --> $DIR/conflict-naming.rs:3:1 + | +3 | #[pin_project(project = A, project_ref = A)] //~ ERROR E0428,E0308 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | `A` redefined here + | previous definition of the type `A` here + | + = note: `A` must be defined only once in the type namespace of this module + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/conflict-naming.rs:3:1 + | +3 | #[pin_project(project = A, project_ref = A)] //~ ERROR E0428,E0308 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability + | + = note: expected mutable reference `&mut ()` + found reference `&()` + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/pin_project/invalid.rs b/tests/ui/pin_project/invalid.rs index 1d056084..d7911df5 100644 --- a/tests/ui/pin_project/invalid.rs +++ b/tests/ui/pin_project/invalid.rs @@ -118,6 +118,18 @@ mod pin_project_argument { #[pin_project(PinnedDrop, UnsafeUnpin, PinnedDrop, UnsafeUnpin)] //~ ERROR duplicate `PinnedDrop` argument struct Duplicate4(#[pin] ()); + #[pin_project(project = A, project = B)] //~ ERROR duplicate `project` argument + struct DuplicateProject(#[pin] ()); + + #[pin_project(project_ref = A, project_ref = B)] //~ ERROR duplicate `project_ref` argument + struct DuplicateProjectRef(#[pin] ()); + + #[pin_project(project_replace = A, project_replace = B)] //~ ERROR duplicate `project_replace` argument + struct DuplicateProjectReplace(#[pin] ()); + + #[pin_project(project_replace = A)] //~ ERROR `project_replace` argument can only be used together with `Replace` argument + struct ProjectReplaceWithoutReplace(#[pin] ()); + #[pin_project(PinnedDrop, Replace)] //~ ERROR arguments `PinnedDrop` and `Replace` are mutually exclusive struct PinnedDropWithReplace1(#[pin] ()); @@ -135,6 +147,24 @@ mod pin_project_argument { #[pin_project(Unpin)] //~ ERROR unexpected argument struct NotUnpin2(#[pin] ()); + + #[pin_project(project)] //~ ERROR expected `=` + struct Project1(#[pin] ()); + + #[pin_project(project = )] //~ ERROR unexpected end of input, expected identifier + struct Project2(#[pin] ()); + + #[pin_project(project_ref)] //~ ERROR expected `=` + struct ProjectRef1(#[pin] ()); + + #[pin_project(project_ref = )] //~ ERROR unexpected end of input, expected identifier + struct ProjectRef2(#[pin] ()); + + #[pin_project(project_replace)] //~ ERROR expected `=` + struct ProjectReplace1(#[pin] ()); + + #[pin_project(project_replace = )] //~ ERROR unexpected end of input, expected identifier + struct ProjectReplace2(#[pin] ()); } mod pin_project_attribute { diff --git a/tests/ui/pin_project/invalid.stderr b/tests/ui/pin_project/invalid.stderr index 95b57f0a..82026aa5 100644 --- a/tests/ui/pin_project/invalid.stderr +++ b/tests/ui/pin_project/invalid.stderr @@ -118,111 +118,183 @@ error: duplicate `PinnedDrop` argument 118 | #[pin_project(PinnedDrop, UnsafeUnpin, PinnedDrop, UnsafeUnpin)] //~ ERROR duplicate `PinnedDrop` argument | ^^^^^^^^^^ +error: duplicate `project` argument + --> $DIR/invalid.rs:121:32 + | +121 | #[pin_project(project = A, project = B)] //~ ERROR duplicate `project` argument + | ^^^^^^^ + +error: duplicate `project_ref` argument + --> $DIR/invalid.rs:124:36 + | +124 | #[pin_project(project_ref = A, project_ref = B)] //~ ERROR duplicate `project_ref` argument + | ^^^^^^^^^^^ + +error: duplicate `project_replace` argument + --> $DIR/invalid.rs:127:40 + | +127 | #[pin_project(project_replace = A, project_replace = B)] //~ ERROR duplicate `project_replace` argument + | ^^^^^^^^^^^^^^^ + +error: `project_replace` argument can only be used together with `Replace` argument + --> $DIR/invalid.rs:130:19 + | +130 | #[pin_project(project_replace = A)] //~ ERROR `project_replace` argument can only be used together with `Replace` argument + | ^^^^^^^^^^^^^^^ + error: arguments `PinnedDrop` and `Replace` are mutually exclusive - --> $DIR/invalid.rs:121:19 + --> $DIR/invalid.rs:133:19 | -121 | #[pin_project(PinnedDrop, Replace)] //~ ERROR arguments `PinnedDrop` and `Replace` are mutually exclusive +133 | #[pin_project(PinnedDrop, Replace)] //~ ERROR arguments `PinnedDrop` and `Replace` are mutually exclusive | ^^^^^^^^^^ error: arguments `PinnedDrop` and `Replace` are mutually exclusive - --> $DIR/invalid.rs:124:41 + --> $DIR/invalid.rs:136:41 | -124 | #[pin_project(Replace, UnsafeUnpin, PinnedDrop)] //~ ERROR arguments `PinnedDrop` and `Replace` are mutually exclusive +136 | #[pin_project(Replace, UnsafeUnpin, PinnedDrop)] //~ ERROR arguments `PinnedDrop` and `Replace` are mutually exclusive | ^^^^^^^^^^ error: arguments `UnsafeUnpin` and `!Unpin` are mutually exclusive - --> $DIR/invalid.rs:127:19 + --> $DIR/invalid.rs:139:19 | -127 | #[pin_project(UnsafeUnpin, !Unpin)] //~ ERROR arguments `UnsafeUnpin` and `!Unpin` are mutually exclusive +139 | #[pin_project(UnsafeUnpin, !Unpin)] //~ ERROR arguments `UnsafeUnpin` and `!Unpin` are mutually exclusive | ^^^^^^^^^^^ error: arguments `UnsafeUnpin` and `!Unpin` are mutually exclusive - --> $DIR/invalid.rs:130:39 + --> $DIR/invalid.rs:142:39 | -130 | #[pin_project(!Unpin, PinnedDrop, UnsafeUnpin)] //~ ERROR arguments `UnsafeUnpin` and `!Unpin` are mutually exclusive +142 | #[pin_project(!Unpin, PinnedDrop, UnsafeUnpin)] //~ ERROR arguments `UnsafeUnpin` and `!Unpin` are mutually exclusive | ^^^^^^^^^^^ error: unexpected end of input, expected `Unpin` - --> $DIR/invalid.rs:133:5 + --> $DIR/invalid.rs:145:5 | -133 | #[pin_project(!)] //~ ERROR unexpected end of input, expected `Unpin` +145 | #[pin_project(!)] //~ ERROR unexpected end of input, expected `Unpin` | ^^^^^^^^^^^^^^^^^ | = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) error: unexpected argument: Unpin - --> $DIR/invalid.rs:136:19 + --> $DIR/invalid.rs:148:19 | -136 | #[pin_project(Unpin)] //~ ERROR unexpected argument +148 | #[pin_project(Unpin)] //~ ERROR unexpected argument | ^^^^^ +error: expected `=` + --> $DIR/invalid.rs:151:5 + | +151 | #[pin_project(project)] //~ ERROR expected `=` + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unexpected end of input, expected identifier + --> $DIR/invalid.rs:154:5 + | +154 | #[pin_project(project = )] //~ ERROR unexpected end of input, expected identifier + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected `=` + --> $DIR/invalid.rs:157:5 + | +157 | #[pin_project(project_ref)] //~ ERROR expected `=` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unexpected end of input, expected identifier + --> $DIR/invalid.rs:160:5 + | +160 | #[pin_project(project_ref = )] //~ ERROR unexpected end of input, expected identifier + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: expected `=` + --> $DIR/invalid.rs:163:5 + | +163 | #[pin_project(project_replace)] //~ ERROR expected `=` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: unexpected end of input, expected identifier + --> $DIR/invalid.rs:166:5 + | +166 | #[pin_project(project_replace = )] //~ ERROR unexpected end of input, expected identifier + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + error: duplicate #[pin_project] attribute - --> $DIR/invalid.rs:144:5 + --> $DIR/invalid.rs:174:5 | -144 | #[pin_project] //~ ERROR duplicate #[pin_project] attribute +174 | #[pin_project] //~ ERROR duplicate #[pin_project] attribute | ^^^^^^^^^^^^^^ error: #[pin_project] attribute may not be used on structs with zero fields - --> $DIR/invalid.rs:152:19 + --> $DIR/invalid.rs:182:19 | -152 | struct Struct {} //~ ERROR may not be used on structs with zero fields +182 | struct Struct {} //~ ERROR may not be used on structs with zero fields | ^^ error: #[pin_project] attribute may not be used on structs with zero fields - --> $DIR/invalid.rs:155:23 + --> $DIR/invalid.rs:185:23 | -155 | struct TupleStruct(); //~ ERROR may not be used on structs with zero fields +185 | struct TupleStruct(); //~ ERROR may not be used on structs with zero fields | ^^ error: #[pin_project] attribute may not be used on structs with zero fields - --> $DIR/invalid.rs:158:12 + --> $DIR/invalid.rs:188:12 | -158 | struct UnitStruct; //~ ERROR may not be used on structs with zero fields +188 | struct UnitStruct; //~ ERROR may not be used on structs with zero fields | ^^^^^^^^^^ error: #[pin_project] attribute may not be used on enums without variants - --> $DIR/invalid.rs:161:20 + --> $DIR/invalid.rs:191:20 | -161 | enum EnumEmpty {} //~ ERROR may not be used on enums without variants +191 | enum EnumEmpty {} //~ ERROR may not be used on enums without variants | ^^ error: #[pin_project] attribute may not be used on enums with discriminants - --> $DIR/invalid.rs:165:13 + --> $DIR/invalid.rs:195:13 | -165 | V = 2, //~ ERROR may not be used on enums with discriminants +195 | V = 2, //~ ERROR may not be used on enums with discriminants | ^ error: #[pin_project] attribute may not be used on enums with zero fields - --> $DIR/invalid.rs:170:9 + --> $DIR/invalid.rs:200:9 | -170 | / Unit, //~ ERROR may not be used on enums with zero fields -171 | | Tuple(), -172 | | Struct {}, +200 | / Unit, //~ ERROR may not be used on enums with zero fields +201 | | Tuple(), +202 | | Struct {}, | |__________________^ error: #[pin_project] attribute may only be used on structs or enums - --> $DIR/invalid.rs:176:5 + --> $DIR/invalid.rs:206:5 | -176 | / union Union { -177 | | //~^ ERROR may only be used on structs or enums -178 | | f: (), -179 | | } +206 | / union Union { +207 | | //~^ ERROR may only be used on structs or enums +208 | | f: (), +209 | | } | |_____^ error: #[pin_project] attribute may not be used on #[repr(packed)] types - --> $DIR/invalid.rs:187:12 + --> $DIR/invalid.rs:217:12 | -187 | #[repr(packed)] +217 | #[repr(packed)] | ^^^^^^ error: #[pin_project] attribute may not be used on #[repr(packed)] types - --> $DIR/invalid.rs:191:12 + --> $DIR/invalid.rs:221:12 | -191 | #[repr(packed)] +221 | #[repr(packed)] | ^^^^^^ error: #[pin_project] attribute may not be used on #[repr(packed)] types - --> $DIR/invalid.rs:195:12 + --> $DIR/invalid.rs:225:12 | -195 | #[repr(packed)] +225 | #[repr(packed)] | ^^^^^^ diff --git a/tests/ui/pin_project/visibility.rs b/tests/ui/pin_project/visibility.rs index 4f0cb1b0..7dce6ab8 100644 --- a/tests/ui/pin_project/visibility.rs +++ b/tests/ui/pin_project/visibility.rs @@ -49,4 +49,34 @@ pub mod pub_crate_use { }; } +mod pub_renamed { + use pin_project::pin_project; + + #[pin_project(project = DProj, project_ref = DProjRef)] + pub struct Default(()); + + #[pin_project(Replace, project = RProj, project_ref = RProjRef, project_replace = RProjOwn)] + pub struct Replace(()); +} +pub mod pub_renamed_use { + #[rustfmt::skip] + pub use crate::pub_renamed::DProj; //~ ERROR E0365 + #[rustfmt::skip] + pub use crate::pub_renamed::DProjRef; //~ ERROR E0365 + #[rustfmt::skip] + pub use crate::pub_renamed::RProj; //~ ERROR E0365 + #[rustfmt::skip] + pub use crate::pub_renamed::RProjOwn; //~ ERROR E0365 + #[rustfmt::skip] + pub use crate::pub_renamed::RProjRef; //~ ERROR E0365 + + // Confirm that the visibility of the original type is not changed. + pub use crate::pub_renamed::{Default, Replace}; +} +pub mod pub_renamed_use2 { + // Ok + #[allow(unused_imports)] + pub(crate) use crate::pub_renamed::{DProj, DProjRef, RProj, RProjOwn, RProjRef}; +} + fn main() {} diff --git a/tests/ui/pin_project/visibility.stderr b/tests/ui/pin_project/visibility.stderr index 1ea60d76..cab0e2e3 100644 --- a/tests/ui/pin_project/visibility.stderr +++ b/tests/ui/pin_project/visibility.stderr @@ -37,3 +37,43 @@ error[E0365]: `__ReplaceProjectionRef` is private, and cannot be re-exported | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `__ReplaceProjectionRef` | = note: consider declaring type or module `__ReplaceProjectionRef` with `pub` + +error[E0365]: `DProj` is private, and cannot be re-exported + --> $DIR/visibility.rs:63:13 + | +63 | pub use crate::pub_renamed::DProj; //~ ERROR E0365 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `DProj` + | + = note: consider declaring type or module `DProj` with `pub` + +error[E0365]: `DProjRef` is private, and cannot be re-exported + --> $DIR/visibility.rs:65:13 + | +65 | pub use crate::pub_renamed::DProjRef; //~ ERROR E0365 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `DProjRef` + | + = note: consider declaring type or module `DProjRef` with `pub` + +error[E0365]: `RProj` is private, and cannot be re-exported + --> $DIR/visibility.rs:67:13 + | +67 | pub use crate::pub_renamed::RProj; //~ ERROR E0365 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `RProj` + | + = note: consider declaring type or module `RProj` with `pub` + +error[E0365]: `RProjOwn` is private, and cannot be re-exported + --> $DIR/visibility.rs:69:13 + | +69 | pub use crate::pub_renamed::RProjOwn; //~ ERROR E0365 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `RProjOwn` + | + = note: consider declaring type or module `RProjOwn` with `pub` + +error[E0365]: `RProjRef` is private, and cannot be re-exported + --> $DIR/visibility.rs:71:13 + | +71 | pub use crate::pub_renamed::RProjRef; //~ ERROR E0365 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `RProjRef` + | + = note: consider declaring type or module `RProjRef` with `pub`