aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorJoel Galenson <jgalenson@google.com>2020-10-05 08:12:06 -0700
committerJoel Galenson <jgalenson@google.com>2020-10-05 08:12:06 -0700
commit9103268fc2400551dc7c32fc95a81f56aae5549b (patch)
tree2b05583cf437a2388364b8f684c187c0528b66a3 /tests
parentfea1d3e4f2bd05c6f081c7fa1a699635c4969c86 (diff)
downloadpin-project-lite-9103268fc2400551dc7c32fc95a81f56aae5549b.tar.gz
Import pin-project-lite-0.1.7
Test: None Change-Id: Ie9be88cf31e2aa79dc3bd59ae2007f2d6661d1d4
Diffstat (limited to 'tests')
-rw-r--r--tests/compiletest.rs8
-rw-r--r--tests/include/basic.rs10
-rw-r--r--tests/lint.rs90
-rw-r--r--tests/lint.txt138
-rw-r--r--tests/test.rs384
-rw-r--r--tests/ui/conflict-drop.rs15
-rw-r--r--tests/ui/conflict-drop.stderr16
-rw-r--r--tests/ui/conflict-unpin.rs40
-rw-r--r--tests/ui/conflict-unpin.stderr50
-rw-r--r--tests/ui/invalid-bounds.rs93
-rw-r--r--tests/ui/invalid-bounds.stderr134
-rw-r--r--tests/ui/invalid.rs25
-rw-r--r--tests/ui/invalid.stderr17
-rw-r--r--tests/ui/overlapping_lifetime_names.rs10
-rw-r--r--tests/ui/overlapping_lifetime_names.stderr75
-rw-r--r--tests/ui/overlapping_unpin_struct.rs19
-rw-r--r--tests/ui/overlapping_unpin_struct.stderr11
-rw-r--r--tests/ui/packed.rs19
-rw-r--r--tests/ui/packed.stderr55
-rw-r--r--tests/ui/proper_unpin.rs41
-rw-r--r--tests/ui/proper_unpin.stderr37
-rw-r--r--tests/ui/unpin_sneaky.rs12
-rw-r--r--tests/ui/unpin_sneaky.stderr11
-rw-r--r--tests/ui/unsupported.rs27
-rw-r--r--tests/ui/unsupported.stderr29
25 files changed, 1366 insertions, 0 deletions
diff --git a/tests/compiletest.rs b/tests/compiletest.rs
new file mode 100644
index 0000000..d181491
--- /dev/null
+++ b/tests/compiletest.rs
@@ -0,0 +1,8 @@
+#![warn(rust_2018_idioms, single_use_lifetimes)]
+
+#[rustversion::attr(not(nightly), ignore)]
+#[test]
+fn ui() {
+ let t = trybuild::TestCases::new();
+ t.compile_fail("tests/ui/*.rs");
+}
diff --git a/tests/include/basic.rs b/tests/include/basic.rs
new file mode 100644
index 0000000..967cf81
--- /dev/null
+++ b/tests/include/basic.rs
@@ -0,0 +1,10 @@
+// default pin_project! is completely safe.
+
+::pin_project_lite::pin_project! {
+ #[derive(Debug)]
+ pub struct DefaultStruct<T, U> {
+ #[pin]
+ pub pinned: T,
+ pub unpinned: U,
+ }
+}
diff --git a/tests/lint.rs b/tests/lint.rs
new file mode 100644
index 0000000..24491bb
--- /dev/null
+++ b/tests/lint.rs
@@ -0,0 +1,90 @@
+#![warn(rust_2018_idioms, single_use_lifetimes)]
+#![warn(future_incompatible, nonstandard_style, rust_2018_compatibility, unused)]
+#![warn(clippy::all, clippy::pedantic, clippy::nursery)]
+#![forbid(unsafe_code)]
+
+#[allow(unknown_lints)] // for old compilers
+#[warn(
+ absolute_paths_not_starting_with_crate,
+ anonymous_parameters,
+ box_pointers,
+ confusable_idents,
+ deprecated_in_future,
+ elided_lifetimes_in_paths,
+ explicit_outlives_requirements,
+ indirect_structural_match,
+ keyword_idents,
+ macro_use_extern_crate,
+ meta_variable_misuse,
+ missing_copy_implementations,
+ missing_crate_level_docs,
+ missing_debug_implementations,
+ missing_docs,
+ missing_doc_code_examples,
+ non_ascii_idents,
+ private_doc_tests,
+ single_use_lifetimes,
+ trivial_casts,
+ trivial_numeric_casts,
+ unaligned_references,
+ unreachable_pub,
+ unstable_features,
+ unused_extern_crates,
+ unused_import_braces,
+ unused_lifetimes,
+ unused_qualifications,
+ unused_results,
+ variant_size_differences
+)]
+// unused_crate_dependencies: unrelated
+// unsafe_code: checked in forbid_unsafe module
+// unsafe_block_in_unsafe_fn: unstable
+pub mod basic {
+ include!("include/basic.rs");
+}
+
+pub mod clippy {
+ use pin_project_lite::pin_project;
+
+ pin_project! {
+ pub struct MutMut<'a, T, U> {
+ #[pin]
+ pub pinned: &'a mut T,
+ pub unpinned: &'a mut U,
+ }
+ }
+
+ pin_project! {
+ pub struct TypeRepetitionInBoundsStruct<T, U>
+ where
+ TypeRepetitionInBoundsStruct<T, U>: Sized,
+ {
+ #[pin]
+ pub pinned: T,
+ pub unpinned: U,
+ }
+ }
+
+ pin_project! {
+ pub struct UsedUnderscoreBindingStruct<T, U> {
+ #[pin]
+ pub _pinned: T,
+ pub _unpinned: U,
+ }
+ }
+}
+
+#[rustversion::attr(not(nightly), ignore)]
+#[test]
+fn check_lint_list() {
+ use std::{env, process::Command};
+
+ (|| -> Result<(), Box<dyn std::error::Error>> {
+ let current = include_str!("lint.txt");
+ let rustc = env::var_os("RUSTC").unwrap_or_else(|| "rustc".into());
+ let new = String::from_utf8(Command::new(rustc).args(&["-W", "help"]).output()?.stdout)?;
+ assert_eq!(current, &new);
+ Ok(())
+ })()
+ .unwrap_or_else(|e| panic!("{}", e));
+}
diff --git a/tests/lint.txt b/tests/lint.txt
new file mode 100644
index 0000000..8de71e0
--- /dev/null
+++ b/tests/lint.txt
@@ -0,0 +1,138 @@
+
+Available lint options:
+ -W <foo> Warn about <foo>
+ -A <foo> Allow <foo>
+ -D <foo> Deny <foo>
+ -F <foo> Forbid <foo> (deny <foo> and all attempts to override)
+
+
+Lint checks provided by rustc:
+
+ name default meaning
+ ---- ------- -------
+ absolute-paths-not-starting-with-crate allow fully qualified paths that start with a module name instead of `crate`, `self`, or an extern crate name
+ anonymous-parameters allow detects anonymous parameters
+ box-pointers allow use of owned (Box type) heap memory
+ confusable-idents allow detects visually confusable pairs between identifiers
+ deprecated-in-future allow detects use of items that will be deprecated in a future version
+ elided-lifetimes-in-paths allow hidden lifetime parameters in types are deprecated
+ explicit-outlives-requirements allow outlives requirements can be inferred
+ indirect-structural-match allow pattern with const indirectly referencing non-structural-match type
+ keyword-idents allow detects edition keywords being used as an identifier
+ macro-use-extern-crate allow the `#[macro_use]` attribute is now deprecated in favor of using macros via the module system
+ meta-variable-misuse allow possible meta-variable misuse at macro definition
+ missing-copy-implementations allow detects potentially-forgotten implementations of `Copy`
+ missing-crate-level-docs allow detects crates with no crate-level documentation
+ missing-debug-implementations allow detects missing implementations of Debug
+ missing-docs allow detects missing documentation for public members
+ missing-doc-code-examples allow detects publicly-exported items without code samples in their documentation
+ non-ascii-idents allow detects non-ASCII identifiers
+ private-doc-tests allow detects code samples in docs of private items not documented by rustdoc
+ single-use-lifetimes allow detects lifetime parameters that are only used once
+ trivial-casts allow detects trivial casts which could be removed
+ trivial-numeric-casts allow detects trivial casts of numeric types which could be removed
+ unaligned-references allow detects unaligned references to fields of packed structs
+ unreachable-pub allow `pub` items not reachable from crate root
+ unsafe-code allow usage of `unsafe` code
+ unsafe-op-in-unsafe-fn allow unsafe operations in unsafe functions without an explicit unsafe block are deprecated
+ unstable-features allow enabling unstable features (deprecated. do not use)
+ unused-crate-dependencies allow crate dependencies that are never used
+ unused-extern-crates allow extern crates that are never used
+ unused-import-braces allow unnecessary braces around an imported item
+ unused-lifetimes allow detects lifetime parameters that are never used
+ unused-qualifications allow detects unnecessarily qualified names
+ unused-results allow unused result of an expression in a statement
+ variant-size-differences allow detects enums with widely varying variant sizes
+ array-into-iter warn detects calling `into_iter` on arrays
+ asm-sub-register warn using only a subset of a register for inline asm inputs
+ bare-trait-objects warn suggest using `dyn Trait` for trait objects
+ bindings-with-variant-name warn detects pattern bindings with the same name as one of the matched variants
+ coherence-leak-check warn distinct impls distinguished only by the leak-check code
+ dead-code warn detect unused, unexported items
+ deprecated warn detects use of deprecated items
+ ellipsis-inclusive-range-patterns warn `...` range patterns are deprecated
+ exported-private-dependencies warn public interface leaks type from a private dependency
+ illegal-floating-point-literal-pattern warn floating-point literals cannot be used in patterns
+ improper-ctypes warn proper use of libc types in foreign modules
+ incomplete-features warn incomplete features that may function improperly in some or all cases
+ inline-no-sanitize warn detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`
+ intra-doc-link-resolution-failure warn failures in resolving intra-doc link targets
+ invalid-codeblock-attribute warn codeblock attribute looks a lot like a known one
+ invalid-value warn an invalid value is being created (such as a NULL reference)
+ irrefutable-let-patterns warn detects irrefutable patterns in if-let and while-let statements
+ late-bound-lifetime-arguments warn detects generic lifetime arguments in path segments with late bound lifetime parameters
+ mutable-borrow-reservation-conflict warn reservation of a two-phased borrow conflicts with other shared borrows
+ non-camel-case-types warn types, variants, traits and type parameters should have camel case names
+ non-shorthand-field-patterns warn using `Struct { x: x }` instead of `Struct { x }` in a pattern
+ non-snake-case warn variables, methods, functions, lifetime parameters and modules should have snake case names
+ non-upper-case-globals warn static constants should have uppercase identifiers
+ no-mangle-generic-items warn generic items must be mangled
+ overlapping-patterns warn detects overlapping patterns
+ path-statements warn path statements with no effect
+ private-in-public warn detect private items in public interfaces not caught by the old implementation
+ proc-macro-derive-resolution-fallback warn detects proc macro derives using inaccessible names from parent modules
+ redundant-semicolons warn detects unnecessary trailing semicolons
+ renamed-and-removed-lints warn lints that have been renamed or removed
+ safe-packed-borrows warn safe borrows of fields of packed structs were erroneously allowed
+ stable-features warn stable features found in `#[feature]` directive
+ trivial-bounds warn these bounds don't depend on an type parameters
+ type-alias-bounds warn bounds in type aliases are not enforced
+ tyvar-behind-raw-pointer warn raw pointer to an inference variable
+ uncommon-codepoints warn detects uncommon Unicode codepoints in identifiers
+ unconditional-recursion warn functions that cannot return without calling themselves
+ unknown-lints warn unrecognized lint attribute
+ unnameable-test-items warn detects an item that cannot be named being marked as `#[test_case]`
+ unreachable-code warn detects unreachable code paths
+ unreachable-patterns warn detects unreachable patterns
+ unstable-name-collisions warn detects name collision with an existing but unstable method
+ unused-allocation warn detects unnecessary allocations that can be eliminated
+ unused-assignments warn detect assignments that will never be read
+ unused-attributes warn detects attributes that were not used by the compiler
+ unused-braces warn unnecessary braces around an expression
+ unused-comparisons warn comparisons made useless by limits of the types involved
+ unused-doc-comments warn detects doc comments that aren't used by rustdoc
+ unused-features warn unused features found in crate-level `#[feature]` directives
+ unused-imports warn imports that are never used
+ unused-labels warn detects labels that are never used
+ unused-macros warn detects macros that were not used
+ unused-must-use warn unused result of a type flagged as `#[must_use]`
+ unused-mut warn detect mut variables which don't need to be mutable
+ unused-parens warn `if`, `match`, `while` and `return` do not need parentheses
+ unused-unsafe warn unnecessary use of an `unsafe` block
+ unused-variables warn detect variables which are not used in any way
+ warnings warn mass-change the level for lints which produce warnings
+ where-clauses-object-safety warn checks the object safety of where clauses
+ while-true warn suggest using `loop { }` instead of `while true { }`
+ ambiguous-associated-items deny ambiguous associated items
+ arithmetic-overflow deny arithmetic operation overflows
+ conflicting-repr-hints deny conflicts between `#[repr(..)]` hints that were previously accepted and used in practice
+ const-err deny constant evaluation detected erroneous expression
+ ill-formed-attribute-input deny ill-formed attribute inputs that were previously accepted and used in practice
+ invalid-type-param-default deny type parameter default erroneously allowed in invalid location
+ macro-expanded-macro-exports-accessed-by-absolute-paths deny macro-expanded `macro_export` macros from the current crate cannot be referred to by absolute paths
+ missing-fragment-specifier deny detects missing fragment specifiers in unused `macro_rules!` patterns
+ mutable-transmutes deny mutating transmuted &mut T from &T may cause undefined behavior
+ no-mangle-const-items deny const items will not have their symbols exported
+ order-dependent-trait-objects deny trait-object types were treated as different depending on marker-trait order
+ overflowing-literals deny literal out of range for its type
+ patterns-in-fns-without-body deny patterns in functions without body were erroneously allowed
+ pub-use-of-private-extern-crate deny detect public re-exports of private extern crates
+ soft-unstable deny a feature gate that doesn't break dependent crates
+ unconditional-panic deny operation will cause a panic at runtime
+ unknown-crate-types deny unknown crate type found in `#[crate_type]` directive
+
+
+Lint groups provided by rustc:
+
+ name sub-lints
+ ---- ---------
+ warnings all lints that are set to issue warnings
+ future-incompatible keyword-idents, anonymous-parameters, illegal-floating-point-literal-pattern, private-in-public, pub-use-of-private-extern-crate, invalid-type-param-default, safe-packed-borrows, patterns-in-fns-without-body, missing-fragment-specifier, late-bound-lifetime-arguments, order-dependent-trait-objects, coherence-leak-check, tyvar-behind-raw-pointer, absolute-paths-not-starting-with-crate, unstable-name-collisions, where-clauses-object-safety, proc-macro-derive-resolution-fallback, macro-expanded-macro-exports-accessed-by-absolute-paths, ill-formed-attribute-input, conflicting-repr-hints, ambiguous-associated-items, mutable-borrow-reservation-conflict, indirect-structural-match, soft-unstable, array-into-iter
+ nonstandard-style non-camel-case-types, non-snake-case, non-upper-case-globals
+ rust-2018-compatibility keyword-idents, anonymous-parameters, tyvar-behind-raw-pointer, absolute-paths-not-starting-with-crate
+ rust-2018-idioms bare-trait-objects, unused-extern-crates, ellipsis-inclusive-range-patterns, elided-lifetimes-in-paths, explicit-outlives-requirements
+ rustdoc intra-doc-link-resolution-failure, invalid-codeblock-attribute, missing-doc-code-examples, private-doc-tests
+ unused unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, overlapping-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comments, unused-extern-crates, unused-features, unused-labels, unused-parens, unused-braces, redundant-semicolons
+
+
+Compiler plugins can provide additional lints and lint groups. To see a listing of these, re-run `rustc -W help` with a crate filename.
diff --git a/tests/test.rs b/tests/test.rs
new file mode 100644
index 0000000..06ec259
--- /dev/null
+++ b/tests/test.rs
@@ -0,0 +1,384 @@
+#![no_std]
+#![warn(rust_2018_idioms, single_use_lifetimes)]
+#![allow(dead_code)]
+
+use core::{marker::PhantomPinned, pin::Pin};
+use pin_project_lite::pin_project;
+
+#[test]
+fn projection() {
+ pin_project! {
+ struct Struct<T, U> {
+ #[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 s = Pin::new(&mut s).project();
+
+ let _: Pin<&mut i32> = s.field1;
+ let _: &mut i32 = s.field2;
+}
+
+#[test]
+fn where_clause() {
+ pin_project! {
+ struct Struct<T>
+ where
+ T: Copy,
+ {
+ field: T,
+ }
+ }
+}
+
+#[test]
+fn where_clause_and_associated_type_field() {
+ pin_project! {
+ struct Struct1<I>
+ where
+ I: Iterator,
+ {
+ #[pin]
+ field1: I,
+ field2: I::Item,
+ }
+ }
+
+ pin_project! {
+ struct Struct2<I, J>
+ where
+ I: Iterator<Item = J>,
+ {
+ #[pin]
+ field1: I,
+ field2: J,
+ }
+ }
+
+ pin_project! {
+ pub struct Struct3<T>
+ where
+ T: 'static,
+ {
+ field: T,
+ }
+ }
+
+ trait Static: 'static {}
+
+ impl<T> Static for Struct3<T> {}
+}
+
+#[test]
+fn derive_copy() {
+ pin_project! {
+ #[derive(Clone, Copy)]
+ struct Struct<T> {
+ val: T,
+ }
+ }
+
+ fn is_copy<T: Copy>() {}
+
+ is_copy::<Struct<u8>>();
+}
+
+#[test]
+fn move_out() {
+ struct NotCopy;
+
+ pin_project! {
+ struct Struct {
+ val: NotCopy,
+ }
+ }
+
+ let x = Struct { val: NotCopy };
+ let _val: NotCopy = x.val;
+}
+
+#[test]
+fn trait_bounds_on_type_generics() {
+ pin_project! {
+ pub struct Struct1<'a, T: ?Sized> {
+ field: &'a mut T,
+ }
+ }
+
+ pin_project! {
+ pub struct Struct2<'a, T: ::core::fmt::Debug> {
+ field: &'a mut T,
+ }
+ }
+
+ pin_project! {
+ pub struct Struct3<'a, T: core::fmt::Debug> {
+ field: &'a mut T,
+ }
+ }
+
+ // pin_project! {
+ // pub struct Struct4<'a, T: core::fmt::Debug + core::fmt::Display> {
+ // field: &'a mut T,
+ // }
+ // }
+
+ // pin_project! {
+ // pub struct Struct5<'a, T: core::fmt::Debug + ?Sized> {
+ // field: &'a mut T,
+ // }
+ // }
+
+ pin_project! {
+ pub struct Struct6<'a, T: core::fmt::Debug = [u8; 16]> {
+ field: &'a mut T,
+ }
+ }
+
+ let _: Struct6<'_> = Struct6 { field: &mut [0u8; 16] };
+
+ pin_project! {
+ pub struct Struct7<T: 'static> {
+ field: T,
+ }
+ }
+
+ trait Static: 'static {}
+
+ impl<T> Static for Struct7<T> {}
+
+ pin_project! {
+ pub struct Struct8<'a, 'b: 'a> {
+ field1: &'a u8,
+ field2: &'b u8,
+ }
+ }
+}
+
+#[test]
+fn private_type_in_public_type() {
+ pin_project! {
+ pub struct PublicStruct<T> {
+ #[pin]
+ inner: PrivateStruct<T>,
+ }
+ }
+
+ struct PrivateStruct<T>(T);
+}
+
+#[test]
+fn lifetime_project() {
+ pin_project! {
+ struct Struct1<T, U> {
+ #[pin]
+ pinned: T,
+ unpinned: U,
+ }
+ }
+
+ pin_project! {
+ struct Struct2<'a, T, U> {
+ #[pin]
+ pinned: &'a mut T,
+ unpinned: U,
+ }
+ }
+
+ impl<T, U> Struct1<T, U> {
+ 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
+ }
+ }
+}
+
+#[test]
+fn lifetime_project_elided() {
+ pin_project! {
+ struct Struct1<T, U> {
+ #[pin]
+ pinned: T,
+ unpinned: U,
+ }
+ }
+
+ pin_project! {
+ struct Struct2<'a, T, U> {
+ #[pin]
+ pinned: &'a mut T,
+ unpinned: U,
+ }
+ }
+
+ impl<T, U> Struct1<T, U> {
+ 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
+ }
+ }
+}
+
+mod visibility {
+ use pin_project_lite::pin_project;
+
+ pin_project! {
+ 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! {
+ pub struct NoGenerics {
+ #[pin]
+ field: PhantomPinned,
+ }
+ }
+}
+
+#[test]
+fn dst() {
+ pin_project! {
+ pub struct Struct1<T: ?Sized> {
+ x: T,
+ }
+ }
+
+ let mut x = Struct1 { x: 0_u8 };
+ let x: Pin<&mut Struct1<dyn core::fmt::Debug>> = Pin::new(&mut x as _);
+ let _y: &mut (dyn core::fmt::Debug) = x.project().x;
+
+ pin_project! {
+ pub struct Struct2<T: ?Sized> {
+ #[pin]
+ x: T,
+ }
+ }
+
+ let mut x = Struct2 { x: 0_u8 };
+ let x: Pin<&mut Struct2<dyn core::fmt::Debug + Unpin>> = Pin::new(&mut x as _);
+ let _y: Pin<&mut (dyn core::fmt::Debug + Unpin)> = x.project().x;
+}
+
+#[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993
+#[test]
+fn unsized_in_where_clause() {
+ pin_project! {
+ struct Struct3<T>
+ where
+ T: ?Sized,
+ {
+ x: T,
+ }
+ }
+
+ pin_project! {
+ struct Struct4<T>
+ where
+ T: ?Sized,
+ {
+ #[pin]
+ x: T,
+ }
+ }
+}
+
+#[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,
+ }
+ }
+}
+
+#[test]
+fn no_infer_outlives() {
+ trait Bar<X> {
+ type Y;
+ }
+
+ struct Example<A>(A);
+
+ impl<X, T> Bar<X> for Example<T> {
+ type Y = Option<T>;
+ }
+
+ pin_project! {
+ struct Foo<A, B> {
+ _x: <Example<A> as Bar<B>>::Y,
+ }
+ }
+}
diff --git a/tests/ui/conflict-drop.rs b/tests/ui/conflict-drop.rs
new file mode 100644
index 0000000..870059d
--- /dev/null
+++ b/tests/ui/conflict-drop.rs
@@ -0,0 +1,15 @@
+use pin_project_lite::pin_project;
+
+pin_project! { //~ ERROR E0119
+ struct Foo<T, U> {
+ #[pin]
+ future: T,
+ field: U,
+ }
+}
+
+impl<T, U> Drop for Foo<T, U> {
+ fn drop(&mut self) {}
+}
+
+fn main() {}
diff --git a/tests/ui/conflict-drop.stderr b/tests/ui/conflict-drop.stderr
new file mode 100644
index 0000000..f97c92b
--- /dev/null
+++ b/tests/ui/conflict-drop.stderr
@@ -0,0 +1,16 @@
+error[E0119]: conflicting implementations of trait `_::MustNotImplDrop` for type `Foo<_, _>`:
+ --> $DIR/conflict-drop.rs:3:1
+ |
+3 | / pin_project! { //~ ERROR E0119
+4 | | struct Foo<T, U> {
+5 | | #[pin]
+6 | | future: T,
+7 | | field: U,
+8 | | }
+9 | | }
+ | | ^
+ | | |
+ | |_first implementation here
+ | conflicting implementation for `Foo<_, _>`
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/conflict-unpin.rs b/tests/ui/conflict-unpin.rs
new file mode 100644
index 0000000..f702f06
--- /dev/null
+++ b/tests/ui/conflict-unpin.rs
@@ -0,0 +1,40 @@
+use pin_project_lite::pin_project;
+
+// The same implementation.
+
+pin_project! { //~ ERROR E0119
+ struct Foo<T, U> {
+ #[pin]
+ future: T,
+ field: U,
+ }
+}
+
+// conflicting implementations
+impl<T, U> Unpin for Foo<T, U> where T: Unpin {} // Conditional Unpin impl
+
+// The implementation that under different conditions.
+
+pin_project! { //~ ERROR E0119
+ struct Bar<T, U> {
+ #[pin]
+ future: T,
+ field: U,
+ }
+}
+
+// conflicting implementations
+impl<T, U> Unpin for Bar<T, U> {} // Non-conditional Unpin impl
+
+pin_project! { //~ ERROR E0119
+ struct Baz<T, U> {
+ #[pin]
+ future: T,
+ field: U,
+ }
+}
+
+// conflicting implementations
+impl<T: Unpin, U: Unpin> Unpin for Baz<T, U> {} // Conditional Unpin impl
+
+fn main() {}
diff --git a/tests/ui/conflict-unpin.stderr b/tests/ui/conflict-unpin.stderr
new file mode 100644
index 0000000..546dafd
--- /dev/null
+++ b/tests/ui/conflict-unpin.stderr
@@ -0,0 +1,50 @@
+error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Foo<_, _>`:
+ --> $DIR/conflict-unpin.rs:5:1
+ |
+5 | / pin_project! { //~ ERROR E0119
+6 | | struct Foo<T, U> {
+7 | | #[pin]
+8 | | future: T,
+9 | | field: U,
+10 | | }
+11 | | }
+ | |_^ conflicting implementation for `Foo<_, _>`
+...
+14 | impl<T, U> Unpin for Foo<T, U> where T: Unpin {} // Conditional Unpin impl
+ | --------------------------------------------- first implementation here
+ |
+ = note: this error originates in a 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:18:1
+ |
+18 | / pin_project! { //~ ERROR E0119
+19 | | struct Bar<T, U> {
+20 | | #[pin]
+21 | | future: T,
+22 | | field: U,
+23 | | }
+24 | | }
+ | |_^ conflicting implementation for `Bar<_, _>`
+...
+27 | impl<T, U> Unpin for Bar<T, U> {} // Non-conditional Unpin impl
+ | ------------------------------ first implementation here
+ |
+ = note: this error originates in a 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:29:1
+ |
+29 | / pin_project! { //~ ERROR E0119
+30 | | struct Baz<T, U> {
+31 | | #[pin]
+32 | | future: T,
+33 | | field: U,
+34 | | }
+35 | | }
+ | |_^ conflicting implementation for `Baz<_, _>`
+...
+38 | impl<T: Unpin, U: Unpin> Unpin for Baz<T, U> {} // Conditional Unpin impl
+ | -------------------------------------------- first implementation here
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/invalid-bounds.rs b/tests/ui/invalid-bounds.rs
new file mode 100644
index 0000000..64b397a
--- /dev/null
+++ b/tests/ui/invalid-bounds.rs
@@ -0,0 +1,93 @@
+use pin_project_lite::pin_project;
+
+pin_project! {
+ struct Generics1<T: 'static : Sized> { //~ ERROR no rules expected the token `:`
+ field: T,
+ }
+}
+
+pin_project! {
+ struct Generics2<T: 'static : ?Sized> { //~ ERROR no rules expected the token `:`
+ field: T,
+ }
+}
+
+pin_project! {
+ struct Generics3<T: Sized : 'static> { //~ ERROR expected one of `+`, `,`, `=`, or `>`, found `:`
+ field: T,
+ }
+}
+
+pin_project! {
+ struct Generics4<T: ?Sized : 'static> { //~ ERROR expected one of `+`, `,`, `=`, or `>`, found `:`
+ field: T,
+ }
+}
+
+pin_project! {
+ struct Generics5<T: Sized : ?Sized> { //~ ERROR expected one of `+`, `,`, `=`, or `>`, found `:`
+ field: T,
+ }
+}
+
+pin_project! {
+ struct Generics6<T: ?Sized : Sized> { //~ ERROR no rules expected the token `Sized`
+ field: T,
+ }
+}
+
+pin_project! {
+ struct WhereClause1<T>
+ where
+ T: 'static : Sized //~ ERROR no rules expected the token `:`
+ {
+ field: T,
+ }
+}
+
+pin_project! {
+ struct WhereClause2<T>
+ where
+ T: 'static : ?Sized //~ ERROR no rules expected the token `:`
+ {
+ field: T,
+ }
+}
+
+pin_project! {
+ struct WhereClause3<T>
+ where
+ T: Sized : 'static //~ ERROR expected `where`, or `{` after struct name, found `:`
+ {
+ field: T,
+ }
+}
+
+pin_project! {
+ struct WhereClause4<T>
+ where
+ T: ?Sized : 'static //~ ERROR expected `where`, or `{` after struct name, found `:`
+ {
+ field: T,
+ }
+}
+
+pin_project! {
+ struct WhereClause5<T>
+ where
+ T: Sized : ?Sized //~ ERROR expected `where`, or `{` after struct name, found `:`
+ {
+ field: T,
+ }
+}
+
+pin_project! {
+ struct WhereClause6<T>
+ where
+ T: ?Sized : Sized //~ ERROR no rules expected the token `Sized`
+ {
+ field: T,
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/invalid-bounds.stderr b/tests/ui/invalid-bounds.stderr
new file mode 100644
index 0000000..59e9b13
--- /dev/null
+++ b/tests/ui/invalid-bounds.stderr
@@ -0,0 +1,134 @@
+error: no rules expected the token `:`
+ --> $DIR/invalid-bounds.rs:4:33
+ |
+4 | struct Generics1<T: 'static : Sized> { //~ ERROR no rules expected the token `:`
+ | ^ no rules expected this token in macro call
+
+error: no rules expected the token `:`
+ --> $DIR/invalid-bounds.rs:10:33
+ |
+10 | struct Generics2<T: 'static : ?Sized> { //~ ERROR no rules expected the token `:`
+ | ^ no rules expected this token in macro call
+
+error: expected one of `+`, `,`, `=`, or `>`, found `:`
+ --> $DIR/invalid-bounds.rs:15:1
+ |
+15 | / pin_project! {
+16 | | struct Generics3<T: Sized : 'static> { //~ ERROR expected one of `+`, `,`, `=`, or `>`, found `:`
+17 | | field: T,
+18 | | }
+19 | | }
+ | | ^
+ | | |
+ | | expected one of `+`, `,`, `=`, or `>`
+ | |_unexpected token
+ | in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected one of `+`, `,`, `=`, or `>`, found `:`
+ --> $DIR/invalid-bounds.rs:21:1
+ |
+21 | / pin_project! {
+22 | | struct Generics4<T: ?Sized : 'static> { //~ ERROR expected one of `+`, `,`, `=`, or `>`, found `:`
+23 | | field: T,
+24 | | }
+25 | | }
+ | | ^
+ | | |
+ | | expected one of `+`, `,`, `=`, or `>`
+ | |_unexpected token
+ | in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected one of `+`, `,`, `=`, or `>`, found `:`
+ --> $DIR/invalid-bounds.rs:27:1
+ |
+27 | / pin_project! {
+28 | | struct Generics5<T: Sized : ?Sized> { //~ ERROR expected one of `+`, `,`, `=`, or `>`, found `:`
+29 | | field: T,
+30 | | }
+31 | | }
+ | | ^
+ | | |
+ | | expected one of `+`, `,`, `=`, or `>`
+ | |_unexpected token
+ | in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: no rules expected the token `Sized`
+ --> $DIR/invalid-bounds.rs:34:34
+ |
+34 | struct Generics6<T: ?Sized : Sized> { //~ ERROR no rules expected the token `Sized`
+ | ^^^^^ no rules expected this token in macro call
+
+error: no rules expected the token `:`
+ --> $DIR/invalid-bounds.rs:42:20
+ |
+42 | T: 'static : Sized //~ ERROR no rules expected the token `:`
+ | ^ no rules expected this token in macro call
+
+error: no rules expected the token `:`
+ --> $DIR/invalid-bounds.rs:51:20
+ |
+51 | T: 'static : ?Sized //~ ERROR no rules expected the token `:`
+ | ^ no rules expected this token in macro call
+
+error: expected `where`, or `{` after struct name, found `:`
+ --> $DIR/invalid-bounds.rs:57:1
+ |
+57 | / pin_project! {
+58 | | struct WhereClause3<T>
+59 | | where
+60 | | T: Sized : 'static //~ ERROR expected `where`, or `{` after struct name, found `:`
+... |
+63 | | }
+64 | | }
+ | | ^
+ | | |
+ | |_expected `where`, or `{` after struct name
+ | in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected `where`, or `{` after struct name, found `:`
+ --> $DIR/invalid-bounds.rs:66:1
+ |
+66 | / pin_project! {
+67 | | struct WhereClause4<T>
+68 | | where
+69 | | T: ?Sized : 'static //~ ERROR expected `where`, or `{` after struct name, found `:`
+... |
+72 | | }
+73 | | }
+ | | ^
+ | | |
+ | |_expected `where`, or `{` after struct name
+ | in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: expected `where`, or `{` after struct name, found `:`
+ --> $DIR/invalid-bounds.rs:75:1
+ |
+75 | / pin_project! {
+76 | | struct WhereClause5<T>
+77 | | where
+78 | | T: Sized : ?Sized //~ ERROR expected `where`, or `{` after struct name, found `:`
+... |
+81 | | }
+82 | | }
+ | | ^
+ | | |
+ | |_expected `where`, or `{` after struct name
+ | in this macro invocation
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: no rules expected the token `Sized`
+ --> $DIR/invalid-bounds.rs:87:21
+ |
+87 | T: ?Sized : Sized //~ ERROR no rules expected the token `Sized`
+ | ^^^^^ no rules expected this token in macro call
diff --git a/tests/ui/invalid.rs b/tests/ui/invalid.rs
new file mode 100644
index 0000000..e0ea61d
--- /dev/null
+++ b/tests/ui/invalid.rs
@@ -0,0 +1,25 @@
+use pin_project_lite::pin_project;
+
+pin_project! {
+ struct A<T> {
+ #[pin()] //~ ERROR no rules expected the token `(`
+ pinned: T,
+ }
+}
+
+pin_project! {
+ #[pin] //~ ERROR cannot find attribute `pin` in this scope
+ struct B<T> {
+ pinned: T,
+ }
+}
+
+pin_project! {
+ struct C<T> {
+ #[pin]
+ #[pin] //~ ERROR no rules expected the token `#`
+ pinned: T,
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/invalid.stderr b/tests/ui/invalid.stderr
new file mode 100644
index 0000000..f780e2e
--- /dev/null
+++ b/tests/ui/invalid.stderr
@@ -0,0 +1,17 @@
+error: no rules expected the token `(`
+ --> $DIR/invalid.rs:5:14
+ |
+5 | #[pin()] //~ ERROR no rules expected the token `(`
+ | ^ no rules expected this token in macro call
+
+error: no rules expected the token `#`
+ --> $DIR/invalid.rs:20:9
+ |
+20 | #[pin] //~ ERROR no rules expected the token `#`
+ | ^ no rules expected this token in macro call
+
+error: cannot find attribute `pin` in this scope
+ --> $DIR/invalid.rs:11:7
+ |
+11 | #[pin] //~ ERROR cannot find attribute `pin` in this scope
+ | ^^^
diff --git a/tests/ui/overlapping_lifetime_names.rs b/tests/ui/overlapping_lifetime_names.rs
new file mode 100644
index 0000000..87a737e
--- /dev/null
+++ b/tests/ui/overlapping_lifetime_names.rs
@@ -0,0 +1,10 @@
+use pin_project_lite::pin_project;
+
+pin_project! { //~ ERROR E0496
+ pub struct Foo<'__pin, T> { //~ ERROR E0263
+ #[pin]
+ field: &'__pin mut T,
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/overlapping_lifetime_names.stderr b/tests/ui/overlapping_lifetime_names.stderr
new file mode 100644
index 0000000..f86942c
--- /dev/null
+++ b/tests/ui/overlapping_lifetime_names.stderr
@@ -0,0 +1,75 @@
+error[E0496]: lifetime name `'__pin` shadows a lifetime name that is already in scope
+ --> $DIR/overlapping_lifetime_names.rs:3:1
+ |
+3 | / pin_project! { //~ ERROR E0496
+4 | | pub struct Foo<'__pin, T> { //~ ERROR E0263
+ | | ------ first declared here
+5 | | #[pin]
+6 | | field: &'__pin mut T,
+7 | | }
+8 | | }
+ | |_^ lifetime '__pin already in scope
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0496]: lifetime name `'__pin` shadows a lifetime name that is already in scope
+ --> $DIR/overlapping_lifetime_names.rs:3:1
+ |
+3 | / pin_project! { //~ ERROR E0496
+4 | | pub struct Foo<'__pin, T> { //~ ERROR E0263
+ | | ------ first declared here
+5 | | #[pin]
+6 | | field: &'__pin mut T,
+7 | | }
+8 | | }
+ | |_^ lifetime '__pin already in scope
+ |
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error[E0263]: lifetime name `'__pin` declared twice in the same scope
+ --> $DIR/overlapping_lifetime_names.rs:4:20
+ |
+3 | / pin_project! { //~ ERROR E0496
+4 | | pub struct Foo<'__pin, T> { //~ ERROR E0263
+ | | ^^^^^^ declared twice
+5 | | #[pin]
+6 | | field: &'__pin mut T,
+7 | | }
+8 | | }
+ | |_- previous declaration here
+
+error[E0263]: lifetime name `'__pin` declared twice in the same scope
+ --> $DIR/overlapping_lifetime_names.rs:4:20
+ |
+3 | / pin_project! { //~ ERROR E0496
+4 | | pub struct Foo<'__pin, T> { //~ ERROR E0263
+ | | ^^^^^^ declared twice
+5 | | #[pin]
+6 | | field: &'__pin mut T,
+7 | | }
+8 | | }
+ | |_- previous declaration here
+
+error[E0263]: lifetime name `'__pin` declared twice in the same scope
+ --> $DIR/overlapping_lifetime_names.rs:4:20
+ |
+3 | / pin_project! { //~ ERROR E0496
+4 | | pub struct Foo<'__pin, T> { //~ ERROR E0263
+ | | ^^^^^^ declared twice
+5 | | #[pin]
+6 | | field: &'__pin mut T,
+7 | | }
+8 | | }
+ | |_- previous declaration here
+
+error[E0263]: lifetime name `'__pin` declared twice in the same scope
+ --> $DIR/overlapping_lifetime_names.rs:4:20
+ |
+3 | / pin_project! { //~ ERROR E0496
+4 | | pub struct Foo<'__pin, T> { //~ ERROR E0263
+ | | ^^^^^^ declared twice
+5 | | #[pin]
+6 | | field: &'__pin mut T,
+7 | | }
+8 | | }
+ | |_- previous declaration here
diff --git a/tests/ui/overlapping_unpin_struct.rs b/tests/ui/overlapping_unpin_struct.rs
new file mode 100644
index 0000000..1338524
--- /dev/null
+++ b/tests/ui/overlapping_unpin_struct.rs
@@ -0,0 +1,19 @@
+use pin_project_lite::pin_project;
+use std::marker::PhantomPinned;
+
+pin_project! {
+ struct Foo<T> {
+ #[pin]
+ inner: T,
+ }
+}
+
+struct __Origin {}
+
+impl Unpin for __Origin {}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+ is_unpin::<Foo<PhantomPinned>>(); //~ ERROR E0277
+}
diff --git a/tests/ui/overlapping_unpin_struct.stderr b/tests/ui/overlapping_unpin_struct.stderr
new file mode 100644
index 0000000..b944b0f
--- /dev/null
+++ b/tests/ui/overlapping_unpin_struct.stderr
@@ -0,0 +1,11 @@
+error[E0277]: `std::marker::PhantomPinned` cannot be unpinned
+ --> $DIR/overlapping_unpin_struct.rs:18:5
+ |
+15 | fn is_unpin<T: Unpin>() {}
+ | ----- required by this bound in `is_unpin`
+...
+18 | is_unpin::<Foo<PhantomPinned>>(); //~ ERROR E0277
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `_::__Origin<'_, std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
+ |
+ = note: required because it appears within the type `_::__Origin<'_, std::marker::PhantomPinned>`
+ = note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo<std::marker::PhantomPinned>`
diff --git a/tests/ui/packed.rs b/tests/ui/packed.rs
new file mode 100644
index 0000000..0bccc1f
--- /dev/null
+++ b/tests/ui/packed.rs
@@ -0,0 +1,19 @@
+use pin_project_lite::pin_project;
+
+pin_project! { //~ ERROR borrow of packed field is unsafe and requires unsafe function or block
+ #[repr(packed, C)]
+ struct A {
+ #[pin]
+ field: u16,
+ }
+}
+
+pin_project! { //~ ERROR borrow of packed field is unsafe and requires unsafe function or block
+ #[repr(packed(2))]
+ struct C {
+ #[pin]
+ field: u32,
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/packed.stderr b/tests/ui/packed.stderr
new file mode 100644
index 0000000..a976163
--- /dev/null
+++ b/tests/ui/packed.stderr
@@ -0,0 +1,55 @@
+error: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
+ --> $DIR/packed.rs:3:1
+ |
+3 | / pin_project! { //~ ERROR borrow of packed field is unsafe and requires unsafe function or block
+4 | | #[repr(packed, C)]
+5 | | struct A {
+6 | | #[pin]
+7 | | field: u16,
+8 | | }
+9 | | }
+ | |_^
+ |
+note: the lint level is defined here
+ --> $DIR/packed.rs:3:1
+ |
+3 | / pin_project! { //~ ERROR borrow of packed field is unsafe and requires unsafe function or block
+4 | | #[repr(packed, C)]
+5 | | struct A {
+6 | | #[pin]
+7 | | field: u16,
+8 | | }
+9 | | }
+ | |_^
+ = 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 <https://github.com/rust-lang/rust/issues/46043>
+ = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: borrow of packed field is unsafe and requires unsafe function or block (error E0133)
+ --> $DIR/packed.rs:11:1
+ |
+11 | / pin_project! { //~ ERROR borrow of packed field is unsafe and requires unsafe function or block
+12 | | #[repr(packed(2))]
+13 | | struct C {
+14 | | #[pin]
+15 | | field: u32,
+16 | | }
+17 | | }
+ | |_^
+ |
+note: the lint level is defined here
+ --> $DIR/packed.rs:11:1
+ |
+11 | / pin_project! { //~ ERROR borrow of packed field is unsafe and requires unsafe function or block
+12 | | #[repr(packed(2))]
+13 | | struct C {
+14 | | #[pin]
+15 | | field: u32,
+16 | | }
+17 | | }
+ | |_^
+ = 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 <https://github.com/rust-lang/rust/issues/46043>
+ = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior
+ = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/tests/ui/proper_unpin.rs b/tests/ui/proper_unpin.rs
new file mode 100644
index 0000000..3c85f2d
--- /dev/null
+++ b/tests/ui/proper_unpin.rs
@@ -0,0 +1,41 @@
+use pin_project_lite::pin_project;
+use std::marker::PhantomPinned;
+
+struct Inner<T> {
+ val: T,
+}
+
+pin_project! {
+ struct Foo<T, U> {
+ #[pin]
+ inner: Inner<T>,
+ other: U,
+ }
+}
+
+pin_project! {
+ pub struct TrivialBounds {
+ #[pin]
+ field1: PhantomPinned,
+ }
+}
+
+pin_project! {
+ struct Bar<'a, T, U> {
+ #[pin]
+ inner: &'a mut Inner<T>,
+ other: U,
+ }
+}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+ is_unpin::<Foo<PhantomPinned, ()>>(); //~ ERROR E0277
+ is_unpin::<Foo<(), PhantomPinned>>(); // Ok
+ is_unpin::<Foo<PhantomPinned, PhantomPinned>>(); //~ ERROR E0277
+
+ is_unpin::<TrivialBounds>(); //~ ERROR E0277
+
+ is_unpin::<Bar<'_, PhantomPinned, PhantomPinned>>(); //~ Ok
+}
diff --git a/tests/ui/proper_unpin.stderr b/tests/ui/proper_unpin.stderr
new file mode 100644
index 0000000..8149918
--- /dev/null
+++ b/tests/ui/proper_unpin.stderr
@@ -0,0 +1,37 @@
+error[E0277]: `std::marker::PhantomPinned` cannot be unpinned
+ --> $DIR/proper_unpin.rs:34:5
+ |
+31 | fn is_unpin<T: Unpin>() {}
+ | ----- required by this bound in `is_unpin`
+...
+34 | is_unpin::<Foo<PhantomPinned, ()>>(); //~ ERROR E0277
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `_::__Origin<'_, std::marker::PhantomPinned, ()>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
+ |
+ = note: required because it appears within the type `Inner<std::marker::PhantomPinned>`
+ = note: required because it appears within the type `_::__Origin<'_, 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/proper_unpin.rs:36:5
+ |
+31 | fn is_unpin<T: Unpin>() {}
+ | ----- required by this bound in `is_unpin`
+...
+36 | is_unpin::<Foo<PhantomPinned, PhantomPinned>>(); //~ ERROR E0277
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `_::__Origin<'_, 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<std::marker::PhantomPinned>`
+ = note: required because it appears within the type `_::__Origin<'_, std::marker::PhantomPinned, std::marker::PhantomPinned>`
+ = note: required because of the requirements on the impl of `std::marker::Unpin` for `Foo<std::marker::PhantomPinned, std::marker::PhantomPinned>`
+
+error[E0277]: `std::marker::PhantomPinned` cannot be unpinned
+ --> $DIR/proper_unpin.rs:38:5
+ |
+31 | fn is_unpin<T: Unpin>() {}
+ | ----- required by this bound in `is_unpin`
+...
+38 | is_unpin::<TrivialBounds>(); //~ ERROR E0277
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ within `_::__Origin<'_>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
+ |
+ = note: required because it appears within the type `_::__Origin<'_>`
+ = note: required because of the requirements on the impl of `std::marker::Unpin` for `TrivialBounds`
diff --git a/tests/ui/unpin_sneaky.rs b/tests/ui/unpin_sneaky.rs
new file mode 100644
index 0000000..984cc2a
--- /dev/null
+++ b/tests/ui/unpin_sneaky.rs
@@ -0,0 +1,12 @@
+use pin_project_lite::pin_project;
+
+pin_project! {
+ struct Foo {
+ #[pin]
+ inner: u8,
+ }
+}
+
+impl Unpin for __Origin {} //~ ERROR E0412,E0321
+
+fn main() {}
diff --git a/tests/ui/unpin_sneaky.stderr b/tests/ui/unpin_sneaky.stderr
new file mode 100644
index 0000000..77ad2dc
--- /dev/null
+++ b/tests/ui/unpin_sneaky.stderr
@@ -0,0 +1,11 @@
+error[E0412]: cannot find type `__Origin` in this scope
+ --> $DIR/unpin_sneaky.rs:10:16
+ |
+10 | impl Unpin for __Origin {} //~ 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:10:1
+ |
+10 | impl Unpin for __Origin {} //~ ERROR E0412,E0321
+ | ^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type
diff --git a/tests/ui/unsupported.rs b/tests/ui/unsupported.rs
new file mode 100644
index 0000000..2f80836
--- /dev/null
+++ b/tests/ui/unsupported.rs
@@ -0,0 +1,27 @@
+use pin_project_lite::pin_project;
+
+pin_project! {
+ struct Struct1 {} //~ ERROR no rules expected the token `}`
+}
+
+pin_project! {
+ struct Struct2(); //~ ERROR no rules expected the token `(`
+}
+
+pin_project! {
+ struct Struct3; //~ ERROR no rules expected the token `;`
+}
+
+pin_project! {
+ enum Enum { //~ ERROR no rules expected the token `enum`
+ A(u8)
+ }
+}
+
+pin_project! {
+ union Union { //~ ERROR no rules expected the token `union`
+ x: u8,
+ }
+}
+
+fn main() {}
diff --git a/tests/ui/unsupported.stderr b/tests/ui/unsupported.stderr
new file mode 100644
index 0000000..4f7b1ae
--- /dev/null
+++ b/tests/ui/unsupported.stderr
@@ -0,0 +1,29 @@
+error: no rules expected the token `}`
+ --> $DIR/unsupported.rs:4:21
+ |
+4 | struct Struct1 {} //~ ERROR no rules expected the token `}`
+ | ^ no rules expected this token in macro call
+
+error: no rules expected the token `(`
+ --> $DIR/unsupported.rs:8:19
+ |
+8 | struct Struct2(); //~ ERROR no rules expected the token `(`
+ | ^ no rules expected this token in macro call
+
+error: no rules expected the token `;`
+ --> $DIR/unsupported.rs:12:19
+ |
+12 | struct Struct3; //~ ERROR no rules expected the token `;`
+ | ^ no rules expected this token in macro call
+
+error: no rules expected the token `enum`
+ --> $DIR/unsupported.rs:16:5
+ |
+16 | enum Enum { //~ ERROR no rules expected the token `enum`
+ | ^^^^ no rules expected this token in macro call
+
+error: no rules expected the token `union`
+ --> $DIR/unsupported.rs:22:5
+ |
+22 | union Union { //~ ERROR no rules expected the token `union`
+ | ^^^^^ no rules expected this token in macro call