From 6f3e9271b123f94f158b1f000c996a558351320f Mon Sep 17 00:00:00 2001 From: Chih-Hung Hsieh Date: Wed, 13 May 2020 16:08:03 -0700 Subject: Import 'pin-project' package version 0.4.16 * Add OWNERS and Android.bp Bug: 156165390 Test: make Change-Id: I8ace68f978b2725ad91e0f64282003fa453674ca --- tests/cfg.rs | 242 ++++++ tests/compiletest.rs | 15 + tests/forbid_unsafe.rs | 108 +++ tests/lints.rs | 126 ++++ tests/overwriting_core_crate.rs | 116 +++ tests/pin_project.rs | 809 +++++++++++++++++++++ tests/pinned_drop.rs | 235 ++++++ tests/project.rs | 297 ++++++++ tests/project_if_attr.rs.in | 44 ++ tests/project_ref.rs | 174 +++++ tests/project_replace.rs | 98 +++ tests/repr_packed.rs | 50 ++ tests/ui/cfg/cfg_attr-resolve.rs | 11 + tests/ui/cfg/cfg_attr-resolve.stderr | 5 + tests/ui/cfg/cfg_attr-type-mismatch.rs | 24 + tests/ui/cfg/cfg_attr-type-mismatch.stderr | 23 + tests/ui/cfg/cfg_attr-unpin.rs | 21 + tests/ui/cfg/cfg_attr-unpin.stderr | 22 + tests/ui/cfg/packed_sneaky-span-issue-1.rs | 18 + tests/ui/cfg/packed_sneaky-span-issue-1.stderr | 1 + tests/ui/cfg/packed_sneaky-span-issue-2.rs | 18 + tests/ui/cfg/packed_sneaky-span-issue-2.stderr | 1 + tests/ui/cfg/packed_sneaky.rs | 12 + tests/ui/cfg/packed_sneaky.stderr | 7 + tests/ui/cfg/proper_unpin.rs | 28 + tests/ui/cfg/proper_unpin.stderr | 11 + tests/ui/cfg/unsupported.rs | 13 + tests/ui/cfg/unsupported.stderr | 1 + tests/ui/not_unpin/assert-not-unpin.rs | 40 + tests/ui/not_unpin/assert-not-unpin.stderr | 83 +++ tests/ui/not_unpin/conflict-unpin.rs | 30 + tests/ui/not_unpin/conflict-unpin.stderr | 26 + tests/ui/not_unpin/impl-unsafe-unpin.rs | 30 + tests/ui/not_unpin/impl-unsafe-unpin.stderr | 32 + tests/ui/pin_project/add-pin-attr-to-struct.rs | 19 + tests/ui/pin_project/add-pin-attr-to-struct.stderr | 15 + tests/ui/pin_project/add-pinned-field.rs | 23 + tests/ui/pin_project/add-pinned-field.stderr | 23 + tests/ui/pin_project/conflict-drop.rs | 31 + tests/ui/pin_project/conflict-drop.stderr | 19 + tests/ui/pin_project/conflict-unpin.rs | 37 + tests/ui/pin_project/conflict-unpin.stderr | 32 + tests/ui/pin_project/impl-unsafe-unpin.rs | 30 + tests/ui/pin_project/impl-unsafe-unpin.stderr | 32 + tests/ui/pin_project/invalid.rs | 199 +++++ tests/ui/pin_project/invalid.stderr | 228 ++++++ tests/ui/pin_project/overlapping_unpin_struct.rs | 18 + .../ui/pin_project/overlapping_unpin_struct.stderr | 11 + tests/ui/pin_project/packed-enum.rs | 20 + tests/ui/pin_project/packed-enum.stderr | 30 + tests/ui/pin_project/packed-name-value.rs | 20 + tests/ui/pin_project/packed-name-value.stderr | 17 + tests/ui/pin_project/packed.rs | 25 + tests/ui/pin_project/packed.stderr | 17 + tests/ui/pin_project/packed_sneaky-1.rs | 33 + tests/ui/pin_project/packed_sneaky-1.stderr | 23 + tests/ui/pin_project/packed_sneaky-2.rs | 12 + tests/ui/pin_project/packed_sneaky-2.stderr | 13 + tests/ui/pin_project/private_in_public-enum.rs | 23 + tests/ui/pin_project/private_in_public-enum.stderr | 17 + tests/ui/pin_project/proper_unpin.rs | 38 + tests/ui/pin_project/proper_unpin.stderr | 37 + tests/ui/pin_project/remove-attr-from-field.rs | 32 + tests/ui/pin_project/remove-attr-from-field.stderr | 21 + tests/ui/pin_project/remove-attr-from-struct.rs | 30 + .../ui/pin_project/remove-attr-from-struct.stderr | 63 ++ tests/ui/pin_project/safe_packed_borrows.rs | 21 + tests/ui/pin_project/safe_packed_borrows.stderr | 24 + tests/ui/pin_project/unpin_sneaky.rs | 11 + tests/ui/pin_project/unpin_sneaky.stderr | 11 + tests/ui/pin_project/visibility.rs | 52 ++ tests/ui/pin_project/visibility.stderr | 39 + tests/ui/pinned_drop/call-drop-inner.rs | 16 + tests/ui/pinned_drop/call-drop-inner.stderr | 10 + tests/ui/pinned_drop/conditional-drop-impl.rs | 26 + tests/ui/pinned_drop/conditional-drop-impl.stderr | 26 + tests/ui/pinned_drop/forget-pinned-drop-impl.rs | 9 + .../ui/pinned_drop/forget-pinned-drop-impl.stderr | 7 + tests/ui/pinned_drop/invalid-self.rs | 14 + tests/ui/pinned_drop/invalid-self.stderr | 25 + tests/ui/pinned_drop/invalid.rs | 207 ++++++ tests/ui/pinned_drop/invalid.stderr | 125 ++++ tests/ui/pinned_drop/pinned-drop-no-attr-arg.rs | 15 + .../ui/pinned_drop/pinned-drop-no-attr-arg.stderr | 8 + tests/ui/pinned_drop/self.rs | 28 + tests/ui/pinned_drop/self.stderr | 23 + tests/ui/pinned_drop/unsafe-call.rs | 17 + tests/ui/pinned_drop/unsafe-call.stderr | 7 + tests/ui/project/ambiguous-let.rs | 24 + tests/ui/project/ambiguous-let.stderr | 5 + tests/ui/project/invalid.rs | 190 +++++ tests/ui/project/invalid.stderr | 155 ++++ tests/ui/project/type-mismatch.rs | 74 ++ tests/ui/project/type-mismatch.stderr | 16 + tests/ui/project/use-public.rs | 15 + tests/ui/project/use-public.stderr | 7 + tests/ui/project/use.rs | 17 + tests/ui/project/use.stderr | 11 + tests/ui/unsafe_unpin/conflict-unpin.rs | 30 + tests/ui/unsafe_unpin/conflict-unpin.stderr | 35 + .../ui/unsafe_unpin/not-implement-unsafe-unpin.rs | 14 + .../unsafe_unpin/not-implement-unsafe-unpin.stderr | 11 + tests/ui/unsafe_unpin/proper_unpin.rs | 41 ++ tests/ui/unsafe_unpin/proper_unpin.stderr | 63 ++ tests/ui/unstable-features/README.md | 5 + .../marker_trait_attr-feature-gate.rs | 19 + .../marker_trait_attr-feature-gate.stderr | 10 + tests/ui/unstable-features/marker_trait_attr.rs | 25 + .../ui/unstable-features/marker_trait_attr.stderr | 10 + .../overlapping_marker_traits-feature-gate.rs | 19 + .../overlapping_marker_traits-feature-gate.stderr | 10 + .../unstable-features/overlapping_marker_traits.rs | 29 + .../overlapping_marker_traits.stderr | 18 + .../run-pass/stmt_expr_attributes.rs | 62 ++ .../stmt_expr_attributes-feature-gate.rs | 55 ++ .../stmt_expr_attributes-feature-gate.stderr | 35 + tests/ui/unstable-features/trivial_bounds-bug.rs | 33 + .../ui/unstable-features/trivial_bounds-bug.stderr | 10 + .../trivial_bounds-feature-gate.rs | 54 ++ .../trivial_bounds-feature-gate.stderr | 50 ++ tests/ui/unstable-features/trivial_bounds.rs | 34 + tests/ui/unstable-features/trivial_bounds.stderr | 17 + tests/unsafe_unpin.rs | 53 ++ 123 files changed, 5936 insertions(+) create mode 100644 tests/cfg.rs create mode 100644 tests/compiletest.rs create mode 100644 tests/forbid_unsafe.rs create mode 100644 tests/lints.rs create mode 100644 tests/overwriting_core_crate.rs create mode 100644 tests/pin_project.rs create mode 100644 tests/pinned_drop.rs create mode 100644 tests/project.rs create mode 100644 tests/project_if_attr.rs.in create mode 100644 tests/project_ref.rs create mode 100644 tests/project_replace.rs create mode 100644 tests/repr_packed.rs create mode 100644 tests/ui/cfg/cfg_attr-resolve.rs create mode 100644 tests/ui/cfg/cfg_attr-resolve.stderr create mode 100644 tests/ui/cfg/cfg_attr-type-mismatch.rs create mode 100644 tests/ui/cfg/cfg_attr-type-mismatch.stderr create mode 100644 tests/ui/cfg/cfg_attr-unpin.rs create mode 100644 tests/ui/cfg/cfg_attr-unpin.stderr create mode 100644 tests/ui/cfg/packed_sneaky-span-issue-1.rs create mode 100644 tests/ui/cfg/packed_sneaky-span-issue-1.stderr create mode 100644 tests/ui/cfg/packed_sneaky-span-issue-2.rs create mode 100644 tests/ui/cfg/packed_sneaky-span-issue-2.stderr create mode 100644 tests/ui/cfg/packed_sneaky.rs create mode 100644 tests/ui/cfg/packed_sneaky.stderr create mode 100644 tests/ui/cfg/proper_unpin.rs create mode 100644 tests/ui/cfg/proper_unpin.stderr create mode 100644 tests/ui/cfg/unsupported.rs create mode 100644 tests/ui/cfg/unsupported.stderr create mode 100644 tests/ui/not_unpin/assert-not-unpin.rs create mode 100644 tests/ui/not_unpin/assert-not-unpin.stderr create mode 100644 tests/ui/not_unpin/conflict-unpin.rs create mode 100644 tests/ui/not_unpin/conflict-unpin.stderr create mode 100644 tests/ui/not_unpin/impl-unsafe-unpin.rs create mode 100644 tests/ui/not_unpin/impl-unsafe-unpin.stderr create mode 100644 tests/ui/pin_project/add-pin-attr-to-struct.rs create mode 100644 tests/ui/pin_project/add-pin-attr-to-struct.stderr create mode 100644 tests/ui/pin_project/add-pinned-field.rs create mode 100644 tests/ui/pin_project/add-pinned-field.stderr create mode 100644 tests/ui/pin_project/conflict-drop.rs create mode 100644 tests/ui/pin_project/conflict-drop.stderr create mode 100644 tests/ui/pin_project/conflict-unpin.rs create mode 100644 tests/ui/pin_project/conflict-unpin.stderr create mode 100644 tests/ui/pin_project/impl-unsafe-unpin.rs create mode 100644 tests/ui/pin_project/impl-unsafe-unpin.stderr create mode 100644 tests/ui/pin_project/invalid.rs create mode 100644 tests/ui/pin_project/invalid.stderr create mode 100644 tests/ui/pin_project/overlapping_unpin_struct.rs create mode 100644 tests/ui/pin_project/overlapping_unpin_struct.stderr create mode 100644 tests/ui/pin_project/packed-enum.rs create mode 100644 tests/ui/pin_project/packed-enum.stderr create mode 100644 tests/ui/pin_project/packed-name-value.rs create mode 100644 tests/ui/pin_project/packed-name-value.stderr create mode 100644 tests/ui/pin_project/packed.rs create mode 100644 tests/ui/pin_project/packed.stderr create mode 100644 tests/ui/pin_project/packed_sneaky-1.rs create mode 100644 tests/ui/pin_project/packed_sneaky-1.stderr create mode 100644 tests/ui/pin_project/packed_sneaky-2.rs create mode 100644 tests/ui/pin_project/packed_sneaky-2.stderr create mode 100644 tests/ui/pin_project/private_in_public-enum.rs create mode 100644 tests/ui/pin_project/private_in_public-enum.stderr create mode 100644 tests/ui/pin_project/proper_unpin.rs create mode 100644 tests/ui/pin_project/proper_unpin.stderr create mode 100644 tests/ui/pin_project/remove-attr-from-field.rs create mode 100644 tests/ui/pin_project/remove-attr-from-field.stderr create mode 100644 tests/ui/pin_project/remove-attr-from-struct.rs create mode 100644 tests/ui/pin_project/remove-attr-from-struct.stderr create mode 100644 tests/ui/pin_project/safe_packed_borrows.rs create mode 100644 tests/ui/pin_project/safe_packed_borrows.stderr create mode 100644 tests/ui/pin_project/unpin_sneaky.rs create mode 100644 tests/ui/pin_project/unpin_sneaky.stderr create mode 100644 tests/ui/pin_project/visibility.rs create mode 100644 tests/ui/pin_project/visibility.stderr create mode 100644 tests/ui/pinned_drop/call-drop-inner.rs create mode 100644 tests/ui/pinned_drop/call-drop-inner.stderr create mode 100644 tests/ui/pinned_drop/conditional-drop-impl.rs create mode 100644 tests/ui/pinned_drop/conditional-drop-impl.stderr create mode 100644 tests/ui/pinned_drop/forget-pinned-drop-impl.rs create mode 100644 tests/ui/pinned_drop/forget-pinned-drop-impl.stderr create mode 100644 tests/ui/pinned_drop/invalid-self.rs create mode 100644 tests/ui/pinned_drop/invalid-self.stderr create mode 100644 tests/ui/pinned_drop/invalid.rs create mode 100644 tests/ui/pinned_drop/invalid.stderr create mode 100644 tests/ui/pinned_drop/pinned-drop-no-attr-arg.rs create mode 100644 tests/ui/pinned_drop/pinned-drop-no-attr-arg.stderr create mode 100644 tests/ui/pinned_drop/self.rs create mode 100644 tests/ui/pinned_drop/self.stderr create mode 100644 tests/ui/pinned_drop/unsafe-call.rs create mode 100644 tests/ui/pinned_drop/unsafe-call.stderr create mode 100644 tests/ui/project/ambiguous-let.rs create mode 100644 tests/ui/project/ambiguous-let.stderr create mode 100644 tests/ui/project/invalid.rs create mode 100644 tests/ui/project/invalid.stderr create mode 100644 tests/ui/project/type-mismatch.rs create mode 100644 tests/ui/project/type-mismatch.stderr create mode 100644 tests/ui/project/use-public.rs create mode 100644 tests/ui/project/use-public.stderr create mode 100644 tests/ui/project/use.rs create mode 100644 tests/ui/project/use.stderr create mode 100644 tests/ui/unsafe_unpin/conflict-unpin.rs create mode 100644 tests/ui/unsafe_unpin/conflict-unpin.stderr create mode 100644 tests/ui/unsafe_unpin/not-implement-unsafe-unpin.rs create mode 100644 tests/ui/unsafe_unpin/not-implement-unsafe-unpin.stderr create mode 100644 tests/ui/unsafe_unpin/proper_unpin.rs create mode 100644 tests/ui/unsafe_unpin/proper_unpin.stderr create mode 100644 tests/ui/unstable-features/README.md create mode 100644 tests/ui/unstable-features/marker_trait_attr-feature-gate.rs create mode 100644 tests/ui/unstable-features/marker_trait_attr-feature-gate.stderr create mode 100644 tests/ui/unstable-features/marker_trait_attr.rs create mode 100644 tests/ui/unstable-features/marker_trait_attr.stderr create mode 100644 tests/ui/unstable-features/overlapping_marker_traits-feature-gate.rs create mode 100644 tests/ui/unstable-features/overlapping_marker_traits-feature-gate.stderr create mode 100644 tests/ui/unstable-features/overlapping_marker_traits.rs create mode 100644 tests/ui/unstable-features/overlapping_marker_traits.stderr create mode 100644 tests/ui/unstable-features/run-pass/stmt_expr_attributes.rs create mode 100644 tests/ui/unstable-features/stmt_expr_attributes-feature-gate.rs create mode 100644 tests/ui/unstable-features/stmt_expr_attributes-feature-gate.stderr create mode 100644 tests/ui/unstable-features/trivial_bounds-bug.rs create mode 100644 tests/ui/unstable-features/trivial_bounds-bug.stderr create mode 100644 tests/ui/unstable-features/trivial_bounds-feature-gate.rs create mode 100644 tests/ui/unstable-features/trivial_bounds-feature-gate.stderr create mode 100644 tests/ui/unstable-features/trivial_bounds.rs create mode 100644 tests/ui/unstable-features/trivial_bounds.stderr create mode 100644 tests/unsafe_unpin.rs (limited to 'tests') diff --git a/tests/cfg.rs b/tests/cfg.rs new file mode 100644 index 0000000..20b8472 --- /dev/null +++ b/tests/cfg.rs @@ -0,0 +1,242 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] +#![allow(dead_code)] + +// Refs: https://doc.rust-lang.org/nightly/reference/attributes.html + +use pin_project::pin_project; +use std::{marker::PhantomPinned, pin::Pin}; + +fn is_unpin() {} + +#[cfg(target_os = "linux")] +struct Linux; +#[cfg(not(target_os = "linux"))] +struct Other; + +// Use this type to check that `cfg(any())` is working properly. +// If `cfg(any())` is not working properly, `is_unpin` will fail. +struct Any(PhantomPinned); + +#[test] +fn cfg() { + // structs + + #[pin_project(Replace)] + struct SameName { + #[cfg(target_os = "linux")] + #[pin] + inner: Linux, + #[cfg(not(target_os = "linux"))] + #[pin] + inner: Other, + #[cfg(any())] + #[pin] + any: Any, + } + + is_unpin::(); + + #[cfg(target_os = "linux")] + let _x = SameName { inner: Linux }; + #[cfg(not(target_os = "linux"))] + let _x = SameName { inner: Other }; + + #[pin_project(Replace)] + struct DifferentName { + #[cfg(target_os = "linux")] + #[pin] + l: Linux, + #[cfg(not(target_os = "linux"))] + #[pin] + o: Other, + #[cfg(any())] + #[pin] + a: Any, + } + + is_unpin::(); + + #[cfg(target_os = "linux")] + let _x = DifferentName { l: Linux }; + #[cfg(not(target_os = "linux"))] + let _x = DifferentName { o: Other }; + + #[pin_project(Replace)] + struct TupleStruct( + #[cfg(target_os = "linux")] + #[pin] + Linux, + #[cfg(not(target_os = "linux"))] + #[pin] + Other, + #[cfg(any())] + #[pin] + Any, + ); + + is_unpin::(); + + #[cfg(target_os = "linux")] + let _x = TupleStruct(Linux); + #[cfg(not(target_os = "linux"))] + let _x = TupleStruct(Other); + + // enums + + #[pin_project(Replace)] + enum Variant { + #[cfg(target_os = "linux")] + Inner(#[pin] Linux), + #[cfg(not(target_os = "linux"))] + Inner(#[pin] Other), + + #[cfg(target_os = "linux")] + Linux(#[pin] Linux), + #[cfg(not(target_os = "linux"))] + Other(#[pin] Other), + #[cfg(any())] + Any(#[pin] Any), + } + + is_unpin::(); + + #[cfg(target_os = "linux")] + let _x = Variant::Inner(Linux); + #[cfg(not(target_os = "linux"))] + let _x = Variant::Inner(Other); + + #[cfg(target_os = "linux")] + let _x = Variant::Linux(Linux); + #[cfg(not(target_os = "linux"))] + let _x = Variant::Other(Other); + + #[pin_project(Replace)] + enum Field { + SameName { + #[cfg(target_os = "linux")] + #[pin] + inner: Linux, + #[cfg(not(target_os = "linux"))] + #[pin] + inner: Other, + #[cfg(any())] + #[pin] + any: Any, + }, + DifferentName { + #[cfg(target_os = "linux")] + #[pin] + l: Linux, + #[cfg(not(target_os = "linux"))] + #[pin] + w: Other, + #[cfg(any())] + #[pin] + any: Any, + }, + TupleVariant( + #[cfg(target_os = "linux")] + #[pin] + Linux, + #[cfg(not(target_os = "linux"))] + #[pin] + Other, + #[cfg(any())] + #[pin] + Any, + ), + } + + is_unpin::(); + + #[cfg(target_os = "linux")] + let _x = Field::SameName { inner: Linux }; + #[cfg(not(target_os = "linux"))] + let _x = Field::SameName { inner: Other }; + + #[cfg(target_os = "linux")] + let _x = Field::DifferentName { l: Linux }; + #[cfg(not(target_os = "linux"))] + let _x = Field::DifferentName { w: Other }; + + #[cfg(target_os = "linux")] + let _x = Field::TupleVariant(Linux); + #[cfg(not(target_os = "linux"))] + let _x = Field::TupleVariant(Other); +} + +#[test] +fn cfg_attr() { + #[pin_project(Replace)] + struct SameCfg { + #[cfg(target_os = "linux")] + #[cfg_attr(target_os = "linux", pin)] + inner: Linux, + #[cfg(not(target_os = "linux"))] + #[cfg_attr(not(target_os = "linux"), pin)] + inner: Other, + #[cfg(any())] + #[cfg_attr(any(), pin)] + any: Any, + } + + is_unpin::(); + + #[cfg(target_os = "linux")] + let mut x = SameCfg { inner: Linux }; + #[cfg(not(target_os = "linux"))] + let mut x = SameCfg { inner: Other }; + + let x = Pin::new(&mut x).project(); + #[cfg(target_os = "linux")] + let _: Pin<&mut Linux> = x.inner; + #[cfg(not(target_os = "linux"))] + let _: Pin<&mut Other> = x.inner; + + #[pin_project(Replace)] + struct DifferentCfg { + #[cfg(target_os = "linux")] + #[cfg_attr(target_os = "linux", pin)] + inner: Linux, + #[cfg(not(target_os = "linux"))] + #[cfg_attr(target_os = "linux", pin)] + inner: Other, + #[cfg(any())] + #[cfg_attr(any(), pin)] + any: Any, + } + + is_unpin::(); + + #[cfg(target_os = "linux")] + let mut x = DifferentCfg { inner: Linux }; + #[cfg(not(target_os = "linux"))] + let mut x = DifferentCfg { inner: Other }; + + let x = Pin::new(&mut x).project(); + #[cfg(target_os = "linux")] + let _: Pin<&mut Linux> = x.inner; + #[cfg(not(target_os = "linux"))] + let _: &mut Other = x.inner; + + #[cfg_attr(not(any()), pin_project)] + struct Foo { + #[cfg_attr(not(any()), pin)] + inner: T, + } + + let mut x = Foo { inner: 0_u8 }; + let x = Pin::new(&mut x).project(); + let _: Pin<&mut u8> = x.inner; +} + +#[test] +fn cfg_attr_any_packed() { + // Since `cfg(any())` can never be true, it is okay for this to pass. + #[pin_project(Replace)] + #[cfg_attr(any(), repr(packed))] + struct Struct { + #[pin] + field: u32, + } +} diff --git a/tests/compiletest.rs b/tests/compiletest.rs new file mode 100644 index 0000000..078abaa --- /dev/null +++ b/tests/compiletest.rs @@ -0,0 +1,15 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] + +#[ignore] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/cfg/*.rs"); + t.compile_fail("tests/ui/not_unpin/*.rs"); + t.compile_fail("tests/ui/pin_project/*.rs"); + t.compile_fail("tests/ui/pinned_drop/*.rs"); + t.compile_fail("tests/ui/project/*.rs"); + t.compile_fail("tests/ui/unsafe_unpin/*.rs"); + t.compile_fail("tests/ui/unstable-features/*.rs"); + t.pass("tests/ui/unstable-features/run-pass/*.rs"); +} diff --git a/tests/forbid_unsafe.rs b/tests/forbid_unsafe.rs new file mode 100644 index 0000000..4b2e248 --- /dev/null +++ b/tests/forbid_unsafe.rs @@ -0,0 +1,108 @@ +#![forbid(unsafe_code)] +#![warn(rust_2018_idioms, single_use_lifetimes)] +#![allow(dead_code)] + +// default #[pin_project], PinnedDrop, Replace, and !Unpin are completely safe. + +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +#[pin_project] +pub struct StructDefault { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pin_project(PinnedDrop)] +pub struct StructPinnedDrop { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pinned_drop] +impl PinnedDrop for StructPinnedDrop { + fn drop(self: Pin<&mut Self>) {} +} + +#[pin_project(Replace)] +pub struct StructReplace { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +// UnsafeUnpin without UnsafeUnpin impl is also safe +#[pin_project(UnsafeUnpin)] +pub struct StructUnsafeUnpin { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pin_project(!Unpin)] +pub struct StructNotUnpin { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pin_project] +pub enum EnumDefault { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[pin_project(PinnedDrop)] +pub enum EnumPinnedDrop { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[pinned_drop] +impl PinnedDrop for EnumPinnedDrop { + fn drop(self: Pin<&mut Self>) {} +} + +#[pin_project(Replace)] +pub enum EnumReplace { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +// UnsafeUnpin without UnsafeUnpin impl is also safe +#[pin_project(UnsafeUnpin)] +pub enum EnumUnsafeUnpin { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[pin_project(!Unpin)] +pub enum EnumNotUnpin { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[test] +fn test() {} diff --git a/tests/lints.rs b/tests/lints.rs new file mode 100644 index 0000000..4009f55 --- /dev/null +++ b/tests/lints.rs @@ -0,0 +1,126 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] +#![warn(unused, future_incompatible)] +#![warn(clippy::all, clippy::pedantic, clippy::nursery)] + +use pin_project::{pin_project, pinned_drop, UnsafeUnpin}; +use std::pin::Pin; + +#[pin_project] +pub struct StructDefault { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pin_project(PinnedDrop)] +pub struct StructPinnedDrop { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pinned_drop] +impl PinnedDrop for StructPinnedDrop { + fn drop(self: Pin<&mut Self>) {} +} + +#[pin_project(Replace)] +pub struct StructReplace { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pin_project(UnsafeUnpin)] +pub struct StructUnsafeUnpin { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +unsafe impl UnsafeUnpin for StructUnsafeUnpin {} + +#[pin_project(!Unpin)] +pub struct StructNotUnpin { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pin_project] +pub struct StructMutMut<'a, T, U> { + #[pin] + pub pinned: &'a mut T, + pub unpinned: &'a mut U, +} + +#[pin_project] +pub enum EnumDefault { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[pin_project(PinnedDrop)] +pub enum EnumPinnedDrop { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[pinned_drop] +impl PinnedDrop for EnumPinnedDrop { + fn drop(self: Pin<&mut Self>) {} +} + +#[pin_project(Replace)] +pub enum EnumReplace { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[pin_project(UnsafeUnpin)] +pub enum EnumUnsafeUnpin { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +unsafe impl UnsafeUnpin for EnumUnsafeUnpin {} + +#[pin_project(!Unpin)] +pub enum EnumNotUnpin { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[pin_project] +pub enum EnumMutMut<'a, T, U> { + Struct { + #[pin] + pinned: &'a mut T, + unpinned: &'a mut U, + }, + Tuple(#[pin] T, U), +} + +#[allow(clippy::missing_const_for_fn)] +#[test] +fn test() {} diff --git a/tests/overwriting_core_crate.rs b/tests/overwriting_core_crate.rs new file mode 100644 index 0000000..121104c --- /dev/null +++ b/tests/overwriting_core_crate.rs @@ -0,0 +1,116 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] + +// See https://github.com/rust-lang/pin-utils/pull/26#discussion_r344491597 +// +// Note: If the proc-macro does not depend on its own items, it may be preferable not to +// support overwriting the name of core/std crate for compatibility with reexport. +#[allow(unused_extern_crates)] +extern crate pin_project as core; + +// Dummy module to check that the expansion refers to the crate. +mod pin_project {} + +use ::pin_project::{pin_project, pinned_drop, UnsafeUnpin}; +use std::pin::Pin; + +#[pin_project] +pub struct StructDefault { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pin_project(PinnedDrop)] +pub struct StructPinnedDrop { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pinned_drop] +impl PinnedDrop for StructPinnedDrop { + fn drop(self: Pin<&mut Self>) {} +} + +#[pin_project(Replace)] +pub struct StructReplace { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pin_project(UnsafeUnpin)] +pub struct StructUnsafeUnpin { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +unsafe impl UnsafeUnpin for StructUnsafeUnpin {} + +#[pin_project(!Unpin)] +pub struct StructNotUnpin { + #[pin] + pub pinned: T, + pub unpinned: U, +} + +#[pin_project] +pub enum EnumDefault { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[pin_project(PinnedDrop)] +pub enum EnumPinnedDrop { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[pinned_drop] +impl PinnedDrop for EnumPinnedDrop { + fn drop(self: Pin<&mut Self>) {} +} + +#[pin_project(Replace)] +pub enum EnumReplace { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[pin_project(UnsafeUnpin)] +pub enum EnumUnsafeUnpin { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +unsafe impl UnsafeUnpin for EnumUnsafeUnpin {} + +#[pin_project(!Unpin)] +pub enum EnumNotUnpin { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Tuple(#[pin] T, U), +} + +#[test] +fn test() {} diff --git a/tests/pin_project.rs b/tests/pin_project.rs new file mode 100644 index 0000000..c84ca4b --- /dev/null +++ b/tests/pin_project.rs @@ -0,0 +1,809 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] +#![allow(dead_code)] + +use core::{ + marker::{PhantomData, PhantomPinned}, + pin::Pin, +}; +use pin_project::{pin_project, pinned_drop, UnsafeUnpin}; + +#[test] +fn projection() { + #[pin_project(Replace)] + struct Struct { + #[pin] + field1: T, + field2: U, + } + + let mut s = Struct { field1: 1, field2: 2 }; + let mut s_orig = Pin::new(&mut s); + let s = s_orig.as_mut().project(); + + let x: Pin<&mut i32> = s.field1; + assert_eq!(*x, 1); + + let y: &mut i32 = s.field2; + assert_eq!(*y, 2); + + assert_eq!(s_orig.as_ref().field1, 1); + assert_eq!(s_orig.as_ref().field2, 2); + + let mut s = Struct { field1: 1, field2: 2 }; + + let __StructProjection { 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 _: Pin<&i32> = field1; + let _: &i32 = field2; + + let mut s = Pin::new(&mut s); + let __StructProjectionOwned { field1, field2 } = + s.as_mut().project_replace(Struct { field1: 3, field2: 4 }); + let _: PhantomData = field1; + let _: i32 = field2; + assert_eq!(field2, 2); + assert_eq!(s.field1, 3); + assert_eq!(s.field2, 4); + + #[pin_project(Replace)] + struct TupleStruct(#[pin] T, U); + + let mut s = TupleStruct(1, 2); + let s = Pin::new(&mut s).project(); + + let x: Pin<&mut i32> = s.0; + assert_eq!(*x, 1); + + let y: &mut i32 = s.1; + assert_eq!(*y, 2); + + #[pin_project(Replace)] + #[derive(Eq, PartialEq, Debug)] + enum Enum { + Variant1(#[pin] A, B), + Variant2 { + #[pin] + field1: C, + field2: D, + }, + None, + } + + let mut e = Enum::Variant1(1, 2); + let mut e_orig = Pin::new(&mut e); + let e = e_orig.as_mut().project(); + + match e { + __EnumProjection::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 } => { + let _x: Pin<&mut i32> = field1; + let _y: &mut i32 = field2; + } + __EnumProjection::None => {} + } + + assert_eq!(Pin::into_ref(e_orig).get_ref(), &Enum::Variant1(1, 2)); + + let mut e = Enum::Variant2 { field1: 3, field2: 4 }; + let mut e = Pin::new(&mut e).project(); + + match &mut e { + __EnumProjection::Variant1(x, y) => { + let _x: &mut Pin<&mut i32> = x; + let _y: &mut &mut i32 = y; + } + __EnumProjection::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 => {} + } + + if let __EnumProjection::Variant2 { field1, field2 } = e { + let x: Pin<&mut i32> = field1; + assert_eq!(*x, 3); + + let y: &mut i32 = field2; + assert_eq!(*y, 4); + } +} + +#[test] +fn enum_project_set() { + #[pin_project(Replace)] + #[derive(Eq, PartialEq, Debug)] + enum Enum { + Variant1(#[pin] u8), + Variant2(bool), + } + + let mut e = Enum::Variant1(25); + let mut e_orig = Pin::new(&mut e); + let e_proj = e_orig.as_mut().project(); + + match e_proj { + __EnumProjection::Variant1(val) => { + let new_e = Enum::Variant2(val.as_ref().get_ref() == &25); + e_orig.set(new_e); + } + _ => unreachable!(), + } + + assert_eq!(e, Enum::Variant2(true)); +} + +#[test] +fn where_clause() { + #[pin_project] + struct Struct + where + T: Copy, + { + field: T, + } + + #[pin_project] + struct TupleStruct(T) + where + T: Copy; + + #[pin_project] + enum EnumWhere + where + T: Copy, + { + Variant(T), + } +} + +#[test] +fn where_clause_and_associated_type_field() { + #[pin_project(Replace)] + struct Struct1 + where + I: Iterator, + { + #[pin] + field1: I, + field2: I::Item, + } + + #[pin_project(Replace)] + struct Struct2 + where + I: Iterator, + { + #[pin] + field1: I, + field2: J, + } + + #[pin_project(Replace)] + struct Struct3 + where + T: 'static, + { + field: T, + } + + trait Static: 'static {} + + impl Static for Struct3 {} + + #[pin_project(Replace)] + struct TupleStruct(#[pin] I, I::Item) + where + I: Iterator; + + #[pin_project(Replace)] + enum Enum + where + I: Iterator, + { + Variant1(#[pin] I), + Variant2(I::Item), + } +} + +#[test] +fn derive_copy() { + #[pin_project(Replace)] + #[derive(Clone, Copy)] + struct Struct { + val: T, + } + + fn is_copy() {} + + is_copy::>(); +} + +#[test] +fn move_out() { + struct NotCopy; + + #[pin_project(Replace)] + struct Struct { + val: NotCopy, + } + + let x = Struct { val: NotCopy }; + let _val: NotCopy = x.val; + + #[pin_project(Replace)] + enum Enum { + Variant(NotCopy), + } + + let x = Enum::Variant(NotCopy); + #[allow(clippy::infallible_destructuring_match)] + let _val: NotCopy = match x { + Enum::Variant(val) => val, + }; +} + +#[test] +fn trait_bounds_on_type_generics() { + #[pin_project(Replace)] + pub struct Struct1<'a, T: ?Sized> { + field: &'a mut T, + } + + #[pin_project(Replace)] + pub struct Struct2<'a, T: ::core::fmt::Debug> { + field: &'a mut T, + } + + #[pin_project(Replace)] + pub struct Struct3<'a, T: core::fmt::Debug> { + field: &'a mut T, + } + + #[pin_project(Replace)] + pub struct Struct4<'a, T: core::fmt::Debug + core::fmt::Display> { + field: &'a mut T, + } + + #[pin_project(Replace)] + pub struct Struct5<'a, T: core::fmt::Debug + ?Sized> { + field: &'a mut T, + } + + #[pin_project(Replace)] + pub struct Struct6<'a, T: core::fmt::Debug = [u8; 16]> { + field: &'a mut T, + } + + let _: Struct6<'_> = Struct6 { field: &mut [0u8; 16] }; + + #[pin_project(Replace)] + pub struct Struct7 { + field: T, + } + + trait Static: 'static {} + + impl Static for Struct7 {} + + #[pin_project(Replace)] + pub struct Struct8<'a, 'b: 'a> { + field1: &'a u8, + field2: &'b u8, + } + + #[pin_project(Replace)] + pub struct TupleStruct<'a, T: ?Sized>(&'a mut T); + + #[pin_project(Replace)] + enum Enum<'a, T: ?Sized> { + Variant(&'a mut T), + } +} + +#[test] +fn overlapping_lifetime_names() { + #[pin_project(Replace)] + pub struct Struct1<'pin, T> { + #[pin] + field: &'pin mut T, + } + + #[pin_project(Replace)] + pub struct Struct2<'pin, 'pin_, 'pin__> { + #[pin] + field: &'pin &'pin_ &'pin__ (), + } + + pub trait A<'a> {} + + #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + #[pin_project(Replace)] + pub struct HRTB<'pin___, T> + where + for<'pin> &'pin T: Unpin, + T: for<'pin> A<'pin>, + for<'pin, 'pin_, 'pin__> &'pin &'pin_ &'pin__ T: Unpin, + { + #[pin] + field: &'pin___ mut T, + } +} + +#[test] +fn combine() { + #[pin_project(PinnedDrop, UnsafeUnpin)] + pub struct Struct1 { + #[pin] + field: T, + } + + #[pinned_drop] + impl PinnedDrop for Struct1 { + fn drop(self: Pin<&mut Self>) {} + } + + unsafe impl UnsafeUnpin for Struct1 {} + + #[pin_project(UnsafeUnpin, Replace)] + pub struct Struct2 { + #[pin] + field: T, + } + + unsafe impl UnsafeUnpin for Struct2 {} + + #[pin_project(PinnedDrop, !Unpin)] + pub struct Struct3 { + #[pin] + field: T, + } + + #[pinned_drop] + impl PinnedDrop for Struct3 { + fn drop(self: Pin<&mut Self>) {} + } + + #[pin_project(!Unpin, Replace)] + pub struct Struct4 { + #[pin] + field: T, + } +} + +#[test] +fn private_type_in_public_type() { + #[pin_project(Replace)] + pub struct PublicStruct { + #[pin] + inner: PrivateStruct, + } + + struct PrivateStruct(T); +} + +#[test] +fn lifetime_project() { + #[pin_project(Replace)] + struct Struct1 { + #[pin] + pinned: T, + unpinned: U, + } + + #[pin_project(Replace)] + struct Struct2<'a, T, U> { + #[pin] + pinned: &'a mut T, + unpinned: U, + } + + #[pin_project(Replace)] + enum Enum { + Variant { + #[pin] + pinned: T, + unpinned: U, + }, + } + + impl Struct1 { + fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> { + self.project_ref().pinned + } + fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> { + self.project().pinned + } + } + + impl<'b, T, U> Struct2<'b, T, U> { + fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a &'b mut T> { + self.project_ref().pinned + } + fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut &'b mut T> { + self.project().pinned + } + } + + impl Enum { + fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> { + match self.project_ref() { + __EnumProjectionRef::Variant { pinned, .. } => pinned, + } + } + fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> { + match self.project() { + __EnumProjection::Variant { pinned, .. } => pinned, + } + } + } +} + +#[rustversion::since(1.36)] // https://github.com/rust-lang/rust/pull/61207 +#[test] +fn lifetime_project_elided() { + #[pin_project(Replace)] + struct Struct1 { + #[pin] + pinned: T, + unpinned: U, + } + + #[pin_project(Replace)] + struct Struct2<'a, T, U> { + #[pin] + pinned: &'a mut T, + unpinned: U, + } + + #[pin_project(Replace)] + enum Enum { + Variant { + #[pin] + pinned: T, + unpinned: U, + }, + } + + impl Struct1 { + fn get_pin_ref(self: Pin<&Self>) -> Pin<&T> { + self.project_ref().pinned + } + fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { + self.project().pinned + } + } + + impl<'b, T, U> Struct2<'b, T, U> { + fn get_pin_ref(self: Pin<&Self>) -> Pin<&&'b mut T> { + self.project_ref().pinned + } + fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut &'b mut T> { + self.project().pinned + } + } + + impl Enum { + fn get_pin_ref(self: Pin<&Self>) -> Pin<&T> { + match self.project_ref() { + __EnumProjectionRef::Variant { pinned, .. } => pinned, + } + } + fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { + match self.project() { + __EnumProjection::Variant { pinned, .. } => pinned, + } + } + } +} + +mod visibility { + use pin_project::pin_project; + + #[pin_project(Replace)] + pub(crate) struct A { + pub b: u8, + } +} + +#[test] +fn visibility() { + let mut x = visibility::A { b: 0 }; + let x = Pin::new(&mut x); + let y = x.as_ref().project_ref(); + let _: &u8 = y.b; + let y = x.project(); + let _: &mut u8 = y.b; +} + +#[test] +fn trivial_bounds() { + #[pin_project(Replace)] + pub struct NoGenerics { + #[pin] + field: PhantomPinned, + } +} + +#[test] +fn dst() { + #[pin_project] + struct Struct1 { + x: T, + } + + let mut x = Struct1 { x: 0_u8 }; + let x: Pin<&mut Struct1> = Pin::new(&mut x as _); + let _y: &mut (dyn core::fmt::Debug) = x.project().x; + + #[pin_project] + struct Struct2 { + #[pin] + x: T, + } + + let mut x = Struct2 { x: 0_u8 }; + let x: Pin<&mut Struct2> = Pin::new(&mut x as _); + let _y: Pin<&mut (dyn core::fmt::Debug + Unpin)> = x.project().x; + + #[pin_project(UnsafeUnpin)] + struct Struct5 { + x: T, + } + + #[pin_project(UnsafeUnpin)] + struct Struct6 { + #[pin] + x: T, + } + + #[pin_project(PinnedDrop)] + struct Struct7 { + x: T, + } + + #[pinned_drop] + impl PinnedDrop for Struct7 { + fn drop(self: Pin<&mut Self>) {} + } + + #[pin_project(PinnedDrop)] + struct Struct8 { + #[pin] + x: T, + } + + #[pinned_drop] + impl PinnedDrop for Struct8 { + fn drop(self: Pin<&mut Self>) {} + } + + #[pin_project(!Unpin)] + struct Struct9 { + x: T, + } + + #[pin_project(!Unpin)] + struct Struct10 { + #[pin] + x: T, + } + + #[pin_project] + struct TupleStruct1(T); + + #[pin_project] + struct TupleStruct2(#[pin] T); + + #[pin_project(UnsafeUnpin)] + struct TupleStruct5(T); + + #[pin_project(UnsafeUnpin)] + struct TupleStruct6(#[pin] T); + + #[pin_project(PinnedDrop)] + struct TupleStruct7(T); + + #[pinned_drop] + impl PinnedDrop for TupleStruct7 { + fn drop(self: Pin<&mut Self>) {} + } + + #[pin_project(PinnedDrop)] + struct TupleStruct8(#[pin] T); + + #[pinned_drop] + impl PinnedDrop for TupleStruct8 { + fn drop(self: Pin<&mut Self>) {} + } + + #[pin_project(!Unpin)] + struct TupleStruct9(T); + + #[pin_project(!Unpin)] + struct TupleStruct10(#[pin] T); +} + +#[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993 +#[test] +fn unsized_in_where_clause() { + #[pin_project] + struct Struct3 + where + T: ?Sized, + { + x: T, + } + + #[pin_project] + struct Struct4 + where + T: ?Sized, + { + #[pin] + x: T, + } + + #[pin_project] + struct TupleStruct3(T) + where + T: ?Sized; + + #[pin_project] + struct TupleStruct4(#[pin] T) + where + T: ?Sized; +} + +#[test] +fn dyn_type() { + #[pin_project] + struct Struct1 { + f: dyn core::fmt::Debug, + } + + #[pin_project] + struct Struct2 { + #[pin] + f: dyn core::fmt::Debug, + } + + #[pin_project] + struct Struct3 { + f: dyn core::fmt::Debug + Send, + } + + #[pin_project] + struct Struct4 { + #[pin] + f: dyn core::fmt::Debug + Send, + } + + #[pin_project] + struct TupleStruct1(dyn core::fmt::Debug); + + #[pin_project] + struct TupleStruct2(#[pin] dyn core::fmt::Debug); + + #[pin_project] + struct TupleStruct3(dyn core::fmt::Debug + Send); + + #[pin_project] + struct TupleStruct4(#[pin] dyn core::fmt::Debug + Send); +} + +#[test] +fn self_in_where_clause() { + pub trait Trait1 {} + + #[pin_project(Replace)] + pub struct Struct1 + where + Self: Trait1, + { + x: T, + } + + impl Trait1 for Struct1 {} + + pub trait Trait2 { + type Assoc; + } + + #[pin_project(Replace)] + pub struct Struct2 + where + Self: Trait2>, + ::Assoc: Trait1, + { + x: T, + } + + impl Trait2 for Struct2 { + type Assoc = Struct1; + } +} + +#[test] +fn no_infer_outlives() { + trait Bar { + type Y; + } + + struct Example(A); + + impl Bar for Example { + type Y = Option; + } + + #[pin_project(Replace)] + struct Foo { + _x: as Bar>::Y, + } +} + +// https://github.com/rust-lang/rust/issues/47949 +// https://github.com/taiki-e/pin-project/pull/194#discussion_r419098111 +#[test] +fn project_replace_panic() { + use std::panic; + + #[pin_project(Replace)] + struct S { + #[pin] + pinned: T, + unpinned: U, + } + + struct D<'a>(&'a mut bool, bool); + impl Drop for D<'_> { + fn drop(&mut self) { + *self.0 = true; + if self.1 { + panic!() + } + } + } + + let (mut a, mut b, mut c, mut d) = (false, false, false, false); + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let mut x = S { pinned: D(&mut a, true), unpinned: D(&mut b, false) }; + let _y = Pin::new(&mut x) + .project_replace(S { pinned: D(&mut c, false), unpinned: D(&mut d, false) }); + // Previous `x.pinned` was dropped and panicked when `project_replace` is called, so this is unreachable. + unreachable!(); + })); + assert!(res.is_err()); + assert!(a); + assert!(b); + assert!(c); + assert!(d); + + let (mut a, mut b, mut c, mut d) = (false, false, false, false); + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let mut x = S { pinned: D(&mut a, false), unpinned: D(&mut b, true) }; + { + let _y = Pin::new(&mut x) + .project_replace(S { pinned: D(&mut c, false), unpinned: D(&mut d, false) }); + // `_y` (previous `x.unpinned`) live to the end of this scope, so this is not unreachable, + // unreachable!(); + } + unreachable!(); + })); + assert!(res.is_err()); + assert!(a); + assert!(b); + assert!(c); + assert!(d); +} diff --git a/tests/pinned_drop.rs b/tests/pinned_drop.rs new file mode 100644 index 0000000..b0677e2 --- /dev/null +++ b/tests/pinned_drop.rs @@ -0,0 +1,235 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] +#![allow(dead_code)] + +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +#[test] +fn safe_project() { + #[pin_project(PinnedDrop)] + pub struct Struct<'a> { + was_dropped: &'a mut bool, + #[pin] + field: u8, + } + + #[pinned_drop] + impl PinnedDrop for Struct<'_> { + fn drop(self: Pin<&mut Self>) { + **self.project().was_dropped = true; + } + } + + let mut was_dropped = false; + drop(Struct { was_dropped: &mut was_dropped, field: 42 }); + assert!(was_dropped); +} + +#[test] +fn mut_self_argument() { + #[pin_project(PinnedDrop)] + struct Struct { + data: usize, + } + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(mut self: Pin<&mut Self>) { + let _: &mut _ = &mut self.data; + } + } +} + +#[test] +fn self_in_vec() { + #[pin_project(PinnedDrop)] + struct Struct { + data: usize, + } + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(self: Pin<&mut Self>) { + let _: Vec<_> = vec![self.data]; + } + } +} + +#[test] +fn self_in_macro_containing_fn() { + #[pin_project(PinnedDrop)] + pub struct Struct { + data: usize, + } + + macro_rules! emit { + ($($tt:tt)*) => { + $($tt)* + }; + } + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(self: Pin<&mut Self>) { + let _ = emit!({ + impl Struct { + pub fn f(self) {} + } + }); + let _ = self.data; + } + } +} + +#[test] +fn self_call() { + #[pin_project(PinnedDrop)] + pub struct Struct { + data: usize, + } + + trait Trait { + fn self_ref(&self) {} + fn self_pin_ref(self: Pin<&Self>) {} + fn self_mut(&mut self) {} + fn self_pin_mut(self: Pin<&mut Self>) {} + fn assoc_fn(_this: Pin<&mut Self>) {} + } + + impl Trait for Struct {} + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(mut self: Pin<&mut Self>) { + self.self_ref(); + self.as_ref().self_pin_ref(); + self.self_mut(); + self.as_mut().self_pin_mut(); + Self::assoc_fn(self.as_mut()); + ::assoc_fn(self.as_mut()); + } + } +} + +#[test] +fn self_expr() { + #[pin_project(PinnedDrop)] + pub struct Struct { + x: usize, + } + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(mut self: Pin<&mut Self>) { + let _: Self = Self { x: 0 }; + } + } + + #[pin_project(PinnedDrop)] + pub struct TupleStruct(usize); + + #[pinned_drop] + impl PinnedDrop for TupleStruct { + fn drop(mut self: Pin<&mut Self>) { + let _: Self = Self(0); + } + } +} + +#[rustversion::since(1.37)] +#[test] +fn self_expr_enum() { + #[pin_project(PinnedDrop)] + pub enum Enum { + StructVariant { x: usize }, + TupleVariant(usize), + } + + #[pinned_drop] + impl PinnedDrop for Enum { + fn drop(mut self: Pin<&mut Self>) { + let _: Self = Self::StructVariant { x: 0 }; + let _: Self = Self::TupleVariant(0); + } + } +} + +#[test] +fn self_pat() { + #[pin_project(PinnedDrop)] + pub struct Struct { + x: usize, + } + + #[pinned_drop] + impl PinnedDrop for Struct { + #[allow(irrefutable_let_patterns)] + #[allow(clippy::match_single_binding)] + fn drop(mut self: Pin<&mut Self>) { + match *self { + Self { x: _ } => {} + } + if let Self { x: _ } = *self {} + let Self { x: _ } = *self; + } + } + + #[pin_project(PinnedDrop)] + pub struct TupleStruct(usize); + + #[pinned_drop] + impl PinnedDrop for TupleStruct { + #[allow(irrefutable_let_patterns)] + fn drop(mut self: Pin<&mut Self>) { + match *self { + Self(_) => {} + } + if let Self(_) = *self {} + let Self(_) = *self; + } + } +} + +#[rustversion::since(1.37)] +#[test] +fn self_pat_enum() { + #[pin_project(PinnedDrop)] + pub enum Enum { + StructVariant { x: usize }, + TupleVariant(usize), + } + + #[pinned_drop] + impl PinnedDrop for Enum { + fn drop(mut self: Pin<&mut Self>) { + match *self { + Self::StructVariant { x: _ } => {} + Self::TupleVariant(_) => {} + } + if let Self::StructVariant { x: _ } = *self {} + if let Self::TupleVariant(_) = *self {} + } + } +} + +// See also `ui/pinned_drop/self.rs`. +#[rustversion::since(1.40)] // https://github.com/rust-lang/rust/pull/64690 +#[test] +fn self_in_macro_def() { + #[pin_project(PinnedDrop)] + pub struct Struct { + x: usize, + } + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(self: Pin<&mut Self>) { + macro_rules! t { + () => {{ + let _ = self; + }}; + } + t!(); + } + } +} diff --git a/tests/project.rs b/tests/project.rs new file mode 100644 index 0000000..a0f8b07 --- /dev/null +++ b/tests/project.rs @@ -0,0 +1,297 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] +#![allow(dead_code)] + +// Ceurrently, `#[attr] if true {}` doesn't even *parse* on MSRV, +// which means that it will error even behind a `#[rustversion::since(..)]` +// +// This trick makes sure that we don't even attempt to parse +// the `#[project] if let _` test on MSRV. +#[rustversion::since(1.43)] +include!("project_if_attr.rs.in"); + +use pin_project::{pin_project, project, project_ref, project_replace}; +use std::pin::Pin; + +#[project] // Nightly does not need a dummy attribute to the function. +#[test] +fn project_stmt_expr() { + #[pin_project] + struct Struct { + #[pin] + field1: T, + field2: U, + } + + let mut s = Struct { field1: 1, field2: 2 }; + + #[project] + let Struct { field1, field2 } = Pin::new(&mut s).project(); + + let x: Pin<&mut i32> = field1; + assert_eq!(*x, 1); + + let y: &mut i32 = field2; + assert_eq!(*y, 2); + + #[pin_project] + struct TupleStruct(#[pin] T, U); + + let mut s = TupleStruct(1, 2); + + #[project] + let TupleStruct(x, y) = Pin::new(&mut s).project(); + + let x: Pin<&mut i32> = x; + assert_eq!(*x, 1); + + let y: &mut i32 = y; + assert_eq!(*y, 2); + + #[pin_project] + enum Enum { + Variant1(#[pin] A, B), + Variant2 { + #[pin] + field1: C, + field2: D, + }, + None, + } + + let mut e = Enum::Variant1(1, 2); + + let mut e = Pin::new(&mut e).project(); + + #[project] + match &mut e { + Enum::Variant1(x, y) => { + let x: &mut Pin<&mut i32> = x; + assert_eq!(**x, 1); + + let y: &mut &mut i32 = y; + assert_eq!(**y, 2); + } + Enum::Variant2 { field1, field2 } => { + let _x: &mut Pin<&mut i32> = field1; + let _y: &mut &mut i32 = field2; + } + Enum::None => {} + } + + #[project] + let val = match &mut e { + Enum::Variant1(_, _) => true, + Enum::Variant2 { .. } => false, + Enum::None => false, + }; + assert_eq!(val, true); +} + +#[test] +fn project_impl() { + #[pin_project] + struct HasGenerics { + #[pin] + field1: T, + field2: U, + } + + #[project] + impl HasGenerics { + fn a(self) { + let Self { field1, field2 } = self; + + let _x: Pin<&mut T> = field1; + let _y: &mut U = field2; + } + } + + #[pin_project] + struct NoneGenerics { + #[pin] + field1: i32, + field2: u32, + } + + #[project] + impl NoneGenerics {} + + #[pin_project] + struct HasLifetimes<'a, T, U> { + #[pin] + field1: &'a mut T, + field2: U, + } + + #[project] + impl HasLifetimes<'_, T, U> {} + + #[pin_project] + struct HasOverlappingLifetimes<'pin, T, U> { + #[pin] + field1: &'pin mut T, + field2: U, + } + + #[allow(single_use_lifetimes)] + #[project] + impl<'pin, T, U> HasOverlappingLifetimes<'pin, T, U> {} + + #[pin_project] + struct HasOverlappingLifetimes2 { + #[pin] + field1: T, + field2: U, + } + + #[allow(single_use_lifetimes)] + #[allow(clippy::needless_lifetimes)] + #[project] + impl HasOverlappingLifetimes2 { + fn foo<'pin>(&'pin self) {} + } +} + +#[pin_project] +struct A { + #[pin] + field: u8, +} + +mod project_use_1 { + use crate::A; + use core::pin::Pin; + use pin_project::project; + + #[project] + use crate::A; + + #[project] + #[test] + fn project_use() { + let mut x = A { field: 0 }; + #[project] + let A { field } = Pin::new(&mut x).project(); + let _: Pin<&mut u8> = field; + } +} + +mod project_use_2 { + #[project] + use crate::A; + use pin_project::project; + + #[project] + impl A { + fn project_use(self) {} + } +} + +#[allow(clippy::unnecessary_operation, clippy::unit_arg)] +#[test] +#[project] +fn non_stmt_expr_match() { + #[pin_project] + enum Enum { + Variant(#[pin] A), + } + + let mut x = Enum::Variant(1); + let x = Pin::new(&mut x).project(); + + Some( + #[project] + match x { + Enum::Variant(_x) => {} + }, + ); +} + +// https://github.com/taiki-e/pin-project/issues/206 +#[allow(clippy::unnecessary_operation, clippy::unit_arg)] +#[test] +#[project] +fn issue_206() { + #[pin_project] + enum Enum { + Variant(#[pin] A), + } + + let mut x = Enum::Variant(1); + let x = Pin::new(&mut x).project(); + + Some({ + #[project] + match &x { + Enum::Variant(_) => {} + } + }); + + #[allow(clippy::never_loop)] + loop { + let _ = { + #[project] + match &x { + Enum::Variant(_) => {} + } + }; + break; + } +} + +#[project] +#[test] +fn combine() { + #[pin_project(Replace)] + enum Enum { + V1(#[pin] A), + V2, + } + + let mut x = Enum::V1(1); + #[project] + match Pin::new(&mut x).project() { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } + #[project_ref] + match Pin::new(&x).project_ref() { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } + #[project_replace] + match Pin::new(&mut x).project_replace(Enum::V2) { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } +} + +// FIXME: This should be denied, but allowed for compatibility at this time. +#[project] +#[project_ref] +#[project_replace] +#[test] +fn combine_compat() { + #[pin_project(Replace)] + enum Enum { + V1(#[pin] A), + V2, + } + + let mut x = Enum::V1(1); + #[project] + match Pin::new(&mut x).project() { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } + #[project_ref] + match Pin::new(&x).project_ref() { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } + #[project_replace] + match Pin::new(&mut x).project_replace(Enum::V2) { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } +} diff --git a/tests/project_if_attr.rs.in b/tests/project_if_attr.rs.in new file mode 100644 index 0000000..a8ceeac --- /dev/null +++ b/tests/project_if_attr.rs.in @@ -0,0 +1,44 @@ +#[test] +#[project] +fn project_if_let() { + #[pin_project] + enum Foo { + Variant1(#[pin] A), + Variant2(u8), + Variant3 { + #[pin] field: B + } + } + + let mut x: Foo = Foo::Variant1(true); + let x = Pin::new(&mut x).project(); + + #[project] + if let Foo::Variant1(a) = x { + let a: Pin<&mut bool> = a; + assert_eq!(*a, true); + } else if let Foo::Variant2(_) = x { + unreachable!(); + } else if let Foo::Variant3 { .. } = x { + unreachable!(); + } +} + +#[allow(clippy::unnecessary_operation, clippy::unit_arg)] +#[test] +#[project] +fn non_stmt_expr_if_let() { + #[pin_project] + enum Enum { + Variant(#[pin] A), + } + + let mut x = Enum::Variant(1); + let x = Pin::new(&mut x).project(); + + #[allow(irrefutable_let_patterns)] + Some( + #[project] + if let Enum::Variant(_x) = x {}, + ); +} diff --git a/tests/project_ref.rs b/tests/project_ref.rs new file mode 100644 index 0000000..e38ef83 --- /dev/null +++ b/tests/project_ref.rs @@ -0,0 +1,174 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] +#![allow(dead_code)] + +use pin_project::{pin_project, project_ref}; +use std::pin::Pin; + +#[project_ref] // Nightly does not need a dummy attribute to the function. +#[test] +fn project_stmt_expr() { + #[pin_project] + struct Struct { + #[pin] + field1: T, + field2: U, + } + + let s = Struct { field1: 1, field2: 2 }; + + #[project_ref] + let Struct { field1, field2 } = Pin::new(&s).project_ref(); + + let x: Pin<&i32> = field1; + assert_eq!(*x, 1); + + let y: &i32 = field2; + assert_eq!(*y, 2); + + // tuple struct + + #[pin_project] + struct TupleStruct(#[pin] T, U); + + let s = TupleStruct(1, 2); + + #[project_ref] + let TupleStruct(x, y) = Pin::new(&s).project_ref(); + + let x: Pin<&i32> = x; + assert_eq!(*x, 1); + + let y: &i32 = y; + assert_eq!(*y, 2); + + #[pin_project] + enum Enum { + Variant1(#[pin] A, B), + Variant2 { + #[pin] + field1: C, + field2: D, + }, + None, + } + + let e = Enum::Variant1(1, 2); + + let e = Pin::new(&e).project_ref(); + + #[project_ref] + match &e { + Enum::Variant1(x, y) => { + let x: &Pin<&i32> = x; + assert_eq!(**x, 1); + + let y: &&i32 = y; + assert_eq!(**y, 2); + } + Enum::Variant2 { field1, field2 } => { + let _x: &Pin<&i32> = field1; + let _y: &&i32 = field2; + } + Enum::None => {} + } + + #[project_ref] + let val = match &e { + Enum::Variant1(_, _) => true, + Enum::Variant2 { .. } => false, + Enum::None => false, + }; + assert_eq!(val, true); +} + +#[test] +fn project_impl() { + #[pin_project] + struct HasGenerics { + #[pin] + field1: T, + field2: U, + } + + #[project_ref] + impl HasGenerics { + fn a(self) { + let Self { field1, field2 } = self; + + let _x: Pin<&T> = field1; + let _y: &U = field2; + } + } + + #[pin_project] + struct NoneGenerics { + #[pin] + field1: i32, + field2: u32, + } + + #[project_ref] + impl NoneGenerics {} + + #[pin_project] + struct HasLifetimes<'a, T, U> { + #[pin] + field1: &'a mut T, + field2: U, + } + + #[project_ref] + impl HasLifetimes<'_, T, U> {} + + #[pin_project] + struct HasOverlappingLifetimes<'pin, T, U> { + #[pin] + field1: &'pin mut T, + field2: U, + } + + #[allow(single_use_lifetimes)] + #[project_ref] + impl<'pin, T, U> HasOverlappingLifetimes<'pin, T, U> {} + + #[pin_project] + struct HasOverlappingLifetimes2 { + #[pin] + field1: T, + field2: U, + } + + #[allow(single_use_lifetimes)] + #[allow(clippy::needless_lifetimes)] + #[project_ref] + impl HasOverlappingLifetimes2 { + fn foo<'pin>(&'pin self) {} + } +} + +#[project_ref] +#[test] +fn combine() { + #[pin_project(Replace)] + enum Enum { + V1(#[pin] A), + V2, + } + + let mut x = Enum::V1(1); + #[project] + match Pin::new(&mut x).project() { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } + #[project_ref] + match Pin::new(&x).project_ref() { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } + #[project_replace] + match Pin::new(&mut x).project_replace(Enum::V2) { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } +} diff --git a/tests/project_replace.rs b/tests/project_replace.rs new file mode 100644 index 0000000..9c8a5ab --- /dev/null +++ b/tests/project_replace.rs @@ -0,0 +1,98 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] +#![allow(dead_code)] + +use pin_project::{pin_project, project_replace}; +use std::{marker::PhantomData, pin::Pin}; + +#[project_replace] // Nightly does not need a dummy attribute to the function. +#[test] +fn project_replace_stmt_expr() { + #[pin_project(Replace)] + struct Struct { + #[pin] + field1: T, + field2: U, + } + + let mut s = Struct { field1: 1, field2: 2 }; + + #[project_replace] + let Struct { field1, field2 } = + Pin::new(&mut s).project_replace(Struct { field1: 42, field2: 43 }); + + let _x: PhantomData = field1; + + let y: i32 = field2; + assert_eq!(y, 2); + + // tuple struct + + #[pin_project(Replace)] + struct TupleStruct(#[pin] T, U); + + let mut s = TupleStruct(1, 2); + + #[project_replace] + let TupleStruct(x, y) = Pin::new(&mut s).project_replace(TupleStruct(42, 43)); + + let _x: PhantomData = x; + let y: i32 = y; + assert_eq!(y, 2); + + #[pin_project(Replace)] + enum Enum { + Variant1(#[pin] A, B), + Variant2 { + #[pin] + field1: C, + field2: D, + }, + None, + } + + let mut e = Enum::Variant1(1, 2); + + let e = Pin::new(&mut e).project_replace(Enum::None); + + #[project_replace] + match e { + Enum::Variant1(x, y) => { + let _x: PhantomData = x; + let y: i32 = y; + assert_eq!(y, 2); + } + Enum::Variant2 { field1, field2 } => { + let _x: PhantomData = field1; + let _y: i32 = field2; + panic!() + } + Enum::None => panic!(), + } +} + +#[project_replace] +#[test] +fn combine() { + #[pin_project(Replace)] + enum Enum { + V1(#[pin] A), + V2, + } + + let mut x = Enum::V1(1); + #[project] + match Pin::new(&mut x).project() { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } + #[project_ref] + match Pin::new(&x).project_ref() { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } + #[project_replace] + match Pin::new(&mut x).project_replace(Enum::V2) { + Enum::V1(_) => {} + Enum::V2 => unreachable!(), + } +} diff --git a/tests/repr_packed.rs b/tests/repr_packed.rs new file mode 100644 index 0000000..ca56959 --- /dev/null +++ b/tests/repr_packed.rs @@ -0,0 +1,50 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] +#![allow(dead_code)] +#![deny(safe_packed_borrows)] + +use std::cell::Cell; + +// Ensure that the compiler doesn't copy the fields +// of #[repr(packed)] types during drop, if the field has alignment 1 +// (that is, any reference to the field is guaranteed to have proper alignment) +// We are currently unable to statically prevent the usage of #[pin_project] +// on #[repr(packed)] types composed entirely of fields of alignment 1. +// This shouldn't lead to undefined behavior, as long as the compiler doesn't +// try to move the field anyway during drop. +// +// This tests validates that the compiler is doing what we expect. +#[test] +fn weird_repr_packed() { + // We keep track of the field address during + // drop using a thread local, to avoid changing + // the layout of our #[repr(packed)] type. + thread_local! { + static FIELD_ADDR: Cell = Cell::new(0); + } + + #[repr(packed)] + struct Foo { + field: u8, + } + + impl Drop for Foo { + fn drop(&mut self) { + FIELD_ADDR.with(|f| { + f.set(&self.field as *const u8 as usize); + }) + } + } + + #[allow(clippy::let_and_return)] + let field_addr = { + // We let this field drop by going out of scope, + // rather than explicitly calling drop(foo). + // Calling drop(foo) causes 'foo' to be moved + // into the 'drop' function, resulting in a different + // address. + let x = Foo { field: 27 }; + let field_addr = &x.field as *const u8 as usize; + field_addr + }; + assert_eq!(field_addr, FIELD_ADDR.with(|f| f.get())); +} diff --git a/tests/ui/cfg/cfg_attr-resolve.rs b/tests/ui/cfg/cfg_attr-resolve.rs new file mode 100644 index 0000000..e16f3e8 --- /dev/null +++ b/tests/ui/cfg/cfg_attr-resolve.rs @@ -0,0 +1,11 @@ +use std::pin::Pin; + +#[cfg_attr(any(), pin_project::pin_project)] +struct Foo { + inner: T, +} + +fn main() { + let mut x = Foo { inner: 0_u8 }; + let _x = Pin::new(&mut x).project(); //~ ERROR E0599 +} diff --git a/tests/ui/cfg/cfg_attr-resolve.stderr b/tests/ui/cfg/cfg_attr-resolve.stderr new file mode 100644 index 0000000..45af3ae --- /dev/null +++ b/tests/ui/cfg/cfg_attr-resolve.stderr @@ -0,0 +1,5 @@ +error[E0599]: no method named `project` found for struct `std::pin::Pin<&mut Foo>` in the current scope + --> $DIR/cfg_attr-resolve.rs:10:31 + | +10 | let _x = Pin::new(&mut x).project(); //~ ERROR E0599 + | ^^^^^^^ method not found in `std::pin::Pin<&mut Foo>` diff --git a/tests/ui/cfg/cfg_attr-type-mismatch.rs b/tests/ui/cfg/cfg_attr-type-mismatch.rs new file mode 100644 index 0000000..2807c87 --- /dev/null +++ b/tests/ui/cfg/cfg_attr-type-mismatch.rs @@ -0,0 +1,24 @@ +use pin_project::pin_project; +use std::pin::Pin; + +#[cfg_attr(not(any()), pin_project)] +struct Foo { + #[cfg_attr(any(), pin)] + inner: T, +} + +#[cfg_attr(not(any()), pin_project)] +struct Bar { + #[cfg_attr(not(any()), pin)] + inner: T, +} + +fn main() { + let mut x = Foo { inner: 0_u8 }; + let x = Pin::new(&mut x).project(); + let _: Pin<&mut u8> = x.inner; //~ ERROR E0308 + + let mut x = Bar { inner: 0_u8 }; + let x = Pin::new(&mut x).project(); + let _: &mut u8 = x.inner; //~ ERROR E0308 +} diff --git a/tests/ui/cfg/cfg_attr-type-mismatch.stderr b/tests/ui/cfg/cfg_attr-type-mismatch.stderr new file mode 100644 index 0000000..2868299 --- /dev/null +++ b/tests/ui/cfg/cfg_attr-type-mismatch.stderr @@ -0,0 +1,23 @@ +error[E0308]: mismatched types + --> $DIR/cfg_attr-type-mismatch.rs:19:27 + | +19 | let _: Pin<&mut u8> = x.inner; //~ ERROR E0308 + | ------------ ^^^^^^^ expected struct `std::pin::Pin`, found `&mut u8` + | | + | expected due to this + | + = note: expected struct `std::pin::Pin<&mut u8>` + found mutable reference `&mut u8` + +error[E0308]: mismatched types + --> $DIR/cfg_attr-type-mismatch.rs:23:22 + | +23 | let _: &mut u8 = x.inner; //~ ERROR E0308 + | ------- ^^^^^^^ + | | | + | | expected `&mut u8`, found struct `std::pin::Pin` + | | help: consider mutably borrowing here: `&mut x.inner` + | expected due to this + | + = note: expected mutable reference `&mut u8` + found struct `std::pin::Pin<&mut u8>` diff --git a/tests/ui/cfg/cfg_attr-unpin.rs b/tests/ui/cfg/cfg_attr-unpin.rs new file mode 100644 index 0000000..7b88205 --- /dev/null +++ b/tests/ui/cfg/cfg_attr-unpin.rs @@ -0,0 +1,21 @@ +use pin_project::pin_project; +use std::marker::PhantomPinned; + +#[cfg_attr(any(), pin_project)] +struct Foo { + inner: T, +} + +#[cfg_attr(not(any()), pin_project)] +struct Bar { + #[cfg_attr(not(any()), pin)] + inner: T, +} + +fn is_unpin() {} + +fn main() { + is_unpin::>(); // ERROR E0277 + is_unpin::>(); // Ok + is_unpin::>(); //~ ERROR E0277 +} diff --git a/tests/ui/cfg/cfg_attr-unpin.stderr b/tests/ui/cfg/cfg_attr-unpin.stderr new file mode 100644 index 0000000..ce31c24 --- /dev/null +++ b/tests/ui/cfg/cfg_attr-unpin.stderr @@ -0,0 +1,22 @@ +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/cfg_attr-unpin.rs:18:5 + | +15 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +18 | is_unpin::>(); // ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `Foo`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `Foo` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/cfg_attr-unpin.rs:20:5 + | +15 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +20 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `__SCOPE_Bar::__Bar<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `__SCOPE_Bar::__Bar<'_, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Bar` diff --git a/tests/ui/cfg/packed_sneaky-span-issue-1.rs b/tests/ui/cfg/packed_sneaky-span-issue-1.rs new file mode 100644 index 0000000..3776dac --- /dev/null +++ b/tests/ui/cfg/packed_sneaky-span-issue-1.rs @@ -0,0 +1,18 @@ +use auxiliary_macros::hidden_repr; +use pin_project::pin_project; + +//~ ERROR may not be used on #[repr(packed)] types +// span is lost. +// Refs: https://github.com/rust-lang/rust/issues/43081 +#[pin_project] +#[hidden_repr(packed)] +struct Foo { + #[cfg(not(any()))] + #[pin] + field: u32, + #[cfg(any())] + #[pin] + field: u8, +} + +fn main() {} diff --git a/tests/ui/cfg/packed_sneaky-span-issue-1.stderr b/tests/ui/cfg/packed_sneaky-span-issue-1.stderr new file mode 100644 index 0000000..f4d7dee --- /dev/null +++ b/tests/ui/cfg/packed_sneaky-span-issue-1.stderr @@ -0,0 +1 @@ +error: #[pin_project] attribute may not be used on #[repr(packed)] types diff --git a/tests/ui/cfg/packed_sneaky-span-issue-2.rs b/tests/ui/cfg/packed_sneaky-span-issue-2.rs new file mode 100644 index 0000000..aa65d33 --- /dev/null +++ b/tests/ui/cfg/packed_sneaky-span-issue-2.rs @@ -0,0 +1,18 @@ +use auxiliary_macros::hidden_repr; +use pin_project::pin_project; + +//~ ERROR may not be used on #[repr(packed)] types +// span is lost. +// Refs: https://github.com/rust-lang/rust/issues/43081 +#[pin_project] +#[hidden_repr(packed)] +struct Foo { + #[cfg(any())] + #[pin] + field: u32, + #[cfg(not(any()))] + #[pin] + field: u8, +} + +fn main() {} diff --git a/tests/ui/cfg/packed_sneaky-span-issue-2.stderr b/tests/ui/cfg/packed_sneaky-span-issue-2.stderr new file mode 100644 index 0000000..f4d7dee --- /dev/null +++ b/tests/ui/cfg/packed_sneaky-span-issue-2.stderr @@ -0,0 +1 @@ +error: #[pin_project] attribute may not be used on #[repr(packed)] types diff --git a/tests/ui/cfg/packed_sneaky.rs b/tests/ui/cfg/packed_sneaky.rs new file mode 100644 index 0000000..3305ed3 --- /dev/null +++ b/tests/ui/cfg/packed_sneaky.rs @@ -0,0 +1,12 @@ +use auxiliary_macros::hidden_repr_cfg_not_any; +use pin_project::pin_project; + +// `#[hidden_repr_cfg_not_any(packed)]` generates `#[cfg_attr(not(any()), repr(packed))]`. +#[pin_project] +#[hidden_repr_cfg_not_any(packed)] //~ ERROR may not be used on #[repr(packed)] types +struct Foo { + #[pin] + field: u32, +} + +fn main() {} diff --git a/tests/ui/cfg/packed_sneaky.stderr b/tests/ui/cfg/packed_sneaky.stderr new file mode 100644 index 0000000..5910cf4 --- /dev/null +++ b/tests/ui/cfg/packed_sneaky.stderr @@ -0,0 +1,7 @@ +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/packed_sneaky.rs:6:1 + | +6 | #[hidden_repr_cfg_not_any(packed)] //~ ERROR may not be used on #[repr(packed)] types + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/cfg/proper_unpin.rs b/tests/ui/cfg/proper_unpin.rs new file mode 100644 index 0000000..b7bb04d --- /dev/null +++ b/tests/ui/cfg/proper_unpin.rs @@ -0,0 +1,28 @@ +use pin_project::pin_project; +use std::marker::PhantomPinned; + +#[pin_project] +struct Foo { + #[cfg(any())] + #[pin] + inner: T, + #[cfg(not(any()))] + inner: T, +} + +#[pin_project] +struct Bar { + #[cfg(any())] + inner: T, + #[cfg(not(any()))] + #[pin] + inner: T, +} + +fn is_unpin() {} + +fn main() { + is_unpin::>(); // Ok + is_unpin::>(); // Ok + is_unpin::>(); //~ ERROR E0277 +} diff --git a/tests/ui/cfg/proper_unpin.stderr b/tests/ui/cfg/proper_unpin.stderr new file mode 100644 index 0000000..407d900 --- /dev/null +++ b/tests/ui/cfg/proper_unpin.stderr @@ -0,0 +1,11 @@ +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/proper_unpin.rs:27:5 + | +22 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +27 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `__SCOPE_Bar::__Bar<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `__SCOPE_Bar::__Bar<'_, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Bar` diff --git a/tests/ui/cfg/unsupported.rs b/tests/ui/cfg/unsupported.rs new file mode 100644 index 0000000..5205307 --- /dev/null +++ b/tests/ui/cfg/unsupported.rs @@ -0,0 +1,13 @@ +use pin_project::pin_project; + +//~ ERROR may not be used on structs with zero fields +// span is lost. +// Refs: https://github.com/rust-lang/rust/issues/43081 +#[pin_project] +struct Struct { + #[cfg(any())] + #[pin] + f: u8, +} + +fn main() {} diff --git a/tests/ui/cfg/unsupported.stderr b/tests/ui/cfg/unsupported.stderr new file mode 100644 index 0000000..0ee8676 --- /dev/null +++ b/tests/ui/cfg/unsupported.stderr @@ -0,0 +1 @@ +error: #[pin_project] attribute may not be used on structs with zero fields diff --git a/tests/ui/not_unpin/assert-not-unpin.rs b/tests/ui/not_unpin/assert-not-unpin.rs new file mode 100644 index 0000000..b8f8238 --- /dev/null +++ b/tests/ui/not_unpin/assert-not-unpin.rs @@ -0,0 +1,40 @@ +use pin_project::pin_project; +use std::marker::PhantomPinned; + +struct Inner { + val: T, +} + +#[pin_project(!Unpin)] +struct Foo { + #[pin] + inner: Inner, + other: U, +} + +#[pin_project(!Unpin)] +struct TrivialBounds { + #[pin] + field1: PhantomPinned, +} + +#[pin_project(!Unpin)] +struct Bar<'a, T, U> { + #[pin] + inner: &'a mut Inner, + other: U, +} + +fn is_unpin() {} + +fn main() { + is_unpin::>(); //~ ERROR E0277 + is_unpin::>(); //~ ERROR E0277 + is_unpin::>(); //~ ERROR E0277 + is_unpin::>(); //~ ERROR E0277 + + is_unpin::(); //~ ERROR E0277 + + is_unpin::>(); //~ ERROR E0277 + is_unpin::>(); //~ ERROR E0277 +} diff --git a/tests/ui/not_unpin/assert-not-unpin.stderr b/tests/ui/not_unpin/assert-not-unpin.stderr new file mode 100644 index 0000000..5e323fc --- /dev/null +++ b/tests/ui/not_unpin/assert-not-unpin.stderr @@ -0,0 +1,83 @@ +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/assert-not-unpin.rs:31:5 + | +28 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +31 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^ within `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo<(), ()>` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/assert-not-unpin.rs:32:5 + | +28 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +32 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/assert-not-unpin.rs:33:5 + | +28 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +33 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo<(), std::marker::PhantomPinned>` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/assert-not-unpin.rs:34:5 + | +28 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +34 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/assert-not-unpin.rs:36:5 + | +28 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +36 | is_unpin::(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ within `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `TrivialBounds` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/assert-not-unpin.rs:38:5 + | +28 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +38 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Bar<'_, (), ()>` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/assert-not-unpin.rs:39:5 + | +28 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +39 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `pin_project::__private::Wrapper<'_, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Bar<'_, std::marker::PhantomPinned, std::marker::PhantomPinned>` diff --git a/tests/ui/not_unpin/conflict-unpin.rs b/tests/ui/not_unpin/conflict-unpin.rs new file mode 100644 index 0000000..f259f6c --- /dev/null +++ b/tests/ui/not_unpin/conflict-unpin.rs @@ -0,0 +1,30 @@ +use pin_project::pin_project; + +#[pin_project(!Unpin)] //~ ERROR E0119 +struct Foo { + #[pin] + future: T, + field: U, +} + +impl Unpin for Foo where T: Unpin {} + +#[pin_project(!Unpin)] //~ ERROR E0119 +struct Bar { + #[pin] + future: T, + field: U, +} + +impl Unpin for Bar {} + +#[pin_project(!Unpin)] //~ ERROR E0119 +struct Baz { + #[pin] + future: T, + field: U, +} + +impl Unpin for Baz {} + +fn main() {} diff --git a/tests/ui/not_unpin/conflict-unpin.stderr b/tests/ui/not_unpin/conflict-unpin.stderr new file mode 100644 index 0000000..7407bdf --- /dev/null +++ b/tests/ui/not_unpin/conflict-unpin.stderr @@ -0,0 +1,26 @@ +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Foo<_, _>`: + --> $DIR/conflict-unpin.rs:3:16 + | +3 | #[pin_project(!Unpin)] //~ ERROR E0119 + | ^^^^^ conflicting implementation for `Foo<_, _>` +... +10 | impl Unpin for Foo where T: Unpin {} + | --------------------------------------------- first implementation here + +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Bar<_, _>`: + --> $DIR/conflict-unpin.rs:12:16 + | +12 | #[pin_project(!Unpin)] //~ ERROR E0119 + | ^^^^^ conflicting implementation for `Bar<_, _>` +... +19 | impl Unpin for Bar {} + | ------------------------------ first implementation here + +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Baz<_, _>`: + --> $DIR/conflict-unpin.rs:21:16 + | +21 | #[pin_project(!Unpin)] //~ ERROR E0119 + | ^^^^^ conflicting implementation for `Baz<_, _>` +... +28 | impl Unpin for Baz {} + | -------------------------------------------- first implementation here diff --git a/tests/ui/not_unpin/impl-unsafe-unpin.rs b/tests/ui/not_unpin/impl-unsafe-unpin.rs new file mode 100644 index 0000000..625dc29 --- /dev/null +++ b/tests/ui/not_unpin/impl-unsafe-unpin.rs @@ -0,0 +1,30 @@ +use pin_project::{pin_project, UnsafeUnpin}; + +#[pin_project(!Unpin)] //~ ERROR E0119 +struct Foo { + #[pin] + future: T, + field: U, +} + +unsafe impl UnsafeUnpin for Foo where T: Unpin {} + +#[pin_project(!Unpin)] //~ ERROR E0119 +struct Bar { + #[pin] + future: T, + field: U, +} + +unsafe impl UnsafeUnpin for Bar {} + +#[pin_project(!Unpin)] //~ ERROR E0119 +struct Baz { + #[pin] + future: T, + field: U, +} + +unsafe impl UnsafeUnpin for Baz {} + +fn main() {} diff --git a/tests/ui/not_unpin/impl-unsafe-unpin.stderr b/tests/ui/not_unpin/impl-unsafe-unpin.stderr new file mode 100644 index 0000000..ba80d5e --- /dev/null +++ b/tests/ui/not_unpin/impl-unsafe-unpin.stderr @@ -0,0 +1,32 @@ +error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Foo<_, _>`: + --> $DIR/impl-unsafe-unpin.rs:3:1 + | +3 | #[pin_project(!Unpin)] //~ ERROR E0119 + | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Foo<_, _>` +... +10 | unsafe impl UnsafeUnpin for Foo where T: Unpin {} + | ---------------------------------------------------------- first implementation here + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Bar<_, _>`: + --> $DIR/impl-unsafe-unpin.rs:12:1 + | +12 | #[pin_project(!Unpin)] //~ ERROR E0119 + | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<_, _>` +... +19 | unsafe impl UnsafeUnpin for Bar {} + | ------------------------------------------- first implementation here + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Baz<_, _>`: + --> $DIR/impl-unsafe-unpin.rs:21:1 + | +21 | #[pin_project(!Unpin)] //~ ERROR E0119 + | ^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Baz<_, _>` +... +28 | unsafe impl UnsafeUnpin for Baz {} + | --------------------------------------------------------- first implementation here + | + = 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/add-pin-attr-to-struct.rs b/tests/ui/pin_project/add-pin-attr-to-struct.rs new file mode 100644 index 0000000..f5364fc --- /dev/null +++ b/tests/ui/pin_project/add-pin-attr-to-struct.rs @@ -0,0 +1,19 @@ +use auxiliary_macros::add_pin_attr; +use pin_project::pin_project; +use std::marker::PhantomPinned; + +#[pin_project] +#[add_pin_attr(struct)] //~ ERROR duplicate #[pin] attribute +struct Foo { + #[pin] + field: PhantomPinned, +} + +#[add_pin_attr(struct)] //~ ERROR #[pin] attribute may only be used on fields of structs or variants +#[pin_project] +struct Bar { + #[pin] + field: PhantomPinned, +} + +fn main() {} diff --git a/tests/ui/pin_project/add-pin-attr-to-struct.stderr b/tests/ui/pin_project/add-pin-attr-to-struct.stderr new file mode 100644 index 0000000..c2adaea --- /dev/null +++ b/tests/ui/pin_project/add-pin-attr-to-struct.stderr @@ -0,0 +1,15 @@ +error: duplicate #[pin] attribute + --> $DIR/add-pin-attr-to-struct.rs:6:1 + | +6 | #[add_pin_attr(struct)] //~ ERROR duplicate #[pin] attribute + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: #[pin] attribute may only be used on fields of structs or variants + --> $DIR/add-pin-attr-to-struct.rs:12:1 + | +12 | #[add_pin_attr(struct)] //~ ERROR #[pin] attribute may only be used on fields of structs or variants + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/pin_project/add-pinned-field.rs b/tests/ui/pin_project/add-pinned-field.rs new file mode 100644 index 0000000..76394cf --- /dev/null +++ b/tests/ui/pin_project/add-pinned-field.rs @@ -0,0 +1,23 @@ +use auxiliary_macros::add_pinned_field; +use pin_project::pin_project; + +fn is_unpin() {} + +#[pin_project] +#[add_pinned_field] +struct Foo { + #[pin] + field: u32, +} + +#[add_pinned_field] +#[pin_project] +struct Bar { + #[pin] + field: u32, +} + +fn main() { + is_unpin::(); //~ ERROR E0277 + is_unpin::(); //~ ERROR E0277 +} diff --git a/tests/ui/pin_project/add-pinned-field.stderr b/tests/ui/pin_project/add-pinned-field.stderr new file mode 100644 index 0000000..db07a74 --- /dev/null +++ b/tests/ui/pin_project/add-pinned-field.stderr @@ -0,0 +1,23 @@ +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/add-pinned-field.rs:21:5 + | +4 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +21 | is_unpin::(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^ within `__SCOPE_Foo::__Foo<'_>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `__SCOPE_Foo::__Foo<'_>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/add-pinned-field.rs:22:5 + | +4 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +22 | is_unpin::(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^ within `__SCOPE_Bar::__Bar<'_>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `__SCOPE_Bar::__Bar<'_>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Bar` diff --git a/tests/ui/pin_project/conflict-drop.rs b/tests/ui/pin_project/conflict-drop.rs new file mode 100644 index 0000000..c965184 --- /dev/null +++ b/tests/ui/pin_project/conflict-drop.rs @@ -0,0 +1,31 @@ +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +#[pin_project] //~ ERROR E0119 +struct Foo { + #[pin] + future: T, + field: U, +} + +impl Drop for Foo { + fn drop(&mut self) {} +} + +#[pin_project(PinnedDrop)] //~ ERROR E0119 +struct Bar { + #[pin] + future: T, + field: U, +} + +#[pinned_drop] +impl PinnedDrop for Bar { + fn drop(self: Pin<&mut Self>) {} +} + +impl Drop for Bar { + fn drop(&mut self) {} +} + +fn main() {} diff --git a/tests/ui/pin_project/conflict-drop.stderr b/tests/ui/pin_project/conflict-drop.stderr new file mode 100644 index 0000000..f97d060 --- /dev/null +++ b/tests/ui/pin_project/conflict-drop.stderr @@ -0,0 +1,19 @@ +error[E0119]: conflicting implementations of trait `__SCOPE_Foo::FooMustNotImplDrop` for type `Foo<_, _>`: + --> $DIR/conflict-drop.rs:4:1 + | +4 | #[pin_project] //~ ERROR E0119 + | ^^^^^^^^^^^^^^ + | | + | first implementation here + | conflicting implementation for `Foo<_, _>` + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `std::ops::Drop` for type `Bar<_, _>`: + --> $DIR/conflict-drop.rs:15:15 + | +15 | #[pin_project(PinnedDrop)] //~ ERROR E0119 + | ^^^^^^^^^^ conflicting implementation for `Bar<_, _>` +... +27 | impl Drop for Bar { + | ----------------------------- first implementation here diff --git a/tests/ui/pin_project/conflict-unpin.rs b/tests/ui/pin_project/conflict-unpin.rs new file mode 100644 index 0000000..0c48d27 --- /dev/null +++ b/tests/ui/pin_project/conflict-unpin.rs @@ -0,0 +1,37 @@ +use pin_project::pin_project; + +// The same implementation. + +#[pin_project] //~ ERROR E0119 +struct Foo { + #[pin] + future: T, + field: U, +} + +// conflicting implementations +impl Unpin for Foo where T: Unpin {} // Conditional Unpin impl + +// The implementation that under different conditions. + +#[pin_project] //~ ERROR E0119 +struct Bar { + #[pin] + future: T, + field: U, +} + +// conflicting implementations +impl Unpin for Bar {} // Non-conditional Unpin impl + +#[pin_project] //~ ERROR E0119 +struct Baz { + #[pin] + future: T, + field: U, +} + +// conflicting implementations +impl Unpin for Baz {} // Conditional Unpin impl + +fn main() {} diff --git a/tests/ui/pin_project/conflict-unpin.stderr b/tests/ui/pin_project/conflict-unpin.stderr new file mode 100644 index 0000000..0d6f439 --- /dev/null +++ b/tests/ui/pin_project/conflict-unpin.stderr @@ -0,0 +1,32 @@ +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Foo<_, _>`: + --> $DIR/conflict-unpin.rs:5:1 + | +5 | #[pin_project] //~ ERROR E0119 + | ^^^^^^^^^^^^^^ conflicting implementation for `Foo<_, _>` +... +13 | impl Unpin for Foo where T: Unpin {} // Conditional Unpin impl + | --------------------------------------------- first implementation here + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Bar<_, _>`: + --> $DIR/conflict-unpin.rs:17:1 + | +17 | #[pin_project] //~ ERROR E0119 + | ^^^^^^^^^^^^^^ conflicting implementation for `Bar<_, _>` +... +25 | impl Unpin for Bar {} // Non-conditional Unpin impl + | ------------------------------ first implementation here + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Baz<_, _>`: + --> $DIR/conflict-unpin.rs:27:1 + | +27 | #[pin_project] //~ ERROR E0119 + | ^^^^^^^^^^^^^^ conflicting implementation for `Baz<_, _>` +... +35 | impl Unpin for Baz {} // Conditional Unpin impl + | -------------------------------------------- first implementation here + | + = 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/impl-unsafe-unpin.rs b/tests/ui/pin_project/impl-unsafe-unpin.rs new file mode 100644 index 0000000..94af322 --- /dev/null +++ b/tests/ui/pin_project/impl-unsafe-unpin.rs @@ -0,0 +1,30 @@ +use pin_project::{pin_project, UnsafeUnpin}; + +#[pin_project] //~ ERROR E0119 +struct Foo { + #[pin] + future: T, + field: U, +} + +unsafe impl UnsafeUnpin for Foo where T: Unpin {} + +#[pin_project] //~ ERROR E0119 +struct Bar { + #[pin] + future: T, + field: U, +} + +unsafe impl UnsafeUnpin for Bar {} + +#[pin_project] //~ ERROR E0119 +struct Baz { + #[pin] + future: T, + field: U, +} + +unsafe impl UnsafeUnpin for Baz {} + +fn main() {} diff --git a/tests/ui/pin_project/impl-unsafe-unpin.stderr b/tests/ui/pin_project/impl-unsafe-unpin.stderr new file mode 100644 index 0000000..78545c2 --- /dev/null +++ b/tests/ui/pin_project/impl-unsafe-unpin.stderr @@ -0,0 +1,32 @@ +error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Foo<_, _>`: + --> $DIR/impl-unsafe-unpin.rs:3:1 + | +3 | #[pin_project] //~ ERROR E0119 + | ^^^^^^^^^^^^^^ conflicting implementation for `Foo<_, _>` +... +10 | unsafe impl UnsafeUnpin for Foo where T: Unpin {} + | ---------------------------------------------------------- first implementation here + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Bar<_, _>`: + --> $DIR/impl-unsafe-unpin.rs:12:1 + | +12 | #[pin_project] //~ ERROR E0119 + | ^^^^^^^^^^^^^^ conflicting implementation for `Bar<_, _>` +... +19 | unsafe impl UnsafeUnpin for Bar {} + | ------------------------------------------- first implementation here + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Baz<_, _>`: + --> $DIR/impl-unsafe-unpin.rs:21:1 + | +21 | #[pin_project] //~ ERROR E0119 + | ^^^^^^^^^^^^^^ conflicting implementation for `Baz<_, _>` +... +28 | unsafe impl UnsafeUnpin for Baz {} + | --------------------------------------------------------- first implementation here + | + = 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 new file mode 100644 index 0000000..1d05608 --- /dev/null +++ b/tests/ui/pin_project/invalid.rs @@ -0,0 +1,199 @@ +mod pin_argument { + use pin_project::pin_project; + + #[pin_project] + struct Struct { + #[pin()] //~ ERROR unexpected token + field: (), + } + + #[pin_project] + struct TupleStruct(#[pin(foo)] ()); //~ ERROR unexpected token + + #[pin_project] + enum EnumTuple { + V(#[pin(foo)] ()), //~ ERROR unexpected token + } + + #[pin_project] + enum EnumStruct { + V { + #[pin(foo)] //~ ERROR unexpected token + field: (), + }, + } +} + +mod pin_attribute { + use pin_project::pin_project; + + #[pin_project] + struct DuplicateStruct { + #[pin] + #[pin] //~ ERROR duplicate #[pin] attribute + field: (), + } + + #[pin_project] + struct DuplicateTupleStruct( + #[pin] + #[pin] + (), + //~^^ ERROR duplicate #[pin] attribute + ); + + #[pin_project] + enum DuplicateEnumTuple { + V( + #[pin] + #[pin] + (), + //~^^ ERROR duplicate #[pin] attribute + ), + } + + #[pin_project] + enum DuplicateEnumStruct { + V { + #[pin] + #[pin] //~ ERROR duplicate #[pin] attribute + field: (), + }, + } +} + +mod pin_item { + use pin_project::pin_project; + + #[pin_project] + #[pin] //~ ERROR may only be used on fields of structs or variants + struct Struct { + #[pin] + field: (), + } + + #[pin_project] + enum Variant { + #[pin] //~ ERROR may only be used on fields of structs or variants + V(()), + } + + #[pin_project] + #[pin] //~ ERROR may only be used on fields of structs or variants + enum Enum { + V(()), + } +} + +mod pin_project_argument { + use pin_project::pin_project; + + #[pin_project(UnsafeUnpin,,)] //~ ERROR expected identifier + struct Unexpected1(#[pin] ()); + + #[pin_project(Foo)] //~ ERROR unexpected argument + struct Unexpected2(#[pin] ()); + + #[pin_project(,UnsafeUnpin)] //~ ERROR expected identifier + struct Unexpected3(#[pin] ()); + + #[pin_project()] // Ok + struct Unexpected4(#[pin] ()); + + #[pin_project(PinnedDrop, PinnedDrop)] //~ ERROR duplicate `PinnedDrop` argument + struct DuplicatePinnedDrop(#[pin] ()); + + #[pin_project(Replace, Replace)] //~ ERROR duplicate `Replace` argument + struct DuplicateReplace(#[pin] ()); + + #[pin_project(UnsafeUnpin, UnsafeUnpin)] //~ ERROR duplicate `UnsafeUnpin` argument + struct DuplicateUnsafeUnpin(#[pin] ()); + + #[pin_project(!Unpin, !Unpin)] //~ ERROR duplicate `!Unpin` argument + struct DuplicateNotUnpin(#[pin] ()); + + #[pin_project(PinnedDrop, UnsafeUnpin, UnsafeUnpin)] //~ ERROR duplicate `UnsafeUnpin` argument + struct Duplicate3(#[pin] ()); + + #[pin_project(PinnedDrop, UnsafeUnpin, PinnedDrop, UnsafeUnpin)] //~ ERROR duplicate `PinnedDrop` argument + struct Duplicate4(#[pin] ()); + + #[pin_project(PinnedDrop, Replace)] //~ ERROR arguments `PinnedDrop` and `Replace` are mutually exclusive + struct PinnedDropWithReplace1(#[pin] ()); + + #[pin_project(Replace, UnsafeUnpin, PinnedDrop)] //~ ERROR arguments `PinnedDrop` and `Replace` are mutually exclusive + struct PinnedDropWithReplace2(#[pin] ()); + + #[pin_project(UnsafeUnpin, !Unpin)] //~ ERROR arguments `UnsafeUnpin` and `!Unpin` are mutually exclusive + struct UnsafeUnpinWithNotUnpin1(#[pin] ()); + + #[pin_project(!Unpin, PinnedDrop, UnsafeUnpin)] //~ ERROR arguments `UnsafeUnpin` and `!Unpin` are mutually exclusive + struct UnsafeUnpinWithNotUnpin2(#[pin] ()); + + #[pin_project(!)] //~ ERROR unexpected end of input, expected `Unpin` + struct NotUnpin1(#[pin] ()); + + #[pin_project(Unpin)] //~ ERROR unexpected argument + struct NotUnpin2(#[pin] ()); +} + +mod pin_project_attribute { + use pin_project::pin_project; + + #[pin_project] + #[pin_project] //~ ERROR duplicate #[pin_project] attribute + struct Duplicate(#[pin] ()); +} + +mod pin_project_item { + use pin_project::pin_project; + + #[pin_project] + struct Struct {} //~ ERROR may not be used on structs with zero fields + + #[pin_project] + struct TupleStruct(); //~ ERROR may not be used on structs with zero fields + + #[pin_project] + struct UnitStruct; //~ ERROR may not be used on structs with zero fields + + #[pin_project] + enum EnumEmpty {} //~ ERROR may not be used on enums without variants + + #[pin_project] + enum EnumDiscriminant { + V = 2, //~ ERROR may not be used on enums with discriminants + } + + #[pin_project] + enum EnumZeroFields { + Unit, //~ ERROR may not be used on enums with zero fields + Tuple(), + Struct {}, + } + + #[pin_project] + union Union { + //~^ ERROR may only be used on structs or enums + f: (), + } +} + +// #[repr(packed)] is always detected first, even on unsupported structs. +mod pin_project_item_packed { + use pin_project::pin_project; + + #[pin_project] + #[repr(packed)] + struct Struct {} //~ ERROR may not be used on #[repr(packed)] types + + #[pin_project] + #[repr(packed)] + struct TupleStruct(); //~ ERROR may not be used on #[repr(packed)] types + + #[pin_project] + #[repr(packed)] + struct UnitStruct; //~ ERROR may not be used on #[repr(packed)] types +} + +fn main() {} diff --git a/tests/ui/pin_project/invalid.stderr b/tests/ui/pin_project/invalid.stderr new file mode 100644 index 0000000..95b57f0 --- /dev/null +++ b/tests/ui/pin_project/invalid.stderr @@ -0,0 +1,228 @@ +error: unexpected token: () + --> $DIR/invalid.rs:6:14 + | +6 | #[pin()] //~ ERROR unexpected token + | ^^ + +error: unexpected token: (foo) + --> $DIR/invalid.rs:11:29 + | +11 | struct TupleStruct(#[pin(foo)] ()); //~ ERROR unexpected token + | ^^^^^ + +error: unexpected token: (foo) + --> $DIR/invalid.rs:15:16 + | +15 | V(#[pin(foo)] ()), //~ ERROR unexpected token + | ^^^^^ + +error: unexpected token: (foo) + --> $DIR/invalid.rs:21:18 + | +21 | #[pin(foo)] //~ ERROR unexpected token + | ^^^^^ + +error: duplicate #[pin] attribute + --> $DIR/invalid.rs:33:9 + | +33 | #[pin] //~ ERROR duplicate #[pin] attribute + | ^^^^^^ + +error: duplicate #[pin] attribute + --> $DIR/invalid.rs:40:9 + | +40 | #[pin] + | ^^^^^^ + +error: duplicate #[pin] attribute + --> $DIR/invalid.rs:49:13 + | +49 | #[pin] + | ^^^^^^ + +error: duplicate #[pin] attribute + --> $DIR/invalid.rs:59:13 + | +59 | #[pin] //~ ERROR duplicate #[pin] attribute + | ^^^^^^ + +error: #[pin] attribute may only be used on fields of structs or variants + --> $DIR/invalid.rs:69:5 + | +69 | #[pin] //~ ERROR may only be used on fields of structs or variants + | ^^^^^^ + +error: #[pin] attribute may only be used on fields of structs or variants + --> $DIR/invalid.rs:77:9 + | +77 | #[pin] //~ ERROR may only be used on fields of structs or variants + | ^^^^^^ + +error: #[pin] attribute may only be used on fields of structs or variants + --> $DIR/invalid.rs:82:5 + | +82 | #[pin] //~ ERROR may only be used on fields of structs or variants + | ^^^^^^ + +error: expected identifier + --> $DIR/invalid.rs:91:31 + | +91 | #[pin_project(UnsafeUnpin,,)] //~ ERROR expected identifier + | ^ + +error: unexpected argument: Foo + --> $DIR/invalid.rs:94:19 + | +94 | #[pin_project(Foo)] //~ ERROR unexpected argument + | ^^^ + +error: expected identifier + --> $DIR/invalid.rs:97:19 + | +97 | #[pin_project(,UnsafeUnpin)] //~ ERROR expected identifier + | ^ + +error: duplicate `PinnedDrop` argument + --> $DIR/invalid.rs:103:31 + | +103 | #[pin_project(PinnedDrop, PinnedDrop)] //~ ERROR duplicate `PinnedDrop` argument + | ^^^^^^^^^^ + +error: duplicate `Replace` argument + --> $DIR/invalid.rs:106:28 + | +106 | #[pin_project(Replace, Replace)] //~ ERROR duplicate `Replace` argument + | ^^^^^^^ + +error: duplicate `UnsafeUnpin` argument + --> $DIR/invalid.rs:109:32 + | +109 | #[pin_project(UnsafeUnpin, UnsafeUnpin)] //~ ERROR duplicate `UnsafeUnpin` argument + | ^^^^^^^^^^^ + +error: duplicate `!Unpin` argument + --> $DIR/invalid.rs:112:27 + | +112 | #[pin_project(!Unpin, !Unpin)] //~ ERROR duplicate `!Unpin` argument + | ^^^^^^ + +error: duplicate `UnsafeUnpin` argument + --> $DIR/invalid.rs:115:44 + | +115 | #[pin_project(PinnedDrop, UnsafeUnpin, UnsafeUnpin)] //~ ERROR duplicate `UnsafeUnpin` argument + | ^^^^^^^^^^^ + +error: duplicate `PinnedDrop` argument + --> $DIR/invalid.rs:118:44 + | +118 | #[pin_project(PinnedDrop, UnsafeUnpin, PinnedDrop, UnsafeUnpin)] //~ ERROR duplicate `PinnedDrop` argument + | ^^^^^^^^^^ + +error: arguments `PinnedDrop` and `Replace` are mutually exclusive + --> $DIR/invalid.rs:121:19 + | +121 | #[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 + | +124 | #[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 + | +127 | #[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 + | +130 | #[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 + | +133 | #[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 + | +136 | #[pin_project(Unpin)] //~ ERROR unexpected argument + | ^^^^^ + +error: duplicate #[pin_project] attribute + --> $DIR/invalid.rs:144:5 + | +144 | #[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 + | +152 | 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 + | +155 | 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 + | +158 | 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 + | +161 | 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 + | +165 | 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 + | +170 | / Unit, //~ ERROR may not be used on enums with zero fields +171 | | Tuple(), +172 | | Struct {}, + | |__________________^ + +error: #[pin_project] attribute may only be used on structs or enums + --> $DIR/invalid.rs:176:5 + | +176 | / union Union { +177 | | //~^ ERROR may only be used on structs or enums +178 | | f: (), +179 | | } + | |_____^ + +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/invalid.rs:187:12 + | +187 | #[repr(packed)] + | ^^^^^^ + +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/invalid.rs:191:12 + | +191 | #[repr(packed)] + | ^^^^^^ + +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/invalid.rs:195:12 + | +195 | #[repr(packed)] + | ^^^^^^ diff --git a/tests/ui/pin_project/overlapping_unpin_struct.rs b/tests/ui/pin_project/overlapping_unpin_struct.rs new file mode 100644 index 0000000..00fef3c --- /dev/null +++ b/tests/ui/pin_project/overlapping_unpin_struct.rs @@ -0,0 +1,18 @@ +use pin_project::pin_project; +use std::marker::PhantomPinned; + +#[pin_project] +struct Foo { + #[pin] + inner: T, +} + +struct __Foo {} + +impl Unpin for __Foo {} + +fn is_unpin() {} + +fn main() { + is_unpin::>(); //~ ERROR E0277 +} diff --git a/tests/ui/pin_project/overlapping_unpin_struct.stderr b/tests/ui/pin_project/overlapping_unpin_struct.stderr new file mode 100644 index 0000000..d0fd4a9 --- /dev/null +++ b/tests/ui/pin_project/overlapping_unpin_struct.stderr @@ -0,0 +1,11 @@ +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/overlapping_unpin_struct.rs:17:5 + | +14 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +17 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `__SCOPE_Foo::__Foo<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `__SCOPE_Foo::__Foo<'_, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo` diff --git a/tests/ui/pin_project/packed-enum.rs b/tests/ui/pin_project/packed-enum.rs new file mode 100644 index 0000000..9d4a4c3 --- /dev/null +++ b/tests/ui/pin_project/packed-enum.rs @@ -0,0 +1,20 @@ +use pin_project::pin_project; + +#[repr(packed)] //~ ERROR E0517 +enum E1 { + V(()), +} + +#[pin_project] +#[repr(packed)] //~ ERROR E0517 +enum E2 { + V(()), +} + +#[repr(packed)] //~ ERROR E0517 +#[pin_project] +enum E3 { + V(()), +} + +fn main() {} diff --git a/tests/ui/pin_project/packed-enum.stderr b/tests/ui/pin_project/packed-enum.stderr new file mode 100644 index 0000000..0a5d31b --- /dev/null +++ b/tests/ui/pin_project/packed-enum.stderr @@ -0,0 +1,30 @@ +error[E0517]: attribute should be applied to struct or union + --> $DIR/packed-enum.rs:3:8 + | +3 | #[repr(packed)] //~ ERROR E0517 + | ^^^^^^ +4 | / enum E1 { +5 | | V(()), +6 | | } + | |_- not a struct or union + +error[E0517]: attribute should be applied to struct or union + --> $DIR/packed-enum.rs:9:8 + | +9 | #[repr(packed)] //~ ERROR E0517 + | ^^^^^^ +10 | / enum E2 { +11 | | V(()), +12 | | } + | |_- not a struct or union + +error[E0517]: attribute should be applied to struct or union + --> $DIR/packed-enum.rs:14:8 + | +14 | #[repr(packed)] //~ ERROR E0517 + | ^^^^^^ +15 | #[pin_project] +16 | / enum E3 { +17 | | V(()), +18 | | } + | |_- not a struct or union diff --git a/tests/ui/pin_project/packed-name-value.rs b/tests/ui/pin_project/packed-name-value.rs new file mode 100644 index 0000000..ed819ca --- /dev/null +++ b/tests/ui/pin_project/packed-name-value.rs @@ -0,0 +1,20 @@ +use pin_project::pin_project; + +#[repr(packed = "")] //~ ERROR E0552 +struct S1 { + f: (), +} + +#[pin_project] +#[repr(packed = "")] //~ ERROR E0552 +struct S2 { + f: (), +} + +#[repr(packed = "")] //~ ERROR E0552 +#[pin_project] +struct S3 { + f: (), +} + +fn main() {} diff --git a/tests/ui/pin_project/packed-name-value.stderr b/tests/ui/pin_project/packed-name-value.stderr new file mode 100644 index 0000000..a3e2571 --- /dev/null +++ b/tests/ui/pin_project/packed-name-value.stderr @@ -0,0 +1,17 @@ +error[E0552]: unrecognized representation hint + --> $DIR/packed-name-value.rs:3:8 + | +3 | #[repr(packed = "")] //~ ERROR E0552 + | ^^^^^^^^^^^ + +error[E0552]: unrecognized representation hint + --> $DIR/packed-name-value.rs:9:8 + | +9 | #[repr(packed = "")] //~ ERROR E0552 + | ^^^^^^^^^^^ + +error[E0552]: unrecognized representation hint + --> $DIR/packed-name-value.rs:14:8 + | +14 | #[repr(packed = "")] //~ ERROR E0552 + | ^^^^^^^^^^^ diff --git a/tests/ui/pin_project/packed.rs b/tests/ui/pin_project/packed.rs new file mode 100644 index 0000000..86f3ecf --- /dev/null +++ b/tests/ui/pin_project/packed.rs @@ -0,0 +1,25 @@ +use pin_project::pin_project; + +#[pin_project] +#[repr(packed, C)] //~ ERROR may not be used on #[repr(packed)] types +struct A { + #[pin] + field: u8, +} + +// Test putting 'repr' before the 'pin_project' attribute +#[repr(packed, C)] //~ ERROR may not be used on #[repr(packed)] types +#[pin_project] +struct B { + #[pin] + field: u8, +} + +#[pin_project] +#[repr(packed(2))] //~ ERROR may not be used on #[repr(packed)] types +struct C { + #[pin] + field: u32, +} + +fn main() {} diff --git a/tests/ui/pin_project/packed.stderr b/tests/ui/pin_project/packed.stderr new file mode 100644 index 0000000..969faea --- /dev/null +++ b/tests/ui/pin_project/packed.stderr @@ -0,0 +1,17 @@ +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/packed.rs:4:8 + | +4 | #[repr(packed, C)] //~ ERROR may not be used on #[repr(packed)] types + | ^^^^^^ + +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/packed.rs:11:8 + | +11 | #[repr(packed, C)] //~ ERROR may not be used on #[repr(packed)] types + | ^^^^^^ + +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/packed.rs:19:8 + | +19 | #[repr(packed(2))] //~ ERROR may not be used on #[repr(packed)] types + | ^^^^^^^^^ diff --git a/tests/ui/pin_project/packed_sneaky-1.rs b/tests/ui/pin_project/packed_sneaky-1.rs new file mode 100644 index 0000000..dcf5464 --- /dev/null +++ b/tests/ui/pin_project/packed_sneaky-1.rs @@ -0,0 +1,33 @@ +use auxiliary_macros::hidden_repr; +use pin_project::{pin_project, pinned_drop, UnsafeUnpin}; +use std::pin::Pin; + +#[pin_project] //~ ERROR may not be used on #[repr(packed)] types +#[hidden_repr(packed)] +struct A { + #[pin] + field: u32, +} + +#[pin_project(UnsafeUnpin)] //~ ERROR may not be used on #[repr(packed)] types +#[hidden_repr(packed)] +struct C { + #[pin] + field: u32, +} + +unsafe impl UnsafeUnpin for C {} + +#[pin_project(PinnedDrop)] //~ ERROR may not be used on #[repr(packed)] types +#[hidden_repr(packed)] +struct D { + #[pin] + field: u32, +} + +#[pinned_drop] +impl PinnedDrop for D { + fn drop(self: Pin<&mut Self>) {} +} + +fn main() {} diff --git a/tests/ui/pin_project/packed_sneaky-1.stderr b/tests/ui/pin_project/packed_sneaky-1.stderr new file mode 100644 index 0000000..06a4f62 --- /dev/null +++ b/tests/ui/pin_project/packed_sneaky-1.stderr @@ -0,0 +1,23 @@ +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/packed_sneaky-1.rs:6:1 + | +6 | #[hidden_repr(packed)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/packed_sneaky-1.rs:13:1 + | +13 | #[hidden_repr(packed)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/packed_sneaky-1.rs:22:1 + | +22 | #[hidden_repr(packed)] + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/pin_project/packed_sneaky-2.rs b/tests/ui/pin_project/packed_sneaky-2.rs new file mode 100644 index 0000000..d162706 --- /dev/null +++ b/tests/ui/pin_project/packed_sneaky-2.rs @@ -0,0 +1,12 @@ +use auxiliary_macros::hidden_repr_macro; +use pin_project::pin_project; + +hidden_repr_macro! { //~ ERROR may not be used on #[repr(packed)] types + #[pin_project] + struct B { + #[pin] + field: u32, + } +} + +fn main() {} diff --git a/tests/ui/pin_project/packed_sneaky-2.stderr b/tests/ui/pin_project/packed_sneaky-2.stderr new file mode 100644 index 0000000..d653a4d --- /dev/null +++ b/tests/ui/pin_project/packed_sneaky-2.stderr @@ -0,0 +1,13 @@ +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/packed_sneaky-2.rs:4:1 + | +4 | / hidden_repr_macro! { //~ ERROR may not be used on #[repr(packed)] types +5 | | #[pin_project] +6 | | struct B { +7 | | #[pin] +8 | | field: u32, +9 | | } +10 | | } + | |_^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/pin_project/private_in_public-enum.rs b/tests/ui/pin_project/private_in_public-enum.rs new file mode 100644 index 0000000..cbffa20 --- /dev/null +++ b/tests/ui/pin_project/private_in_public-enum.rs @@ -0,0 +1,23 @@ +// Even if allows private_in_public, these are errors. + +#![allow(private_in_public)] + +pub enum PublicEnum { + Variant(PrivateEnum), //~ ERROR E0446 +} + +enum PrivateEnum { + Variant(u8), +} + +mod foo { + pub(crate) enum CrateEnum { + Variant(PrivateEnum), //~ ERROR E0446 + } + + enum PrivateEnum { + Variant(u8), + } +} + +fn main() {} diff --git a/tests/ui/pin_project/private_in_public-enum.stderr b/tests/ui/pin_project/private_in_public-enum.stderr new file mode 100644 index 0000000..6f2988f --- /dev/null +++ b/tests/ui/pin_project/private_in_public-enum.stderr @@ -0,0 +1,17 @@ +error[E0446]: private type `PrivateEnum` in public interface + --> $DIR/private_in_public-enum.rs:6:13 + | +6 | Variant(PrivateEnum), //~ ERROR E0446 + | ^^^^^^^^^^^ can't leak private type +... +9 | enum PrivateEnum { + | - `PrivateEnum` declared as private + +error[E0446]: private type `foo::PrivateEnum` in public interface + --> $DIR/private_in_public-enum.rs:15:17 + | +15 | Variant(PrivateEnum), //~ ERROR E0446 + | ^^^^^^^^^^^ can't leak private type +... +18 | enum PrivateEnum { + | - `foo::PrivateEnum` declared as private diff --git a/tests/ui/pin_project/proper_unpin.rs b/tests/ui/pin_project/proper_unpin.rs new file mode 100644 index 0000000..e61789b --- /dev/null +++ b/tests/ui/pin_project/proper_unpin.rs @@ -0,0 +1,38 @@ +use pin_project::pin_project; +use std::marker::PhantomPinned; + +struct Inner { + val: T, +} + +#[pin_project] +struct Foo { + #[pin] + inner: Inner, + other: U, +} + +#[pin_project] +struct TrivialBounds { + #[pin] + field1: PhantomPinned, +} + +#[pin_project] +struct Bar<'a, T, U> { + #[pin] + inner: &'a mut Inner, + other: U, +} + +fn is_unpin() {} + +fn main() { + is_unpin::>(); //~ ERROR E0277 + is_unpin::>(); // Ok + is_unpin::>(); //~ ERROR E0277 + + is_unpin::(); //~ ERROR E0277 + + is_unpin::>(); // Ok +} diff --git a/tests/ui/pin_project/proper_unpin.stderr b/tests/ui/pin_project/proper_unpin.stderr new file mode 100644 index 0000000..9142887 --- /dev/null +++ b/tests/ui/pin_project/proper_unpin.stderr @@ -0,0 +1,37 @@ +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/proper_unpin.rs:31:5 + | +28 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +31 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `__SCOPE_Foo::__Foo<'_, std::marker::PhantomPinned, ()>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `Inner` + = note: required because it appears within the type `__SCOPE_Foo::__Foo<'_, std::marker::PhantomPinned, ()>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/proper_unpin.rs:33:5 + | +28 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +33 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `__SCOPE_Foo::__Foo<'_, std::marker::PhantomPinned, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `Inner` + = note: required because it appears within the type `__SCOPE_Foo::__Foo<'_, std::marker::PhantomPinned, std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/proper_unpin.rs:35:5 + | +28 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +35 | is_unpin::(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^ within `__SCOPE_TrivialBounds::__TrivialBounds<'_>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `__SCOPE_TrivialBounds::__TrivialBounds<'_>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `TrivialBounds` diff --git a/tests/ui/pin_project/remove-attr-from-field.rs b/tests/ui/pin_project/remove-attr-from-field.rs new file mode 100644 index 0000000..eebd3cd --- /dev/null +++ b/tests/ui/pin_project/remove-attr-from-field.rs @@ -0,0 +1,32 @@ +use auxiliary_macros::remove_attr; +use pin_project::pin_project; +use std::{marker::PhantomPinned, pin::Pin}; + +fn is_unpin() {} + +#[pin_project] +#[remove_attr(field)] +struct Foo { + #[pin] + field: PhantomPinned, +} + +#[remove_attr(field)] +#[pin_project] +struct Bar { + #[pin] + field: PhantomPinned, +} + +fn main() { + is_unpin::(); + is_unpin::(); + + let mut x = Foo { field: PhantomPinned }; + let x = Pin::new(&mut x).project(); + let _: Pin<&mut PhantomPinned> = x.field; //~ ERROR E0308 + + let mut x = Bar { field: PhantomPinned }; + let x = Pin::new(&mut x).project(); + let _: Pin<&mut PhantomPinned> = x.field; //~ ERROR E0308 +} diff --git a/tests/ui/pin_project/remove-attr-from-field.stderr b/tests/ui/pin_project/remove-attr-from-field.stderr new file mode 100644 index 0000000..15195e7 --- /dev/null +++ b/tests/ui/pin_project/remove-attr-from-field.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/remove-attr-from-field.rs:27:38 + | +27 | let _: Pin<&mut PhantomPinned> = x.field; //~ ERROR E0308 + | ----------------------- ^^^^^^^ expected struct `std::pin::Pin`, found `&mut std::marker::PhantomPinned` + | | + | expected due to this + | + = note: expected struct `std::pin::Pin<&mut std::marker::PhantomPinned>` + found mutable reference `&mut std::marker::PhantomPinned` + +error[E0308]: mismatched types + --> $DIR/remove-attr-from-field.rs:31:38 + | +31 | let _: Pin<&mut PhantomPinned> = x.field; //~ ERROR E0308 + | ----------------------- ^^^^^^^ expected struct `std::pin::Pin`, found `&mut std::marker::PhantomPinned` + | | + | expected due to this + | + = note: expected struct `std::pin::Pin<&mut std::marker::PhantomPinned>` + found mutable reference `&mut std::marker::PhantomPinned` diff --git a/tests/ui/pin_project/remove-attr-from-struct.rs b/tests/ui/pin_project/remove-attr-from-struct.rs new file mode 100644 index 0000000..b395a42 --- /dev/null +++ b/tests/ui/pin_project/remove-attr-from-struct.rs @@ -0,0 +1,30 @@ +use auxiliary_macros::remove_attr; +use pin_project::pin_project; +use std::{marker::PhantomPinned, pin::Pin}; + +fn is_unpin() {} + +#[pin_project] +#[remove_attr(struct)] +struct Foo { + #[pin] //~ ERROR cannot find attribute `pin` in this scope + field: PhantomPinned, +} + +#[remove_attr(struct)] +#[pin_project] +struct Bar { + #[pin] //~ ERROR cannot find attribute `pin` in this scope + field: PhantomPinned, +} + +fn main() { + is_unpin::(); //~ ERROR E0277 + is_unpin::(); //~ ERROR E0277 + + let mut x = Foo { field: PhantomPinned }; + let _x = Pin::new(&mut x).project(); //~ ERROR E0277,E0599 + + let mut x = Bar { field: PhantomPinned }; + let _x = Pin::new(&mut x).project(); //~ ERROR E0277,E0599 +} diff --git a/tests/ui/pin_project/remove-attr-from-struct.stderr b/tests/ui/pin_project/remove-attr-from-struct.stderr new file mode 100644 index 0000000..3173248 --- /dev/null +++ b/tests/ui/pin_project/remove-attr-from-struct.stderr @@ -0,0 +1,63 @@ +error: cannot find attribute `pin` in this scope + --> $DIR/remove-attr-from-struct.rs:10:7 + | +10 | #[pin] //~ ERROR cannot find attribute `pin` in this scope + | ^^^ + +error: cannot find attribute `pin` in this scope + --> $DIR/remove-attr-from-struct.rs:17:7 + | +17 | #[pin] //~ ERROR cannot find attribute `pin` in this scope + | ^^^ + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/remove-attr-from-struct.rs:22:5 + | +5 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +22 | is_unpin::(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^ within `Foo`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `Foo` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/remove-attr-from-struct.rs:23:5 + | +5 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +23 | is_unpin::(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^ within `Bar`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `Bar` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/remove-attr-from-struct.rs:26:14 + | +26 | let _x = Pin::new(&mut x).project(); //~ ERROR E0277,E0599 + | ^^^^^^^^ within `Foo`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `Foo` + = note: required by `std::pin::Pin::

::new` + +error[E0599]: no method named `project` found for struct `std::pin::Pin<&mut Foo>` in the current scope + --> $DIR/remove-attr-from-struct.rs:26:31 + | +26 | let _x = Pin::new(&mut x).project(); //~ ERROR E0277,E0599 + | ^^^^^^^ method not found in `std::pin::Pin<&mut Foo>` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/remove-attr-from-struct.rs:29:14 + | +29 | let _x = Pin::new(&mut x).project(); //~ ERROR E0277,E0599 + | ^^^^^^^^ within `Bar`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `Bar` + = note: required by `std::pin::Pin::

::new` + +error[E0599]: no method named `project` found for struct `std::pin::Pin<&mut Bar>` in the current scope + --> $DIR/remove-attr-from-struct.rs:29:31 + | +29 | let _x = Pin::new(&mut x).project(); //~ ERROR E0277,E0599 + | ^^^^^^^ method not found in `std::pin::Pin<&mut Bar>` diff --git a/tests/ui/pin_project/safe_packed_borrows.rs b/tests/ui/pin_project/safe_packed_borrows.rs new file mode 100644 index 0000000..c1a7d55 --- /dev/null +++ b/tests/ui/pin_project/safe_packed_borrows.rs @@ -0,0 +1,21 @@ +#![deny(safe_packed_borrows)] + +// Refs: https://github.com/rust-lang/rust/issues/46043 + +#[repr(packed)] +struct A { + field: u32, +} + +#[repr(packed(2))] +struct B { + field: u32, +} + +fn main() { + let a = A { field: 1 }; + &a.field; //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + + let b = B { field: 1 }; + &b.field; //~ ERROR borrow of packed field is unsafe and requires unsafe function or block +} diff --git a/tests/ui/pin_project/safe_packed_borrows.stderr b/tests/ui/pin_project/safe_packed_borrows.stderr new file mode 100644 index 0000000..7b4cc08 --- /dev/null +++ b/tests/ui/pin_project/safe_packed_borrows.stderr @@ -0,0 +1,24 @@ +error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> $DIR/safe_packed_borrows.rs:17:5 + | +17 | &a.field; //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/safe_packed_borrows.rs:1:9 + | +1 | #![deny(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> $DIR/safe_packed_borrows.rs:20:5 + | +20 | &b.field; //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior diff --git a/tests/ui/pin_project/unpin_sneaky.rs b/tests/ui/pin_project/unpin_sneaky.rs new file mode 100644 index 0000000..3ccb1a9 --- /dev/null +++ b/tests/ui/pin_project/unpin_sneaky.rs @@ -0,0 +1,11 @@ +use pin_project::pin_project; + +#[pin_project] +struct Foo { + #[pin] + inner: u8, +} + +impl Unpin for __Foo {} //~ ERROR E0412,E0321 + +fn main() {} diff --git a/tests/ui/pin_project/unpin_sneaky.stderr b/tests/ui/pin_project/unpin_sneaky.stderr new file mode 100644 index 0000000..0637a66 --- /dev/null +++ b/tests/ui/pin_project/unpin_sneaky.stderr @@ -0,0 +1,11 @@ +error[E0412]: cannot find type `__Foo` in this scope + --> $DIR/unpin_sneaky.rs:9:16 + | +9 | impl Unpin for __Foo {} //~ ERROR E0412,E0321 + | ^^^^^ not found in this scope + +error[E0321]: cross-crate traits with a default impl, like `std::marker::Unpin`, can only be implemented for a struct/enum type, not `[type error]` + --> $DIR/unpin_sneaky.rs:9:1 + | +9 | impl Unpin for __Foo {} //~ ERROR E0412,E0321 + | ^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type diff --git a/tests/ui/pin_project/visibility.rs b/tests/ui/pin_project/visibility.rs new file mode 100644 index 0000000..4f0cb1b --- /dev/null +++ b/tests/ui/pin_project/visibility.rs @@ -0,0 +1,52 @@ +mod pub_ { + use pin_project::pin_project; + + #[pin_project] + pub struct Default(()); + + #[pin_project(Replace)] + pub struct Replace(()); +} +pub mod pub_use { + #[rustfmt::skip] + pub use crate::pub_::__DefaultProjection; //~ ERROR E0365 + #[rustfmt::skip] + pub use crate::pub_::__DefaultProjectionRef; //~ ERROR E0365 + #[rustfmt::skip] + pub use crate::pub_::__ReplaceProjection; //~ ERROR E0365 + #[rustfmt::skip] + pub use crate::pub_::__ReplaceProjectionOwned; //~ ERROR E0365 + #[rustfmt::skip] + pub use crate::pub_::__ReplaceProjectionRef; //~ ERROR E0365 + + // Confirm that the visibility of the original type is not changed. + pub use crate::pub_::{Default, Replace}; +} +pub mod pub_use2 { + // Ok + #[allow(unused_imports)] + pub(crate) use crate::pub_::{ + __DefaultProjection, __DefaultProjectionRef, __ReplaceProjection, __ReplaceProjectionOwned, + __ReplaceProjectionRef, + }; +} + +mod pub_crate { + use pin_project::pin_project; + + #[pin_project] + pub(crate) struct Default(()); + + #[pin_project(Replace)] + pub(crate) struct Replace(()); +} +pub mod pub_crate_use { + // Ok + #[allow(unused_imports)] + pub(crate) use crate::pub_crate::{ + __DefaultProjection, __DefaultProjectionRef, __ReplaceProjection, __ReplaceProjectionOwned, + __ReplaceProjectionRef, + }; +} + +fn main() {} diff --git a/tests/ui/pin_project/visibility.stderr b/tests/ui/pin_project/visibility.stderr new file mode 100644 index 0000000..1ea60d7 --- /dev/null +++ b/tests/ui/pin_project/visibility.stderr @@ -0,0 +1,39 @@ +error[E0365]: `__DefaultProjection` is private, and cannot be re-exported + --> $DIR/visibility.rs:12:13 + | +12 | pub use crate::pub_::__DefaultProjection; //~ ERROR E0365 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `__DefaultProjection` + | + = note: consider declaring type or module `__DefaultProjection` with `pub` + +error[E0365]: `__DefaultProjectionRef` is private, and cannot be re-exported + --> $DIR/visibility.rs:14:13 + | +14 | pub use crate::pub_::__DefaultProjectionRef; //~ ERROR E0365 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `__DefaultProjectionRef` + | + = note: consider declaring type or module `__DefaultProjectionRef` with `pub` + +error[E0365]: `__ReplaceProjection` is private, and cannot be re-exported + --> $DIR/visibility.rs:16:13 + | +16 | pub use crate::pub_::__ReplaceProjection; //~ ERROR E0365 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `__ReplaceProjection` + | + = note: consider declaring type or module `__ReplaceProjection` with `pub` + +error[E0365]: `__ReplaceProjectionOwned` is private, and cannot be re-exported + --> $DIR/visibility.rs:18:13 + | +18 | pub use crate::pub_::__ReplaceProjectionOwned; //~ ERROR E0365 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `__ReplaceProjectionOwned` + | + = note: consider declaring type or module `__ReplaceProjectionOwned` with `pub` + +error[E0365]: `__ReplaceProjectionRef` is private, and cannot be re-exported + --> $DIR/visibility.rs:20:13 + | +20 | pub use crate::pub_::__ReplaceProjectionRef; //~ ERROR E0365 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ re-export of private `__ReplaceProjectionRef` + | + = note: consider declaring type or module `__ReplaceProjectionRef` with `pub` diff --git a/tests/ui/pinned_drop/call-drop-inner.rs b/tests/ui/pinned_drop/call-drop-inner.rs new file mode 100644 index 0000000..c953acb --- /dev/null +++ b/tests/ui/pinned_drop/call-drop-inner.rs @@ -0,0 +1,16 @@ +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +#[pin_project(PinnedDrop)] +struct Struct { + dropped: bool, +} + +#[pinned_drop] +impl PinnedDrop for Struct { + fn drop(mut self: Pin<&mut Self>) { + __drop_inner(__self); + } +} + +fn main() {} diff --git a/tests/ui/pinned_drop/call-drop-inner.stderr b/tests/ui/pinned_drop/call-drop-inner.stderr new file mode 100644 index 0000000..eb55ce7 --- /dev/null +++ b/tests/ui/pinned_drop/call-drop-inner.stderr @@ -0,0 +1,10 @@ +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/call-drop-inner.rs:12:9 + | +9 | #[pinned_drop] + | -------------- defined here +... +12 | __drop_inner(__self); + | ^^^^^^^^^^^^ ------ supplied 1 argument + | | + | expected 0 arguments diff --git a/tests/ui/pinned_drop/conditional-drop-impl.rs b/tests/ui/pinned_drop/conditional-drop-impl.rs new file mode 100644 index 0000000..42d18b7 --- /dev/null +++ b/tests/ui/pinned_drop/conditional-drop-impl.rs @@ -0,0 +1,26 @@ +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +// In `Drop` impl, the implementor must specify the same requirement as type definition. + +struct DropImpl { + field: T, +} + +impl Drop for DropImpl { + //~^ ERROR E0367 + fn drop(&mut self) {} +} + +#[pin_project(PinnedDrop)] //~ ERROR E0277 +struct PinnedDropImpl { + #[pin] + field: T, +} + +#[pinned_drop] +impl PinnedDrop for PinnedDropImpl { + fn drop(self: Pin<&mut Self>) {} +} + +fn main() {} diff --git a/tests/ui/pinned_drop/conditional-drop-impl.stderr b/tests/ui/pinned_drop/conditional-drop-impl.stderr new file mode 100644 index 0000000..ad8fb69 --- /dev/null +++ b/tests/ui/pinned_drop/conditional-drop-impl.stderr @@ -0,0 +1,26 @@ +error[E0367]: `Drop` impl requires `T: std::marker::Unpin` but the struct it is implemented for does not + --> $DIR/conditional-drop-impl.rs:10:9 + | +10 | impl Drop for DropImpl { + | ^^^^^ + | +note: the implementor must specify the same requirement + --> $DIR/conditional-drop-impl.rs:6:1 + | +6 | / struct DropImpl { +7 | | field: T, +8 | | } + | |_^ + +error[E0277]: `T` cannot be unpinned + --> $DIR/conditional-drop-impl.rs:15:15 + | +15 | #[pin_project(PinnedDrop)] //~ ERROR E0277 + | ^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `T` + | + = note: required because of the requirements on the impl of `pin_project::__private::PinnedDrop` for `PinnedDropImpl` + = note: required by `pin_project::__private::PinnedDrop::drop` +help: consider restricting type parameter `T` + | +16 | struct PinnedDropImpl { + | ^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/pinned_drop/forget-pinned-drop-impl.rs b/tests/ui/pinned_drop/forget-pinned-drop-impl.rs new file mode 100644 index 0000000..6c9f718 --- /dev/null +++ b/tests/ui/pinned_drop/forget-pinned-drop-impl.rs @@ -0,0 +1,9 @@ +use pin_project::pin_project; + +#[pin_project(PinnedDrop)] //~ ERROR E0277 +struct Struct { + #[pin] + field: u8, +} + +fn main() {} diff --git a/tests/ui/pinned_drop/forget-pinned-drop-impl.stderr b/tests/ui/pinned_drop/forget-pinned-drop-impl.stderr new file mode 100644 index 0000000..67bdbe1 --- /dev/null +++ b/tests/ui/pinned_drop/forget-pinned-drop-impl.stderr @@ -0,0 +1,7 @@ +error[E0277]: the trait bound `Struct: pin_project::__private::PinnedDrop` is not satisfied + --> $DIR/forget-pinned-drop-impl.rs:3:15 + | +3 | #[pin_project(PinnedDrop)] //~ ERROR E0277 + | ^^^^^^^^^^ the trait `pin_project::__private::PinnedDrop` is not implemented for `Struct` + | + = note: required by `pin_project::__private::PinnedDrop::drop` diff --git a/tests/ui/pinned_drop/invalid-self.rs b/tests/ui/pinned_drop/invalid-self.rs new file mode 100644 index 0000000..73d3b43 --- /dev/null +++ b/tests/ui/pinned_drop/invalid-self.rs @@ -0,0 +1,14 @@ +// by-ref binding `ref (mut) self` and sub-patterns `@` are not allowed in receivers (rejected by rustc). + +use std::pin::Pin; + +struct Struct {} + +impl Struct { + fn take_ref_self(ref self: Pin<&mut Self>) {} //~ ERROR expected identifier, found keyword `self` + fn take_ref_mut_self(ref mut self: Pin<&mut Self>) {} //~ ERROR expected identifier, found keyword `self` + + fn self_subpat(self @ Struct {}: Self) {} //~ ERROR expected one of `)`, `,`, or `:`, found `@` +} + +fn main() {} diff --git a/tests/ui/pinned_drop/invalid-self.stderr b/tests/ui/pinned_drop/invalid-self.stderr new file mode 100644 index 0000000..a43e91d --- /dev/null +++ b/tests/ui/pinned_drop/invalid-self.stderr @@ -0,0 +1,25 @@ +error: expected identifier, found keyword `self` + --> $DIR/invalid-self.rs:8:26 + | +8 | fn take_ref_self(ref self: Pin<&mut Self>) {} //~ ERROR expected identifier, found keyword `self` + | ^^^^ expected identifier, found keyword + +error: expected identifier, found keyword `self` + --> $DIR/invalid-self.rs:9:34 + | +9 | fn take_ref_mut_self(ref mut self: Pin<&mut Self>) {} //~ ERROR expected identifier, found keyword `self` + | ^^^^ expected identifier, found keyword + +error: expected parameter name, found `@` + --> $DIR/invalid-self.rs:11:25 + | +11 | fn self_subpat(self @ Struct {}: Self) {} //~ ERROR expected one of `)`, `,`, or `:`, found `@` + | ^ expected parameter name + +error: expected one of `)`, `,`, or `:`, found `@` + --> $DIR/invalid-self.rs:11:25 + | +11 | fn self_subpat(self @ Struct {}: Self) {} //~ ERROR expected one of `)`, `,`, or `:`, found `@` + | -^ expected one of `)`, `,`, or `:` + | | + | help: missing `,` diff --git a/tests/ui/pinned_drop/invalid.rs b/tests/ui/pinned_drop/invalid.rs new file mode 100644 index 0000000..9ff5de2 --- /dev/null +++ b/tests/ui/pinned_drop/invalid.rs @@ -0,0 +1,207 @@ +mod argument { + use pin_project::{pin_project, pinned_drop}; + use std::pin::Pin; + + #[pin_project(PinnedDrop)] + struct UnexpectedArg1(()); + + #[pinned_drop(foo)] //~ ERROR unexpected token + impl PinnedDrop for UnexpectedArg1 { + fn drop(self: Pin<&mut Self>) {} + } + + #[pin_project(PinnedDrop)] + struct UnexpectedArg2(()); + + #[pinned_drop()] // Ok + impl PinnedDrop for UnexpectedArg2 { + fn drop(self: Pin<&mut Self>) {} + } +} + +mod attribute { + use pin_project::{pin_project, pinned_drop}; + + #[pin_project(PinnedDrop)] + struct Duplicate(()); + + #[pinned_drop] + #[pinned_drop] //~ ERROR duplicate #[pinned_drop] attribute + impl PinnedDrop for Duplicate { + fn drop(self: Pin<&mut Self>) {} + } +} + +mod item { + use pin_project::{pin_project, pinned_drop}; + + #[pin_project(PinnedDrop)] + struct TraitImpl(()); + + #[pinned_drop] + impl Drop for TraitImpl {} //~ ERROR may only be used on implementation for the `PinnedDrop` trait + + #[pin_project(PinnedDrop)] + struct InherentImpl(()); + + #[pinned_drop] + impl InherentImpl {} //~ ERROR may only be used on implementation for the `PinnedDrop` trait + + #[pinned_drop] + fn drop(_: Pin<&mut ()>) {} //~ ERROR expected `impl` +} + +mod unsafety { + use pin_project::{pin_project, pinned_drop}; + + #[pin_project(PinnedDrop)] + struct Impl(()); + + #[pinned_drop] + unsafe impl PinnedDrop for Impl { + //~^ ERROR implementing the trait `PinnedDrop` is not unsafe + fn drop(self: Pin<&mut Self>) {} + } + + #[pin_project(PinnedDrop)] + struct Method(()); + + #[pinned_drop] + impl PinnedDrop for Method { + unsafe fn drop(self: Pin<&mut Self>) {} //~ ERROR implementing the method `drop` is not unsafe + } +} + +mod assoc_item { + use pin_project::{pin_project, pinned_drop}; + + #[pin_project(PinnedDrop)] + struct Empty(()); + + #[pinned_drop] + impl PinnedDrop for Empty {} //~ ERROR not all trait items implemented, missing: `drop` + + #[pin_project(PinnedDrop)] + struct Const1(()); + + #[pinned_drop] + impl PinnedDrop for Const1 { + const A: u8 = 0; //~ ERROR const `A` is not a member of trait `PinnedDrop` + fn drop(self: Pin<&mut Self>) {} + } + + #[pin_project(PinnedDrop)] + struct Const2(()); + + #[pinned_drop] + impl PinnedDrop for Const2 { + fn drop(self: Pin<&mut Self>) {} + const A: u8 = 0; //~ ERROR const `A` is not a member of trait `PinnedDrop` + } + + #[pin_project(PinnedDrop)] + struct Type1(()); + + #[pinned_drop] + impl PinnedDrop for Type1 { + type A = u8; //~ ERROR type `A` is not a member of trait `PinnedDrop` + fn drop(self: Pin<&mut Self>) {} + } + + #[pin_project(PinnedDrop)] + struct Type2(()); + + #[pinned_drop] + impl PinnedDrop for Type2 { + fn drop(self: Pin<&mut Self>) {} + type A = u8; //~ ERROR type `A` is not a member of trait `PinnedDrop` + } + + #[pin_project(PinnedDrop)] + struct Duplicate(()); + + #[pinned_drop] + impl PinnedDrop for Duplicate { + fn drop(self: Pin<&mut Self>) {} + fn drop(self: Pin<&mut Self>) {} //~ ERROR duplicate definitions with name `drop` + } +} + +mod method { + use pin_project::{pin_project, pinned_drop}; + use std::pin::Pin; + + #[pin_project(PinnedDrop)] + struct RetUnit(()); + + #[pinned_drop] + impl PinnedDrop for RetUnit { + fn drop(self: Pin<&mut Self>) -> () {} // Ok + } + + #[pin_project(PinnedDrop)] + struct RetTy(()); + + #[pinned_drop] + impl PinnedDrop for RetTy { + fn drop(self: Pin<&mut Self>) -> Self {} //~ ERROR method `drop` must return the unit type + } + + #[pin_project(PinnedDrop)] + struct NoArg(()); + + #[pinned_drop] + impl PinnedDrop for NoArg { + fn drop() {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + } + + #[pin_project(PinnedDrop)] + struct MultiArg(()); + + #[pinned_drop] + impl PinnedDrop for MultiArg { + fn drop(self: Pin<&mut Self>, _: ()) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + } + + #[pin_project(PinnedDrop)] + struct InvalidArg1(()); + + #[pinned_drop] + impl PinnedDrop for InvalidArg1 { + fn drop(&mut self) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + } + + #[pin_project(PinnedDrop)] + struct InvalidArg2(()); + + #[pinned_drop] + impl PinnedDrop for InvalidArg2 { + fn drop(_: Pin<&mut Self>) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + } + + #[pin_project(PinnedDrop)] + struct InvalidArg3(()); + + #[pinned_drop] + impl PinnedDrop for InvalidArg3 { + fn drop(self: Pin<&Self>) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + } + + #[pin_project(PinnedDrop)] + struct InvalidArg4(()); + + #[pinned_drop] + impl PinnedDrop for InvalidArg4 { + fn drop(self: Pin<&mut ()>) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + } + + #[pin_project(PinnedDrop)] + struct InvalidName(()); + + #[pinned_drop] + impl PinnedDrop for InvalidName { + fn pinned_drop(&mut self) {} //~ ERROR method `pinned_drop` is not a member of trait `PinnedDrop + } +} + +fn main() {} diff --git a/tests/ui/pinned_drop/invalid.stderr b/tests/ui/pinned_drop/invalid.stderr new file mode 100644 index 0000000..8046903 --- /dev/null +++ b/tests/ui/pinned_drop/invalid.stderr @@ -0,0 +1,125 @@ +error: unexpected token: foo + --> $DIR/invalid.rs:8:19 + | +8 | #[pinned_drop(foo)] //~ ERROR unexpected token + | ^^^ + +error: duplicate #[pinned_drop] attribute + --> $DIR/invalid.rs:29:5 + | +29 | #[pinned_drop] //~ ERROR duplicate #[pinned_drop] attribute + | ^^^^^^^^^^^^^^ + +error: #[pinned_drop] may only be used on implementation for the `PinnedDrop` trait + --> $DIR/invalid.rs:42:10 + | +42 | impl Drop for TraitImpl {} //~ ERROR may only be used on implementation for the `PinnedDrop` trait + | ^^^^ + +error: #[pinned_drop] may only be used on implementation for the `PinnedDrop` trait + --> $DIR/invalid.rs:48:10 + | +48 | impl InherentImpl {} //~ ERROR may only be used on implementation for the `PinnedDrop` trait + | ^^^^^^^^^^^^ + +error: expected `impl` + --> $DIR/invalid.rs:51:5 + | +51 | fn drop(_: Pin<&mut ()>) {} //~ ERROR expected `impl` + | ^^ + +error: implementing the trait `PinnedDrop` is not unsafe + --> $DIR/invalid.rs:61:5 + | +61 | unsafe impl PinnedDrop for Impl { + | ^^^^^^ + +error: implementing the method `drop` is not unsafe + --> $DIR/invalid.rs:71:9 + | +71 | unsafe fn drop(self: Pin<&mut Self>) {} //~ ERROR implementing the method `drop` is not unsafe + | ^^^^^^ + +error: not all trait items implemented, missing: `drop` + --> $DIR/invalid.rs:82:5 + | +82 | impl PinnedDrop for Empty {} //~ ERROR not all trait items implemented, missing: `drop` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: const `A` is not a member of trait `PinnedDrop` + --> $DIR/invalid.rs:89:9 + | +89 | const A: u8 = 0; //~ ERROR const `A` is not a member of trait `PinnedDrop` + | ^^^^^^^^^^^^^^^^ + +error: const `A` is not a member of trait `PinnedDrop` + --> $DIR/invalid.rs:99:9 + | +99 | const A: u8 = 0; //~ ERROR const `A` is not a member of trait `PinnedDrop` + | ^^^^^^^^^^^^^^^^ + +error: type `A` is not a member of trait `PinnedDrop` + --> $DIR/invalid.rs:107:9 + | +107 | type A = u8; //~ ERROR type `A` is not a member of trait `PinnedDrop` + | ^^^^^^^^^^^^ + +error: type `A` is not a member of trait `PinnedDrop` + --> $DIR/invalid.rs:117:9 + | +117 | type A = u8; //~ ERROR type `A` is not a member of trait `PinnedDrop` + | ^^^^^^^^^^^^ + +error: duplicate definitions with name `drop` + --> $DIR/invalid.rs:126:9 + | +126 | fn drop(self: Pin<&mut Self>) {} //~ ERROR duplicate definitions with name `drop` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: method `drop` must return the unit type + --> $DIR/invalid.rs:147:42 + | +147 | fn drop(self: Pin<&mut Self>) -> Self {} //~ ERROR method `drop` must return the unit type + | ^^^^ + +error: method `drop` must take an argument `self: Pin<&mut Self>` + --> $DIR/invalid.rs:155:16 + | +155 | fn drop() {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + | ^^ + +error: method `drop` must take an argument `self: Pin<&mut Self>` + --> $DIR/invalid.rs:163:17 + | +163 | fn drop(self: Pin<&mut Self>, _: ()) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: method `drop` must take an argument `self: Pin<&mut Self>` + --> $DIR/invalid.rs:171:17 + | +171 | fn drop(&mut self) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + | ^^^^^^^^^ + +error: method `drop` must take an argument `self: Pin<&mut Self>` + --> $DIR/invalid.rs:179:17 + | +179 | fn drop(_: Pin<&mut Self>) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + | ^^^^^^^^^^^^^^^^^ + +error: method `drop` must take an argument `self: Pin<&mut Self>` + --> $DIR/invalid.rs:187:17 + | +187 | fn drop(self: Pin<&Self>) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + | ^^^^^^^^^^^^^^^^ + +error: method `drop` must take an argument `self: Pin<&mut Self>` + --> $DIR/invalid.rs:195:17 + | +195 | fn drop(self: Pin<&mut ()>) {} //~ ERROR method `drop` must take an argument `self: Pin<&mut Self>` + | ^^^^^^^^^^^^^^^^^^ + +error: method `pinned_drop` is not a member of trait `PinnedDrop + --> $DIR/invalid.rs:203:12 + | +203 | fn pinned_drop(&mut self) {} //~ ERROR method `pinned_drop` is not a member of trait `PinnedDrop + | ^^^^^^^^^^^ diff --git a/tests/ui/pinned_drop/pinned-drop-no-attr-arg.rs b/tests/ui/pinned_drop/pinned-drop-no-attr-arg.rs new file mode 100644 index 0000000..1241b5b --- /dev/null +++ b/tests/ui/pinned_drop/pinned-drop-no-attr-arg.rs @@ -0,0 +1,15 @@ +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +#[pin_project] +struct Foo { + #[pin] + field: u8, +} + +#[pinned_drop] +impl PinnedDrop for Foo { //~ ERROR E0119 + fn drop(self: Pin<&mut Self>) {} +} + +fn main() {} diff --git a/tests/ui/pinned_drop/pinned-drop-no-attr-arg.stderr b/tests/ui/pinned_drop/pinned-drop-no-attr-arg.stderr new file mode 100644 index 0000000..7353dc4 --- /dev/null +++ b/tests/ui/pinned_drop/pinned-drop-no-attr-arg.stderr @@ -0,0 +1,8 @@ +error[E0119]: conflicting implementations of trait `pin_project::__private::PinnedDrop` for type `Foo`: + --> $DIR/pinned-drop-no-attr-arg.rs:11:1 + | +4 | #[pin_project] + | -------------- first implementation here +... +11 | impl PinnedDrop for Foo { //~ ERROR E0119 + | ^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Foo` diff --git a/tests/ui/pinned_drop/self.rs b/tests/ui/pinned_drop/self.rs new file mode 100644 index 0000000..cd53b04 --- /dev/null +++ b/tests/ui/pinned_drop/self.rs @@ -0,0 +1,28 @@ +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +fn self_in_macro_def() { + #[pin_project(PinnedDrop)] + pub struct Struct { + x: usize, + } + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(self: Pin<&mut Self>) { + macro_rules! t { + () => {{ + let _ = self; //~ ERROR can't capture dynamic environment in a fn item + + fn f(self: ()) { + //~^ ERROR `self` parameter is only allowed in associated functions + let _ = self; + } + }}; + } + t!(); + } + } +} + +fn main() {} diff --git a/tests/ui/pinned_drop/self.stderr b/tests/ui/pinned_drop/self.stderr new file mode 100644 index 0000000..3ba333b --- /dev/null +++ b/tests/ui/pinned_drop/self.stderr @@ -0,0 +1,23 @@ +error: `self` parameter is only allowed in associated functions + --> $DIR/self.rs:17:26 + | +17 | fn f(self: ()) { + | ^^^^ not semantically valid as function parameter +... +23 | t!(); + | ----- in this macro invocation + | + = note: associated functions are those in `impl` or `trait` definitions + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0434]: can't capture dynamic environment in a fn item + --> $DIR/self.rs:15:29 + | +15 | let _ = self; //~ ERROR can't capture dynamic environment in a fn item + | ^^^^ +... +23 | t!(); + | ----- in this macro invocation + | + = help: use the `|| { ... }` closure form instead + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/pinned_drop/unsafe-call.rs b/tests/ui/pinned_drop/unsafe-call.rs new file mode 100644 index 0000000..2f400c1 --- /dev/null +++ b/tests/ui/pinned_drop/unsafe-call.rs @@ -0,0 +1,17 @@ +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +#[pin_project(PinnedDrop)] +struct Struct { + #[pin] + field: u8, +} + +#[pinned_drop] +impl PinnedDrop for Struct { + fn drop(self: Pin<&mut Self>) { + self.project().field.get_unchecked_mut(); //~ ERROR call to unsafe function is unsafe and requires unsafe function or block [E0133] + } +} + +fn main() {} diff --git a/tests/ui/pinned_drop/unsafe-call.stderr b/tests/ui/pinned_drop/unsafe-call.stderr new file mode 100644 index 0000000..4e8e00b --- /dev/null +++ b/tests/ui/pinned_drop/unsafe-call.stderr @@ -0,0 +1,7 @@ +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/unsafe-call.rs:13:9 + | +13 | self.project().field.get_unchecked_mut(); //~ ERROR call to unsafe function is unsafe and requires unsafe function or block [E0133] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior diff --git a/tests/ui/project/ambiguous-let.rs b/tests/ui/project/ambiguous-let.rs new file mode 100644 index 0000000..a706749 --- /dev/null +++ b/tests/ui/project/ambiguous-let.rs @@ -0,0 +1,24 @@ +use pin_project::{pin_project, project}; + +#[pin_project] +enum Enum { + A(#[pin] A), + B(B), +} + +struct Struct(T); + +#[project] +fn foo() { + let mut foo: Enum = Enum::A(true); + + #[project] + let Struct(x) = match Pin::new(&mut foo).project() { + //~^ ERROR Both initializer expression and pattern are replaceable, you need to split the initializer expression into separate let bindings to avoid ambiguity + Enum::A(_) => Struct(true), + Enum::B(_) => unreachable!(), + }; + assert!(x); +} + +fn main() {} diff --git a/tests/ui/project/ambiguous-let.stderr b/tests/ui/project/ambiguous-let.stderr new file mode 100644 index 0000000..e6552c8 --- /dev/null +++ b/tests/ui/project/ambiguous-let.stderr @@ -0,0 +1,5 @@ +error: Both initializer expression and pattern are replaceable, you need to split the initializer expression into separate let bindings to avoid ambiguity + --> $DIR/ambiguous-let.rs:16:9 + | +16 | let Struct(x) = match Pin::new(&mut foo).project() { + | ^^^^^^^^^ diff --git a/tests/ui/project/invalid.rs b/tests/ui/project/invalid.rs new file mode 100644 index 0000000..07e9970 --- /dev/null +++ b/tests/ui/project/invalid.rs @@ -0,0 +1,190 @@ +mod argument { + use pin_project::{pin_project, project}; + + #[pin_project] + struct A(#[pin] ()); + + #[project] + fn unexpected_local1() { + let mut x = A(()); + #[project()] //~ ERROR unexpected token + let A(_) = Pin::new(&mut x).project(); + } + + #[project] + fn unexpected_local1() { + let mut x = A(()); + #[project(foo)] //~ ERROR unexpected token + let A(_) = Pin::new(&mut x).project(); + } + + #[project] + fn unexpected_expr1() { + let mut x = A(()); + #[project()] //~ ERROR unexpected token + match Pin::new(&mut x).project() { + A(_) => {} + } + } + + #[project] + fn unexpected_expr1() { + let mut x = A(()); + #[project(foo)] //~ ERROR unexpected token + match Pin::new(&mut x).project() { + A(_) => {} + } + } + + #[project()] // Ok + fn unexpected_item1() {} + + #[project(foo)] //~ ERROR unexpected token + fn unexpected_item2() {} +} + +mod attribute { + use pin_project::{pin_project, project, project_ref, project_replace}; + + #[pin_project(Replace)] + struct A(#[pin] ()); + + #[project] + fn duplicate_stmt_project() { + let mut x = A(()); + #[project] + #[project] //~ ERROR duplicate #[project] attribute + let A(_) = Pin::new(&mut x).project(); + } + + #[project_ref] + fn duplicate_stmt_project_ref() { + let mut x = A(()); + #[project_ref] + #[project_ref] //~ ERROR duplicate #[project_ref] attribute + let A(_) = Pin::new(&mut x).project(); + } + + #[project_replace] + fn duplicate_stmt_project_replace() { + let mut x = A(()); + #[project_replace] + #[project_replace] //~ ERROR duplicate #[project_replace] attribute + let A(_) = Pin::new(&mut x).project(); + } + + #[project] + fn combine_stmt_project1() { + let mut x = A(()); + #[project] + #[project_ref] //~ ERROR are mutually exclusive + let A(_) = Pin::new(&mut x).project(); + } + + #[project] + fn combine_stmt_project2() { + let mut x = A(()); + #[project] + #[project_replace] //~ ERROR are mutually exclusive + let A(_) = Pin::new(&mut x).project(); + } + + #[project] + fn combine_stmt_project3() { + let mut x = A(()); + #[project_ref] + #[project_replace] //~ ERROR are mutually exclusive + let A(_) = Pin::new(&mut x).project(); + } + + #[project_ref] + fn combine_stmt_project_ref1() { + let mut x = A(()); + #[project] + #[project_ref] //~ ERROR are mutually exclusive + let A(_) = Pin::new(&mut x).project(); + } + + #[project_ref] + fn combine_stmt_project_ref2() { + let mut x = A(()); + #[project] + #[project_replace] //~ ERROR are mutually exclusive + let A(_) = Pin::new(&mut x).project(); + } + + #[project_ref] + fn combine_stmt_project_ref3() { + let mut x = A(()); + #[project_ref] + #[project_replace] //~ ERROR are mutually exclusive + let A(_) = Pin::new(&mut x).project(); + } + + #[project_replace] + fn combine_stmt_project_replace1() { + let mut x = A(()); + #[project] + #[project_ref] //~ ERROR are mutually exclusive + let A(_) = Pin::new(&mut x).project(); + } + + #[project_replace] + fn combine_stmt_project_replace2() { + let mut x = A(()); + #[project] + #[project_replace] //~ ERROR are mutually exclusive + let A(_) = Pin::new(&mut x).project(); + } + + #[project_replace] + fn combine_stmt_project_replace3() { + let mut x = A(()); + #[project_ref] + #[project_replace] //~ ERROR are mutually exclusive + let A(_) = Pin::new(&mut x).project(); + } + + #[project] + #[project] //~ ERROR duplicate #[project] attribute + fn duplicate_fn_project() {} + + #[project_ref] + #[project_ref] //~ ERROR duplicate #[project_ref] attribute + fn duplicate_fn_project_ref() {} + + #[project_replace] + #[project_replace] //~ ERROR duplicate #[project_replace] attribute + fn duplicate_fn_project_replace() {} + + #[project] + #[project] //~ ERROR duplicate #[project] attribute + impl A {} + + #[project_ref] + #[project_ref] //~ ERROR duplicate #[project_ref] attribute + impl A {} + + #[project_replace] + #[project_replace] //~ ERROR duplicate #[project_replace] attribute + impl A {} + + #[allow(unused_imports)] + mod use_ { + use pin_project::{project, project_ref, project_replace}; + + #[project] + #[project] //~ ERROR duplicate #[project] attribute + use super::A; + + #[project_ref] + #[project_ref] //~ ERROR duplicate #[project_ref] attribute + use super::A; + + #[project_replace] + #[project_replace] //~ ERROR duplicate #[project_replace] attribute + use super::A; + } +} + +fn main() {} diff --git a/tests/ui/project/invalid.stderr b/tests/ui/project/invalid.stderr new file mode 100644 index 0000000..287cac8 --- /dev/null +++ b/tests/ui/project/invalid.stderr @@ -0,0 +1,155 @@ +error: unexpected token: () + --> $DIR/invalid.rs:10:18 + | +10 | #[project()] //~ ERROR unexpected token + | ^^ + +error: unexpected token: (foo) + --> $DIR/invalid.rs:17:18 + | +17 | #[project(foo)] //~ ERROR unexpected token + | ^^^^^ + +error: unexpected token: () + --> $DIR/invalid.rs:24:18 + | +24 | #[project()] //~ ERROR unexpected token + | ^^ + +error: unexpected token: (foo) + --> $DIR/invalid.rs:33:18 + | +33 | #[project(foo)] //~ ERROR unexpected token + | ^^^^^ + +error: unexpected token: foo + --> $DIR/invalid.rs:42:15 + | +42 | #[project(foo)] //~ ERROR unexpected token + | ^^^ + +error: duplicate #[project] attribute + --> $DIR/invalid.rs:56:9 + | +56 | #[project] //~ ERROR duplicate #[project] attribute + | ^^^^^^^^^^ + +error: duplicate #[project_ref] attribute + --> $DIR/invalid.rs:64:9 + | +64 | #[project_ref] //~ ERROR duplicate #[project_ref] attribute + | ^^^^^^^^^^^^^^ + +error: duplicate #[project_replace] attribute + --> $DIR/invalid.rs:72:9 + | +72 | #[project_replace] //~ ERROR duplicate #[project_replace] attribute + | ^^^^^^^^^^^^^^^^^^ + +error: attributes `project_ref` and `project` are mutually exclusive + --> $DIR/invalid.rs:79:9 + | +79 | #[project] + | ^^^^^^^^^^ + +error: attributes `project` and `project_replace` are mutually exclusive + --> $DIR/invalid.rs:88:9 + | +88 | #[project_replace] //~ ERROR are mutually exclusive + | ^^^^^^^^^^^^^^^^^^ + +error: attributes `project_ref` and `project_replace` are mutually exclusive + --> $DIR/invalid.rs:96:9 + | +96 | #[project_replace] //~ ERROR are mutually exclusive + | ^^^^^^^^^^^^^^^^^^ + +error: attributes `project_ref` and `project` are mutually exclusive + --> $DIR/invalid.rs:103:9 + | +103 | #[project] + | ^^^^^^^^^^ + +error: attributes `project` and `project_replace` are mutually exclusive + --> $DIR/invalid.rs:112:9 + | +112 | #[project_replace] //~ ERROR are mutually exclusive + | ^^^^^^^^^^^^^^^^^^ + +error: attributes `project_ref` and `project_replace` are mutually exclusive + --> $DIR/invalid.rs:120:9 + | +120 | #[project_replace] //~ ERROR are mutually exclusive + | ^^^^^^^^^^^^^^^^^^ + +error: attributes `project_ref` and `project` are mutually exclusive + --> $DIR/invalid.rs:127:9 + | +127 | #[project] + | ^^^^^^^^^^ + +error: attributes `project` and `project_replace` are mutually exclusive + --> $DIR/invalid.rs:136:9 + | +136 | #[project_replace] //~ ERROR are mutually exclusive + | ^^^^^^^^^^^^^^^^^^ + +error: attributes `project_ref` and `project_replace` are mutually exclusive + --> $DIR/invalid.rs:144:9 + | +144 | #[project_replace] //~ ERROR are mutually exclusive + | ^^^^^^^^^^^^^^^^^^ + +error: duplicate #[project] attribute + --> $DIR/invalid.rs:149:5 + | +149 | #[project] //~ ERROR duplicate #[project] attribute + | ^^^^^^^^^^ + +error: duplicate #[project_ref] attribute + --> $DIR/invalid.rs:153:5 + | +153 | #[project_ref] //~ ERROR duplicate #[project_ref] attribute + | ^^^^^^^^^^^^^^ + +error: duplicate #[project_replace] attribute + --> $DIR/invalid.rs:157:5 + | +157 | #[project_replace] //~ ERROR duplicate #[project_replace] attribute + | ^^^^^^^^^^^^^^^^^^ + +error: duplicate #[project] attribute + --> $DIR/invalid.rs:161:5 + | +161 | #[project] //~ ERROR duplicate #[project] attribute + | ^^^^^^^^^^ + +error: duplicate #[project_ref] attribute + --> $DIR/invalid.rs:165:5 + | +165 | #[project_ref] //~ ERROR duplicate #[project_ref] attribute + | ^^^^^^^^^^^^^^ + +error: duplicate #[project_replace] attribute + --> $DIR/invalid.rs:169:5 + | +169 | #[project_replace] //~ ERROR duplicate #[project_replace] attribute + | ^^^^^^^^^^^^^^^^^^ + +error: duplicate #[project] attribute + --> $DIR/invalid.rs:177:9 + | +177 | #[project] //~ ERROR duplicate #[project] attribute + | ^^^^^^^^^^ + +error: duplicate #[project_ref] attribute + --> $DIR/invalid.rs:181:9 + | +181 | #[project_ref] //~ ERROR duplicate #[project_ref] attribute + | ^^^^^^^^^^^^^^ + +error: duplicate #[project_replace] attribute + --> $DIR/invalid.rs:185:9 + | +185 | #[project_replace] //~ ERROR duplicate #[project_replace] attribute + | ^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/project/type-mismatch.rs b/tests/ui/project/type-mismatch.rs new file mode 100644 index 0000000..41a70eb --- /dev/null +++ b/tests/ui/project/type-mismatch.rs @@ -0,0 +1,74 @@ +#![feature(proc_macro_hygiene, stmt_expr_attributes)] + +use pin_project::{pin_project, project}; +use std::pin::Pin; + +#[project] +fn type_mismatch() { + #[pin_project] + enum Enum { + Variant1(#[pin] A, B), + Variant2 { + #[pin] + field1: C, + field2: D, + }, + None, + } + + let mut foo = Enum::Variant1(1, 2); + let mut foo = Pin::new(&mut foo).project(); + + #[project] + match &mut foo { + Enum::Variant1(x, y) => { + let x: &mut Pin<&mut i32> = x; + assert_eq!(**x, 1); + + let y: &mut &mut i32 = y; + assert_eq!(**y, 2); + } + Enum::Variant2 { field1, field2 } => { + let _x: &mut Pin<&mut i32> = field1; + let _y: &mut &mut i32 = field2; + } + None => {} //~ ERROR mismatched types + } +} + +//~ ERROR mismatched types +// span is lost. +// Refs: https://github.com/rust-lang/rust/issues/43081 +fn type_mismatch_span_issue() { + #[pin_project] + enum Enum { + Variant1(#[pin] A, B), + Variant2 { + #[pin] + field1: C, + field2: D, + }, + None, + } + + let mut foo = Enum::Variant1(1, 2); + let mut foo = Pin::new(&mut foo).project(); + + #[project] + match &mut foo { + Enum::Variant1(x, y) => { + let x: &mut Pin<&mut i32> = x; + assert_eq!(**x, 1); + + let y: &mut &mut i32 = y; + assert_eq!(**y, 2); + } + Enum::Variant2 { field1, field2 } => { + let _x: &mut Pin<&mut i32> = field1; + let _y: &mut &mut i32 = field2; + } + None => {} + } +} + +fn main() {} diff --git a/tests/ui/project/type-mismatch.stderr b/tests/ui/project/type-mismatch.stderr new file mode 100644 index 0000000..b4c97d5 --- /dev/null +++ b/tests/ui/project/type-mismatch.stderr @@ -0,0 +1,16 @@ +error[E0308]: mismatched types + --> $DIR/type-mismatch.rs:35:9 + | +23 | match &mut foo { + | -------- this expression has type `&mut type_mismatch::__EnumProjection<'_, {integer}, {integer}, _, _>` +... +35 | None => {} //~ ERROR mismatched types + | ^^^^ expected enum `type_mismatch::__EnumProjection`, found enum `std::option::Option` + | + = note: expected enum `type_mismatch::__EnumProjection<'_, {integer}, {integer}, _, _>` + found enum `std::option::Option<_>` + +error[E0308]: mismatched types + | + = note: expected enum `type_mismatch_span_issue::__EnumProjection<'_, {integer}, {integer}, _, _>` + found enum `std::option::Option<_>` diff --git a/tests/ui/project/use-public.rs b/tests/ui/project/use-public.rs new file mode 100644 index 0000000..23c9b89 --- /dev/null +++ b/tests/ui/project/use-public.rs @@ -0,0 +1,15 @@ +use pin_project::pin_project; + +#[pin_project] +struct A { + field: u8, +} + +pub mod b { + use pin_project::project; + + #[project] + pub use crate::A; //~ ERROR E0365 +} + +fn main() {} diff --git a/tests/ui/project/use-public.stderr b/tests/ui/project/use-public.stderr new file mode 100644 index 0000000..7919d65 --- /dev/null +++ b/tests/ui/project/use-public.stderr @@ -0,0 +1,7 @@ +error[E0365]: `__AProjection` is private, and cannot be re-exported + --> $DIR/use-public.rs:12:13 + | +12 | pub use crate::A; //~ ERROR E0365 + | ^^^^^^^^ re-export of private `__AProjection` + | + = note: consider declaring type or module `__AProjection` with `pub` diff --git a/tests/ui/project/use.rs b/tests/ui/project/use.rs new file mode 100644 index 0000000..d4b02c1 --- /dev/null +++ b/tests/ui/project/use.rs @@ -0,0 +1,17 @@ +use pin_project::pin_project; + +#[pin_project] +struct A { + field: u8, +} + +mod b { + use pin_project::project; + + #[project] + use crate::A as B; //~ ERROR #[project] attribute may not be used on renamed imports + #[project] + use crate::*; //~ ERROR #[project] attribute may not be used on glob imports +} + +fn main() {} diff --git a/tests/ui/project/use.stderr b/tests/ui/project/use.stderr new file mode 100644 index 0000000..07d0241 --- /dev/null +++ b/tests/ui/project/use.stderr @@ -0,0 +1,11 @@ +error: #[project] attribute may not be used on renamed imports + --> $DIR/use.rs:12:16 + | +12 | use crate::A as B; //~ ERROR #[project] attribute may not be used on renamed imports + | ^^^^^^ + +error: #[project] attribute may not be used on glob imports + --> $DIR/use.rs:14:16 + | +14 | use crate::*; //~ ERROR #[project] attribute may not be used on glob imports + | ^ diff --git a/tests/ui/unsafe_unpin/conflict-unpin.rs b/tests/ui/unsafe_unpin/conflict-unpin.rs new file mode 100644 index 0000000..e0c8a7b --- /dev/null +++ b/tests/ui/unsafe_unpin/conflict-unpin.rs @@ -0,0 +1,30 @@ +use pin_project::pin_project; + +#[pin_project(UnsafeUnpin)] //~ ERROR E0119 +struct Foo { + #[pin] + future: T, + field: U, +} + +impl Unpin for Foo where T: Unpin {} + +#[pin_project(UnsafeUnpin)] //~ ERROR E0119 +struct Bar { + #[pin] + future: T, + field: U, +} + +impl Unpin for Bar {} + +#[pin_project(UnsafeUnpin)] //~ ERROR E0119 +struct Baz { + #[pin] + future: T, + field: U, +} + +impl Unpin for Baz {} + +fn main() {} diff --git a/tests/ui/unsafe_unpin/conflict-unpin.stderr b/tests/ui/unsafe_unpin/conflict-unpin.stderr new file mode 100644 index 0000000..62de016 --- /dev/null +++ b/tests/ui/unsafe_unpin/conflict-unpin.stderr @@ -0,0 +1,35 @@ +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Foo<_, _>`: + --> $DIR/conflict-unpin.rs:3:1 + | +3 | #[pin_project(UnsafeUnpin)] //~ ERROR E0119 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Foo<_, _>` +... +10 | impl Unpin for Foo where T: Unpin {} + | --------------------------------------------- first implementation here + | + = note: upstream crates may add a new impl of trait `pin_project::UnsafeUnpin` for type `pin_project::__private::Wrapper<'_, Foo<_, _>>` in future versions + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Bar<_, _>`: + --> $DIR/conflict-unpin.rs:12:1 + | +12 | #[pin_project(UnsafeUnpin)] //~ ERROR E0119 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Bar<_, _>` +... +19 | impl Unpin for Bar {} + | ------------------------------ first implementation here + | + = note: upstream crates may add a new impl of trait `pin_project::UnsafeUnpin` for type `pin_project::__private::Wrapper<'_, Bar<_, _>>` in future versions + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Baz<_, _>`: + --> $DIR/conflict-unpin.rs:21:1 + | +21 | #[pin_project(UnsafeUnpin)] //~ ERROR E0119 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Baz<_, _>` +... +28 | impl Unpin for Baz {} + | -------------------------------------------- first implementation here + | + = note: upstream crates may add a new impl of trait `pin_project::UnsafeUnpin` for type `pin_project::__private::Wrapper<'_, Baz<_, _>>` in future versions + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/unsafe_unpin/not-implement-unsafe-unpin.rs b/tests/ui/unsafe_unpin/not-implement-unsafe-unpin.rs new file mode 100644 index 0000000..429d60f --- /dev/null +++ b/tests/ui/unsafe_unpin/not-implement-unsafe-unpin.rs @@ -0,0 +1,14 @@ +use pin_project::pin_project; + +#[pin_project(UnsafeUnpin)] +struct Struct { + #[pin] + inner: T, + other: U, +} + +fn is_unpin() {} + +fn main() { + is_unpin::>(); //~ ERROR E0277 +} diff --git a/tests/ui/unsafe_unpin/not-implement-unsafe-unpin.stderr b/tests/ui/unsafe_unpin/not-implement-unsafe-unpin.stderr new file mode 100644 index 0000000..0baefe3 --- /dev/null +++ b/tests/ui/unsafe_unpin/not-implement-unsafe-unpin.stderr @@ -0,0 +1,11 @@ +error[E0277]: the trait bound `Struct<(), ()>: pin_project::UnsafeUnpin` is not satisfied + --> $DIR/not-implement-unsafe-unpin.rs:13:16 + | +10 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +13 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^ the trait `pin_project::UnsafeUnpin` is not implemented for `Struct<(), ()>` + | + = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, Struct<(), ()>>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Struct<(), ()>` diff --git a/tests/ui/unsafe_unpin/proper_unpin.rs b/tests/ui/unsafe_unpin/proper_unpin.rs new file mode 100644 index 0000000..6573aec --- /dev/null +++ b/tests/ui/unsafe_unpin/proper_unpin.rs @@ -0,0 +1,41 @@ +use pin_project::{pin_project, UnsafeUnpin}; +use std::marker::PhantomPinned; + +fn is_unpin() {} + +#[pin_project(UnsafeUnpin)] +struct Blah { + field1: U, + #[pin] + field2: T, +} + +unsafe impl UnsafeUnpin for Blah {} + +#[pin_project(UnsafeUnpin)] +struct TrivialBounds { + #[pin] + field1: PhantomPinned, +} + +#[pin_project(UnsafeUnpin)] +struct OverlappingLifetimeNames<'pin, T, U> { + #[pin] + field1: U, + #[pin] + field2: Option, + field3: &'pin (), +} + +unsafe impl UnsafeUnpin for OverlappingLifetimeNames<'_, T, U> {} + +fn main() { + is_unpin::>(); //~ ERROR E0277 + is_unpin::>(); // Ok + is_unpin::>(); //~ ERROR E0277 + + is_unpin::(); //~ ERROR E0277 + + is_unpin::>(); //~ ERROR E0277 + is_unpin::>(); //~ ERROR E0277 +} diff --git a/tests/ui/unsafe_unpin/proper_unpin.stderr b/tests/ui/unsafe_unpin/proper_unpin.stderr new file mode 100644 index 0000000..410dd0e --- /dev/null +++ b/tests/ui/unsafe_unpin/proper_unpin.stderr @@ -0,0 +1,63 @@ +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/proper_unpin.rs:33:5 + | +4 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +33 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `Blah` + = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, Blah>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Blah` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/proper_unpin.rs:35:5 + | +4 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +35 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `Blah` + = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, Blah>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `Blah` + +error[E0277]: the trait bound `TrivialBounds: pin_project::UnsafeUnpin` is not satisfied + --> $DIR/proper_unpin.rs:37:16 + | +4 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +37 | is_unpin::(); //~ ERROR E0277 + | ^^^^^^^^^^^^^ the trait `pin_project::UnsafeUnpin` is not implemented for `TrivialBounds` + | + = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, TrivialBounds>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `TrivialBounds` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/proper_unpin.rs:39:5 + | +4 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +39 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `OverlappingLifetimeNames<'_, std::marker::PhantomPinned, ()>` + = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, OverlappingLifetimeNames<'_, std::marker::PhantomPinned, ()>>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `OverlappingLifetimeNames<'_, std::marker::PhantomPinned, ()>` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/proper_unpin.rs:40:5 + | +4 | fn is_unpin() {} + | ----- required by this bound in `is_unpin` +... +40 | is_unpin::>(); //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `OverlappingLifetimeNames<'_, (), std::marker::PhantomPinned>` + = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, OverlappingLifetimeNames<'_, (), std::marker::PhantomPinned>>` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `OverlappingLifetimeNames<'_, (), std::marker::PhantomPinned>` diff --git a/tests/ui/unstable-features/README.md b/tests/ui/unstable-features/README.md new file mode 100644 index 0000000..b9215b6 --- /dev/null +++ b/tests/ui/unstable-features/README.md @@ -0,0 +1,5 @@ +# UI tests for unstable features + +These tests check how the guarantees and features provided by pin-project interact with unstable language features. + +The names of the files contained in this directory need to begin with the name of the feature. diff --git a/tests/ui/unstable-features/marker_trait_attr-feature-gate.rs b/tests/ui/unstable-features/marker_trait_attr-feature-gate.rs new file mode 100644 index 0000000..fa4b01e --- /dev/null +++ b/tests/ui/unstable-features/marker_trait_attr-feature-gate.rs @@ -0,0 +1,19 @@ +// NB: If you change this test, change 'marker_trait_attr.rs' at the same time. + +use pin_project::pin_project; +use std::marker::PhantomPinned; + +#[pin_project] //~ ERROR E0119 +struct Struct { + #[pin] + x: T, +} + +// unsound Unpin impl +impl Unpin for Struct {} + +fn is_unpin() {} + +fn main() { + is_unpin::>() +} diff --git a/tests/ui/unstable-features/marker_trait_attr-feature-gate.stderr b/tests/ui/unstable-features/marker_trait_attr-feature-gate.stderr new file mode 100644 index 0000000..bab534b --- /dev/null +++ b/tests/ui/unstable-features/marker_trait_attr-feature-gate.stderr @@ -0,0 +1,10 @@ +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Struct<_>`: + --> $DIR/marker_trait_attr-feature-gate.rs:6:1 + | +6 | #[pin_project] //~ ERROR E0119 + | ^^^^^^^^^^^^^^ conflicting implementation for `Struct<_>` +... +13 | impl Unpin for Struct {} + | --------------------------- first implementation here + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/unstable-features/marker_trait_attr.rs b/tests/ui/unstable-features/marker_trait_attr.rs new file mode 100644 index 0000000..0b8b30a --- /dev/null +++ b/tests/ui/unstable-features/marker_trait_attr.rs @@ -0,0 +1,25 @@ +// NB: If you change this test, change 'marker_trait_attr-feature-gate.rs' at the same time. + +// marker_trait_attr +// Tracking issue: https://github.com/rust-lang/rust/issues/29864 +#![feature(marker_trait_attr)] + +// See https://github.com/taiki-e/pin-project/issues/105#issuecomment-535355974 + +use pin_project::pin_project; +use std::marker::PhantomPinned; + +#[pin_project] //~ ERROR E0119 +struct Struct { + #[pin] + x: T, +} + +// unsound Unpin impl +impl Unpin for Struct {} + +fn is_unpin() {} + +fn main() { + is_unpin::>() +} diff --git a/tests/ui/unstable-features/marker_trait_attr.stderr b/tests/ui/unstable-features/marker_trait_attr.stderr new file mode 100644 index 0000000..9b3ec57 --- /dev/null +++ b/tests/ui/unstable-features/marker_trait_attr.stderr @@ -0,0 +1,10 @@ +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Struct<_>`: + --> $DIR/marker_trait_attr.rs:12:1 + | +12 | #[pin_project] //~ ERROR E0119 + | ^^^^^^^^^^^^^^ conflicting implementation for `Struct<_>` +... +19 | impl Unpin for Struct {} + | --------------------------- first implementation here + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/unstable-features/overlapping_marker_traits-feature-gate.rs b/tests/ui/unstable-features/overlapping_marker_traits-feature-gate.rs new file mode 100644 index 0000000..0bd4a32 --- /dev/null +++ b/tests/ui/unstable-features/overlapping_marker_traits-feature-gate.rs @@ -0,0 +1,19 @@ +// NB: If you change this test, change 'overlapping_marker_traits.rs' at the same time. + +use pin_project::pin_project; +use std::marker::PhantomPinned; + +#[pin_project] //~ ERROR E0119 +struct Struct { + #[pin] + x: T, +} + +// unsound Unpin impl +impl Unpin for Struct {} + +fn is_unpin() {} + +fn main() { + is_unpin::>() +} diff --git a/tests/ui/unstable-features/overlapping_marker_traits-feature-gate.stderr b/tests/ui/unstable-features/overlapping_marker_traits-feature-gate.stderr new file mode 100644 index 0000000..4a8e238 --- /dev/null +++ b/tests/ui/unstable-features/overlapping_marker_traits-feature-gate.stderr @@ -0,0 +1,10 @@ +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Struct<_>`: + --> $DIR/overlapping_marker_traits-feature-gate.rs:6:1 + | +6 | #[pin_project] //~ ERROR E0119 + | ^^^^^^^^^^^^^^ conflicting implementation for `Struct<_>` +... +13 | impl Unpin for Struct {} + | --------------------------- first implementation here + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/unstable-features/overlapping_marker_traits.rs b/tests/ui/unstable-features/overlapping_marker_traits.rs new file mode 100644 index 0000000..27d37a3 --- /dev/null +++ b/tests/ui/unstable-features/overlapping_marker_traits.rs @@ -0,0 +1,29 @@ +// NB: If you change this test, change 'overlapping_marker_traits-feature-gate.rs' at the same time. + +// This feature could break the guarantee for Unpin provided by pin-project, +// but was removed in https://github.com/rust-lang/rust/pull/68544 (nightly-2020-02-06). +// Refs: +// * https://github.com/rust-lang/rust/issues/29864#issuecomment-515780867. +// * https://github.com/taiki-e/pin-project/issues/105 + +// overlapping_marker_traits +// Tracking issue: https://github.com/rust-lang/rust/issues/29864 +#![feature(overlapping_marker_traits)] + +use pin_project::pin_project; +use std::marker::PhantomPinned; + +#[pin_project] +struct Struct { + #[pin] + x: T, +} + +// unsound Unpin impl +impl Unpin for Struct {} + +fn is_unpin() {} + +fn main() { + is_unpin::>() +} diff --git a/tests/ui/unstable-features/overlapping_marker_traits.stderr b/tests/ui/unstable-features/overlapping_marker_traits.stderr new file mode 100644 index 0000000..91aaf6c --- /dev/null +++ b/tests/ui/unstable-features/overlapping_marker_traits.stderr @@ -0,0 +1,18 @@ +error[E0557]: feature has been removed + --> $DIR/overlapping_marker_traits.rs:11:12 + | +11 | #![feature(overlapping_marker_traits)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ feature has been removed + | + = note: removed in favor of `#![feature(marker_trait_attr)]` + +error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Struct<_>`: + --> $DIR/overlapping_marker_traits.rs:16:1 + | +16 | #[pin_project] + | ^^^^^^^^^^^^^^ conflicting implementation for `Struct<_>` +... +23 | impl Unpin for Struct {} + | --------------------------- first implementation here + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/unstable-features/run-pass/stmt_expr_attributes.rs b/tests/ui/unstable-features/run-pass/stmt_expr_attributes.rs new file mode 100644 index 0000000..8ad8e41 --- /dev/null +++ b/tests/ui/unstable-features/run-pass/stmt_expr_attributes.rs @@ -0,0 +1,62 @@ +// NB: If you change this test, change 'stmt_expr_attributes-feature-gate.rs' at the same time. + +// proc_macro_hygiene +// Tracking issue: https://github.com/rust-lang/rust/issues/54727 +#![feature(proc_macro_hygiene)] +// stmt_expr_attributes +// Tracking issue: https://github.com/rust-lang/rust/issues/15701 +#![feature(stmt_expr_attributes)] + +use pin_project::{pin_project, project}; +use std::pin::Pin; + +fn project_stmt_expr_nightly() { + #[pin_project] + enum Baz { + Variant1(#[pin] A, B), + Variant2 { + #[pin] + field1: C, + field2: D, + }, + None, + } + + let mut baz = Baz::Variant1(1, 2); + + let mut baz = Pin::new(&mut baz).project(); + + #[project] + match &mut baz { + Baz::Variant1(x, y) => { + let x: &mut Pin<&mut i32> = x; + assert_eq!(**x, 1); + + let y: &mut &mut i32 = y; + assert_eq!(**y, 2); + } + Baz::Variant2 { field1, field2 } => { + let _x: &mut Pin<&mut i32> = field1; + let _y: &mut &mut i32 = field2; + } + Baz::None => {} + } + + let () = #[project] + match &mut baz { + Baz::Variant1(x, y) => { + let x: &mut Pin<&mut i32> = x; + assert_eq!(**x, 1); + + let y: &mut &mut i32 = y; + assert_eq!(**y, 2); + } + Baz::Variant2 { field1, field2 } => { + let _x: &mut Pin<&mut i32> = field1; + let _y: &mut &mut i32 = field2; + } + Baz::None => {} + }; +} + +fn main() {} diff --git a/tests/ui/unstable-features/stmt_expr_attributes-feature-gate.rs b/tests/ui/unstable-features/stmt_expr_attributes-feature-gate.rs new file mode 100644 index 0000000..8226723 --- /dev/null +++ b/tests/ui/unstable-features/stmt_expr_attributes-feature-gate.rs @@ -0,0 +1,55 @@ +// NB: If you change this test, change 'stmt_expr_attributes.rs' at the same time. + +use pin_project::{pin_project, project}; +use std::pin::Pin; + +fn project_stmt_expr_nightly() { + #[pin_project] + enum Enum { + Variant1(#[pin] A, B), + Variant2 { + #[pin] + field1: C, + field2: D, + }, + None, + } + + let mut baz = Enum::Variant1(1, 2); + + let mut baz = Pin::new(&mut baz).project(); + + #[project] //~ ERROR E0658 + match &mut baz { + Enum::Variant1(x, y) => { + let x: &mut Pin<&mut i32> = x; + assert_eq!(**x, 1); + + let y: &mut &mut i32 = y; + assert_eq!(**y, 2); + } + Enum::Variant2 { field1, field2 } => { + let _x: &mut Pin<&mut i32> = field1; + let _y: &mut &mut i32 = field2; + } + Enum::None => {} + } + + let () = #[project] //~ ERROR E0658 + match &mut baz { + Enum::Variant1(x, y) => { + let x: &mut Pin<&mut i32> = x; + assert_eq!(**x, 1); + + let y: &mut &mut i32 = y; + assert_eq!(**y, 2); + } + Enum::Variant2 { field1, field2 } => { + let _x: &mut Pin<&mut i32> = field1; + let _y: &mut &mut i32 = field2; + } + Enum::None => {} + }; +} + +fn main() {} diff --git a/tests/ui/unstable-features/stmt_expr_attributes-feature-gate.stderr b/tests/ui/unstable-features/stmt_expr_attributes-feature-gate.stderr new file mode 100644 index 0000000..6510ec7 --- /dev/null +++ b/tests/ui/unstable-features/stmt_expr_attributes-feature-gate.stderr @@ -0,0 +1,35 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attributes-feature-gate.rs:22:5 + | +22 | #[project] //~ ERROR E0658 + | ^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: attributes on expressions are experimental + --> $DIR/stmt_expr_attributes-feature-gate.rs:38:14 + | +38 | let () = #[project] //~ ERROR E0658 + | ^^^^^^^^^^ + | + = note: see issue #15701 for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error[E0658]: custom attributes cannot be applied to expressions + --> $DIR/stmt_expr_attributes-feature-gate.rs:22:5 + | +22 | #[project] //~ ERROR E0658 + | ^^^^^^^^^^ + | + = note: see issue #54727 for more information + = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable + +error[E0658]: custom attributes cannot be applied to expressions + --> $DIR/stmt_expr_attributes-feature-gate.rs:38:14 + | +38 | let () = #[project] //~ ERROR E0658 + | ^^^^^^^^^^ + | + = note: see issue #54727 for more information + = help: add `#![feature(proc_macro_hygiene)]` to the crate attributes to enable diff --git a/tests/ui/unstable-features/trivial_bounds-bug.rs b/tests/ui/unstable-features/trivial_bounds-bug.rs new file mode 100644 index 0000000..2ec4960 --- /dev/null +++ b/tests/ui/unstable-features/trivial_bounds-bug.rs @@ -0,0 +1,33 @@ +// NB: If you change this test, change 'trivial_bounds-feature-gate.rs' at the same time. + +// trivial_bounds +// Tracking issue: https://github.com/rust-lang/rust/issues/48214 +#![feature(trivial_bounds)] + +mod phantom_pinned { + use std::marker::{PhantomData, PhantomPinned}; + + struct A(PhantomPinned); + + // bug of trivial_bounds? + impl Unpin for A where PhantomPinned: Unpin {} //~ ERROR E0277 + + struct Wrapper(T); + + impl Unpin for Wrapper where T: Unpin {} + + struct B(PhantomPinned); + + impl Unpin for B where Wrapper: Unpin {} // Ok + + struct WrapperWithLifetime<'a, T>(PhantomData<&'a ()>, T); + + impl Unpin for WrapperWithLifetime<'_, T> where T: Unpin {} + + struct C(PhantomPinned); + + // Ok + impl<'a> Unpin for C where WrapperWithLifetime<'a, PhantomPinned>: Unpin {} +} + +fn main() {} diff --git a/tests/ui/unstable-features/trivial_bounds-bug.stderr b/tests/ui/unstable-features/trivial_bounds-bug.stderr new file mode 100644 index 0000000..7ddf10c --- /dev/null +++ b/tests/ui/unstable-features/trivial_bounds-bug.stderr @@ -0,0 +1,10 @@ +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/trivial_bounds-bug.rs:13:43 + | +13 | impl Unpin for A where PhantomPinned: Unpin {} //~ ERROR E0277 + | ^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + ::: /Users/taiki/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libcore/marker.rs:736:1 + | +736 | pub auto trait Unpin {} + | -------------------- required by this bound in `std::marker::Unpin` diff --git a/tests/ui/unstable-features/trivial_bounds-feature-gate.rs b/tests/ui/unstable-features/trivial_bounds-feature-gate.rs new file mode 100644 index 0000000..0453a3f --- /dev/null +++ b/tests/ui/unstable-features/trivial_bounds-feature-gate.rs @@ -0,0 +1,54 @@ +// NB: If you change this test, change 'trivial_bounds.rs' at the same time. + +mod phantom_pinned { + use std::marker::{PhantomData, PhantomPinned}; + + struct A(PhantomPinned); + + impl Unpin for A where PhantomPinned: Unpin {} //~ ERROR E0277 + + struct Wrapper(T); + + impl Unpin for Wrapper where T: Unpin {} + + struct B(PhantomPinned); + + impl Unpin for B where Wrapper: Unpin {} //~ ERROR E0277 + + struct WrapperWithLifetime<'a, T>(PhantomData<&'a ()>, T); + + impl Unpin for WrapperWithLifetime<'_, T> where T: Unpin {} + + struct C(PhantomPinned); + + impl<'a> Unpin for C where WrapperWithLifetime<'a, PhantomPinned>: Unpin {} + // Ok +} + +mod inner { + use std::marker::{PhantomData, PhantomPinned}; + + struct Inner(PhantomPinned); + + struct A(Inner); + + impl Unpin for A where Inner: Unpin {} //~ ERROR E0277 + + struct Wrapper(T); + + impl Unpin for Wrapper where T: Unpin {} + + struct B(Inner); + + impl Unpin for B where Wrapper: Unpin {} //~ ERROR E0277 + + struct WrapperWithLifetime<'a, T>(PhantomData<&'a ()>, T); + + impl Unpin for WrapperWithLifetime<'_, T> where T: Unpin {} + + struct C(Inner); + + impl<'a> Unpin for C where WrapperWithLifetime<'a, Inner>: Unpin {} // Ok +} + +fn main() {} diff --git a/tests/ui/unstable-features/trivial_bounds-feature-gate.stderr b/tests/ui/unstable-features/trivial_bounds-feature-gate.stderr new file mode 100644 index 0000000..31196a2 --- /dev/null +++ b/tests/ui/unstable-features/trivial_bounds-feature-gate.stderr @@ -0,0 +1,50 @@ +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/trivial_bounds-feature-gate.rs:8:5 + | +8 | impl Unpin for A where PhantomPinned: Unpin {} //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/trivial_bounds-feature-gate.rs:8:43 + | +8 | impl Unpin for A where PhantomPinned: Unpin {} //~ ERROR E0277 + | ^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + ::: /Users/taiki/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/src/rust/src/libcore/marker.rs:736:1 + | +736 | pub auto trait Unpin {} + | -------------------- required by this bound in `std::marker::Unpin` + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/trivial_bounds-feature-gate.rs:16:5 + | +16 | impl Unpin for B where Wrapper: Unpin {} //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because of the requirements on the impl of `std::marker::Unpin` for `phantom_pinned::Wrapper` + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/trivial_bounds-feature-gate.rs:35:5 + | +35 | impl Unpin for A where Inner: Unpin {} //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `inner::Inner`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `inner::Inner` + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: `std::marker::PhantomPinned` cannot be unpinned + --> $DIR/trivial_bounds-feature-gate.rs:43:5 + | +43 | impl Unpin for B where Wrapper: Unpin {} //~ ERROR E0277 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `inner::Inner`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned` + | + = note: required because it appears within the type `inner::Inner` + = note: required because of the requirements on the impl of `std::marker::Unpin` for `inner::Wrapper` + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable diff --git a/tests/ui/unstable-features/trivial_bounds.rs b/tests/ui/unstable-features/trivial_bounds.rs new file mode 100644 index 0000000..680effe --- /dev/null +++ b/tests/ui/unstable-features/trivial_bounds.rs @@ -0,0 +1,34 @@ +// NB: If you change this test, change 'trivial_bounds-feature-gate.rs' at the same time. + +// trivial_bounds +// Tracking issue: https://github.com/rust-lang/rust/issues/48214 +#![feature(trivial_bounds)] +#![deny(trivial_bounds)] + +use std::marker::{PhantomData, PhantomPinned}; + +fn inner() { + struct Inner(PhantomPinned); + + struct A(Inner); + + impl Unpin for A where Inner: Unpin {} //~ ERROR std::marker::Unpin does not depend on any type or lifetime parameters + + struct Wrapper(T); + + impl Unpin for Wrapper where T: Unpin {} + + struct B(Inner); + + impl Unpin for B where Wrapper: Unpin {} //~ ERROR std::marker::Unpin does not depend on any type or lifetime parameters + + struct WrapperWithLifetime<'a, T>(PhantomData<&'a ()>, T); + + impl Unpin for WrapperWithLifetime<'_, T> where T: Unpin {} + + struct C(Inner); + + impl<'a> Unpin for C where WrapperWithLifetime<'a, Inner>: Unpin {} // Ok +} + +fn main() {} diff --git a/tests/ui/unstable-features/trivial_bounds.stderr b/tests/ui/unstable-features/trivial_bounds.stderr new file mode 100644 index 0000000..03d0161 --- /dev/null +++ b/tests/ui/unstable-features/trivial_bounds.stderr @@ -0,0 +1,17 @@ +error: Trait bound inner::Inner: std::marker::Unpin does not depend on any type or lifetime parameters + --> $DIR/trivial_bounds.rs:15:35 + | +15 | impl Unpin for A where Inner: Unpin {} //~ ERROR std::marker::Unpin does not depend on any type or lifetime parameters + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/trivial_bounds.rs:6:9 + | +6 | #![deny(trivial_bounds)] + | ^^^^^^^^^^^^^^ + +error: Trait bound inner::Wrapper: std::marker::Unpin does not depend on any type or lifetime parameters + --> $DIR/trivial_bounds.rs:23:44 + | +23 | impl Unpin for B where Wrapper: Unpin {} //~ ERROR std::marker::Unpin does not depend on any type or lifetime parameters + | ^^^^^ diff --git a/tests/unsafe_unpin.rs b/tests/unsafe_unpin.rs new file mode 100644 index 0000000..5e0e7cf --- /dev/null +++ b/tests/unsafe_unpin.rs @@ -0,0 +1,53 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] +#![allow(dead_code)] + +use pin_project::{pin_project, UnsafeUnpin}; +use std::{marker::PhantomPinned, pin::Pin}; + +fn is_unpin() {} + +#[pin_project(UnsafeUnpin)] +pub struct Blah { + field1: U, + #[pin] + field2: T, +} + +unsafe impl UnsafeUnpin for Blah {} + +#[pin_project(UnsafeUnpin)] +pub struct OverlappingLifetimeNames<'pin, T, U> { + #[pin] + field1: T, + field2: U, + field3: &'pin (), +} + +unsafe impl UnsafeUnpin for OverlappingLifetimeNames<'_, T, U> {} + +#[test] +fn unsafe_unpin() { + is_unpin::>(); + is_unpin::>(); +} + +#[test] +fn trivial_bounds() { + #[pin_project(UnsafeUnpin)] + pub struct NotImplementUnsafUnpin { + #[pin] + field: PhantomPinned, + } +} + +#[test] +fn test() { + let mut x = OverlappingLifetimeNames { field1: 0, field2: 1, field3: &() }; + let x = Pin::new(&mut x); + let y = x.as_ref().project_ref(); + let _: Pin<&u8> = y.field1; + let _: &u8 = y.field2; + let y = x.project(); + let _: Pin<&mut u8> = y.field1; + let _: &mut u8 = y.field2; +} -- cgit v1.2.3