mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Rollup merge of #128721 - Brezak:pointee-in-strange-places, r=pnkfelix
Don't allow the `#[pointee]` attribute where it doesn't belong Error if the `#[pointee]` attribute is applied to anything but generic type parameters. Closes #128485 Related to #123430
This commit is contained in:
commit
bd2e7ee976
@ -235,6 +235,8 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive
|
|||||||
.label = declared `#[non_exhaustive]` here
|
.label = declared `#[non_exhaustive]` here
|
||||||
.help = consider a manual implementation of `Default`
|
.help = consider a manual implementation of `Default`
|
||||||
|
|
||||||
|
builtin_macros_non_generic_pointee = the `#[pointee]` attribute may only be used on generic parameters
|
||||||
|
|
||||||
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
|
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
|
||||||
.help = consider a manual implementation of `Default`
|
.help = consider a manual implementation of `Default`
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ use rustc_span::symbol::{Ident, sym};
|
|||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use thin_vec::{ThinVec, thin_vec};
|
use thin_vec::{ThinVec, thin_vec};
|
||||||
|
|
||||||
|
use crate::errors;
|
||||||
|
|
||||||
macro_rules! path {
|
macro_rules! path {
|
||||||
($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] }
|
($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] }
|
||||||
}
|
}
|
||||||
@ -25,6 +27,8 @@ pub(crate) fn expand_deriving_smart_ptr(
|
|||||||
push: &mut dyn FnMut(Annotatable),
|
push: &mut dyn FnMut(Annotatable),
|
||||||
_is_const: bool,
|
_is_const: bool,
|
||||||
) {
|
) {
|
||||||
|
item.visit_with(&mut DetectNonGenericPointeeAttr { cx });
|
||||||
|
|
||||||
let (name_ident, generics) = if let Annotatable::Item(aitem) = item
|
let (name_ident, generics) = if let Annotatable::Item(aitem) = item
|
||||||
&& let ItemKind::Struct(struct_data, g) = &aitem.kind
|
&& let ItemKind::Struct(struct_data, g) = &aitem.kind
|
||||||
{
|
{
|
||||||
@ -396,3 +400,63 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct DetectNonGenericPointeeAttr<'a, 'b> {
|
||||||
|
cx: &'a ExtCtxt<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonGenericPointeeAttr<'a, 'b> {
|
||||||
|
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result {
|
||||||
|
if attr.has_name(sym::pointee) {
|
||||||
|
self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_generic_param(&mut self, param: &'a rustc_ast::GenericParam) -> Self::Result {
|
||||||
|
let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx };
|
||||||
|
|
||||||
|
match ¶m.kind {
|
||||||
|
GenericParamKind::Type { default } => {
|
||||||
|
// The `default` may end up containing a block expression.
|
||||||
|
// The problem is block expressions may define structs with generics.
|
||||||
|
// A user may attach a #[pointee] attribute to one of these generics
|
||||||
|
// We want to catch that. The simple solution is to just
|
||||||
|
// always raise a `NonGenericPointee` error when this happens.
|
||||||
|
//
|
||||||
|
// This solution does reject valid rust programs but,
|
||||||
|
// such a code would have to, in order:
|
||||||
|
// - Define a smart pointer struct.
|
||||||
|
// - Somewhere in this struct definition use a type with a const generic argument.
|
||||||
|
// - Calculate this const generic in a expression block.
|
||||||
|
// - Define a new smart pointer type in this block.
|
||||||
|
// - Have this smart pointer type have more than 1 generic type.
|
||||||
|
// In this case, the inner smart pointer derive would be complaining that it
|
||||||
|
// needs a pointer attribute. Meanwhile, the outer macro would be complaining
|
||||||
|
// that we attached a #[pointee] to a generic type argument while helpfully
|
||||||
|
// informing the user that #[pointee] can only be attached to generic pointer arguments
|
||||||
|
rustc_ast::visit::visit_opt!(error_on_pointee, visit_ty, default);
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericParamKind::Const { .. } | GenericParamKind::Lifetime => {
|
||||||
|
rustc_ast::visit::walk_generic_param(&mut error_on_pointee, param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn visit_ty(&mut self, t: &'a rustc_ast::Ty) -> Self::Result {
|
||||||
|
let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx };
|
||||||
|
error_on_pointee.visit_ty(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AlwaysErrorOnGenericParam<'a, 'b> {
|
||||||
|
cx: &'a ExtCtxt<'b>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> {
|
||||||
|
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result {
|
||||||
|
if attr.has_name(sym::pointee) {
|
||||||
|
self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -940,3 +940,10 @@ pub(crate) struct NakedFunctionTestingAttribute {
|
|||||||
#[label]
|
#[label]
|
||||||
pub testing_span: Span,
|
pub testing_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Diagnostic)]
|
||||||
|
#[diag(builtin_macros_non_generic_pointee)]
|
||||||
|
pub(crate) struct NonGenericPointee {
|
||||||
|
#[primary_span]
|
||||||
|
pub span: Span,
|
||||||
|
}
|
||||||
|
@ -53,6 +53,39 @@ struct NoMaybeSized<'a, #[pointee] T> {
|
|||||||
ptr: &'a T,
|
ptr: &'a T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(SmartPointer)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct PointeeOnField<'a, #[pointee] T: ?Sized> {
|
||||||
|
#[pointee]
|
||||||
|
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
|
||||||
|
ptr: &'a T
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SmartPointer)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
|
||||||
|
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
|
||||||
|
ptr: &'a T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SmartPointer)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct PointeeInConstConstBlock<
|
||||||
|
'a,
|
||||||
|
T: ?Sized,
|
||||||
|
const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
|
||||||
|
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
|
||||||
|
{
|
||||||
|
ptr: &'a T,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(SmartPointer)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> {
|
||||||
|
ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
|
||||||
|
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
|
||||||
|
}
|
||||||
|
|
||||||
// However, reordering attributes should work nevertheless.
|
// However, reordering attributes should work nevertheless.
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(SmartPointer)]
|
#[derive(SmartPointer)]
|
||||||
|
@ -58,6 +58,30 @@ error: `derive(SmartPointer)` requires T to be marked `?Sized`
|
|||||||
LL | struct NoMaybeSized<'a, #[pointee] T> {
|
LL | struct NoMaybeSized<'a, #[pointee] T> {
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
|
error: the `#[pointee]` attribute may only be used on generic parameters
|
||||||
|
--> $DIR/deriving-smart-pointer-neg.rs:59:5
|
||||||
|
|
|
||||||
|
LL | #[pointee]
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: the `#[pointee]` attribute may only be used on generic parameters
|
||||||
|
--> $DIR/deriving-smart-pointer-neg.rs:66:74
|
||||||
|
|
|
||||||
|
LL | struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: the `#[pointee]` attribute may only be used on generic parameters
|
||||||
|
--> $DIR/deriving-smart-pointer-neg.rs:76:34
|
||||||
|
|
|
||||||
|
LL | const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
|
error: the `#[pointee]` attribute may only be used on generic parameters
|
||||||
|
--> $DIR/deriving-smart-pointer-neg.rs:85:56
|
||||||
|
|
|
||||||
|
LL | ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
|
||||||
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error[E0392]: lifetime parameter `'a` is never used
|
error[E0392]: lifetime parameter `'a` is never used
|
||||||
--> $DIR/deriving-smart-pointer-neg.rs:15:16
|
--> $DIR/deriving-smart-pointer-neg.rs:15:16
|
||||||
|
|
|
|
||||||
@ -90,6 +114,6 @@ LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
|
|||||||
|
|
|
|
||||||
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
|
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
|
||||||
|
|
||||||
error: aborting due to 12 previous errors
|
error: aborting due to 16 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0392`.
|
For more information about this error, try `rustc --explain E0392`.
|
||||||
|
Loading…
Reference in New Issue
Block a user