Import 'pin-project' package version 0.4.16 am: 6f3e9271b1 am: 0d926734e2 am: c74636f6b4

Change-Id: I0c3e94e081ebe31577ff3f1ed53c0426a18e8f20
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..c93ffc7
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,16 @@
+# EditorConfig configuration
+# https://editorconfig.org
+
+# Top-most EditorConfig file
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+charset = utf-8
+indent_style = space
+indent_size = 4
+
+[*.{json,yml,md}]
+indent_size = 2
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..45bca84
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,4 @@
+[attr]rust text eol=lf whitespace=tab-in-indent,trailing-space,tabwidth=4
+
+* text=auto eol=lf
+*.rs rust
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000..2fdc28f
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @taiki-e
diff --git a/.github/bors.toml b/.github/bors.toml
new file mode 100644
index 0000000..1779788
--- /dev/null
+++ b/.github/bors.toml
@@ -0,0 +1,2 @@
+status = ["ci"]
+delete_merged_branches = true
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..89b20e6
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,146 @@
+name: CI
+
+on:
+  pull_request:
+  push:
+    branches:
+      - master
+      - staging
+      - trying
+  schedule:
+    - cron: '00 01 * * *'
+
+env:
+  RUSTFLAGS: -Dwarnings
+  RUST_BACKTRACE: 1
+
+defaults:
+  run:
+    shell: bash
+
+jobs:
+  test:
+    name: test
+    strategy:
+      matrix:
+        include:
+          # This is the minimum supported Rust version of this crate.
+          # When updating this, the reminder to update the minimum supported
+          # Rust version in README.md.
+          - build: 1.34.0
+            rust: 1.34.0
+          - build: 1.36.0
+            rust: 1.36.0
+          - build: 1.37.0
+            rust: 1.37.0
+          - build: stable
+            rust: stable
+          - build: beta
+            rust: beta
+          - build: nightly
+            rust: nightly
+          # pin-project itself has no platform-dependent implementation.
+          # macOS is only used to check that pin-project can interoperate
+          # correctly with `#[cfg()]`.
+          - build: macos
+            os: macos
+            rust: nightly
+          # - build: windows
+          #   os: windows
+          #   rust: nightly
+    runs-on: ${{ matrix.os || 'ubuntu' }}-latest
+    steps:
+      - uses: actions/checkout@master
+      - name: Install Rust
+        run: |
+          . ./ci/install-rust.sh ${{ matrix.rust }}
+      - name: Install cargo-hack
+        if: matrix.rust == 'nightly'
+        run: |
+          cargo install cargo-hack
+      - name: Install cargo-expand
+        if: matrix.rust == 'nightly' && matrix.build != 'macos'
+        run: |
+          cargo install cargo-expand
+      - name: Add targets
+        if: matrix.rust == 'nightly'
+        run: |
+          rustup target add thumbv7m-none-eabi
+      - name: cargo test (stable)
+        if: matrix.rust != 'nightly'
+        run: |
+          cargo test --all --all-features --exclude expandtest
+      - name: cargo test (nightly)
+        if: matrix.rust == 'nightly'
+        run: |
+          cargo test --all --all-features -- -Zunstable-options --include-ignored
+      - name: cargo check --target thumbv7m-none-eabi
+        if: matrix.rust == 'nightly'
+        run: |
+          cargo check --target thumbv7m-none-eabi --manifest-path tests/no-std/Cargo.toml
+      # Refs: https://github.com/rust-lang/cargo/issues/5657
+      - name: cargo check -Zminimal-versions
+        if: matrix.rust == 'nightly'
+        run: |
+          cargo update -Zminimal-versions
+          cargo hack check --all --all-features --no-dev-deps --ignore-private
+
+  style:
+    name: style
+    strategy:
+      fail-fast: false
+      matrix:
+        component:
+          - clippy
+          - rustfmt
+          - rustdoc
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout@master
+      - name: Install Rust
+        run: |
+          . ./ci/install-rust.sh
+      - name: Install component
+        if: matrix.component != 'rustdoc'
+        run: |
+          . ./ci/install-component.sh ${{ matrix.component }}
+      - name: cargo clippy
+        if: matrix.component == 'clippy'
+        run: |
+          cargo clippy --all --all-features --all-targets
+      - name: cargo fmt -- --check
+        if: matrix.component == 'rustfmt'
+        run: |
+          cargo fmt --all -- --check
+      - name: cargo doc
+        if: matrix.component == 'rustdoc'
+        env:
+          # TODO: once https://github.com/rust-lang/rust/issues/70814 fixed, remove '-Aunused_braces'
+          RUSTDOCFLAGS: -Dwarnings -Aunused_braces
+        run: |
+          cargo doc --no-deps --all --all-features
+
+  # Refs: https://github.com/rust-lang/crater/blob/9ab6f9697c901c4a44025cf0a39b73ad5b37d198/.github/workflows/bors.yml#L125-L149
+  #
+  # ALL THE PREVIOUS JOBS NEEDS TO BE ADDED TO THE `needs` SECTION OF THIS JOB!
+
+  ci-success:
+    name: ci
+    if: github.event_name == 'push' && success()
+    needs:
+      - style
+      - test
+    runs-on: ubuntu-latest
+    steps:
+      - name: Mark the job as a success
+        run: exit 0
+  ci-failure:
+    name: ci
+    if: github.event_name == 'push' && !success()
+    needs:
+      - style
+      - test
+    runs-on: ubuntu-latest
+    steps:
+      - name: Mark the job as a failure
+        run: exit 1
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..214d7a8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+target
+Cargo.lock
+
+# For platform and editor specific settings, it is recommended to add to
+# a global .gitignore file.
+# Refs: https://help.github.com/en/articles/ignoring-files#create-a-global-gitignore
diff --git a/.rustfmt.toml b/.rustfmt.toml
new file mode 100644
index 0000000..dc49733
--- /dev/null
+++ b/.rustfmt.toml
@@ -0,0 +1,19 @@
+# Rustfmt configuration
+# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md
+
+# This is required for bug-fixes, which technically can't be made to the stable
+# first version.
+version = "Two" # Tracking issue: https://github.com/rust-lang/rustfmt/issues/3383
+
+# Refs: https://internals.rust-lang.org/t/running-rustfmt-on-rust-lang-rust-and-other-rust-lang-repositories/8732/72
+use_small_heuristics = "Max"
+
+# Apply rustfmt to more places.
+merge_imports = true # Tracking issue: https://github.com/rust-lang/rustfmt/issues/3362
+format_code_in_doc_comments = true # Tracking issue: https://github.com/rust-lang/rustfmt/issues/3348
+
+# Set the default settings again to always apply the proper formatting without
+# being affected by the editor settings.
+# Refs: https://github.com/rust-lang/rls/issues/501#issuecomment-333717736
+edition = "2018"
+tab_spaces = 4
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..de06908
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,18 @@
+// This file is generated by cargo2android.py.
+
+rust_library_host_rlib {
+    name: "libpin_project",
+    crate_name: "pin_project",
+    srcs: ["src/lib.rs"],
+    edition: "2018",
+    proc_macros: [
+        "libpin_project_internal",
+    ],
+}
+
+// dependent_library ["feature_list"]
+//   pin-project-internal-0.4.16
+//   proc-macro2-1.0.12 "default,proc-macro"
+//   quote-1.0.4 "default,proc-macro"
+//   syn-1.0.19 "clone-impls,default,derive,full,parsing,printing,proc-macro,quote,visit-mut"
+//   unicode-xid-0.2.0 "default"
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..28f705c
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,461 @@
+# Changelog
+
+All notable changes to this project will be documented in this file.
+
+This project adheres to [Semantic Versioning](https://semver.org).
+
+## [Unreleased]
+
+## [0.4.16] - 2020-05-11
+
+* [Fixed an issue that users can call internal function generated by `#[pinned_drop]`.][223]
+
+[223]: https://github.com/taiki-e/pin-project/pull/223
+
+## [0.4.15] - 2020-05-10
+
+* [`#[project]` attribute can now handle all project* attributes in that scope with one wrapper attribute.][220]
+
+[220]: https://github.com/taiki-e/pin-project/pull/220
+
+## [0.4.14] - 2020-05-09
+
+* [Added `!Unpin` option to `#[pin_project]` attribute for guarantee the type is `!Unpin`.][219]
+
+  ```rust
+  use pin_project::pin_project;
+  #[pin_project(!Unpin)]
+  struct Struct<T, U> {
+      field: T,
+  }
+  ```
+
+  This is equivalent to use `#[pin]` attribute for `PhantomPinned` field.
+
+  ```rust
+  use pin_project::pin_project;
+  use std::marker::PhantomPinned;
+  #[pin_project]
+  struct Struct<T, U> {
+      field: T,
+      #[pin] // Note that using `PhantomPinned` without `#[pin]` attribute has no effect.
+      _pin: PhantomPinned,
+  }
+  ```
+
+  *[Note: This raises the minimum supported Rust version of this crate from rustc 1.33 to rustc 1.34.](https://github.com/taiki-e/pin-project/pull/219#pullrequestreview-408644187)*
+
+* [Fixed an issue where duplicate `#[project]` attributes were ignored.][218]
+
+* [Fixed compile error and warnings with HRTB.][217]
+
+* [Hide generated items from --document-private-items.][211] See [#211][211] for more details.
+
+* Improve documentation
+
+[211]: https://github.com/taiki-e/pin-project/pull/211
+[217]: https://github.com/taiki-e/pin-project/pull/217
+[218]: https://github.com/taiki-e/pin-project/pull/218
+[219]: https://github.com/taiki-e/pin-project/pull/219
+
+## [0.4.13] - 2020-05-07
+
+* [Fixed a regression in 0.4.11.][207]
+
+  Changes from [0.4.10](https://github.com/taiki-e/pin-project/releases/tag/v0.4.10) and [0.4.12](https://github.com/taiki-e/pin-project/releases/tag/v0.4.12):
+
+  * [Fixed an issue that `#[project]` on non-statement expression does not work without unstable features.][197]
+
+  * [Support overwriting the name of core crate.][199]
+
+  * Improve documentation
+
+[207]: https://github.com/taiki-e/pin-project/pull/207
+
+## [0.4.12] - 2020-05-07
+
+* A release to avoid [a regression in 0.4.11][206]. No code changes from [0.4.10](https://github.com/taiki-e/pin-project/releases/tag/v0.4.10).
+
+[206]: https://github.com/taiki-e/pin-project/issues/206
+
+## [0.4.11] - 2020-05-07 - YANKED
+
+* [Fixed an issue that `#[project]` on non-statement expression does not work without unstable features.][197]
+
+* [Support overwriting the name of core crate.][199]
+
+* Improve documentation
+
+[197]: https://github.com/taiki-e/pin-project/pull/197
+[199]: https://github.com/taiki-e/pin-project/pull/199
+
+## [0.4.10] - 2020-05-04
+
+* [Added `project_replace` method and `#[project_replace]` attribute.][194]
+  `project_replace` method is optional and can be enabled by passing the `Replace` argument to `#[pin_project]` attribute.
+  See [the documentation](https://docs.rs/pin-project/0.4/pin_project/attr.pin_project.html#project_replace) for more details.
+
+[194]: https://github.com/taiki-e/pin-project/pull/194
+
+## [0.4.9] - 2020-04-14
+
+* [Fixed lifetime inference error when associated types are used in fields.][188]
+
+* [Fixed compile error with tuple structs with `where` clauses.][186]
+
+* [`#[project]` attribute can now be used for `if let` expressions.][181]
+
+[181]: https://github.com/taiki-e/pin-project/pull/181
+[186]: https://github.com/taiki-e/pin-project/pull/186
+[188]: https://github.com/taiki-e/pin-project/pull/188
+
+## [0.4.8] - 2020-01-27
+
+* [Ensured that users cannot implement `PinnedDrop` without proper attribute argument.][180]
+
+[180]: https://github.com/taiki-e/pin-project/pull/180
+
+## [0.4.7] - 2020-01-20
+
+* [Fixed support for lifetime bounds.][176]
+
+[176]: https://github.com/taiki-e/pin-project/pull/176
+
+## [0.4.6] - 2019-11-20
+
+* [Fixed compile error when there is `Self` in the where clause.][169]
+
+[169]: https://github.com/taiki-e/pin-project/pull/169
+
+## [0.4.5] - 2019-10-21
+
+* [Fixed compile error with `dyn` types.][158]
+
+[158]: https://github.com/taiki-e/pin-project/pull/158
+
+## [0.4.4] - 2019-10-17
+
+* [Fixed an issue where `PinnedDrop` implementations can call unsafe code without an unsafe block.][149]
+
+[149]: https://github.com/taiki-e/pin-project/pull/149
+
+## [0.4.3] - 2019-10-15 - YANKED
+
+* [`#[pin_project]` can now interoperate with `#[cfg_attr()]`.][135]
+
+* [`#[pin_project]` can now interoperate with `#[cfg()]` on tuple structs and tuple variants.][135]
+
+* [Fixed support for DSTs(Dynamically Sized Types) on `#[pin_project(UnsafeUnpin)]`][120]
+
+[120]: https://github.com/taiki-e/pin-project/pull/120
+[135]: https://github.com/taiki-e/pin-project/pull/135
+
+## [0.4.2] - 2019-09-29 - YANKED
+
+* [Fixed support for DSTs(Dynamically Sized Types).][113]
+
+[113]: https://github.com/taiki-e/pin-project/pull/113
+
+## [0.4.1] - 2019-09-26 - YANKED
+
+* [Fixed an issue that caused an error when using `#[pin_project]` on a type that has `#[pin]` + `!Unpin` field with no generics or lifetime.][111]
+
+[111]: https://github.com/taiki-e/pin-project/pull/111
+
+## [0.4.0] - 2019-09-25 - YANKED
+
+* [**Pin projection has become a safe operation.**][18] In the absence of other unsafe code that you write, it is impossible to cause undefined behavior.
+
+* `#[unsafe_project]` attribute has been replaced with `#[pin_project]` attribute. ([#18][18], [#33][33])
+
+* [The `Unpin` argument has been removed - an `Unpin` impl is now generated by default.][18]
+
+* Drop impls must be specified with `#[pinned_drop]` instead of via a normal `Drop` impl. ([#18][18], [#33][33], [#86][86])
+
+* [`Unpin` impls must be specified with an impl of `UnsafeUnpin`, instead of implementing the normal `Unpin` trait.][18]
+
+* [`#[pin_project]` attribute now determines the visibility of the projection type/method is based on the original type.][96]
+
+* [`#[pin_project]` can now be used for public type with private field types.][53]
+
+* [`#[pin_project]` can now interoperate with `#[cfg()]`.][77]
+
+* [Added `project_ref` method to `#[pin_project]` types.][93]
+
+* [Added `#[project_ref]` attribute.][93]
+
+* [Removed "project_attr" feature and always enable `#[project]` attribute.][94]
+
+* [`#[project]` attribute can now be used for `impl` blocks.][46]
+
+* [`#[project]` attribute can now be used for `use` statements.][85]
+
+* [`#[project]` attribute now supports `match` expressions at the position of the initializer expression of `let` expressions.][51]
+
+Changes since the 0.4.0-beta.1 release:
+
+* [Fixed an issue that caused an error when using `#[pin_project(UnsafeUnpin)]` and not providing a manual `UnsafeUnpin` implementation on a type with no generics or lifetime.][107]
+
+[18]: https://github.com/taiki-e/pin-project/pull/18
+[33]: https://github.com/taiki-e/pin-project/pull/107
+[107]: https://github.com/taiki-e/pin-project/pull/107
+
+## [0.4.0-beta.1] - 2019-09-21
+
+* [Changed the argument type of project method back to `self: Pin<&mut Self>`.][90]
+
+* [Removed "project_attr" feature and always enable `#[project]` attribute.][94]
+
+* [Removed "renamed" feature.][100]
+
+* [`#[project]` attribute can now be used for `use` statements.][85]
+
+* [Added `project_ref` method and `#[project_ref]` attribute.][93]
+
+* [`#[pin_project]` attribute now determines the visibility of the projection type/method is based on the original type.][96]
+
+[85]: https://github.com/taiki-e/pin-project/pull/85
+[90]: https://github.com/taiki-e/pin-project/pull/90
+[93]: https://github.com/taiki-e/pin-project/pull/93
+[94]: https://github.com/taiki-e/pin-project/pull/94
+[96]: https://github.com/taiki-e/pin-project/pull/96
+[100]: https://github.com/taiki-e/pin-project/pull/100
+
+## [0.4.0-alpha.11] - 2019-09-11
+
+* [Changed #[pinned_drop] to trait implementation.][86]
+
+  ```rust
+  #[pinned_drop]
+  impl<T> PinnedDrop for Foo<'_, T> {
+      fn drop(mut self: Pin<&mut Self>) {
+          **self.project().was_dropped = true;
+      }
+  }
+  ```
+
+* Added some examples and generated code.
+
+* Improve error messages.
+
+[86]: https://github.com/taiki-e/pin-project/pull/86
+
+## [0.4.0-alpha.10] - 2019-09-07
+
+* [`#[pin_project]` can now interoperate with `#[cfg()]`.][77]
+
+* Improved documentation.
+
+[77]: https://github.com/taiki-e/pin-project/pull/77
+
+## [0.4.0-alpha.9] - 2019-09-05
+
+* [Added 'project_into' method to #[pin_project] types][69]. This can be useful when returning a pin projection from a method.
+  ```rust
+  fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> {
+      self.project_into().pinned
+  }
+  ```
+
+* [Prevented UnpinStruct from appearing in the document by default.][71] See [#71][71] for more details.
+
+[69]: https://github.com/taiki-e/pin-project/pull/69
+[71]: https://github.com/taiki-e/pin-project/pull/69
+
+## [0.4.0-alpha.8] - 2019-09-03
+
+* [Improved document of generated code.][62]. Also added an option to control the document of generated code. See [#62][62] for more details.
+
+* [Improved error messages][61]
+
+[61]: https://github.com/taiki-e/pin-project/pull/61
+[62]: https://github.com/taiki-e/pin-project/pull/62
+
+## [0.4.0-alpha.7] - 2019-09-02
+
+* [Applied `#[allow(dead_code)]` to generated types.][57]
+
+[57]: https://github.com/taiki-e/pin-project/pull/57
+
+## [0.4.0-alpha.6] - 2019-09-01
+
+* [Allowed using `#[pin_project]` type with private field types][53]
+
+[53]: https://github.com/taiki-e/pin-project/pull/53
+
+## [0.4.0-alpha.5] - 2019-08-24
+
+* [`#[project]` attribute now supports `match` expressions at the position of the initializer expression of `let` expressions.][51]
+
+[51]: https://github.com/taiki-e/pin-project/pull/51
+
+## [0.4.0-alpha.4] - 2019-08-23
+
+* Avoided clippy::drop_bounds lint in generated code.
+
+## [0.4.0-alpha.3] - 2019-08-23
+
+* [Changed `project` method generated by `#[pin_project]` attribute to take an `&mut Pin<&mut Self>` argument.][47]
+
+* [`#[project]` attribute can now be used for impl blocks.][46]
+
+* [`#[pin_project]` attribute can now detect that the type used does not have its own drop implementation without actually implementing drop.][48] This removed some restrictions.
+
+[46]: https://github.com/taiki-e/pin-project/pull/46
+[47]: https://github.com/taiki-e/pin-project/pull/47
+[48]: https://github.com/taiki-e/pin-project/pull/48
+
+## [0.4.0-alpha.2] - 2019-08-13
+
+* Updated `proc-macro2`, `syn`, and `quote` to 1.0.
+
+## [0.4.0-alpha.1] - 2019-08-11
+
+* **Pin projection has become a safe operation.**
+
+* `#[unsafe_project]` has been replaced with `#[pin_project]`.
+
+* The `Unpin` argument has been removed - an `Unpin` impl is now generated by default.
+
+* Drop impls must be specified with `#[pinned_drop]` instead of via a normal `Drop` impl.
+
+* `Unpin` impls must be specified with an impl of `UnsafeUnpin`, instead of implementing the normal `Unpin` trait.
+
+* Made `#[project]` attribute disabled by default.
+
+See also [tracking issue for 0.4 release][21].
+
+[21]: https://github.com/taiki-e/pin-project/issues/21
+
+## [0.3.5] - 2019-08-14
+
+* Updated `proc-macro2`, `syn`, and `quote` to 1.0.
+
+## [0.3.4] - 2019-07-21
+
+* Improved error messages.
+
+## [0.3.3] - 2019-07-15 - YANKED
+
+* Improved error messages.
+
+## [0.3.2] - 2019-03-30
+
+* Avoided suffixes on tuple index.
+
+## [0.3.1] - 2019-03-02
+
+* Improved documentation.
+
+* Updated minimum `syn` version to 0.15.22.
+
+## [0.3.0] - 2019-02-20
+
+* Removed `unsafe_fields` attribute.
+
+* Removed `unsafe_variants` attribute.
+
+## [0.2.2] - 2019-02-20
+
+* Fixed a bug that generates incorrect code for the some structures with trait bounds on type generics.
+
+## [0.2.1] - 2019-02-20
+
+* Fixed a bug that generates incorrect code for the structures with where clause and associated type fields.
+
+## [0.2.0] - 2019-02-11
+
+* Made `unsafe_fields` optional.
+
+* Improved documentation.
+
+## [0.1.8] - 2019-02-02
+
+* Added the feature to create projected enums to `unsafe_project`.
+
+* Added `project` attribute to support pattern matching.
+
+## [0.1.7] - 2019-01-19
+
+* Fixed documentation.
+
+## [0.1.6] - 2019-01-19
+
+* `unsafe_fields` can now opt-out.
+
+* Added `unsafe_variants` attribute. This attribute is available if pin-project is built with the "unsafe_variants" feature.
+
+## [0.1.5] - 2019-01-17
+
+* Added support for tuple struct to `unsafe_project`.
+
+## [0.1.4] - 2019-01-12
+
+* Added options for automatically implementing `Unpin` to both `unsafe_project` and `unsafe_fields`.
+
+## [0.1.3] - 2019-01-11
+
+* Fixed dependencies.
+
+* Added `unsafe_fields` attribute.
+
+## [0.1.2] - 2019-01-09
+
+* Improved documentation.
+
+## [0.1.1] - 2019-01-08
+
+* Renamed from `unsafe_pin_project` to `unsafe_project`.
+
+## [0.1.0] - 2019-01-08 - YANKED
+
+Initial release
+
+[Unreleased]: https://github.com/taiki-e/pin-project/compare/v0.4.16...HEAD
+[0.4.16]: https://github.com/taiki-e/pin-project/compare/v0.4.15...v0.4.16
+[0.4.15]: https://github.com/taiki-e/pin-project/compare/v0.4.14...v0.4.15
+[0.4.14]: https://github.com/taiki-e/pin-project/compare/v0.4.13...v0.4.14
+[0.4.13]: https://github.com/taiki-e/pin-project/compare/v0.4.11...v0.4.13
+[0.4.12]: https://github.com/taiki-e/pin-project/compare/v0.4.10...v0.4.12
+[0.4.11]: https://github.com/taiki-e/pin-project/compare/v0.4.10...v0.4.11
+[0.4.10]: https://github.com/taiki-e/pin-project/compare/v0.4.9...v0.4.10
+[0.4.9]: https://github.com/taiki-e/pin-project/compare/v0.4.8...v0.4.9
+[0.4.8]: https://github.com/taiki-e/pin-project/compare/v0.4.7...v0.4.8
+[0.4.7]: https://github.com/taiki-e/pin-project/compare/v0.4.6...v0.4.7
+[0.4.6]: https://github.com/taiki-e/pin-project/compare/v0.4.5...v0.4.6
+[0.4.5]: https://github.com/taiki-e/pin-project/compare/v0.4.4...v0.4.5
+[0.4.4]: https://github.com/taiki-e/pin-project/compare/v0.4.3...v0.4.4
+[0.4.3]: https://github.com/taiki-e/pin-project/compare/v0.4.2...v0.4.3
+[0.4.2]: https://github.com/taiki-e/pin-project/compare/v0.4.1...v0.4.2
+[0.4.1]: https://github.com/taiki-e/pin-project/compare/v0.4.0...v0.4.1
+[0.4.0]: https://github.com/taiki-e/pin-project/compare/v0.4.0-beta.1...v0.4.0
+[0.4.0-beta.1]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.11...v0.4.0-beta.1
+[0.4.0-alpha.11]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.10...v0.4.0-alpha.11
+[0.4.0-alpha.10]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.9...v0.4.0-alpha.10
+[0.4.0-alpha.9]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.8...v0.4.0-alpha.9
+[0.4.0-alpha.8]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.7...v0.4.0-alpha.8
+[0.4.0-alpha.7]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.6...v0.4.0-alpha.7
+[0.4.0-alpha.6]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.5...v0.4.0-alpha.6
+[0.4.0-alpha.5]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.4...v0.4.0-alpha.5
+[0.4.0-alpha.4]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.3...v0.4.0-alpha.4
+[0.4.0-alpha.3]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.2...v0.4.0-alpha.3
+[0.4.0-alpha.2]: https://github.com/taiki-e/pin-project/compare/v0.4.0-alpha.1...v0.4.0-alpha.2
+[0.4.0-alpha.1]: https://github.com/taiki-e/pin-project/compare/v0.3.5...v0.4.0-alpha.1
+[0.3.5]: https://github.com/taiki-e/pin-project/compare/v0.3.4...v0.3.5
+[0.3.4]: https://github.com/taiki-e/pin-project/compare/v0.3.3...v0.3.4
+[0.3.3]: https://github.com/taiki-e/pin-project/compare/v0.3.2...v0.3.3
+[0.3.2]: https://github.com/taiki-e/pin-project/compare/v0.3.1...v0.3.2
+[0.3.1]: https://github.com/taiki-e/pin-project/compare/v0.3.0...v0.3.1
+[0.3.0]: https://github.com/taiki-e/pin-project/compare/v0.2.2...v0.3.0
+[0.2.2]: https://github.com/taiki-e/pin-project/compare/v0.2.1...v0.2.2
+[0.2.1]: https://github.com/taiki-e/pin-project/compare/v0.2.0...v0.2.1
+[0.2.0]: https://github.com/taiki-e/pin-project/compare/v0.1.8...v0.2.0
+[0.1.8]: https://github.com/taiki-e/pin-project/compare/v0.1.7...v0.1.8
+[0.1.7]: https://github.com/taiki-e/pin-project/compare/v0.1.6...v0.1.7
+[0.1.6]: https://github.com/taiki-e/pin-project/compare/v0.1.5...v0.1.6
+[0.1.5]: https://github.com/taiki-e/pin-project/compare/v0.1.4...v0.1.5
+[0.1.4]: https://github.com/taiki-e/pin-project/compare/v0.1.3...v0.1.4
+[0.1.3]: https://github.com/taiki-e/pin-project/compare/v0.1.2...v0.1.3
+[0.1.2]: https://github.com/taiki-e/pin-project/compare/v0.1.1...v0.1.2
+[0.1.1]: https://github.com/taiki-e/pin-project/compare/v0.1.0...v0.1.1
+[0.1.0]: https://github.com/taiki-e/pin-project/releases/tag/v0.1.0
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..39280ab
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,30 @@
+# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
+#
+# When uploading crates to the registry Cargo will automatically
+# "normalize" Cargo.toml files for maximal compatibility
+# with all versions of Cargo and also rewrite `path` dependencies
+# to registry (e.g., crates.io) dependencies
+#
+# If you believe there's an error in this file please file an
+# issue against the rust-lang/cargo repository. If you're
+# editing this file be aware that the upstream Cargo.toml
+# will likely look very different (and much more reasonable)
+
+[package]
+edition = "2018"
+name = "pin-project"
+version = "0.4.16"
+authors = ["Taiki Endo <te316e89@gmail.com>"]
+description = "A crate for safe and ergonomic pin-projection.\n"
+homepage = "https://github.com/taiki-e/pin-project"
+documentation = "https://docs.rs/pin-project"
+readme = "README.md"
+keywords = ["pin", "macros", "attribute"]
+categories = ["no-std", "rust-patterns"]
+license = "Apache-2.0 OR MIT"
+repository = "https://github.com/taiki-e/pin-project"
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+[dependencies.pin-project-internal]
+version = "=0.4.16"
+default-features = false
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
new file mode 100644
index 0000000..c886996
--- /dev/null
+++ b/Cargo.toml.orig
@@ -0,0 +1,31 @@
+[package]
+name = "pin-project"
+version = "0.4.16"
+authors = ["Taiki Endo <te316e89@gmail.com>"]
+edition = "2018"
+license = "Apache-2.0 OR MIT"
+repository = "https://github.com/taiki-e/pin-project"
+homepage = "https://github.com/taiki-e/pin-project"
+documentation = "https://docs.rs/pin-project"
+keywords = ["pin", "macros", "attribute"]
+categories = ["no-std", "rust-patterns"]
+readme = "README.md"
+description = """
+A crate for safe and ergonomic pin-projection.
+"""
+
+[package.metadata.docs.rs]
+targets = ["x86_64-unknown-linux-gnu"]
+
+[workspace]
+members = [
+    "pin-project-internal",
+    "tests/ui/auxiliary",
+    "tests/doc",
+    "tests/expand",
+    "tests/rust-2015"
+]
+
+[dependencies]
+pin-project-internal = { version = "=0.4.16", path = "pin-project-internal", default-features = false }
+
diff --git a/LICENSE b/LICENSE
new file mode 120000
index 0000000..6b579aa
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1 @@
+LICENSE-APACHE
\ No newline at end of file
diff --git a/LICENSE-APACHE b/LICENSE-APACHE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/LICENSE-APACHE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
diff --git a/LICENSE-MIT b/LICENSE-MIT
new file mode 100644
index 0000000..31aa793
--- /dev/null
+++ b/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/METADATA b/METADATA
new file mode 100644
index 0000000..7c1feb9
--- /dev/null
+++ b/METADATA
@@ -0,0 +1,19 @@
+name: "pin-project"
+description: "A crate for safe and ergonomic pin-projection."
+third_party {
+  url {
+    type: HOMEPAGE
+    value: "https://crates.io/crates/pin-project"
+  }
+  url {
+    type: GIT
+    value: "https://github.com/taiki-e/pin-project"
+  }
+  version: "0.4.16"
+  license_type: NOTICE
+  last_upgrade_date {
+    year: 2020
+    month: 5
+    day: 11
+  }
+}
diff --git a/MODULE_LICENSE_APACHE2 b/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/MODULE_LICENSE_APACHE2
diff --git a/NOTICE b/NOTICE
new file mode 120000
index 0000000..7a694c9
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1 @@
+LICENSE
\ No newline at end of file
diff --git a/OWNERS b/OWNERS
new file mode 100644
index 0000000..46fc303
--- /dev/null
+++ b/OWNERS
@@ -0,0 +1 @@
+include platform/prebuilts/rust:/OWNERS
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..840d1fa
--- /dev/null
+++ b/README.md
@@ -0,0 +1,77 @@
+# pin-project
+
+[![crates-badge]][crates-url]
+[![docs-badge]][docs-url]
+[![license-badge]][license]
+[![rustc-badge]][rustc-url]
+
+[crates-badge]: https://img.shields.io/crates/v/pin-project.svg
+[crates-url]: https://crates.io/crates/pin-project
+[docs-badge]: https://docs.rs/pin-project/badge.svg
+[docs-url]: https://docs.rs/pin-project
+[license-badge]: https://img.shields.io/crates/l/pin-project.svg
+[license]: #license
+[rustc-badge]: https://img.shields.io/badge/rustc-1.34+-lightgray.svg
+[rustc-url]: https://blog.rust-lang.org/2019/04/11/Rust-1.34.0.html
+
+A crate for safe and ergonomic pin-projection.
+
+[Documentation][docs-url]
+
+[Examples](examples/README.md)
+
+## Usage
+
+Add this to your `Cargo.toml`:
+
+```toml
+[dependencies]
+pin-project = "0.4"
+```
+
+The current pin-project requires Rust 1.34 or later.
+
+## Examples
+
+[`pin_project`] attribute creates a projection struct covering all the fields.
+
+```rust
+use pin_project::pin_project;
+use std::pin::Pin;
+
+#[pin_project]
+struct Struct<T, U> {
+    #[pin]
+    pinned: T,
+    unpinned: U,
+}
+
+impl<T, U> Struct<T, U> {
+    fn foo(self: Pin<&mut Self>) {
+        let this = self.project();
+        let _: Pin<&mut T> = this.pinned; // Pinned reference to the field
+        let _: &mut U = this.unpinned; // Normal reference to the field
+    }
+}
+```
+
+[Code like this will be generated](examples/struct-default-expanded.rs)
+
+See [API documentation][docs-url] for more details.
+
+Also, there are examples and generated code of each feature in [examples](examples/README.md) directory.
+
+[`pin_project`]: https://docs.rs/pin-project/0.4/pin_project/attr.pin_project.html
+
+## License
+
+Licensed under either of
+
+* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
+* MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
+
+at your option.
+
+### Contribution
+
+Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
diff --git a/ci.sh b/ci.sh
new file mode 100644
index 0000000..df0131e
--- /dev/null
+++ b/ci.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# A script to run a simplified version of the checks done by CI.
+#
+# Usage
+#
+# ```sh
+# . ./ci.sh
+# ```
+
+echo "Running 'cargo fmt -- --check'"
+cargo +nightly fmt --all -- --check
+
+echo "Running 'cargo clippy'"
+cargo +nightly clippy --all --all-features --all-targets
+
+echo "Running 'cargo test'"
+cargo +nightly test --all --all-features
+
+echo "Running 'cargo doc'"
+cargo +nightly doc --no-deps --all --all-features
+
+echo "Running 'compiletest'"
+. ./compiletest.sh
+
+echo "Running 'expandtest'"
+# See also https://docs.rs/macrotest/1/macrotest/#updating-expandedrs
+# rm **/*.expanded.rs
+cargo +nightly test --manifest-path tests/expand/Cargo.toml
diff --git a/ci/install-component.sh b/ci/install-component.sh
new file mode 100644
index 0000000..de08b8f
--- /dev/null
+++ b/ci/install-component.sh
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -euo pipefail
+
+component="${1}"
+
+if ! rustup component add "${component}" 2>/dev/null; then
+    # If the component is unavailable on the latest nightly,
+    # use the latest toolchain with the component available.
+    # Refs: https://github.com/rust-lang/rustup-components-history#the-web-part
+    target=$(curl -sSf "https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/${component}")
+    echo "'${component}' is unavailable on the default toolchain, use the toolchain 'nightly-${target}' instead"
+
+    . ci/install-rust.sh "nightly-${target}"
+
+    rustup component add "${component}"
+fi
+
+case "${component}" in
+    rustfmt | rustdoc) "${component}" -V ;;
+    *) cargo "${component}" -V ;;
+esac
diff --git a/ci/install-rust.sh b/ci/install-rust.sh
new file mode 100644
index 0000000..b6625b6
--- /dev/null
+++ b/ci/install-rust.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+set -euo pipefail
+
+toolchain="${1:-nightly}"
+
+rustup set profile minimal
+rustup update "${toolchain}" --no-self-update
+rustup default "${toolchain}"
+
+rustup -V
+rustc -V
+cargo -V
diff --git a/compiletest.sh b/compiletest.sh
new file mode 100644
index 0000000..9af5a5f
--- /dev/null
+++ b/compiletest.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+# A script to run compile tests with the same condition of the checks done by CI.
+#
+# Usage
+#
+# ```sh
+# . ./compiletest.sh
+# ```
+
+TRYBUILD=overwrite cargo +nightly test -p pin-project --all-features --test compiletest -- --ignored
+# cargo +nightly test -p pin-project --all-features --test compiletest -- --ignored
diff --git a/examples/README.md b/examples/README.md
new file mode 100644
index 0000000..94f49b5
--- /dev/null
+++ b/examples/README.md
@@ -0,0 +1,35 @@
+# Examples and generated code of each feature of pin-project
+
+### Basic usage of `#[pin_project]` on structs
+
+  * [example](struct-default.rs)
+  * [generated code](struct-default-expanded.rs)
+
+### Basic usage of `#[pin_project]` on enums
+
+  * [example](enum-default.rs)
+  * [generated code](enum-default-expanded.rs)
+
+### Manual implementation of `Unpin` by `UnsafeUnpin`
+
+  * [example](unsafe_unpin.rs)
+  * [generated code](unsafe_unpin-expanded.rs)
+  * [`UnsafeUnpin` documentation](https://docs.rs/pin-project/0.4/pin_project/trait.UnsafeUnpin.html)
+
+### Manual implementation of `Drop` by `#[pinned_drop]`
+
+  * [example](pinned_drop.rs)
+  * [generated code](pinned_drop-expanded.rs)
+  * [`#[pinned_drop]` documentation](https://docs.rs/pin-project/0.4/pin_project/attr.pinned_drop.html)
+
+### `project_replace()` method
+
+  * [example](project_replace.rs)
+  * [generated code](project_replace-expanded.rs)
+  * [`project_replace()` documentation](https://docs.rs/pin-project/0.4/pin_project/attr.pin_project.html#project_replace)
+
+### Ensure `!Unpin` by `#[pin_project(!Unpin)]`
+
+  * [example](not_unpin.rs)
+  * [generated code](not_unpin-expanded.rs)
+  * [`!Unpin` documentation](https://docs.rs/pin-project/0.4/pin_project/attr.pin_project.html#unpin)
diff --git a/examples/enum-default-expanded.rs b/examples/enum-default-expanded.rs
new file mode 100644
index 0000000..036c01f
--- /dev/null
+++ b/examples/enum-default-expanded.rs
@@ -0,0 +1,109 @@
+// Original code (./enum-default.rs):
+//
+// ```rust
+// #![allow(dead_code)]
+//
+// use pin_project::pin_project;
+//
+// #[pin_project]
+// enum Enum<T, U> {
+//     Pinned(#[pin] T),
+//     Unpinned(U),
+// }
+//
+// fn main() {}
+// ```
+
+#![allow(dead_code, unused_imports, unused_parens)]
+#![allow(clippy::no_effect, clippy::just_underscores_and_digits)]
+
+use pin_project::pin_project;
+
+enum Enum<T, U> {
+    Pinned(/* #[pin] */ T),
+    Unpinned(U),
+}
+
+#[doc(hidden)]
+#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+enum __EnumProjection<'pin, T, U>
+where
+    Enum<T, U>: 'pin,
+{
+    Pinned(::pin_project::__reexport::pin::Pin<&'pin mut (T)>),
+    Unpinned(&'pin mut (U)),
+}
+#[doc(hidden)]
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+enum __EnumProjectionRef<'pin, T, U>
+where
+    Enum<T, U>: 'pin,
+{
+    Pinned(::pin_project::__reexport::pin::Pin<&'pin (T)>),
+    Unpinned(&'pin (U)),
+}
+
+#[doc(hidden)]
+#[allow(non_upper_case_globals)]
+#[allow(single_use_lifetimes)]
+const __SCOPE_Enum: () = {
+    impl<T, U> Enum<T, U> {
+        fn project<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin mut Self>,
+        ) -> __EnumProjection<'pin, T, U> {
+            unsafe {
+                match self.get_unchecked_mut() {
+                    Enum::Pinned(_0) => __EnumProjection::Pinned(
+                        ::pin_project::__reexport::pin::Pin::new_unchecked(_0),
+                    ),
+                    Enum::Unpinned(_0) => __EnumProjection::Unpinned(_0),
+                }
+            }
+        }
+        fn project_ref<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin Self>,
+        ) -> __EnumProjectionRef<'pin, T, U> {
+            unsafe {
+                match self.get_ref() {
+                    Enum::Pinned(_0) => __EnumProjectionRef::Pinned(
+                        ::pin_project::__reexport::pin::Pin::new_unchecked(_0),
+                    ),
+                    Enum::Unpinned(_0) => __EnumProjectionRef::Unpinned(_0),
+                }
+            }
+        }
+    }
+
+    // Automatically create the appropriate conditional `Unpin` implementation.
+    //
+    // See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/53.
+    // for details.
+    struct __Enum<'pin, T, U> {
+        __pin_project_use_generics: ::pin_project::__private::AlwaysUnpin<'pin, (T, U)>,
+        __field0: T,
+    }
+    impl<'pin, T, U> ::pin_project::__reexport::marker::Unpin for Enum<T, U> where
+        __Enum<'pin, T, U>: ::pin_project::__reexport::marker::Unpin
+    {
+    }
+    unsafe impl<T, U> ::pin_project::UnsafeUnpin for Enum<T, U> {}
+
+    // Ensure that enum does not implement `Drop`.
+    //
+    // See ./struct-default-expanded.rs for details.
+    trait EnumMustNotImplDrop {}
+    #[allow(clippy::drop_bounds)]
+    impl<T: ::pin_project::__reexport::ops::Drop> EnumMustNotImplDrop for T {}
+    impl<T, U> EnumMustNotImplDrop for Enum<T, U> {}
+    impl<T, U> ::pin_project::__private::PinnedDrop for Enum<T, U> {
+        unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {}
+    }
+
+    // We don't need to check for `#[repr(packed)]`,
+    // since it does not apply to enums.
+};
+
+fn main() {}
diff --git a/examples/enum-default.rs b/examples/enum-default.rs
new file mode 100644
index 0000000..ab5a4bc
--- /dev/null
+++ b/examples/enum-default.rs
@@ -0,0 +1,13 @@
+// See ./enum-default-expanded.rs for generated code.
+
+#![allow(dead_code)]
+
+use pin_project::pin_project;
+
+#[pin_project]
+enum Enum<T, U> {
+    Pinned(#[pin] T),
+    Unpinned(U),
+}
+
+fn main() {}
diff --git a/examples/not_unpin-expanded.rs b/examples/not_unpin-expanded.rs
new file mode 100644
index 0000000..45f1321
--- /dev/null
+++ b/examples/not_unpin-expanded.rs
@@ -0,0 +1,125 @@
+// Original code (./not_unpin.rs):
+//
+// ```rust
+// #![allow(dead_code)]
+//
+// use pin_project::pin_project;
+//
+// #[pin_project(!Unpin)]
+// pub struct Struct<T, U> {
+//     #[pin]
+//     pinned: T,
+//     unpinned: U,
+// }
+//
+// fn main() {
+//     fn _is_unpin<T: Unpin>() {}
+//     // _is_unpin::<Struct<(), ()>>(); //~ ERROR `std::marker::PhantomPinned` cannot be unpinned
+// }
+// ```
+
+#![allow(dead_code, unused_imports, unused_parens)]
+#![allow(clippy::no_effect)]
+
+use pin_project::pin_project;
+
+pub struct Struct<T, U> {
+    // #[pin]
+    pinned: T,
+    unpinned: U,
+}
+
+#[doc(hidden)]
+#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+pub(crate) struct __StructProjection<'pin, T, U>
+where
+    Struct<T, U>: 'pin,
+{
+    pinned: ::pin_project::__reexport::pin::Pin<&'pin mut (T)>,
+    unpinned: &'pin mut (U),
+}
+#[doc(hidden)]
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+pub(crate) struct __StructProjectionRef<'pin, T, U>
+where
+    Struct<T, U>: 'pin,
+{
+    pinned: ::pin_project::__reexport::pin::Pin<&'pin (T)>,
+    unpinned: &'pin (U),
+}
+
+#[doc(hidden)]
+#[allow(non_upper_case_globals)]
+#[allow(single_use_lifetimes)]
+const __SCOPE_Struct: () = {
+    impl<T, U> Struct<T, U> {
+        pub(crate) fn project<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin mut Self>,
+        ) -> __StructProjection<'pin, T, U> {
+            unsafe {
+                let Self { pinned, unpinned } = self.get_unchecked_mut();
+                __StructProjection {
+                    pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned),
+                    unpinned,
+                }
+            }
+        }
+        pub(crate) fn project_ref<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin Self>,
+        ) -> __StructProjectionRef<'pin, T, U> {
+            unsafe {
+                let Self { pinned, unpinned } = self.get_ref();
+                __StructProjectionRef {
+                    pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned),
+                    unpinned,
+                }
+            }
+        }
+    }
+
+    // Create `Unpin` impl that has trivial `Unpin` bounds.
+    //
+    // See https://github.com/taiki-e/pin-project/issues/102#issuecomment-540472282
+    // for details.
+    impl<'pin, T, U> ::pin_project::__reexport::marker::Unpin for Struct<T, U> where
+        ::pin_project::__private::Wrapper<'pin, ::pin_project::__reexport::marker::PhantomPinned>:
+            ::pin_project::__reexport::marker::Unpin
+    {
+    }
+    // A dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it.
+    //
+    // To ensure that users don't accidentally write a non-functional `UnsafeUnpin`
+    // impls, we emit one ourselves. If the user ends up writing a `UnsafeUnpin` impl,
+    // they'll get a "conflicting implementations of trait" error when coherence
+    // checks are run.
+    unsafe impl<T, U> ::pin_project::UnsafeUnpin for Struct<T, U> {}
+
+    // Ensure that struct does not implement `Drop`.
+    //
+    // See ./struct-default-expanded.rs for details.
+    trait StructMustNotImplDrop {}
+    #[allow(clippy::drop_bounds)]
+    impl<T: ::pin_project::__reexport::ops::Drop> StructMustNotImplDrop for T {}
+    impl<T, U> StructMustNotImplDrop for Struct<T, U> {}
+    impl<T, U> ::pin_project::__private::PinnedDrop for Struct<T, U> {
+        unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {}
+    }
+
+    // Ensure that it's impossible to use pin projections on a #[repr(packed)] struct.
+    //
+    // See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/34
+    // for details.
+    #[deny(safe_packed_borrows)]
+    fn __assert_not_repr_packed<T, U>(val: &Struct<T, U>) {
+        &val.pinned;
+        &val.unpinned;
+    }
+};
+
+fn main() {
+    fn _is_unpin<T: Unpin>() {}
+    // _is_unpin::<Struct<(), ()>>(); //~ ERROR `std::marker::PhantomPinned` cannot be unpinned
+}
diff --git a/examples/not_unpin.rs b/examples/not_unpin.rs
new file mode 100644
index 0000000..2ad72a8
--- /dev/null
+++ b/examples/not_unpin.rs
@@ -0,0 +1,17 @@
+// See ./not_unpin-expanded.rs for generated code.
+
+#![allow(dead_code)]
+
+use pin_project::pin_project;
+
+#[pin_project(!Unpin)]
+pub struct Struct<T, U> {
+    #[pin]
+    pinned: T,
+    unpinned: U,
+}
+
+fn main() {
+    fn _is_unpin<T: Unpin>() {}
+    // _is_unpin::<Struct<(), ()>>(); //~ ERROR `std::marker::PhantomPinned` cannot be unpinned
+}
diff --git a/examples/pinned_drop-expanded.rs b/examples/pinned_drop-expanded.rs
new file mode 100644
index 0000000..15dde89
--- /dev/null
+++ b/examples/pinned_drop-expanded.rs
@@ -0,0 +1,154 @@
+// Original code (./pinned_drop.rs):
+//
+// ```rust
+// #![allow(dead_code)]
+//
+// use pin_project::{pin_project, pinned_drop};
+// use std::pin::Pin;
+//
+// #[pin_project(PinnedDrop)]
+// pub struct Struct<'a, T> {
+//     was_dropped: &'a mut bool,
+//     #[pin]
+//     field: T,
+// }
+//
+// #[pinned_drop]
+// fn drop_Struct<T>(mut this: Pin<&mut Struct<'_, T>>) {
+//     **this.project().was_dropped = true;
+// }
+//
+// fn main() {}
+// ```
+
+#![allow(dead_code, unused_imports, unused_parens)]
+#![allow(clippy::no_effect)]
+
+use pin_project::{pin_project, pinned_drop};
+use std::pin::Pin;
+
+pub struct Struct<'a, T> {
+    was_dropped: &'a mut bool,
+    // #[pin]
+    field: T,
+}
+
+#[doc(hidden)]
+#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+pub(crate) struct __StructProjection<'pin, 'a, T>
+where
+    Struct<'a, T>: 'pin,
+{
+    was_dropped: &'pin mut (&'a mut bool),
+    field: ::pin_project::__reexport::pin::Pin<&'pin mut (T)>,
+}
+#[doc(hidden)]
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+pub(crate) struct __StructProjectionRef<'pin, 'a, T>
+where
+    Struct<'a, T>: 'pin,
+{
+    was_dropped: &'pin (&'a mut bool),
+    field: ::pin_project::__reexport::pin::Pin<&'pin (T)>,
+}
+
+#[doc(hidden)]
+#[allow(non_upper_case_globals)]
+#[allow(single_use_lifetimes)]
+const __SCOPE_Struct: () = {
+    impl<'a, T> Struct<'a, T> {
+        pub(crate) fn project<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin mut Self>,
+        ) -> __StructProjection<'pin, 'a, T> {
+            unsafe {
+                let Self { was_dropped, field } = self.get_unchecked_mut();
+                __StructProjection {
+                    was_dropped,
+                    field: ::pin_project::__reexport::pin::Pin::new_unchecked(field),
+                }
+            }
+        }
+        pub(crate) fn project_ref<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin Self>,
+        ) -> __StructProjectionRef<'pin, 'a, T> {
+            unsafe {
+                let Self { was_dropped, field } = self.get_ref();
+                __StructProjectionRef {
+                    was_dropped,
+                    field: ::pin_project::__reexport::pin::Pin::new_unchecked(field),
+                }
+            }
+        }
+    }
+
+    impl<'a, T> ::pin_project::__reexport::ops::Drop for Struct<'a, T> {
+        fn drop(&mut self) {
+            // Safety - we're in 'drop', so we know that 'self' will
+            // never move again.
+            let pinned_self = unsafe { ::pin_project::__reexport::pin::Pin::new_unchecked(self) };
+            // We call `pinned_drop` only once. Since `PinnedDrop::drop`
+            // is an unsafe method and a private API, it is never called again in safe
+            // code *unless the user uses a maliciously crafted macro*.
+            unsafe {
+                ::pin_project::__private::PinnedDrop::drop(pinned_self);
+            }
+        }
+    }
+
+    // Automatically create the appropriate conditional `Unpin` implementation.
+    //
+    // See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/53.
+    // for details.
+    pub struct __Struct<'pin, 'a, T> {
+        __pin_project_use_generics: ::pin_project::__private::AlwaysUnpin<'pin, (T)>,
+        __field0: T,
+        __lifetime0: &'a (),
+    }
+    impl<'pin, 'a, T> ::pin_project::__reexport::marker::Unpin for Struct<'a, T> where
+        __Struct<'pin, 'a, T>: ::pin_project::__reexport::marker::Unpin
+    {
+    }
+    unsafe impl<'a, T> ::pin_project::UnsafeUnpin for Struct<'a, T> {}
+
+    // Ensure that it's impossible to use pin projections on a #[repr(packed)] struct.
+    //
+    // See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/34
+    // for details.
+    #[deny(safe_packed_borrows)]
+    fn __assert_not_repr_packed<'a, T>(val: &Struct<'a, T>) {
+        &val.was_dropped;
+        &val.field;
+    }
+};
+
+// Implementing `PinnedDrop::drop` is safe, but calling it is not safe.
+// This is because destructors can be called multiple times in safe code and
+// [double dropping is unsound](https://github.com/rust-lang/rust/pull/62360).
+//
+// Ideally, it would be desirable to be able to forbid manual calls in
+// the same way as `Drop::drop`, but the library cannot do it. So, by using
+// macros and replacing them with private traits, we prevent users from
+// calling `PinnedDrop::drop`.
+//
+// Users can implement [`Drop`] safely using `#[pinned_drop]` and can drop a
+// type that implements `PinnedDrop` using the [`drop`] function safely.
+// **Do not call or implement this trait directly.**
+impl<T> ::pin_project::__private::PinnedDrop for Struct<'_, T> {
+    // Since calling it twice on the same object would be UB,
+    // this method is unsafe.
+    unsafe fn drop(self: Pin<&mut Self>) {
+        #[allow(clippy::needless_pass_by_value)]
+        fn __drop_inner<T>(__self: Pin<&mut Struct<'_, T>>) {
+            // A dummy `__drop_inner` function to prevent users call outer `__drop_inner`.
+            fn __drop_inner() {}
+
+            **__self.project().was_dropped = true;
+        }
+        __drop_inner(self);
+    }
+}
+
+fn main() {}
diff --git a/examples/pinned_drop.rs b/examples/pinned_drop.rs
new file mode 100644
index 0000000..4dfd228
--- /dev/null
+++ b/examples/pinned_drop.rs
@@ -0,0 +1,22 @@
+// See ./pinned_drop-expanded.rs for generated code.
+
+#![allow(dead_code)]
+
+use pin_project::{pin_project, pinned_drop};
+use std::pin::Pin;
+
+#[pin_project(PinnedDrop)]
+pub struct Struct<'a, T> {
+    was_dropped: &'a mut bool,
+    #[pin]
+    field: T,
+}
+
+#[pinned_drop]
+impl<T> PinnedDrop for Struct<'_, T> {
+    fn drop(self: Pin<&mut Self>) {
+        **self.project().was_dropped = true;
+    }
+}
+
+fn main() {}
diff --git a/examples/project_replace-expanded.rs b/examples/project_replace-expanded.rs
new file mode 100644
index 0000000..ec9f00e
--- /dev/null
+++ b/examples/project_replace-expanded.rs
@@ -0,0 +1,158 @@
+// Original code (./struct-default.rs):
+//
+// ```rust
+// #![allow(dead_code)]
+//
+// use pin_project::pin_project;
+//
+// #[pin_project(Replace)]
+// struct Struct<T, U> {
+//     #[pin]
+//     pinned: T,
+//     unpinned: U,
+// }
+//
+// fn main() {}
+// ```
+
+#![allow(dead_code, unused_imports, unused_parens)]
+#![allow(clippy::no_effect)]
+
+use pin_project::pin_project;
+
+struct Struct<T, U> {
+    // #[pin]
+    pinned: T,
+    unpinned: U,
+}
+
+#[doc(hidden)]
+#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+struct __StructProjection<'pin, T, U>
+where
+    Struct<T, U>: 'pin,
+{
+    pinned: ::pin_project::__reexport::pin::Pin<&'pin mut (T)>,
+    unpinned: &'pin mut (U),
+}
+#[doc(hidden)]
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+struct __StructProjectionRef<'pin, T, U>
+where
+    Struct<T, U>: 'pin,
+{
+    pinned: ::pin_project::__reexport::pin::Pin<&'pin (T)>,
+    unpinned: &'pin (U),
+}
+
+#[doc(hidden)]
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+struct __StructProjectionOwned<T, U> {
+    pinned: ::pin_project::__reexport::marker::PhantomData<T>,
+    unpinned: U,
+}
+
+#[doc(hidden)]
+#[allow(non_upper_case_globals)]
+#[allow(single_use_lifetimes)]
+const __SCOPE_Struct: () = {
+    impl<T, U> Struct<T, U> {
+        fn project<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin mut Self>,
+        ) -> __StructProjection<'pin, T, U> {
+            unsafe {
+                let Self { pinned, unpinned } = self.get_unchecked_mut();
+                __StructProjection {
+                    pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned),
+                    unpinned,
+                }
+            }
+        }
+        fn project_ref<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin Self>,
+        ) -> __StructProjectionRef<'pin, T, U> {
+            unsafe {
+                let Self { pinned, unpinned } = self.get_ref();
+                __StructProjectionRef {
+                    pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned),
+                    unpinned,
+                }
+            }
+        }
+        fn project_replace(
+            self: ::pin_project::__reexport::pin::Pin<&mut Self>,
+            __replacement: Self,
+        ) -> __StructProjectionOwned<T, U> {
+            unsafe {
+                let __self_ptr: *mut Self = self.get_unchecked_mut();
+                let Self { pinned, unpinned } = &mut *__self_ptr;
+
+                // First, extract all the unpinned fields
+                let __result = __StructProjectionOwned {
+                    pinned: ::pin_project::__reexport::marker::PhantomData,
+                    unpinned: ::pin_project::__reexport::ptr::read(unpinned),
+                };
+
+                // Destructors will run in reverse order, so next create a guard to overwrite
+                // `self` with the replacement value without calling destructors.
+                let __guard = ::pin_project::__private::UnsafeOverwriteGuard {
+                    target: __self_ptr,
+                    value: ::pin_project::__reexport::mem::ManuallyDrop::new(__replacement),
+                };
+
+                // Now create guards to drop all the pinned fields
+                //
+                // Due to a compiler bug (https://github.com/rust-lang/rust/issues/47949)
+                // this must be in its own scope, or else `__result` will not be dropped
+                // if any of the destructors panic.
+                {
+                    let __guard = ::pin_project::__private::UnsafeDropInPlaceGuard(pinned);
+                }
+
+                // Finally, return the result
+                __result
+            }
+        }
+    }
+
+    // Automatically create the appropriate conditional `Unpin` implementation.
+    //
+    // See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/53.
+    // for details.
+    struct __Struct<'pin, T, U> {
+        __pin_project_use_generics: ::pin_project::__private::AlwaysUnpin<'pin, (T, U)>,
+        __field0: T,
+    }
+    impl<'pin, T, U> ::pin_project::__reexport::marker::Unpin for Struct<T, U> where
+        __Struct<'pin, T, U>: ::pin_project::__reexport::marker::Unpin
+    {
+    }
+    unsafe impl<T, U> ::pin_project::UnsafeUnpin for Struct<T, U> {}
+
+    // Ensure that struct does not implement `Drop`.
+    //
+    // See ./struct-default-expanded.rs for details.
+    trait StructMustNotImplDrop {}
+    #[allow(clippy::drop_bounds)]
+    impl<T: ::pin_project::__reexport::ops::Drop> StructMustNotImplDrop for T {}
+    impl<T, U> StructMustNotImplDrop for Struct<T, U> {}
+    impl<T, U> ::pin_project::__private::PinnedDrop for Struct<T, U> {
+        unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {}
+    }
+
+    // Ensure that it's impossible to use pin projections on a #[repr(packed)] struct.
+    //
+    // See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/34
+    // for details.
+    #[deny(safe_packed_borrows)]
+    fn __assert_not_repr_packed<T, U>(val: &Struct<T, U>) {
+        &val.pinned;
+        &val.unpinned;
+    }
+};
+
+fn main() {}
diff --git a/examples/project_replace.rs b/examples/project_replace.rs
new file mode 100644
index 0000000..4482625
--- /dev/null
+++ b/examples/project_replace.rs
@@ -0,0 +1,14 @@
+// See ./struct-default-expanded.rs for generated code.
+
+#![allow(dead_code)]
+
+use pin_project::pin_project;
+
+#[pin_project(Replace)]
+struct Struct<T, U> {
+    #[pin]
+    pinned: T,
+    unpinned: U,
+}
+
+fn main() {}
diff --git a/examples/struct-default-expanded.rs b/examples/struct-default-expanded.rs
new file mode 100644
index 0000000..2bf7edd
--- /dev/null
+++ b/examples/struct-default-expanded.rs
@@ -0,0 +1,157 @@
+// Original code (./struct-default.rs):
+//
+// ```rust
+// #![allow(dead_code)]
+//
+// use pin_project::pin_project;
+//
+// #[pin_project]
+// struct Struct<T, U> {
+//     #[pin]
+//     pinned: T,
+//     unpinned: U,
+// }
+//
+// fn main() {}
+// ```
+
+#![allow(dead_code, unused_imports, unused_parens)]
+#![allow(clippy::no_effect)]
+
+use pin_project::pin_project;
+
+struct Struct<T, U> {
+    // #[pin]
+    pinned: T,
+    unpinned: U,
+}
+
+#[doc(hidden)]
+#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+struct __StructProjection<'pin, T, U>
+where
+    Struct<T, U>: 'pin,
+{
+    pinned: ::pin_project::__reexport::pin::Pin<&'pin mut (T)>,
+    unpinned: &'pin mut (U),
+}
+#[doc(hidden)]
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+struct __StructProjectionRef<'pin, T, U>
+where
+    Struct<T, U>: 'pin,
+{
+    pinned: ::pin_project::__reexport::pin::Pin<&'pin (T)>,
+    unpinned: &'pin (U),
+}
+
+#[doc(hidden)]
+#[allow(non_upper_case_globals)]
+#[allow(single_use_lifetimes)]
+const __SCOPE_Struct: () = {
+    impl<T, U> Struct<T, U> {
+        fn project<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin mut Self>,
+        ) -> __StructProjection<'pin, T, U> {
+            unsafe {
+                let Self { pinned, unpinned } = self.get_unchecked_mut();
+                __StructProjection {
+                    pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned),
+                    unpinned,
+                }
+            }
+        }
+        fn project_ref<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin Self>,
+        ) -> __StructProjectionRef<'pin, T, U> {
+            unsafe {
+                let Self { pinned, unpinned } = self.get_ref();
+                __StructProjectionRef {
+                    pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned),
+                    unpinned,
+                }
+            }
+        }
+    }
+
+    // Automatically create the appropriate conditional `Unpin` implementation.
+    //
+    // Basically this is equivalent to the following code:
+    //
+    // ```rust
+    // impl<T, U> Unpin for Struct<T, U> where T: Unpin {}
+    // ```
+    //
+    // However, if struct is public and there is a private type field,
+    // this would cause an E0446 (private type in public interface).
+    //
+    // When RFC 2145 is implemented (rust-lang/rust#48054),
+    // this will become a lint, rather then a hard error.
+    //
+    // As a workaround for this, we generate a new struct, containing all of the pinned
+    // fields from our #[pin_project] type. This struct is declared within
+    // a function, which makes it impossible to be named by user code.
+    // This guarantees that it will use the default auto-trait impl for Unpin -
+    // that is, it will implement Unpin iff all of its fields implement Unpin.
+    // This type can be safely declared as 'public', satisfying the privacy
+    // checker without actually allowing user code to access it.
+    //
+    // This allows users to apply the #[pin_project] attribute to types
+    // regardless of the privacy of the types of their fields.
+    //
+    // See also https://github.com/taiki-e/pin-project/pull/53.
+    struct __Struct<'pin, T, U> {
+        __pin_project_use_generics: ::pin_project::__private::AlwaysUnpin<'pin, (T, U)>,
+        __field0: T,
+    }
+    impl<'pin, T, U> ::pin_project::__reexport::marker::Unpin for Struct<T, U> where
+        __Struct<'pin, T, U>: ::pin_project::__reexport::marker::Unpin
+    {
+    }
+    // A dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it.
+    //
+    // To ensure that users don't accidentally write a non-functional `UnsafeUnpin`
+    // impls, we emit one ourselves. If the user ends up writing a `UnsafeUnpin` impl,
+    // they'll get a "conflicting implementations of trait" error when coherence
+    // checks are run.
+    unsafe impl<T, U> ::pin_project::UnsafeUnpin for Struct<T, U> {}
+
+    // Ensure that struct does not implement `Drop`.
+    //
+    // If you attempt to provide an Drop impl, the blanket impl will
+    // then apply to your type, causing a compile-time error due to
+    // the conflict with the second impl.
+    trait StructMustNotImplDrop {}
+    #[allow(clippy::drop_bounds)]
+    impl<T: ::pin_project::__reexport::ops::Drop> StructMustNotImplDrop for T {}
+    impl<T, U> StructMustNotImplDrop for Struct<T, U> {}
+    // A dummy impl of `PinnedDrop`, to ensure that users don't accidentally
+    // write a non-functional `PinnedDrop` impls.
+    impl<T, U> ::pin_project::__private::PinnedDrop for Struct<T, U> {
+        unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {}
+    }
+
+    // Ensure that it's impossible to use pin projections on a #[repr(packed)] struct.
+    //
+    // Taking a reference to a packed field is unsafe, and applying
+    // #[deny(safe_packed_borrows)] makes sure that doing this without
+    // an 'unsafe' block (which we deliberately do not generate)
+    // is a hard error.
+    //
+    // If the struct ends up having #[repr(packed)] applied somehow,
+    // this will generate an (unfriendly) error message. Under all reasonable
+    // circumstances, we'll detect the #[repr(packed)] attribute, and generate
+    // a much nicer error above.
+    //
+    // See https://github.com/taiki-e/pin-project/pull/34 for more details.
+    #[deny(safe_packed_borrows)]
+    fn __assert_not_repr_packed<T, U>(val: &Struct<T, U>) {
+        &val.pinned;
+        &val.unpinned;
+    }
+};
+
+fn main() {}
diff --git a/examples/struct-default.rs b/examples/struct-default.rs
new file mode 100644
index 0000000..46808a5
--- /dev/null
+++ b/examples/struct-default.rs
@@ -0,0 +1,14 @@
+// See ./struct-default-expanded.rs for generated code.
+
+#![allow(dead_code)]
+
+use pin_project::pin_project;
+
+#[pin_project]
+struct Struct<T, U> {
+    #[pin]
+    pinned: T,
+    unpinned: U,
+}
+
+fn main() {}
diff --git a/examples/unsafe_unpin-expanded.rs b/examples/unsafe_unpin-expanded.rs
new file mode 100644
index 0000000..7d8ad8e
--- /dev/null
+++ b/examples/unsafe_unpin-expanded.rs
@@ -0,0 +1,111 @@
+// Original code (./unsafe_unpin.rs):
+//
+// ```rust
+// #![allow(dead_code)]
+//
+// use pin_project::{pin_project, UnsafeUnpin};
+//
+// #[pin_project(UnsafeUnpin)]
+// pub struct Struct<T, U> {
+//     #[pin]
+//     pinned: T,
+//     unpinned: U,
+// }
+//
+// unsafe impl<T: Unpin, U> UnsafeUnpin for Struct<T, U> {}
+//
+// fn main() {}
+// ```
+
+#![allow(dead_code, unused_imports, unused_parens)]
+#![allow(clippy::no_effect)]
+
+use pin_project::{pin_project, UnsafeUnpin};
+
+pub struct Struct<T, U> {
+    // #[pin]
+    pinned: T,
+    unpinned: U,
+}
+
+#[doc(hidden)]
+#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+pub(crate) struct __StructProjection<'pin, T, U>
+where
+    Struct<T, U>: 'pin,
+{
+    pinned: ::pin_project::__reexport::pin::Pin<&'pin mut (T)>,
+    unpinned: &'pin mut (U),
+}
+#[doc(hidden)]
+#[allow(dead_code)] // This lint warns unused fields/variants.
+#[allow(single_use_lifetimes)]
+pub(crate) struct __StructProjectionRef<'pin, T, U>
+where
+    Struct<T, U>: 'pin,
+{
+    pinned: ::pin_project::__reexport::pin::Pin<&'pin (T)>,
+    unpinned: &'pin (U),
+}
+
+#[doc(hidden)]
+#[allow(non_upper_case_globals)]
+#[allow(single_use_lifetimes)]
+const __SCOPE_Struct: () = {
+    impl<T, U> Struct<T, U> {
+        pub(crate) fn project<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin mut Self>,
+        ) -> __StructProjection<'pin, T, U> {
+            unsafe {
+                let Self { pinned, unpinned } = self.get_unchecked_mut();
+                __StructProjection {
+                    pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned),
+                    unpinned,
+                }
+            }
+        }
+        pub(crate) fn project_ref<'pin>(
+            self: ::pin_project::__reexport::pin::Pin<&'pin Self>,
+        ) -> __StructProjectionRef<'pin, T, U> {
+            unsafe {
+                let Self { pinned, unpinned } = self.get_ref();
+                __StructProjectionRef {
+                    pinned: ::pin_project::__reexport::pin::Pin::new_unchecked(pinned),
+                    unpinned,
+                }
+            }
+        }
+    }
+
+    impl<'pin, T, U> ::pin_project::__reexport::marker::Unpin for Struct<T, U> where
+        ::pin_project::__private::Wrapper<'pin, Self>: ::pin_project::UnsafeUnpin
+    {
+    }
+
+    // Ensure that struct does not implement `Drop`.
+    //
+    // See ./struct-default-expanded.rs for details.
+    trait StructMustNotImplDrop {}
+    #[allow(clippy::drop_bounds)]
+    impl<T: ::pin_project::__reexport::ops::Drop> StructMustNotImplDrop for T {}
+    impl<T, U> StructMustNotImplDrop for Struct<T, U> {}
+    impl<T, U> ::pin_project::__private::PinnedDrop for Struct<T, U> {
+        unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {}
+    }
+
+    // Ensure that it's impossible to use pin projections on a #[repr(packed)] struct.
+    //
+    // See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/34
+    // for details.
+    #[deny(safe_packed_borrows)]
+    fn __assert_not_repr_packed<T, U>(val: &Struct<T, U>) {
+        &val.pinned;
+        &val.unpinned;
+    }
+};
+
+unsafe impl<T: Unpin, U> UnsafeUnpin for Struct<T, U> {}
+
+fn main() {}
diff --git a/examples/unsafe_unpin.rs b/examples/unsafe_unpin.rs
new file mode 100644
index 0000000..5ec0cd2
--- /dev/null
+++ b/examples/unsafe_unpin.rs
@@ -0,0 +1,16 @@
+// See ./unsafe_unpin-expanded.rs for generated code.
+
+#![allow(dead_code)]
+
+use pin_project::{pin_project, UnsafeUnpin};
+
+#[pin_project(UnsafeUnpin)]
+pub struct Struct<T, U> {
+    #[pin]
+    pinned: T,
+    unpinned: U,
+}
+
+unsafe impl<T: Unpin, U> UnsafeUnpin for Struct<T, U> {}
+
+fn main() {}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..45c58fa
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,239 @@
+//! A crate for safe and ergonomic pin-projection.
+//!
+//! ## Examples
+//!
+//! [`pin_project`] attribute creates a projection type covering all the fields of struct or enum.
+//!
+//! ```rust
+//! use pin_project::pin_project;
+//! use std::pin::Pin;
+//!
+//! #[pin_project]
+//! struct Struct<T, U> {
+//!     #[pin]
+//!     pinned: T,
+//!     unpinned: U,
+//! }
+//!
+//! impl<T, U> Struct<T, U> {
+//!     fn foo(self: Pin<&mut Self>) {
+//!         let this = self.project();
+//!         let _: Pin<&mut T> = this.pinned; // Pinned reference to the field
+//!         let _: &mut U = this.unpinned; // Normal reference to the field
+//!     }
+//! }
+//! ```
+//!
+//! [Code like this will be generated](https://github.com/taiki-e/pin-project/blob/master/examples/struct-default-expanded.rs)
+//!
+//! See [`pin_project`] attribute for more details.
+//!
+//! Also, there are examples and generated code of each feature in [examples](https://github.com/taiki-e/pin-project/blob/master/examples/README.md) directory.
+//!
+//! [`pin_project`]: attr.pin_project.html
+
+#![no_std]
+#![recursion_limit = "256"]
+#![doc(html_root_url = "https://docs.rs/pin-project/0.4.16")]
+#![doc(test(
+    no_crate_inject,
+    attr(deny(warnings, rust_2018_idioms, single_use_lifetimes), allow(dead_code))
+))]
+#![warn(missing_docs, rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
+#![warn(clippy::all, clippy::default_trait_access)]
+// mem::take requires Rust 1.40
+#![allow(clippy::mem_replace_with_default)]
+#![allow(clippy::needless_doctest_main)]
+
+#[doc(inline)]
+pub use pin_project_internal::pin_project;
+
+#[doc(inline)]
+pub use pin_project_internal::pinned_drop;
+
+#[doc(inline)]
+pub use pin_project_internal::project;
+
+#[doc(inline)]
+pub use pin_project_internal::project_ref;
+
+#[doc(inline)]
+pub use pin_project_internal::project_replace;
+
+/// A trait used for custom implementations of [`Unpin`].
+/// This trait is used in conjunction with the `UnsafeUnpin`
+/// argument to [`pin_project`]
+///
+/// The Rust [`Unpin`] trait is safe to implement - by itself,
+/// implementing it cannot lead to undefined behavior. Undefined
+/// behavior can only occur when other unsafe code is used.
+///
+/// It turns out that using pin projections, which requires unsafe code,
+/// imposes additional requirements on an [`Unpin`] impl. Normally, all of this
+/// unsafety is contained within this crate, ensuring that it's impossible for
+/// you to violate any of the guarantees required by pin projection.
+///
+/// However, things change if you want to provide a custom [`Unpin`] impl
+/// for your `#[pin_project]` type. As stated in [the Rust
+/// documentation](https://doc.rust-lang.org/nightly/std/pin/index.html#projections-and-structural-pinning),
+/// you must be sure to only implement [`Unpin`] when all of your `#[pin]` fields (i.e. structurally
+/// pinned fields) are also [`Unpin`].
+///
+/// To help highlight this unsafety, the `UnsafeUnpin` trait is provided.
+/// Implementing this trait is logically equivalent to implementing [`Unpin`] -
+/// this crate will generate an [`Unpin`] impl for your type that 'forwards' to
+/// your `UnsafeUnpin` impl. However, this trait is `unsafe` - since your type
+/// uses structural pinning (otherwise, you wouldn't be using this crate!),
+/// you must be sure that your `UnsafeUnpin` impls follows all of
+/// the requirements for an [`Unpin`] impl of a structurally-pinned type.
+///
+/// Note that if you specify `#[pin_project(UnsafeUnpin)]`, but do *not*
+/// provide an impl of `UnsafeUnpin`, your type will never implement [`Unpin`].
+/// This is effectively the same thing as adding a [`PhantomPinned`] to your type
+///
+/// Since this trait is `unsafe`, impls of it will be detected by the `unsafe_code` lint,
+/// and by tools like `cargo geiger`.
+///
+/// ## Examples
+///
+/// An `UnsafeUnpin` impl which, in addition to requiring that structurally pinned
+/// fields be [`Unpin`], imposes an additional requirement:
+///
+/// ```rust
+/// use pin_project::{pin_project, UnsafeUnpin};
+///
+/// #[pin_project(UnsafeUnpin)]
+/// struct Foo<K, V> {
+///     #[pin]
+///     field_1: K,
+///     field_2: V,
+/// }
+///
+/// unsafe impl<K, V> UnsafeUnpin for Foo<K, V> where K: Unpin + Clone {}
+/// ```
+///
+/// [`PhantomPinned`]: core::marker::PhantomPinned
+/// [`pin_project`]: attr.pin_project.html
+pub unsafe trait UnsafeUnpin {}
+
+// Not public API.
+#[doc(hidden)]
+pub mod __private {
+    use super::UnsafeUnpin;
+    use core::{marker::PhantomData, mem::ManuallyDrop, pin::Pin, ptr};
+
+    #[doc(hidden)]
+    pub use pin_project_internal::__PinProjectInternalDerive;
+
+    // Implementing `PinnedDrop::drop` is safe, but calling it is not safe.
+    // This is because destructors can be called multiple times in safe code and
+    // [double dropping is unsound](https://github.com/rust-lang/rust/pull/62360).
+    //
+    // Ideally, it would be desirable to be able to forbid manual calls in
+    // the same way as [`Drop::drop`], but the library cannot do it. So, by using
+    // macros and replacing them with private traits, we prevent users from
+    // calling `PinnedDrop::drop`.
+    //
+    // Users can implement [`Drop`] safely using `#[pinned_drop]` and can drop a
+    // type that implements `PinnedDrop` using the [`drop`] function safely.
+    // **Do not call or implement this trait directly.**
+    #[doc(hidden)]
+    pub trait PinnedDrop {
+        #[doc(hidden)]
+        unsafe fn drop(self: Pin<&mut Self>);
+    }
+
+    // This is an internal helper struct used by `pin-project-internal`.
+    // This allows us to force an error if the user tries to provide
+    // a regular `Unpin` impl when they specify the `UnsafeUnpin` argument.
+    // This is why we need Wrapper:
+    //
+    // Supposed we have the following code:
+    //
+    // #[pin_project(UnsafeUnpin)]
+    // struct MyStruct<T> {
+    //     #[pin] field: T
+    // }
+    //
+    // impl<T> Unpin for MyStruct<T> where MyStruct<T>: UnsafeUnpin {} // generated by pin-project-internal
+    // impl<T> Unpin for MyStruct<T> where T: Copy // written by the user
+    //
+    // We want this code to be rejected - the user is completely bypassing `UnsafeUnpin`,
+    // and providing an unsound Unpin impl in safe code!
+    //
+    // Unfortunately, the Rust compiler will accept the above code.
+    // Because MyStruct is declared in the same crate as the user-provided impl,
+    // the compiler will notice that 'MyStruct<T>: UnsafeUnpin' never holds.
+    //
+    // The solution is to introduce the 'Wrapper' struct, which is defined
+    // in the 'pin-project' crate.
+    //
+    // We now have code that looks like this:
+    //
+    // impl<T> Unpin for MyStruct<T> where Wrapper<MyStruct<T>>: UnsafeUnpin {} // generated by pin-project-internal
+    // impl<T> Unpin for MyStruct<T> where T: Copy // written by the user
+    //
+    // We also have 'unsafe impl<T> UnsafeUnpin for Wrapper<T> where T: UnsafeUnpin {}' in the
+    // 'pin-project' crate.
+    //
+    // Now, our generated impl has a bound involving a type defined in another crate - Wrapper.
+    // This will cause rust to conservatively assume that 'Wrapper<MyStruct<T>>: UnsafeUnpin'
+    // holds, in the interest of preserving forwards compatibility (in case such an impl is added
+    // for Wrapper<T> in a new version of the crate).
+    //
+    // This will cause rust to reject any other Unpin impls for MyStruct<T>, since it will
+    // assume that our generated impl could potentially apply in any situation.
+    //
+    // This achieves the desired effect - when the user writes `#[pin_project(UnsafeUnpin)]`,
+    // the user must either provide no impl of `UnsafeUnpin` (which is equivalent
+    // to making the type never implement Unpin), or provide an impl of `UnsafeUnpin`.
+    // It is impossible for them to provide an impl of `Unpin`
+    #[doc(hidden)]
+    pub struct Wrapper<'a, T: ?Sized>(PhantomData<&'a ()>, T);
+
+    unsafe impl<T: ?Sized> UnsafeUnpin for Wrapper<'_, T> where T: UnsafeUnpin {}
+
+    // This is an internal helper struct used by `pin-project-internal`.
+    //
+    // See https://github.com/taiki-e/pin-project/pull/53 for more details.
+    #[doc(hidden)]
+    pub struct AlwaysUnpin<'a, T: ?Sized>(PhantomData<&'a ()>, PhantomData<T>);
+
+    impl<T: ?Sized> Unpin for AlwaysUnpin<'_, T> {}
+
+    // This is an internal helper used to ensure a value is dropped.
+    #[doc(hidden)]
+    pub struct UnsafeDropInPlaceGuard<T: ?Sized>(pub *mut T);
+
+    impl<T: ?Sized> Drop for UnsafeDropInPlaceGuard<T> {
+        fn drop(&mut self) {
+            unsafe {
+                ptr::drop_in_place(self.0);
+            }
+        }
+    }
+
+    // This is an internal helper used to ensure a value is overwritten without
+    // its destructor being called.
+    #[doc(hidden)]
+    pub struct UnsafeOverwriteGuard<T> {
+        pub value: ManuallyDrop<T>,
+        pub target: *mut T,
+    }
+
+    impl<T> Drop for UnsafeOverwriteGuard<T> {
+        fn drop(&mut self) {
+            unsafe {
+                ptr::write(self.target, ptr::read(&*self.value));
+            }
+        }
+    }
+}
+
+// Not public API.
+// See tests/overwriting_core_crate.rs for more.
+#[doc(hidden)]
+pub mod __reexport {
+    #[doc(hidden)]
+    pub use core::{marker, mem, ops, pin, ptr};
+}
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<T: 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::<SameName>();
+
+    #[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::<DifferentName>();
+
+    #[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::<TupleStruct>();
+
+    #[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::<Variant>();
+
+    #[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::<Field>();
+
+    #[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::<SameCfg>();
+
+    #[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::<DifferentCfg>();
+
+    #[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<T> {
+        #[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<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pin_project(PinnedDrop)]
+pub struct StructPinnedDrop<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pinned_drop]
+impl<T, U> PinnedDrop for StructPinnedDrop<T, U> {
+    fn drop(self: Pin<&mut Self>) {}
+}
+
+#[pin_project(Replace)]
+pub struct StructReplace<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+// UnsafeUnpin without UnsafeUnpin impl is also safe
+#[pin_project(UnsafeUnpin)]
+pub struct StructUnsafeUnpin<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pin_project(!Unpin)]
+pub struct StructNotUnpin<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pin_project]
+pub enum EnumDefault<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+#[pin_project(PinnedDrop)]
+pub enum EnumPinnedDrop<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+#[pinned_drop]
+impl<T, U> PinnedDrop for EnumPinnedDrop<T, U> {
+    fn drop(self: Pin<&mut Self>) {}
+}
+
+#[pin_project(Replace)]
+pub enum EnumReplace<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+// UnsafeUnpin without UnsafeUnpin impl is also safe
+#[pin_project(UnsafeUnpin)]
+pub enum EnumUnsafeUnpin<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+#[pin_project(!Unpin)]
+pub enum EnumNotUnpin<T, U> {
+    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<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pin_project(PinnedDrop)]
+pub struct StructPinnedDrop<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pinned_drop]
+impl<T, U> PinnedDrop for StructPinnedDrop<T, U> {
+    fn drop(self: Pin<&mut Self>) {}
+}
+
+#[pin_project(Replace)]
+pub struct StructReplace<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pin_project(UnsafeUnpin)]
+pub struct StructUnsafeUnpin<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+unsafe impl<T: Unpin, U> UnsafeUnpin for StructUnsafeUnpin<T, U> {}
+
+#[pin_project(!Unpin)]
+pub struct StructNotUnpin<T, U> {
+    #[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<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+#[pin_project(PinnedDrop)]
+pub enum EnumPinnedDrop<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+#[pinned_drop]
+impl<T, U> PinnedDrop for EnumPinnedDrop<T, U> {
+    fn drop(self: Pin<&mut Self>) {}
+}
+
+#[pin_project(Replace)]
+pub enum EnumReplace<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+#[pin_project(UnsafeUnpin)]
+pub enum EnumUnsafeUnpin<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+unsafe impl<T: Unpin, U> UnsafeUnpin for EnumUnsafeUnpin<T, U> {}
+
+#[pin_project(!Unpin)]
+pub enum EnumNotUnpin<T, U> {
+    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<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pin_project(PinnedDrop)]
+pub struct StructPinnedDrop<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pinned_drop]
+impl<T, U> PinnedDrop for StructPinnedDrop<T, U> {
+    fn drop(self: Pin<&mut Self>) {}
+}
+
+#[pin_project(Replace)]
+pub struct StructReplace<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pin_project(UnsafeUnpin)]
+pub struct StructUnsafeUnpin<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+unsafe impl<T: Unpin, U> UnsafeUnpin for StructUnsafeUnpin<T, U> {}
+
+#[pin_project(!Unpin)]
+pub struct StructNotUnpin<T, U> {
+    #[pin]
+    pub pinned: T,
+    pub unpinned: U,
+}
+
+#[pin_project]
+pub enum EnumDefault<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+#[pin_project(PinnedDrop)]
+pub enum EnumPinnedDrop<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+#[pinned_drop]
+impl<T, U> PinnedDrop for EnumPinnedDrop<T, U> {
+    fn drop(self: Pin<&mut Self>) {}
+}
+
+#[pin_project(Replace)]
+pub enum EnumReplace<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+#[pin_project(UnsafeUnpin)]
+pub enum EnumUnsafeUnpin<T, U> {
+    Struct {
+        #[pin]
+        pinned: T,
+        unpinned: U,
+    },
+    Tuple(#[pin] T, U),
+}
+
+unsafe impl<T: Unpin, U> UnsafeUnpin for EnumUnsafeUnpin<T, U> {}
+
+#[pin_project(!Unpin)]
+pub enum EnumNotUnpin<T, U> {
+    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<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 __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<i32> = field1;
+    let _: i32 = field2;
+    assert_eq!(field2, 2);
+    assert_eq!(s.field1, 3);
+    assert_eq!(s.field2, 4);
+
+    #[pin_project(Replace)]
+    struct TupleStruct<T, U>(#[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<A, B, C, D> {
+        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<T>
+    where
+        T: Copy,
+    {
+        field: T,
+    }
+
+    #[pin_project]
+    struct TupleStruct<T>(T)
+    where
+        T: Copy;
+
+    #[pin_project]
+    enum EnumWhere<T>
+    where
+        T: Copy,
+    {
+        Variant(T),
+    }
+}
+
+#[test]
+fn where_clause_and_associated_type_field() {
+    #[pin_project(Replace)]
+    struct Struct1<I>
+    where
+        I: Iterator,
+    {
+        #[pin]
+        field1: I,
+        field2: I::Item,
+    }
+
+    #[pin_project(Replace)]
+    struct Struct2<I, J>
+    where
+        I: Iterator<Item = J>,
+    {
+        #[pin]
+        field1: I,
+        field2: J,
+    }
+
+    #[pin_project(Replace)]
+    struct Struct3<T>
+    where
+        T: 'static,
+    {
+        field: T,
+    }
+
+    trait Static: 'static {}
+
+    impl<T> Static for Struct3<T> {}
+
+    #[pin_project(Replace)]
+    struct TupleStruct<I>(#[pin] I, I::Item)
+    where
+        I: Iterator;
+
+    #[pin_project(Replace)]
+    enum Enum<I>
+    where
+        I: Iterator,
+    {
+        Variant1(#[pin] I),
+        Variant2(I::Item),
+    }
+}
+
+#[test]
+fn derive_copy() {
+    #[pin_project(Replace)]
+    #[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(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<T: 'static> {
+        field: T,
+    }
+
+    trait Static: 'static {}
+
+    impl<T> Static for Struct7<T> {}
+
+    #[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<T> {
+        #[pin]
+        field: T,
+    }
+
+    #[pinned_drop]
+    impl<T> PinnedDrop for Struct1<T> {
+        fn drop(self: Pin<&mut Self>) {}
+    }
+
+    unsafe impl<T: Unpin> UnsafeUnpin for Struct1<T> {}
+
+    #[pin_project(UnsafeUnpin, Replace)]
+    pub struct Struct2<T> {
+        #[pin]
+        field: T,
+    }
+
+    unsafe impl<T: Unpin> UnsafeUnpin for Struct2<T> {}
+
+    #[pin_project(PinnedDrop, !Unpin)]
+    pub struct Struct3<T> {
+        #[pin]
+        field: T,
+    }
+
+    #[pinned_drop]
+    impl<T> PinnedDrop for Struct3<T> {
+        fn drop(self: Pin<&mut Self>) {}
+    }
+
+    #[pin_project(!Unpin, Replace)]
+    pub struct Struct4<T> {
+        #[pin]
+        field: T,
+    }
+}
+
+#[test]
+fn private_type_in_public_type() {
+    #[pin_project(Replace)]
+    pub struct PublicStruct<T> {
+        #[pin]
+        inner: PrivateStruct<T>,
+    }
+
+    struct PrivateStruct<T>(T);
+}
+
+#[test]
+fn lifetime_project() {
+    #[pin_project(Replace)]
+    struct Struct1<T, U> {
+        #[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<T, U> {
+        Variant {
+            #[pin]
+            pinned: 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
+        }
+    }
+
+    impl<T, U> Enum<T, U> {
+        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<T, U> {
+        #[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<T, U> {
+        Variant {
+            #[pin]
+            pinned: 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
+        }
+    }
+
+    impl<T, U> Enum<T, U> {
+        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<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]
+    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;
+
+    #[pin_project(UnsafeUnpin)]
+    struct Struct5<T: ?Sized> {
+        x: T,
+    }
+
+    #[pin_project(UnsafeUnpin)]
+    struct Struct6<T: ?Sized> {
+        #[pin]
+        x: T,
+    }
+
+    #[pin_project(PinnedDrop)]
+    struct Struct7<T: ?Sized> {
+        x: T,
+    }
+
+    #[pinned_drop]
+    impl<T: ?Sized> PinnedDrop for Struct7<T> {
+        fn drop(self: Pin<&mut Self>) {}
+    }
+
+    #[pin_project(PinnedDrop)]
+    struct Struct8<T: ?Sized> {
+        #[pin]
+        x: T,
+    }
+
+    #[pinned_drop]
+    impl<T: ?Sized> PinnedDrop for Struct8<T> {
+        fn drop(self: Pin<&mut Self>) {}
+    }
+
+    #[pin_project(!Unpin)]
+    struct Struct9<T: ?Sized> {
+        x: T,
+    }
+
+    #[pin_project(!Unpin)]
+    struct Struct10<T: ?Sized> {
+        #[pin]
+        x: T,
+    }
+
+    #[pin_project]
+    struct TupleStruct1<T: ?Sized>(T);
+
+    #[pin_project]
+    struct TupleStruct2<T: ?Sized>(#[pin] T);
+
+    #[pin_project(UnsafeUnpin)]
+    struct TupleStruct5<T: ?Sized>(T);
+
+    #[pin_project(UnsafeUnpin)]
+    struct TupleStruct6<T: ?Sized>(#[pin] T);
+
+    #[pin_project(PinnedDrop)]
+    struct TupleStruct7<T: ?Sized>(T);
+
+    #[pinned_drop]
+    impl<T: ?Sized> PinnedDrop for TupleStruct7<T> {
+        fn drop(self: Pin<&mut Self>) {}
+    }
+
+    #[pin_project(PinnedDrop)]
+    struct TupleStruct8<T: ?Sized>(#[pin] T);
+
+    #[pinned_drop]
+    impl<T: ?Sized> PinnedDrop for TupleStruct8<T> {
+        fn drop(self: Pin<&mut Self>) {}
+    }
+
+    #[pin_project(!Unpin)]
+    struct TupleStruct9<T: ?Sized>(T);
+
+    #[pin_project(!Unpin)]
+    struct TupleStruct10<T: ?Sized>(#[pin] T);
+}
+
+#[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,
+    }
+
+    #[pin_project]
+    struct TupleStruct3<T>(T)
+    where
+        T: ?Sized;
+
+    #[pin_project]
+    struct TupleStruct4<T>(#[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<T>
+    where
+        Self: Trait1,
+    {
+        x: T,
+    }
+
+    impl<T> Trait1 for Struct1<T> {}
+
+    pub trait Trait2 {
+        type Assoc;
+    }
+
+    #[pin_project(Replace)]
+    pub struct Struct2<T>
+    where
+        Self: Trait2<Assoc = Struct1<T>>,
+        <Self as Trait2>::Assoc: Trait1,
+    {
+        x: T,
+    }
+
+    impl<T> Trait2 for Struct2<T> {
+        type Assoc = Struct1<T>;
+    }
+}
+
+#[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(Replace)]
+    struct Foo<A, B> {
+        _x: <Example<A> as Bar<B>>::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<T, U> {
+        #[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());
+            <Self>::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<T, U> {
+        #[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<T, U>(#[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<A, B, C, D> {
+        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<T, U> {
+        #[pin]
+        field1: T,
+        field2: U,
+    }
+
+    #[project]
+    impl<T, U> HasGenerics<T, U> {
+        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<T, U> 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<T, U> {
+        #[pin]
+        field1: T,
+        field2: U,
+    }
+
+    #[allow(single_use_lifetimes)]
+    #[allow(clippy::needless_lifetimes)]
+    #[project]
+    impl<T, U> HasOverlappingLifetimes2<T, U> {
+        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<A> {
+        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<A> {
+        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<A> {
+        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<A> {
+        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<A, B> {
+        Variant1(#[pin] A),
+        Variant2(u8),
+        Variant3 {
+            #[pin] field: B
+        }
+    }
+
+    let mut x: Foo<bool, f32> = 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<A> {
+        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<T, U> {
+        #[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<T, U>(#[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<A, B, C, D> {
+        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<T, U> {
+        #[pin]
+        field1: T,
+        field2: U,
+    }
+
+    #[project_ref]
+    impl<T, U> HasGenerics<T, U> {
+        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<T, U> 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<T, U> {
+        #[pin]
+        field1: T,
+        field2: U,
+    }
+
+    #[allow(single_use_lifetimes)]
+    #[allow(clippy::needless_lifetimes)]
+    #[project_ref]
+    impl<T, U> HasOverlappingLifetimes2<T, U> {
+        fn foo<'pin>(&'pin self) {}
+    }
+}
+
+#[project_ref]
+#[test]
+fn combine() {
+    #[pin_project(Replace)]
+    enum Enum<A> {
+        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<T, U> {
+        #[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<i32> = field1;
+
+    let y: i32 = field2;
+    assert_eq!(y, 2);
+
+    // tuple struct
+
+    #[pin_project(Replace)]
+    struct TupleStruct<T, U>(#[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<i32> = x;
+    let y: i32 = y;
+    assert_eq!(y, 2);
+
+    #[pin_project(Replace)]
+    enum Enum<A, B, C, D> {
+        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<i32> = x;
+            let y: i32 = y;
+            assert_eq!(y, 2);
+        }
+        Enum::Variant2 { field1, field2 } => {
+            let _x: PhantomData<i32> = field1;
+            let _y: i32 = field2;
+            panic!()
+        }
+        Enum::None => panic!(),
+    }
+}
+
+#[project_replace]
+#[test]
+fn combine() {
+    #[pin_project(Replace)]
+    enum Enum<A> {
+        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<usize> = 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<T> {
+    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<u8>>` 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<u8>>`
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<T> {
+    #[cfg_attr(any(), pin)]
+    inner: T,
+}
+
+#[cfg_attr(not(any()), pin_project)]
+struct Bar<T> {
+    #[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<T> {
+    inner: T,
+}
+
+#[cfg_attr(not(any()), pin_project)]
+struct Bar<T> {
+    #[cfg_attr(not(any()), pin)]
+    inner: T,
+}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+    is_unpin::<Foo<PhantomPinned>>(); // ERROR E0277
+    is_unpin::<Bar<()>>(); // Ok
+    is_unpin::<Bar<PhantomPinned>>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+18 |     is_unpin::<Foo<PhantomPinned>>(); // ERROR E0277
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `Foo<std::marker::PhantomPinned>`, the trait `std::marker::Unpin` is not implemented for `std::marker::PhantomPinned`
+   |
+   = note: required because it appears within the type `Foo<std::marker::PhantomPinned>`
+
+error[E0277]: `std::marker::PhantomPinned` cannot be unpinned
+  --> $DIR/cfg_attr-unpin.rs:20:5
+   |
+15 | fn is_unpin<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+20 |     is_unpin::<Bar<PhantomPinned>>(); //~ 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<std::marker::PhantomPinned>`
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<T> {
+    #[cfg(any())]
+    #[pin]
+    inner: T,
+    #[cfg(not(any()))]
+    inner: T,
+}
+
+#[pin_project]
+struct Bar<T> {
+    #[cfg(any())]
+    inner: T,
+    #[cfg(not(any()))]
+    #[pin]
+    inner: T,
+}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+    is_unpin::<Foo<PhantomPinned>>(); // Ok
+    is_unpin::<Bar<()>>(); // Ok
+    is_unpin::<Bar<PhantomPinned>>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+27 |     is_unpin::<Bar<PhantomPinned>>(); //~ 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<std::marker::PhantomPinned>`
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<T> {
+    val: T,
+}
+
+#[pin_project(!Unpin)]
+struct Foo<T, U> {
+    #[pin]
+    inner: Inner<T>,
+    other: U,
+}
+
+#[pin_project(!Unpin)]
+struct TrivialBounds {
+    #[pin]
+    field1: PhantomPinned,
+}
+
+#[pin_project(!Unpin)]
+struct Bar<'a, T, U> {
+    #[pin]
+    inner: &'a mut Inner<T>,
+    other: U,
+}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+    is_unpin::<Foo<(), ()>>(); //~ ERROR E0277
+    is_unpin::<Foo<PhantomPinned, ()>>(); //~ ERROR E0277
+    is_unpin::<Foo<(), PhantomPinned>>(); //~ ERROR E0277
+    is_unpin::<Foo<PhantomPinned, PhantomPinned>>(); //~ ERROR E0277
+
+    is_unpin::<TrivialBounds>(); //~ ERROR E0277
+
+    is_unpin::<Bar<'_, (), ()>>(); //~ ERROR E0277
+    is_unpin::<Bar<'_, PhantomPinned, PhantomPinned>>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+31 |     is_unpin::<Foo<(), ()>>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+32 |     is_unpin::<Foo<PhantomPinned, ()>>(); //~ 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:33:5
+   |
+28 | fn is_unpin<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+33 |     is_unpin::<Foo<(), PhantomPinned>>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+34 |     is_unpin::<Foo<PhantomPinned, PhantomPinned>>(); //~ 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, std::marker::PhantomPinned>`
+
+error[E0277]: `std::marker::PhantomPinned` cannot be unpinned
+  --> $DIR/assert-not-unpin.rs:36:5
+   |
+28 | fn is_unpin<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+36 |     is_unpin::<TrivialBounds>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+38 |     is_unpin::<Bar<'_, (), ()>>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+39 |     is_unpin::<Bar<'_, PhantomPinned, PhantomPinned>>(); //~ 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<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+impl<T, U> Unpin for Foo<T, U> where T: Unpin {}
+
+#[pin_project(!Unpin)] //~ ERROR E0119
+struct Bar<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+impl<T, U> Unpin for Bar<T, U> {}
+
+#[pin_project(!Unpin)] //~ ERROR E0119
+struct Baz<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+impl<T: Unpin, U: Unpin> Unpin for Baz<T, U> {}
+
+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<T, U> Unpin for Foo<T, U> 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<T, U> Unpin for Bar<T, U> {}
+   | ------------------------------ 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<T: Unpin, U: Unpin> Unpin for Baz<T, U> {}
+   | -------------------------------------------- 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<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+unsafe impl<T, U> UnsafeUnpin for Foo<T, U> where T: Unpin {}
+
+#[pin_project(!Unpin)] //~ ERROR E0119
+struct Bar<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+unsafe impl<T, U> UnsafeUnpin for Bar<T, U> {}
+
+#[pin_project(!Unpin)] //~ ERROR E0119
+struct Baz<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+unsafe impl<T: Unpin, U: Unpin> UnsafeUnpin for Baz<T, U> {}
+
+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<T, U> UnsafeUnpin for Foo<T, U> 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<T, U> UnsafeUnpin for Bar<T, U> {}
+   | ------------------------------------------- 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<T: Unpin, U: Unpin> UnsafeUnpin for Baz<T, U> {}
+   | --------------------------------------------------------- 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<T: 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::<Foo>(); //~ ERROR E0277
+    is_unpin::<Bar>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+21 |     is_unpin::<Foo>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+22 |     is_unpin::<Bar>(); //~ 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<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+impl<T, U> Drop for Foo<T, U> {
+    fn drop(&mut self) {}
+}
+
+#[pin_project(PinnedDrop)] //~ ERROR E0119
+struct Bar<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+#[pinned_drop]
+impl<T, U> PinnedDrop for Bar<T, U> {
+    fn drop(self: Pin<&mut Self>) {}
+}
+
+impl<T, U> Drop for Bar<T, U> {
+    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<T, U> Drop for Bar<T, U> {
+   | ----------------------------- 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<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/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<T, U> Unpin for Foo<T, U> 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<T, U> Unpin for Bar<T, U> {} // 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<T: Unpin, U: Unpin> Unpin for Baz<T, U> {} // 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<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+unsafe impl<T, U> UnsafeUnpin for Foo<T, U> where T: Unpin {}
+
+#[pin_project] //~ ERROR E0119
+struct Bar<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+unsafe impl<T, U> UnsafeUnpin for Bar<T, U> {}
+
+#[pin_project] //~ ERROR E0119
+struct Baz<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+unsafe impl<T: Unpin, U: Unpin> UnsafeUnpin for Baz<T, U> {}
+
+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<T, U> UnsafeUnpin for Foo<T, U> 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<T, U> UnsafeUnpin for Bar<T, U> {}
+   | ------------------------------------------- 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<T: Unpin, U: Unpin> UnsafeUnpin for Baz<T, U> {}
+   | --------------------------------------------------------- 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<T> {
+    #[pin]
+    inner: T,
+}
+
+struct __Foo {}
+
+impl Unpin for __Foo {}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+    is_unpin::<Foo<PhantomPinned>>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+17 |     is_unpin::<Foo<PhantomPinned>>(); //~ 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<std::marker::PhantomPinned>`
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<T> {
+    val: T,
+}
+
+#[pin_project]
+struct Foo<T, U> {
+    #[pin]
+    inner: Inner<T>,
+    other: U,
+}
+
+#[pin_project]
+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/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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+31 |     is_unpin::<Foo<PhantomPinned, ()>>(); //~ 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<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<std::marker::PhantomPinned, ()>`
+
+error[E0277]: `std::marker::PhantomPinned` cannot be unpinned
+  --> $DIR/proper_unpin.rs:33:5
+   |
+28 | fn is_unpin<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+33 |     is_unpin::<Foo<PhantomPinned, PhantomPinned>>(); //~ 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<std::marker::PhantomPinned>`
+   = 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<std::marker::PhantomPinned, std::marker::PhantomPinned>`
+
+error[E0277]: `std::marker::PhantomPinned` cannot be unpinned
+  --> $DIR/proper_unpin.rs:35:5
+   |
+28 | fn is_unpin<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+35 |     is_unpin::<TrivialBounds>(); //~ 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<T: 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::<Foo>();
+    is_unpin::<Bar>();
+
+    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<T: 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::<Foo>(); //~ ERROR E0277
+    is_unpin::<Bar>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+22 |     is_unpin::<Foo>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+23 |     is_unpin::<Bar>(); //~ 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::<P>::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::<P>::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 <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
+
+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 <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
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<T> {
+    field: T,
+}
+
+impl<T: Unpin> Drop for DropImpl<T> {
+    //~^ ERROR E0367
+    fn drop(&mut self) {}
+}
+
+#[pin_project(PinnedDrop)] //~ ERROR E0277
+struct PinnedDropImpl<T> {
+    #[pin]
+    field: T,
+}
+
+#[pinned_drop]
+impl<T: Unpin> PinnedDrop for PinnedDropImpl<T> {
+    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<T: Unpin> Drop for DropImpl<T> {
+   |         ^^^^^
+   |
+note: the implementor must specify the same requirement
+  --> $DIR/conditional-drop-impl.rs:6:1
+   |
+6  | / struct DropImpl<T> {
+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<T>`
+   = note: required by `pin_project::__private::PinnedDrop::drop`
+help: consider restricting type parameter `T`
+   |
+16 | struct PinnedDropImpl<T: std::marker::Unpin> {
+   |                        ^^^^^^^^^^^^^^^^^^^^
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, B> {
+    A(#[pin] A),
+    B(B),
+}
+
+struct Struct<T>(T);
+
+#[project]
+fn foo() {
+    let mut foo: Enum<bool, bool> = 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<A, B, C, D> {
+        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<A, B, C, D> {
+        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<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+impl<T, U> Unpin for Foo<T, U> where T: Unpin {}
+
+#[pin_project(UnsafeUnpin)] //~ ERROR E0119
+struct Bar<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+impl<T, U> Unpin for Bar<T, U> {}
+
+#[pin_project(UnsafeUnpin)] //~ ERROR E0119
+struct Baz<T, U> {
+    #[pin]
+    future: T,
+    field: U,
+}
+
+impl<T: Unpin, U: Unpin> Unpin for Baz<T, U> {}
+
+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<T, U> Unpin for Foo<T, U> 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<T, U> Unpin for Bar<T, U> {}
+   | ------------------------------ 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<T: Unpin, U: Unpin> Unpin for Baz<T, U> {}
+   | -------------------------------------------- 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<T, U> {
+    #[pin]
+    inner: T,
+    other: U,
+}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+    is_unpin::<Struct<(), ()>>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+13 |     is_unpin::<Struct<(), ()>>(); //~ 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<T: Unpin>() {}
+
+#[pin_project(UnsafeUnpin)]
+struct Blah<T, U> {
+    field1: U,
+    #[pin]
+    field2: T,
+}
+
+unsafe impl<T: Unpin, U> UnsafeUnpin for Blah<T, U> {}
+
+#[pin_project(UnsafeUnpin)]
+struct TrivialBounds {
+    #[pin]
+    field1: PhantomPinned,
+}
+
+#[pin_project(UnsafeUnpin)]
+struct OverlappingLifetimeNames<'pin, T, U> {
+    #[pin]
+    field1: U,
+    #[pin]
+    field2: Option<T>,
+    field3: &'pin (),
+}
+
+unsafe impl<T: Unpin, U: Unpin> UnsafeUnpin for OverlappingLifetimeNames<'_, T, U> {}
+
+fn main() {
+    is_unpin::<Blah<PhantomPinned, ()>>(); //~ ERROR E0277
+    is_unpin::<Blah<(), PhantomPinned>>(); // Ok
+    is_unpin::<Blah<PhantomPinned, PhantomPinned>>(); //~ ERROR E0277
+
+    is_unpin::<TrivialBounds>(); //~ ERROR E0277
+
+    is_unpin::<OverlappingLifetimeNames<'_, PhantomPinned, ()>>(); //~ ERROR E0277
+    is_unpin::<OverlappingLifetimeNames<'_, (), PhantomPinned>>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+33 |     is_unpin::<Blah<PhantomPinned, ()>>(); //~ 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<std::marker::PhantomPinned, ()>`
+   = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, Blah<std::marker::PhantomPinned, ()>>`
+   = note: required because of the requirements on the impl of `std::marker::Unpin` for `Blah<std::marker::PhantomPinned, ()>`
+
+error[E0277]: `std::marker::PhantomPinned` cannot be unpinned
+  --> $DIR/proper_unpin.rs:35:5
+   |
+4  | fn is_unpin<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+35 |     is_unpin::<Blah<PhantomPinned, PhantomPinned>>(); //~ 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<std::marker::PhantomPinned, std::marker::PhantomPinned>`
+   = note: required because of the requirements on the impl of `pin_project::UnsafeUnpin` for `pin_project::__private::Wrapper<'_, Blah<std::marker::PhantomPinned, std::marker::PhantomPinned>>`
+   = note: required because of the requirements on the impl of `std::marker::Unpin` for `Blah<std::marker::PhantomPinned, std::marker::PhantomPinned>`
+
+error[E0277]: the trait bound `TrivialBounds: pin_project::UnsafeUnpin` is not satisfied
+  --> $DIR/proper_unpin.rs:37:16
+   |
+4  | fn is_unpin<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+37 |     is_unpin::<TrivialBounds>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+39 |     is_unpin::<OverlappingLifetimeNames<'_, PhantomPinned, ()>>(); //~ 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<T: Unpin>() {}
+   |                ----- required by this bound in `is_unpin`
+...
+40 |     is_unpin::<OverlappingLifetimeNames<'_, (), PhantomPinned>>(); //~ 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<T> {
+    #[pin]
+    x: T,
+}
+
+// unsound Unpin impl
+impl<T> Unpin for Struct<T> {}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+    is_unpin::<Struct<PhantomPinned>>()
+}
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<T> Unpin for Struct<T> {}
+   | --------------------------- 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<T> {
+    #[pin]
+    x: T,
+}
+
+// unsound Unpin impl
+impl<T> Unpin for Struct<T> {}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+    is_unpin::<Struct<PhantomPinned>>()
+}
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<T> Unpin for Struct<T> {}
+   | --------------------------- 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<T> {
+    #[pin]
+    x: T,
+}
+
+// unsound Unpin impl
+impl<T> Unpin for Struct<T> {}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+    is_unpin::<Struct<PhantomPinned>>()
+}
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<T> Unpin for Struct<T> {}
+   | --------------------------- 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<T> {
+    #[pin]
+    x: T,
+}
+
+// unsound Unpin impl
+impl<T> Unpin for Struct<T> {}
+
+fn is_unpin<T: Unpin>() {}
+
+fn main() {
+    is_unpin::<Struct<PhantomPinned>>()
+}
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<T> Unpin for Struct<T> {}
+   | --------------------------- 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<A, B, C, D> {
+        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<A, B, C, D> {
+        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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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 <https://github.com/rust-lang/rust/issues/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>(T);
+
+    impl<T> Unpin for Wrapper<T> where T: Unpin {}
+
+    struct B(PhantomPinned);
+
+    impl Unpin for B where Wrapper<PhantomPinned>: Unpin {} // Ok
+
+    struct WrapperWithLifetime<'a, T>(PhantomData<&'a ()>, T);
+
+    impl<T> 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>(T);
+
+    impl<T> Unpin for Wrapper<T> where T: Unpin {}
+
+    struct B(PhantomPinned);
+
+    impl Unpin for B where Wrapper<PhantomPinned>: Unpin {} //~ ERROR E0277
+
+    struct WrapperWithLifetime<'a, T>(PhantomData<&'a ()>, T);
+
+    impl<T> 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>(T);
+
+    impl<T> Unpin for Wrapper<T> where T: Unpin {}
+
+    struct B(Inner);
+
+    impl Unpin for B where Wrapper<Inner>: Unpin {} //~ ERROR E0277
+
+    struct WrapperWithLifetime<'a, T>(PhantomData<&'a ()>, T);
+
+    impl<T> 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<PhantomPinned>: 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<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: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<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`
+   = note: required because of the requirements on the impl of `std::marker::Unpin` for `inner::Wrapper<inner::Inner>`
+   = 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>(T);
+
+    impl<T> Unpin for Wrapper<T> where T: Unpin {}
+
+    struct B(Inner);
+
+    impl Unpin for B where Wrapper<Inner>: Unpin {} //~ ERROR std::marker::Unpin does not depend on any type or lifetime parameters
+
+    struct WrapperWithLifetime<'a, T>(PhantomData<&'a ()>, T);
+
+    impl<T> 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<inner::Inner>: 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<Inner>: 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<T: Unpin>() {}
+
+#[pin_project(UnsafeUnpin)]
+pub struct Blah<T, U> {
+    field1: U,
+    #[pin]
+    field2: T,
+}
+
+unsafe impl<T: Unpin, U> UnsafeUnpin for Blah<T, U> {}
+
+#[pin_project(UnsafeUnpin)]
+pub struct OverlappingLifetimeNames<'pin, T, U> {
+    #[pin]
+    field1: T,
+    field2: U,
+    field3: &'pin (),
+}
+
+unsafe impl<T: Unpin, U> UnsafeUnpin for OverlappingLifetimeNames<'_, T, U> {}
+
+#[test]
+fn unsafe_unpin() {
+    is_unpin::<Blah<(), PhantomPinned>>();
+    is_unpin::<OverlappingLifetimeNames<'_, (), ()>>();
+}
+
+#[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;
+}