From 0b4edb2487005d7db85a1261fcc77e26e1955553 Mon Sep 17 00:00:00 2001 From: Ding Xiang Fei Date: Thu, 4 Jul 2024 02:50:56 +0800 Subject: [PATCH] reject SmartPointer constructions not serving the purpose --- .../src/deriving/smart_ptr.rs | 39 +++++++++- .../ui/deriving/deriving-smart-pointer-neg.rs | 45 +++++++++++ .../deriving-smart-pointer-neg.stderr | 75 +++++++++++++++++++ tests/ui/deriving/deriving-smart-pointer.rs | 1 + .../feature-gate-derive-smart-pointer.rs | 1 + .../feature-gate-derive-smart-pointer.stderr | 2 +- 6 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 tests/ui/deriving/deriving-smart-pointer-neg.rs create mode 100644 tests/ui/deriving/deriving-smart-pointer-neg.stderr 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..bfb4e86b39601 --- /dev/null +++ b/tests/ui/deriving/deriving-smart-pointer-neg.rs @@ -0,0 +1,45 @@ +#![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, +} + +// However, reordering attributes should work nevertheless. +#[repr(transparent)] +#[derive(SmartPointer)] +struct ThisIsAPossibleSmartPointer<'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`. diff --git a/tests/ui/deriving/deriving-smart-pointer.rs b/tests/ui/deriving/deriving-smart-pointer.rs index cfc3369850bd6..d34a502da684f 100644 --- a/tests/ui/deriving/deriving-smart-pointer.rs +++ b/tests/ui/deriving/deriving-smart-pointer.rs @@ -4,6 +4,7 @@ use std::marker::SmartPointer; #[derive(SmartPointer)] +#[repr(transparent)] struct MyPointer<'a, #[pointee] T: ?Sized> { ptr: &'a T, } diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs index ae8005592cdb6..3257a9ca624ba 100644 --- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs +++ b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs @@ -1,6 +1,7 @@ use std::marker::SmartPointer; //~ ERROR use of unstable library feature 'derive_smart_pointer' #[derive(SmartPointer)] //~ ERROR use of unstable library feature 'derive_smart_pointer' +#[repr(transparent)] struct MyPointer<'a, #[pointee] T: ?Sized> { //~^ ERROR the `#[pointee]` attribute is an experimental feature ptr: &'a T, diff --git a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr index 0ffd82fb9e120..19501939dc5be 100644 --- a/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr +++ b/tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr @@ -9,7 +9,7 @@ LL | #[derive(SmartPointer)] = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date error[E0658]: the `#[pointee]` attribute is an experimental feature - --> $DIR/feature-gate-derive-smart-pointer.rs:4:22 + --> $DIR/feature-gate-derive-smart-pointer.rs:5:22 | LL | struct MyPointer<'a, #[pointee] T: ?Sized> { | ^^^^^^^^^^