Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 33 additions & 12 deletions pin-project-internal/src/pin_project/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use quote::{format_ident, quote, quote_spanned, ToTokens};
use syn::{
parse_quote, token, visit_mut::VisitMut, Attribute, Data, DataEnum, DeriveInput, Error, Field,
Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index, Lifetime, LifetimeDef, Meta,
MetaList, NestedMeta, Result, Token, Type, Variant, Visibility, WhereClause,
MetaList, MetaNameValue, NestedMeta, Result, Token, Type, Variant, Visibility, WhereClause,
};

use super::{
Expand Down Expand Up @@ -326,7 +326,7 @@ fn parse_struct<'a>(
generate: &mut GenerateTokens,
) -> Result<()> {
// Do this first for a better error message.
let packed_check = ensure_not_packed(&cx.orig, fields)?;
let packed_check = ensure_not_packed(&cx.orig, Some(fields))?;

validate_struct(cx.orig.ident, fields)?;

Expand Down Expand Up @@ -414,8 +414,12 @@ fn parse_enum<'a>(
));
}

// We don't need to check for `#[repr(packed)]`,
// since it does not apply to enums.
// #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
// However, we should not rely on the behavior of rustc that rejects this.
// https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
//
// Do this first for a better error message.
ensure_not_packed(&cx.orig, None)?;

validate_enum(*brace_token, variants)?;

Expand Down Expand Up @@ -996,28 +1000,45 @@ fn make_proj_impl(
/// * Checks the attributes of structs to ensure there is no `[repr(packed)]`.
/// * Generates a function that borrows fields without an unsafe block and
/// forbidding `unaligned_references` lint.
fn ensure_not_packed(orig: &OriginalType<'_>, fields: &Fields) -> Result<TokenStream> {
fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result<TokenStream> {
for meta in orig.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) {
if let Meta::List(list) = meta {
if list.path.is_ident("repr") {
for repr in list.nested.iter() {
match repr {
NestedMeta::Meta(Meta::Path(path))
| NestedMeta::Meta(Meta::List(MetaList { path, .. }))
if path.is_ident("packed") =>
{
return Err(error!(
repr,
"#[pin_project] attribute may not be used on #[repr(packed)] types"
));
| NestedMeta::Meta(Meta::NameValue(MetaNameValue { path, .. })) => {
if path.is_ident("packed") {
let msg = if fields.is_none() {
// #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
// However, we should not rely on the behavior of rustc that rejects this.
// https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
"#[repr(packed)] attribute should be applied to a struct or union"
} else if let NestedMeta::Meta(Meta::NameValue(..)) = repr {
// #[repr(packed = "")] is not valid format of #[repr(packed)] and will be
// rejected by rustc.
// However, we should not rely on the behavior of rustc that rejects this.
// https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
"#[repr(packed)] attribute should not be name-value pair"
} else {
"#[pin_project] attribute may not be used on #[repr(packed)] types"
};
return Err(error!(repr, msg));
}
}
_ => {}
NestedMeta::Lit(..) => {}
}
}
}
}
}

let fields = match fields {
Some(fields) => fields,
None => return Ok(TokenStream::new()),
};

// Workaround for https://github.com/taiki-e/pin-project/issues/32
// Through the tricky use of proc macros, it's possible to bypass
// the above check for the `repr` attribute.
Expand Down
3 changes: 1 addition & 2 deletions tests/ui/cfg/packed_sneaky-span-issue-1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use auxiliary_macro::hidden_repr;
use pin_project::pin_project;

#[pin_project]
#[hidden_repr(packed)]
#[hidden_repr(packed)] //~ ERROR may not be used on #[repr(packed)] types
struct S {
//~^ ERROR may not be used on #[repr(packed)] types
#[cfg(not(any()))]
#[pin]
f: u32,
Expand Down
14 changes: 4 additions & 10 deletions tests/ui/cfg/packed_sneaky-span-issue-1.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
error: #[pin_project] attribute may not be used on #[repr(packed)] types
--> $DIR/packed_sneaky-span-issue-1.rs:6:1
|
6 | / struct S {
7 | | //~^ ERROR may not be used on #[repr(packed)] types
8 | | #[cfg(not(any()))]
9 | | #[pin]
... |
13 | | f: u8,
14 | | }
| |_^
--> $DIR/packed_sneaky-span-issue-1.rs:5:15
|
5 | #[hidden_repr(packed)] //~ ERROR may not be used on #[repr(packed)] types
| ^^^^^^
3 changes: 1 addition & 2 deletions tests/ui/cfg/packed_sneaky-span-issue-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@ use auxiliary_macro::hidden_repr;
use pin_project::pin_project;

#[pin_project]
#[hidden_repr(packed)]
#[hidden_repr(packed)] //~ ERROR may not be used on #[repr(packed)] types
struct S {
//~^ ERROR may not be used on #[repr(packed)] types
#[cfg(any())]
#[pin]
f: u32,
Expand Down
14 changes: 4 additions & 10 deletions tests/ui/cfg/packed_sneaky-span-issue-2.stderr
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
error: #[pin_project] attribute may not be used on #[repr(packed)] types
--> $DIR/packed_sneaky-span-issue-2.rs:6:1
|
6 | / struct S {
7 | | //~^ ERROR may not be used on #[repr(packed)] types
8 | | #[cfg(any())]
9 | | #[pin]
... |
13 | | f: u8,
14 | | }
| |_^
--> $DIR/packed_sneaky-span-issue-2.rs:5:15
|
5 | #[hidden_repr(packed)] //~ ERROR may not be used on #[repr(packed)] types
| ^^^^^^
5 changes: 3 additions & 2 deletions tests/ui/cfg/unsupported.stderr
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
error: #[pin_project] attribute may not be used on structs with zero fields
--> $DIR/unsupported.rs:4:1
--> $DIR/unsupported.rs:4:10
|
4 | / struct S {
4 | struct S {
| __________^
5 | | //~^ ERROR may not be used on structs with zero fields
6 | | #[cfg(any())]
7 | | #[pin]
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/not_unpin/conflict-unpin.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Foo<_, _>`:
error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Foo<_, _>`
--> $DIR/conflict-unpin.rs:3:15
|
3 | #[pin_project(!Unpin)] //~ ERROR E0119
Expand All @@ -7,7 +7,7 @@ error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type
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<_, _>`:
error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Bar<_, _>`
--> $DIR/conflict-unpin.rs:12:15
|
12 | #[pin_project(!Unpin)] //~ ERROR E0119
Expand All @@ -16,7 +16,7 @@ error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type
19 | impl<T, U> Unpin for Bar<T, U> {}
| ------------------------------ first implementation here

error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Baz<_, _>`:
error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Baz<_, _>`
--> $DIR/conflict-unpin.rs:21:15
|
21 | #[pin_project(!Unpin)] //~ ERROR E0119
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/not_unpin/impl-unsafe-unpin.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Foo<_, _>`:
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
Expand All @@ -9,7 +9,7 @@ error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` fo
|
= 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<_, _>`:
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
Expand All @@ -20,7 +20,7 @@ error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` fo
|
= 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<_, _>`:
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
Expand Down
14 changes: 12 additions & 2 deletions tests/ui/pin_project/add-pinned-field.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@ error[E0277]: `PhantomPinned` cannot be unpinned
21 | is_unpin::<Foo>(); //~ ERROR E0277
| ^^^^^^^^^^^^^^^ within `__Foo<'_>`, the trait `Unpin` is not implemented for `PhantomPinned`
|
= note: required because it appears within the type `__Foo<'_>`
= note: consider using `Box::pin`
note: required because it appears within the type `__Foo<'_>`
--> $DIR/add-pinned-field.rs:8:8
|
8 | struct Foo {
| ^^^
= note: required because of the requirements on the impl of `Unpin` for `Foo`

error[E0277]: `PhantomPinned` cannot be unpinned
Expand All @@ -19,5 +24,10 @@ error[E0277]: `PhantomPinned` cannot be unpinned
22 | is_unpin::<Bar>(); //~ ERROR E0277
| ^^^^^^^^^^^^^^^ within `__Bar<'_>`, the trait `Unpin` is not implemented for `PhantomPinned`
|
= note: required because it appears within the type `__Bar<'_>`
= note: consider using `Box::pin`
note: required because it appears within the type `__Bar<'_>`
--> $DIR/add-pinned-field.rs:15:8
|
15 | struct Bar {
| ^^^
= note: required because of the requirements on the impl of `Unpin` for `Bar`
4 changes: 2 additions & 2 deletions tests/ui/pin_project/conflict-drop.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0119]: conflicting implementations of trait `_::FooMustNotImplDrop` for type `Foo<_, _>`:
error[E0119]: conflicting implementations of trait `_::FooMustNotImplDrop` for type `Foo<_, _>`
--> $DIR/conflict-drop.rs:5:1
|
5 | #[pin_project] //~ ERROR E0119
Expand All @@ -9,7 +9,7 @@ error[E0119]: conflicting implementations of trait `_::FooMustNotImplDrop` for t
|
= 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<_, _>`:
error[E0119]: conflicting implementations of trait `std::ops::Drop` for type `Bar<_, _>`
--> $DIR/conflict-drop.rs:16:15
|
16 | #[pin_project(PinnedDrop)] //~ ERROR E0119
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/pin_project/conflict-unpin.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Foo<_, _>`:
error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Foo<_, _>`
--> $DIR/conflict-unpin.rs:5:1
|
5 | #[pin_project] //~ ERROR E0119
Expand All @@ -9,7 +9,7 @@ error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type
|
= 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<_, _>`:
error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Bar<_, _>`
--> $DIR/conflict-unpin.rs:17:1
|
17 | #[pin_project] //~ ERROR E0119
Expand All @@ -20,7 +20,7 @@ error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type
|
= 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<_, _>`:
error[E0119]: conflicting implementations of trait `std::marker::Unpin` for type `Baz<_, _>`
--> $DIR/conflict-unpin.rs:27:1
|
27 | #[pin_project] //~ ERROR E0119
Expand Down
6 changes: 3 additions & 3 deletions tests/ui/pin_project/impl-unsafe-unpin.stderr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Foo<_, _>`:
error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Foo<_, _>`
--> $DIR/impl-unsafe-unpin.rs:3:1
|
3 | #[pin_project] //~ ERROR E0119
Expand All @@ -9,7 +9,7 @@ error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` fo
|
= 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<_, _>`:
error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Bar<_, _>`
--> $DIR/impl-unsafe-unpin.rs:12:1
|
12 | #[pin_project] //~ ERROR E0119
Expand All @@ -20,7 +20,7 @@ error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` fo
|
= 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<_, _>`:
error[E0119]: conflicting implementations of trait `pin_project::UnsafeUnpin` for type `Baz<_, _>`
--> $DIR/impl-unsafe-unpin.rs:21:1
|
21 | #[pin_project] //~ ERROR E0119
Expand Down
7 changes: 6 additions & 1 deletion tests/ui/pin_project/overlapping_unpin_struct.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,10 @@ error[E0277]: `PhantomPinned` cannot be unpinned
18 | is_unpin::<S<PhantomPinned>>(); //~ ERROR E0277
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ within `_::__S<'_, PhantomPinned>`, the trait `Unpin` is not implemented for `PhantomPinned`
|
= note: required because it appears within the type `_::__S<'_, PhantomPinned>`
= note: consider using `Box::pin`
note: required because it appears within the type `_::__S<'_, PhantomPinned>`
--> $DIR/overlapping_unpin_struct.rs:6:8
|
6 | struct S<T> {
| ^
= note: required because of the requirements on the impl of `Unpin` for `S<PhantomPinned>`
4 changes: 4 additions & 0 deletions tests/ui/pin_project/packed-enum.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
use pin_project::pin_project;

// #[repr(packed)] cannot be apply on enums and will be rejected by rustc.
// However, we should not rely on the behavior of rustc that rejects this.
// https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001

#[repr(packed)] //~ ERROR E0517
enum E1 {
V(()),
Expand Down
50 changes: 31 additions & 19 deletions tests/ui/pin_project/packed-enum.stderr
Original file line number Diff line number Diff line change
@@ -1,30 +1,42 @@
error: #[repr(packed)] attribute should be applied to a struct or union
--> $DIR/packed-enum.rs:13:8
|
13 | #[repr(packed)] //~ ERROR E0517
| ^^^^^^

error: #[repr(packed)] attribute should be applied to a struct or union
--> $DIR/packed-enum.rs:18:8
|
18 | #[repr(packed)] //~ ERROR E0517
| ^^^^^^

error[E0517]: attribute should be applied to a 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
--> $DIR/packed-enum.rs:7:8
|
7 | #[repr(packed)] //~ ERROR E0517
| ^^^^^^
8 | / enum E1 {
9 | | V(()),
10 | | }
| |_- not a struct or union

error[E0517]: attribute should be applied to a struct or union
--> $DIR/packed-enum.rs:9:8
--> $DIR/packed-enum.rs:13:8
|
9 | #[repr(packed)] //~ ERROR E0517
13 | #[repr(packed)] //~ ERROR E0517
| ^^^^^^
10 | / enum E2 {
11 | | V(()),
12 | | }
14 | / enum E2 {
15 | | V(()),
16 | | }
| |_- not a struct or union

error[E0517]: attribute should be applied to a struct or union
--> $DIR/packed-enum.rs:14:8
--> $DIR/packed-enum.rs:18:8
|
14 | #[repr(packed)] //~ ERROR E0517
18 | #[repr(packed)] //~ ERROR E0517
| ^^^^^^
15 | #[pin_project]
16 | / enum E3 {
17 | | V(()),
18 | | }
19 | #[pin_project]
20 | / enum E3 {
21 | | V(()),
22 | | }
| |_- not a struct or union
Loading