diff --git a/pin-project-internal/src/pin_project/attribute.rs b/pin-project-internal/src/pin_project/attribute.rs index 233e8e95..b0c34aee 100644 --- a/pin-project-internal/src/pin_project/attribute.rs +++ b/pin-project-internal/src/pin_project/attribute.rs @@ -338,14 +338,21 @@ fn ensure_not_packed(item: &ItemStruct) -> Result { for meta in item.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) { if let Meta::List(l) = meta { if l.path.is_ident("repr") { - for repr in &l.nested { - if let NestedMeta::Meta(Meta::Path(p)) = repr { - if p.is_ident("packed") { + for repr in l.nested.iter() { + match repr { + NestedMeta::Meta(Meta::Path(p)) if p.is_ident("packed") => { return Err(error!( p, "#[pin_project] attribute may not be used on #[repr(packed)] types" )); } + NestedMeta::Meta(Meta::List(l)) if l.path.is_ident("packed") => { + return Err(error!( + l, + "#[pin_project] attribute may not be used on #[repr(packed(N))] types" + )); + } + _ => {} } } } @@ -394,7 +401,8 @@ fn ensure_not_packed(item: &ItemStruct) -> Result { for Field { attrs, ident, .. } in named { let cfg = collect_cfg(attrs); field_refs.push(quote! { - #(#cfg)* { &val.#ident; } + #(#cfg)* + { &val.#ident; } }); } } diff --git a/tests/repr_packed.rs b/tests/repr_packed.rs index e16e41c0..3b196511 100644 --- a/tests/repr_packed.rs +++ b/tests/repr_packed.rs @@ -1,6 +1,7 @@ #![warn(unsafe_code)] #![warn(rust_2018_idioms, single_use_lifetimes)] #![allow(dead_code)] +#![deny(safe_packed_borrows)] use std::cell::Cell; diff --git a/tests/ui/cfg/auxiliary/sneaky_macro.rs b/tests/ui/cfg/auxiliary/sneaky_macro.rs index 764906ba..3e73c00e 100644 --- a/tests/ui/cfg/auxiliary/sneaky_macro.rs +++ b/tests/ui/cfg/auxiliary/sneaky_macro.rs @@ -65,3 +65,13 @@ pub fn add_pinned_field(_: TokenStream, input: TokenStream) -> TokenStream { pub fn hidden_repr(attr: TokenStream, item: TokenStream) -> TokenStream { format!("#[repr({})] {}", attr, item).parse().unwrap() } + +#[proc_macro_attribute] +pub fn hidden_repr_cfg_any(attr: TokenStream, item: TokenStream) -> TokenStream { + format!("#[cfg_attr(any(), repr({}))] {}", attr, item).parse().unwrap() +} + +#[proc_macro_attribute] +pub fn hidden_repr_cfg_not_any(attr: TokenStream, item: TokenStream) -> TokenStream { + format!("#[cfg_attr(not(any()), repr({}))] {}", attr, item).parse().unwrap() +} diff --git a/tests/ui/cfg/packed_sneaky.rs b/tests/ui/cfg/packed_sneaky-1.rs similarity index 100% rename from tests/ui/cfg/packed_sneaky.rs rename to tests/ui/cfg/packed_sneaky-1.rs diff --git a/tests/ui/cfg/packed_sneaky.stderr b/tests/ui/cfg/packed_sneaky-1.stderr similarity index 92% rename from tests/ui/cfg/packed_sneaky.stderr rename to tests/ui/cfg/packed_sneaky-1.stderr index da598b61..9602c029 100644 --- a/tests/ui/cfg/packed_sneaky.stderr +++ b/tests/ui/cfg/packed_sneaky-1.stderr @@ -1,11 +1,11 @@ error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) - --> $DIR/packed_sneaky.rs:20:1 + --> $DIR/packed_sneaky-1.rs:20:1 | 20 | #[pin_project] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block | ^^^^^^^^^^^^^^ | note: lint level defined here - --> $DIR/packed_sneaky.rs:20:1 + --> $DIR/packed_sneaky-1.rs:20:1 | 20 | #[pin_project] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block | ^^^^^^^^^^^^^^ diff --git a/tests/ui/cfg/packed_sneaky-2.rs b/tests/ui/cfg/packed_sneaky-2.rs new file mode 100644 index 00000000..8a30dc1d --- /dev/null +++ b/tests/ui/cfg/packed_sneaky-2.rs @@ -0,0 +1,17 @@ +// run-pass +// aux-build:sneaky_macro.rs + +#[macro_use] +extern crate sneaky_macro; + +use pin_project::pin_project; + +// #[cfg_attr(any(), repr(packed))] +#[pin_project] +#[hidden_repr_cfg_any(packed)] +struct Foo { + #[pin] + field: u32, +} + +fn main() {} diff --git a/tests/ui/pin_project/packed_sneaky.rs b/tests/ui/cfg/packed_sneaky-3.rs similarity index 78% rename from tests/ui/pin_project/packed_sneaky.rs rename to tests/ui/cfg/packed_sneaky-3.rs index dcf68a4a..86baa3c7 100644 --- a/tests/ui/pin_project/packed_sneaky.rs +++ b/tests/ui/cfg/packed_sneaky-3.rs @@ -6,8 +6,9 @@ extern crate sneaky_macro; use pin_project::pin_project; +// #[cfg_attr(not(any()), repr(packed))] #[pin_project] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block -#[hidden_repr(packed)] +#[hidden_repr_cfg_not_any(packed)] struct Foo { #[pin] field: u32, diff --git a/tests/ui/cfg/packed_sneaky-3.stderr b/tests/ui/cfg/packed_sneaky-3.stderr new file mode 100644 index 00000000..fe53663f --- /dev/null +++ b/tests/ui/cfg/packed_sneaky-3.stderr @@ -0,0 +1,17 @@ +error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> $DIR/packed_sneaky-3.rs:10:1 + | +10 | #[pin_project] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/packed_sneaky-3.rs:10:1 + | +10 | #[pin_project] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: aborting due to previous error + diff --git a/tests/ui/pin_project/auxiliary/sneaky_macro.rs b/tests/ui/pin_project/auxiliary/sneaky_macro.rs index 0d4f49a4..4d7978cf 100644 --- a/tests/ui/pin_project/auxiliary/sneaky_macro.rs +++ b/tests/ui/pin_project/auxiliary/sneaky_macro.rs @@ -1,4 +1,4 @@ -// force-host +// force-host // no-prefer-dynamic #![crate_type = "proc-macro"] @@ -12,3 +12,7 @@ pub fn hidden_repr(attr: TokenStream, item: TokenStream) -> TokenStream { format!("#[repr({})] {}", attr, item).parse().unwrap() } +#[proc_macro] +pub fn hidden_repr_macro(item: TokenStream) -> TokenStream { + format!("#[repr(packed)] {}", item).parse().unwrap() +} diff --git a/tests/ui/pin_project/packed.rs b/tests/ui/pin_project/packed.rs index 5770e877..3f7e5880 100644 --- a/tests/ui/pin_project/packed.rs +++ b/tests/ui/pin_project/packed.rs @@ -3,18 +3,25 @@ use pin_project::pin_project; #[pin_project] -#[repr(packed, C)] //~ ERROR may not be used on #[repr(packed)] type -struct Foo { +#[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)] type +#[repr(packed, C)] //~ ERROR may not be used on #[repr(packed)] types #[pin_project] -struct Foo2 { +struct B { #[pin] field: u8, } +#[pin_project] +#[repr(packed(2))] //~ ERROR may not be used on #[repr(packed(N))] types +struct C { + #[pin] + field: u32, +} + fn main() {} diff --git a/tests/ui/pin_project/packed.stderr b/tests/ui/pin_project/packed.stderr index 118c7cb3..19142c32 100644 --- a/tests/ui/pin_project/packed.stderr +++ b/tests/ui/pin_project/packed.stderr @@ -1,14 +1,20 @@ error: #[pin_project] attribute may not be used on #[repr(packed)] types --> $DIR/packed.rs:6:8 | -6 | #[repr(packed, C)] //~ ERROR may not be used on #[repr(packed)] type +6 | #[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:13:8 | -13 | #[repr(packed, C)] //~ ERROR may not be used on #[repr(packed)] type +13 | #[repr(packed, C)] //~ ERROR may not be used on #[repr(packed)] types | ^^^^^^ -error: aborting due to 2 previous errors +error: #[pin_project] attribute may not be used on #[repr(packed(N))] types + --> $DIR/packed.rs:21:8 + | +21 | #[repr(packed(2))] //~ ERROR may not be used on #[repr(packed(N))] types + | ^^^^^^^^^ + +error: aborting due to 3 previous errors 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 00000000..7093d345 --- /dev/null +++ b/tests/ui/pin_project/packed_sneaky-1.rs @@ -0,0 +1,36 @@ +// compile-fail +// aux-build:sneaky_macro.rs + +#[macro_use] +extern crate sneaky_macro; + +use pin_project::{pin_project, pinned_drop, UnsafeUnpin}; +use std::pin::Pin; + +#[pin_project] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block +#[hidden_repr(packed)] +struct A { + #[pin] + field: u32, +} + +#[pin_project(UnsafeUnpin)] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block +#[hidden_repr(packed)] +struct C { + #[pin] + field: u32, +} + +unsafe impl UnsafeUnpin for C {} + +#[pin_project(PinnedDrop)] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block +#[hidden_repr(packed)] +struct D { + #[pin] + field: u32, +} + +#[pinned_drop] +fn drop_d(_: Pin<&mut D>) {} + +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 00000000..b0d36ede --- /dev/null +++ b/tests/ui/pin_project/packed_sneaky-1.stderr @@ -0,0 +1,47 @@ +error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> $DIR/packed_sneaky-1.rs:10:1 + | +10 | #[pin_project] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/packed_sneaky-1.rs:10:1 + | +10 | #[pin_project] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> $DIR/packed_sneaky-1.rs:17:1 + | +17 | #[pin_project(UnsafeUnpin)] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/packed_sneaky-1.rs:17:1 + | +17 | #[pin_project(UnsafeUnpin)] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> $DIR/packed_sneaky-1.rs:26:1 + | +26 | #[pin_project(PinnedDrop)] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: lint level defined here + --> $DIR/packed_sneaky-1.rs:26:1 + | +26 | #[pin_project(PinnedDrop)] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: aborting due to 3 previous errors + 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 00000000..2bddbbf9 --- /dev/null +++ b/tests/ui/pin_project/packed_sneaky-2.rs @@ -0,0 +1,17 @@ +// compile-fail +// aux-build:sneaky_macro.rs + +#[macro_use] +extern crate sneaky_macro; + +use pin_project::pin_project; + +hidden_repr_macro! { //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + #[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 00000000..b8fe49ad --- /dev/null +++ b/tests/ui/pin_project/packed_sneaky-2.stderr @@ -0,0 +1,16 @@ +error: #[pin_project] attribute may not be used on #[repr(packed)] types + --> $DIR/packed_sneaky-2.rs:9:1 + | +9 | / hidden_repr_macro! { //~ ERROR borrow of packed field is unsafe and requires unsafe function or block +10 | | #[pin_project] +11 | | struct B { +12 | | #[pin] +13 | | field: u32, +14 | | } +15 | | } + | | ^ in this macro invocation + | |_| + | + +error: aborting due to previous error + diff --git a/tests/ui/pin_project/packed_sneaky.stderr b/tests/ui/pin_project/packed_sneaky.stderr deleted file mode 100644 index 02460b22..00000000 --- a/tests/ui/pin_project/packed_sneaky.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) - --> $DIR/packed_sneaky.rs:9:1 - | -9 | #[pin_project] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block - | ^^^^^^^^^^^^^^ - | -note: lint level defined here - --> $DIR/packed_sneaky.rs:9:1 - | -9 | #[pin_project] //~ ERROR borrow of packed field is unsafe and requires unsafe function or block - | ^^^^^^^^^^^^^^ - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #46043 - = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior - -error: aborting due to previous error - 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 00000000..8ae06119 --- /dev/null +++ b/tests/ui/pin_project/safe_packed_borrows.rs @@ -0,0 +1,25 @@ +// compile-fail + +#![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 foo() { + 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 +} + +fn main() {} 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 00000000..8f1865fc --- /dev/null +++ b/tests/ui/pin_project/safe_packed_borrows.stderr @@ -0,0 +1,27 @@ +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: lint level defined here + --> $DIR/safe_packed_borrows.rs:1:9 + | +1 | #![deny(safe_packed_borrows)] + | ^^^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> $DIR/safe_packed_borrows.rs:20:5 + | +20 | &b.field; //~ ERROR borrow of packed field is unsafe and requires unsafe function or block + | ^^^^^^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior + +error: aborting due to 2 previous errors +