Skip to content

Commit bd2e7ee

Browse files
Rollup merge of rust-lang#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 rust-lang#128485 Related to rust-lang#123430
2 parents 7caad69 + aa4f16a commit bd2e7ee

File tree

5 files changed

+131
-1
lines changed

5 files changed

+131
-1
lines changed

compiler/rustc_builtin_macros/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,8 @@ builtin_macros_non_exhaustive_default = default variant must be exhaustive
235235
.label = declared `#[non_exhaustive]` here
236236
.help = consider a manual implementation of `Default`
237237
238+
builtin_macros_non_generic_pointee = the `#[pointee]` attribute may only be used on generic parameters
239+
238240
builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
239241
.help = consider a manual implementation of `Default`
240242

compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs

+64
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ use rustc_span::symbol::{Ident, sym};
1313
use rustc_span::{Span, Symbol};
1414
use thin_vec::{ThinVec, thin_vec};
1515

16+
use crate::errors;
17+
1618
macro_rules! path {
1719
($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] }
1820
}
@@ -25,6 +27,8 @@ pub(crate) fn expand_deriving_smart_ptr(
2527
push: &mut dyn FnMut(Annotatable),
2628
_is_const: bool,
2729
) {
30+
item.visit_with(&mut DetectNonGenericPointeeAttr { cx });
31+
2832
let (name_ident, generics) = if let Annotatable::Item(aitem) = item
2933
&& let ItemKind::Struct(struct_data, g) = &aitem.kind
3034
{
@@ -396,3 +400,63 @@ impl<'a> ast::mut_visit::MutVisitor for TypeSubstitution<'a> {
396400
}
397401
}
398402
}
403+
404+
struct DetectNonGenericPointeeAttr<'a, 'b> {
405+
cx: &'a ExtCtxt<'b>,
406+
}
407+
408+
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for DetectNonGenericPointeeAttr<'a, 'b> {
409+
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result {
410+
if attr.has_name(sym::pointee) {
411+
self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span });
412+
}
413+
}
414+
415+
fn visit_generic_param(&mut self, param: &'a rustc_ast::GenericParam) -> Self::Result {
416+
let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx };
417+
418+
match &param.kind {
419+
GenericParamKind::Type { default } => {
420+
// The `default` may end up containing a block expression.
421+
// The problem is block expressions may define structs with generics.
422+
// A user may attach a #[pointee] attribute to one of these generics
423+
// We want to catch that. The simple solution is to just
424+
// always raise a `NonGenericPointee` error when this happens.
425+
//
426+
// This solution does reject valid rust programs but,
427+
// such a code would have to, in order:
428+
// - Define a smart pointer struct.
429+
// - Somewhere in this struct definition use a type with a const generic argument.
430+
// - Calculate this const generic in a expression block.
431+
// - Define a new smart pointer type in this block.
432+
// - Have this smart pointer type have more than 1 generic type.
433+
// In this case, the inner smart pointer derive would be complaining that it
434+
// needs a pointer attribute. Meanwhile, the outer macro would be complaining
435+
// that we attached a #[pointee] to a generic type argument while helpfully
436+
// informing the user that #[pointee] can only be attached to generic pointer arguments
437+
rustc_ast::visit::visit_opt!(error_on_pointee, visit_ty, default);
438+
}
439+
440+
GenericParamKind::Const { .. } | GenericParamKind::Lifetime => {
441+
rustc_ast::visit::walk_generic_param(&mut error_on_pointee, param);
442+
}
443+
}
444+
}
445+
446+
fn visit_ty(&mut self, t: &'a rustc_ast::Ty) -> Self::Result {
447+
let mut error_on_pointee = AlwaysErrorOnGenericParam { cx: self.cx };
448+
error_on_pointee.visit_ty(t)
449+
}
450+
}
451+
452+
struct AlwaysErrorOnGenericParam<'a, 'b> {
453+
cx: &'a ExtCtxt<'b>,
454+
}
455+
456+
impl<'a, 'b> rustc_ast::visit::Visitor<'a> for AlwaysErrorOnGenericParam<'a, 'b> {
457+
fn visit_attribute(&mut self, attr: &'a rustc_ast::Attribute) -> Self::Result {
458+
if attr.has_name(sym::pointee) {
459+
self.cx.dcx().emit_err(errors::NonGenericPointee { span: attr.span });
460+
}
461+
}
462+
}

compiler/rustc_builtin_macros/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -940,3 +940,10 @@ pub(crate) struct NakedFunctionTestingAttribute {
940940
#[label]
941941
pub testing_span: Span,
942942
}
943+
944+
#[derive(Diagnostic)]
945+
#[diag(builtin_macros_non_generic_pointee)]
946+
pub(crate) struct NonGenericPointee {
947+
#[primary_span]
948+
pub span: Span,
949+
}

tests/ui/deriving/deriving-smart-pointer-neg.rs

+33
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,39 @@ struct NoMaybeSized<'a, #[pointee] T> {
5353
ptr: &'a T,
5454
}
5555

56+
#[derive(SmartPointer)]
57+
#[repr(transparent)]
58+
struct PointeeOnField<'a, #[pointee] T: ?Sized> {
59+
#[pointee]
60+
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
61+
ptr: &'a T
62+
}
63+
64+
#[derive(SmartPointer)]
65+
#[repr(transparent)]
66+
struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
67+
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
68+
ptr: &'a T,
69+
}
70+
71+
#[derive(SmartPointer)]
72+
#[repr(transparent)]
73+
struct PointeeInConstConstBlock<
74+
'a,
75+
T: ?Sized,
76+
const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
77+
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
78+
{
79+
ptr: &'a T,
80+
}
81+
82+
#[derive(SmartPointer)]
83+
#[repr(transparent)]
84+
struct PointeeInAnotherTypeConstBlock<'a, #[pointee] T: ?Sized> {
85+
ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
86+
//~^ ERROR: the `#[pointee]` attribute may only be used on generic parameters
87+
}
88+
5689
// However, reordering attributes should work nevertheless.
5790
#[repr(transparent)]
5891
#[derive(SmartPointer)]

tests/ui/deriving/deriving-smart-pointer-neg.stderr

+25-1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,30 @@ error: `derive(SmartPointer)` requires T to be marked `?Sized`
5858
LL | struct NoMaybeSized<'a, #[pointee] T> {
5959
| ^
6060

61+
error: the `#[pointee]` attribute may only be used on generic parameters
62+
--> $DIR/deriving-smart-pointer-neg.rs:59:5
63+
|
64+
LL | #[pointee]
65+
| ^^^^^^^^^^
66+
67+
error: the `#[pointee]` attribute may only be used on generic parameters
68+
--> $DIR/deriving-smart-pointer-neg.rs:66:74
69+
|
70+
LL | struct PointeeInTypeConstBlock<'a, T: ?Sized = [u32; const { struct UhOh<#[pointee] T>(T); 10 }]> {
71+
| ^^^^^^^^^^
72+
73+
error: the `#[pointee]` attribute may only be used on generic parameters
74+
--> $DIR/deriving-smart-pointer-neg.rs:76:34
75+
|
76+
LL | const V: u32 = { struct UhOh<#[pointee] T>(T); 10 }>
77+
| ^^^^^^^^^^
78+
79+
error: the `#[pointee]` attribute may only be used on generic parameters
80+
--> $DIR/deriving-smart-pointer-neg.rs:85:56
81+
|
82+
LL | ptr: PointeeInConstConstBlock<'a, T, { struct UhOh<#[pointee] T>(T); 0 }>
83+
| ^^^^^^^^^^
84+
6185
error[E0392]: lifetime parameter `'a` is never used
6286
--> $DIR/deriving-smart-pointer-neg.rs:15:16
6387
|
@@ -90,6 +114,6 @@ LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
90114
|
91115
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
92116

93-
error: aborting due to 12 previous errors
117+
error: aborting due to 16 previous errors
94118

95119
For more information about this error, try `rustc --explain E0392`.

0 commit comments

Comments
 (0)