Skip to content

Commit

Permalink
Reject invalid #[repr(packed)] attributes
Browse files Browse the repository at this point in the history
They will be rejected by rustc but, we should not rely on the behavior
of rustc that rejects them.
  • Loading branch information
taiki-e committed Apr 13, 2021
1 parent 8b411b3 commit 8dd9b64
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 86 deletions.
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
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
19 changes: 13 additions & 6 deletions tests/ui/pin_project/packed-name-value.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
use pin_project::pin_project;

#[repr(packed = "")] //~ ERROR E0552
struct S1 {
f: (),
}
// #[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

// https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001
// https://github.com/rust-lang/rust/issues/83921
// #[repr(packed = "")] //~ ERROR E0552
// struct S1 {
// f: (),
// }

#[pin_project]
#[repr(packed = "")] //~ ERROR E0552
#[repr(packed = "")] //~ ERROR attribute should not be name-value pair
struct S2 {
f: (),
}

#[repr(packed = "")] //~ ERROR E0552
#[repr(packed = "")] //~ ERROR attribute should not be name-value pair
#[pin_project]
struct S3 {
f: (),
Expand Down
57 changes: 8 additions & 49 deletions tests/ui/pin_project/packed-name-value.stderr
Original file line number Diff line number Diff line change
@@ -1,52 +1,11 @@
error: internal compiler error: unrecognized representation hint
--> $DIR/packed-name-value.rs:3:8
|
3 | #[repr(packed = "")] //~ ERROR E0552
| ^^^^^^^^^^^
|
= note: delayed at compiler/rustc_attr/src/builtin.rs:940:32

error: internal compiler error: unrecognized representation hint
--> $DIR/packed-name-value.rs:9:8
|
9 | #[repr(packed = "")] //~ ERROR E0552
| ^^^^^^^^^^^
|
= note: delayed at compiler/rustc_attr/src/builtin.rs:940:32

error: internal compiler error: unrecognized representation hint
--> $DIR/packed-name-value.rs:14:8
error: #[repr(packed)] attribute should not be name-value pair
--> $DIR/packed-name-value.rs:16:8
|
14 | #[repr(packed = "")] //~ ERROR E0552
16 | #[repr(packed = "")] //~ ERROR attribute should not be name-value pair
| ^^^^^^^^^^^
|
= note: delayed at compiler/rustc_attr/src/builtin.rs:940:32

thread 'rustc' panicked at 'no errors encountered even though `delay_span_bug` issued', compiler/rustc_errors/src/lib.rs:1018:13
stack backtrace:
0: _rust_begin_unwind
1: std::panicking::begin_panic_fmt
2: rustc_errors::HandlerInner::flush_delayed
3: <rustc_errors::HandlerInner as core::ops::drop::Drop>::drop
4: core::ptr::drop_in_place<rustc_session::parse::ParseSess>
5: <alloc::rc::Rc<T> as core::ops::drop::Drop>::drop
6: core::ptr::drop_in_place<rustc_interface::interface::Compiler>
7: rustc_span::with_source_map
8: rustc_interface::interface::create_compiler_and_run
9: scoped_tls::ScopedKey<T>::set
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.

error: internal compiler error: unexpected panic

note: the compiler unexpectedly panicked. this is a bug.

note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md

note: rustc 1.53.0-nightly (d0695c908 2021-04-12) running on x86_64-apple-darwin

note: compiler flags: -C embed-bitcode=no -C split-debuginfo=unpacked -C debuginfo=2 --crate-type bin

note: some of the compiler flags provided by cargo are hidden

query stack during panic:
end of query stack
error: #[repr(packed)] attribute should not be name-value pair
--> $DIR/packed-name-value.rs:21:8
|
21 | #[repr(packed = "")] //~ ERROR attribute should not be name-value pair
| ^^^^^^^^^^^

0 comments on commit 8dd9b64

Please sign in to comment.