Skip to content

Commit 4eef4b4

Browse files
reject SmartPointer constructions not serving the purpose
1 parent 1086aff commit 4eef4b4

File tree

6 files changed

+152
-4
lines changed

6 files changed

+152
-4
lines changed

compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs

+36-3
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@ use std::mem::swap;
33
use ast::HasAttrs;
44
use rustc_ast::{
55
self as ast, GenericArg, GenericBound, GenericParamKind, ItemKind, MetaItem,
6-
TraitBoundModifiers,
6+
TraitBoundModifiers, VariantData,
77
};
8+
use rustc_attr as attr;
89
use rustc_expand::base::{Annotatable, ExtCtxt};
910
use rustc_span::symbol::{sym, Ident};
1011
use rustc_span::Span;
@@ -24,11 +25,43 @@ pub fn expand_deriving_smart_ptr(
2425
_is_const: bool,
2526
) {
2627
let (name_ident, generics) = if let Annotatable::Item(aitem) = item
27-
&& let ItemKind::Struct(_, g) = &aitem.kind
28+
&& let ItemKind::Struct(struct_data, g) = &aitem.kind
2829
{
30+
let is_transparent = aitem.attrs.iter().any(|attr| {
31+
attr::find_repr_attrs(cx.sess, attr)
32+
.into_iter()
33+
.any(|r| matches!(r, attr::ReprTransparent))
34+
});
35+
if !is_transparent {
36+
cx.dcx()
37+
.struct_span_err(
38+
span,
39+
"`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
40+
)
41+
.emit();
42+
return;
43+
}
44+
if !matches!(
45+
struct_data,
46+
VariantData::Struct { fields, recovered: _ } | VariantData::Tuple(fields, _)
47+
if !fields.is_empty())
48+
{
49+
cx.dcx()
50+
.struct_span_err(
51+
span,
52+
"`SmartPointer` can only be derived on `struct`s with at least one field",
53+
)
54+
.emit();
55+
return;
56+
}
2957
(aitem.ident, g)
3058
} else {
31-
cx.dcx().struct_span_err(span, "`SmartPointer` can only be derived on `struct`s").emit();
59+
cx.dcx()
60+
.struct_span_err(
61+
span,
62+
"`SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`",
63+
)
64+
.emit();
3265
return;
3366
};
3467

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
#![feature(derive_smart_pointer, arbitrary_self_types)]
2+
3+
use std::marker::SmartPointer;
4+
5+
#[derive(SmartPointer)]
6+
//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
7+
enum NotStruct<'a, T: ?Sized> {
8+
Variant(&'a T),
9+
}
10+
11+
#[derive(SmartPointer)]
12+
//~^ ERROR: At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits
13+
#[repr(transparent)]
14+
struct NoPointee<'a, T: ?Sized> {
15+
ptr: &'a T,
16+
}
17+
18+
#[derive(SmartPointer)]
19+
//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
20+
#[repr(transparent)]
21+
struct NoField<'a, #[pointee] T: ?Sized> {}
22+
//~^ ERROR: lifetime parameter `'a` is never used
23+
//~| ERROR: type parameter `T` is never used
24+
25+
#[derive(SmartPointer)]
26+
//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
27+
#[repr(transparent)]
28+
struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
29+
//~^ ERROR: lifetime parameter `'a` is never used
30+
//~| ERROR: type parameter `T` is never used
31+
32+
#[derive(SmartPointer)]
33+
//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
34+
struct NotTransparent<'a, #[pointee] T: ?Sized> {
35+
ptr: &'a T,
36+
}
37+
38+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
2+
--> $DIR/deriving-smart-pointer-neg.rs:5:10
3+
|
4+
LL | #[derive(SmartPointer)]
5+
| ^^^^^^^^^^^^
6+
|
7+
= note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
8+
9+
error: At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits
10+
--> $DIR/deriving-smart-pointer-neg.rs:11:10
11+
|
12+
LL | #[derive(SmartPointer)]
13+
| ^^^^^^^^^^^^
14+
|
15+
= note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
16+
17+
error: `SmartPointer` can only be derived on `struct`s with at least one field
18+
--> $DIR/deriving-smart-pointer-neg.rs:18:10
19+
|
20+
LL | #[derive(SmartPointer)]
21+
| ^^^^^^^^^^^^
22+
|
23+
= note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
24+
25+
error: `SmartPointer` can only be derived on `struct`s with at least one field
26+
--> $DIR/deriving-smart-pointer-neg.rs:25:10
27+
|
28+
LL | #[derive(SmartPointer)]
29+
| ^^^^^^^^^^^^
30+
|
31+
= note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
32+
33+
error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
34+
--> $DIR/deriving-smart-pointer-neg.rs:32:10
35+
|
36+
LL | #[derive(SmartPointer)]
37+
| ^^^^^^^^^^^^
38+
|
39+
= note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
40+
41+
error[E0392]: lifetime parameter `'a` is never used
42+
--> $DIR/deriving-smart-pointer-neg.rs:21:16
43+
|
44+
LL | struct NoField<'a, #[pointee] T: ?Sized> {}
45+
| ^^ unused lifetime parameter
46+
|
47+
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
48+
49+
error[E0392]: type parameter `T` is never used
50+
--> $DIR/deriving-smart-pointer-neg.rs:21:31
51+
|
52+
LL | struct NoField<'a, #[pointee] T: ?Sized> {}
53+
| ^ unused type parameter
54+
|
55+
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
56+
57+
error[E0392]: lifetime parameter `'a` is never used
58+
--> $DIR/deriving-smart-pointer-neg.rs:28:20
59+
|
60+
LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
61+
| ^^ unused lifetime parameter
62+
|
63+
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
64+
65+
error[E0392]: type parameter `T` is never used
66+
--> $DIR/deriving-smart-pointer-neg.rs:28:35
67+
|
68+
LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
69+
| ^ unused type parameter
70+
|
71+
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
72+
73+
error: aborting due to 9 previous errors
74+
75+
For more information about this error, try `rustc --explain E0392`.

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

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
use std::marker::SmartPointer;
55

66
#[derive(SmartPointer)]
7+
#[repr(transparent)]
78
struct MyPointer<'a, #[pointee] T: ?Sized> {
89
ptr: &'a T,
910
}

tests/ui/feature-gates/feature-gate-derive-smart-pointer.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::marker::SmartPointer; //~ ERROR use of unstable library feature 'derive_smart_pointer'
22

33
#[derive(SmartPointer)] //~ ERROR use of unstable library feature 'derive_smart_pointer'
4+
#[repr(transparent)]
45
struct MyPointer<'a, #[pointee] T: ?Sized> {
56
//~^ ERROR the `#[pointee]` attribute is an experimental feature
67
ptr: &'a T,

tests/ui/feature-gates/feature-gate-derive-smart-pointer.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ LL | #[derive(SmartPointer)]
99
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
1010

1111
error[E0658]: the `#[pointee]` attribute is an experimental feature
12-
--> $DIR/feature-gate-derive-smart-pointer.rs:4:22
12+
--> $DIR/feature-gate-derive-smart-pointer.rs:5:22
1313
|
1414
LL | struct MyPointer<'a, #[pointee] T: ?Sized> {
1515
| ^^^^^^^^^^

0 commit comments

Comments
 (0)