diff --git a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs index ea054a7e35526..bbc7cd3962720 100644 --- a/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs +++ b/compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs @@ -3,8 +3,9 @@ use std::mem::swap; use ast::HasAttrs; use rustc_ast::{ self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem, - TraitBoundModifiers, + TraitBoundModifiers, VariantData, }; +use rustc_attr as attr; use rustc_expand::base::{Annotatable, ExtCtxt}; use rustc_span::symbol::{sym, Ident}; use rustc_span::Span; @@ -24,11 +25,43 @@ pub fn expand_deriving_smart_ptr( _is_const: bool, ) { let (name_ident, generics) = if let Annotatable::Item(aitem) = item - && let ItemKind::Struct(_, g) = &aitem.kind + && let ItemKind::Struct(struct_data, g) = &aitem.kind { + let is_transparent = aitem.attrs.iter().any(|attr| { + attr::find_repr_attrs(cx.sess, attr) + .into_iter() + .any(|r| matches!(r, attr::ReprTransparent)) + }); + if !is_transparent { + cx.dcx() + .struct_span_err( + span, + "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`", + ) + .emit(); + return; + } + if !matches!( + struct_data, + VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _) + if !fields.is_empty()) + { + cx.dcx() + .struct_span_err( + span, + "`SmartPointer` can only be derived on `struct`s with at least one field", + ) + .emit(); + return; + } (aitem.ident, g) } else { - cx.dcx().struct_span_err(span, "`SmartPointer` can only be derived on `struct`s").emit(); + cx.dcx() + .struct_span_err( + span, + "`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`", + ) + .emit(); return; }; diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.rs b/tests/ui/deriving/deriving-smart-pointer-neg.rs new file mode 100644 index 0000000000000..0b94dc3bb160e --- /dev/null +++ b/tests/ui/deriving/deriving-smart-pointer-neg.rs @@ -0,0 +1,38 @@ +#![feature(derive_smart_pointer, arbitrary_self_types)] + +use std::marker::SmartPointer; + +#[derive(SmartPointer)] +//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` +enum NotStruct<'a, T: ?Sized> { + Variant(&'a T), +} + +#[derive(SmartPointer)] +//~^ ERROR: At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits +#[repr(transparent)] +struct NoPointee<'a, T: ?Sized> { + ptr: &'a T, +} + +#[derive(SmartPointer)] +//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field +#[repr(transparent)] +struct NoField<'a, #[pointee] T: ?Sized> {} +//~^ ERROR: lifetime parameter `'a` is never used +//~| ERROR: type parameter `T` is never used + +#[derive(SmartPointer)] +//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field +#[repr(transparent)] +struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); +//~^ ERROR: lifetime parameter `'a` is never used +//~| ERROR: type parameter `T` is never used + +#[derive(SmartPointer)] +//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` +struct NotTransparent<'a, #[pointee] T: ?Sized> { + ptr: &'a T, +} + +fn main() {} diff --git a/tests/ui/deriving/deriving-smart-pointer-neg.stderr b/tests/ui/deriving/deriving-smart-pointer-neg.stderr new file mode 100644 index 0000000000000..d994a6ee376b0 --- /dev/null +++ b/tests/ui/deriving/deriving-smart-pointer-neg.stderr @@ -0,0 +1,75 @@ +error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` + --> $DIR/deriving-smart-pointer-neg.rs:5:10 + | +LL | #[derive(SmartPointer)] + | ^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits + --> $DIR/deriving-smart-pointer-neg.rs:11:10 + | +LL | #[derive(SmartPointer)] + | ^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `SmartPointer` can only be derived on `struct`s with at least one field + --> $DIR/deriving-smart-pointer-neg.rs:18:10 + | +LL | #[derive(SmartPointer)] + | ^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `SmartPointer` can only be derived on `struct`s with at least one field + --> $DIR/deriving-smart-pointer-neg.rs:25:10 + | +LL | #[derive(SmartPointer)] + | ^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]` + --> $DIR/deriving-smart-pointer-neg.rs:32:10 + | +LL | #[derive(SmartPointer)] + | ^^^^^^^^^^^^ + | + = note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/deriving-smart-pointer-neg.rs:21:16 + | +LL | struct NoField<'a, #[pointee] T: ?Sized> {} + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: type parameter `T` is never used + --> $DIR/deriving-smart-pointer-neg.rs:21:31 + | +LL | struct NoField<'a, #[pointee] T: ?Sized> {} + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: lifetime parameter `'a` is never used + --> $DIR/deriving-smart-pointer-neg.rs:28:20 + | +LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); + | ^^ unused lifetime parameter + | + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` + +error[E0392]: type parameter `T` is never used + --> $DIR/deriving-smart-pointer-neg.rs:28:35 + | +LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>(); + | ^ unused type parameter + | + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0392`.