Skip to content

Commit bb43160

Browse files
derive(SmartPointer): assume pointee from the single generic and better error messages
1 parent c8b14ba commit bb43160

File tree

5 files changed

+100
-38
lines changed

5 files changed

+100
-38
lines changed

compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs

+54-22
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,20 @@ use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
1111
use rustc_expand::base::{Annotatable, ExtCtxt};
1212
use rustc_span::symbol::{sym, Ident};
1313
use rustc_span::{Span, Symbol};
14-
use smallvec::{smallvec, SmallVec};
1514
use thin_vec::{thin_vec, ThinVec};
1615

1716
macro_rules! path {
1817
($span:expr, $($part:ident)::*) => { vec![$(Ident::new(sym::$part, $span),)*] }
1918
}
2019

20+
enum PointeeChoice {
21+
None,
22+
Exactly(usize, Span),
23+
Assumed(usize),
24+
Ambiguous,
25+
MultiplePointeeChoice(Span, Span),
26+
}
27+
2128
pub fn expand_deriving_smart_ptr(
2229
cx: &ExtCtxt<'_>,
2330
span: Span,
@@ -68,8 +75,7 @@ pub fn expand_deriving_smart_ptr(
6875
};
6976

7077
// Convert generic parameters (from the struct) into generic args.
71-
let mut pointee_param = None;
72-
let mut multiple_pointee_diag: SmallVec<[_; 2]> = smallvec![];
78+
let mut pointee_param = PointeeChoice::None;
7379
let self_params = generics
7480
.params
7581
.iter()
@@ -78,33 +84,59 @@ pub fn expand_deriving_smart_ptr(
7884
GenericParamKind::Lifetime => GenericArg::Lifetime(cx.lifetime(p.span(), p.ident)),
7985
GenericParamKind::Type { .. } => {
8086
if p.attrs().iter().any(|attr| attr.has_name(sym::pointee)) {
81-
if pointee_param.is_some() {
82-
multiple_pointee_diag.push(cx.dcx().struct_span_err(
83-
p.span(),
84-
"`SmartPointer` can only admit one type as pointee",
85-
));
86-
} else {
87-
pointee_param = Some(idx);
87+
match pointee_param {
88+
PointeeChoice::Assumed(_)
89+
| PointeeChoice::Ambiguous
90+
| PointeeChoice::None => {
91+
pointee_param = PointeeChoice::Exactly(idx, p.span())
92+
}
93+
PointeeChoice::Exactly(_, another) => {
94+
pointee_param = PointeeChoice::MultiplePointeeChoice(another, p.span())
95+
}
96+
PointeeChoice::MultiplePointeeChoice(_, _) => {}
97+
}
98+
} else {
99+
match pointee_param {
100+
PointeeChoice::None => pointee_param = PointeeChoice::Assumed(idx),
101+
PointeeChoice::Assumed(_) | PointeeChoice::Ambiguous => {
102+
pointee_param = PointeeChoice::Ambiguous
103+
}
104+
PointeeChoice::Exactly(_, _)
105+
| PointeeChoice::MultiplePointeeChoice(_, _) => {}
88106
}
89107
}
90108
GenericArg::Type(cx.ty_ident(p.span(), p.ident))
91109
}
92110
GenericParamKind::Const { .. } => GenericArg::Const(cx.const_ident(p.span(), p.ident)),
93111
})
94112
.collect::<Vec<_>>();
95-
let Some(pointee_param_idx) = pointee_param else {
96-
cx.dcx().struct_span_err(
97-
span,
98-
"At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits",
99-
).emit();
100-
return;
101-
};
102-
if !multiple_pointee_diag.is_empty() {
103-
for diag in multiple_pointee_diag {
104-
diag.emit();
113+
let pointee_param_idx = match pointee_param {
114+
PointeeChoice::Assumed(idx) | PointeeChoice::Exactly(idx, _) => idx,
115+
PointeeChoice::None => {
116+
cx.dcx().struct_span_err(
117+
span,
118+
"`SmartPointer` can only be derived on `struct`s that are generic over at least one type",
119+
).emit();
120+
return;
105121
}
106-
return;
107-
}
122+
PointeeChoice::Ambiguous => {
123+
cx.dcx().struct_span_err(
124+
span,
125+
"Exactly one generic parameters when there are at least two generic type parameters \
126+
should be designated as `#[pointee]` in order to derive `SmartPointer` traits",
127+
).emit();
128+
return;
129+
}
130+
PointeeChoice::MultiplePointeeChoice(one, another) => {
131+
cx.dcx()
132+
.struct_span_err(
133+
vec![one, another],
134+
"`SmartPointer` can only admit one type as pointee",
135+
)
136+
.emit();
137+
return;
138+
}
139+
};
108140

109141
// Create the type of `self`.
110142
let path = cx.path_all(span, false, vec![name_ident], self_params.clone());

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

+6
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,9 @@ where
2020
data: &'a mut T,
2121
x: core::marker::PhantomData<X>,
2222
}
23+
24+
#[derive(SmartPointer)]
25+
#[repr(transparent)]
26+
struct MyPointerWithoutPointee<'a, T: ?Sized> {
27+
ptr: &'a T,
28+
}

tests/ui/deriving/deriving-smart-pointer-expanded.stdout

+15
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,18 @@ impl<'a, Y, Z: MyTrait<T> + MyTrait<__S>, T: ?Sized + MyTrait<T> +
4242
MyTrait<__S>> ::core::ops::CoerceUnsized<MyPointer2<'a, Y, Z, __S, X>> for
4343
MyPointer2<'a, Y, Z, T, X> where Y: MyTrait<T>, Y: MyTrait<__S> {
4444
}
45+
46+
#[repr(transparent)]
47+
struct MyPointerWithoutPointee<'a, T: ?Sized> {
48+
ptr: &'a T,
49+
}
50+
#[automatically_derived]
51+
impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized>
52+
::core::ops::DispatchFromDyn<MyPointerWithoutPointee<'a, __S>> for
53+
MyPointerWithoutPointee<'a, T> {
54+
}
55+
#[automatically_derived]
56+
impl<'a, T: ?Sized + ::core::marker::Unsize<__S>, __S: ?Sized>
57+
::core::ops::CoerceUnsized<MyPointerWithoutPointee<'a, __S>> for
58+
MyPointerWithoutPointee<'a, T> {
59+
}

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

+10-7
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,6 @@ enum NotStruct<'a, T: ?Sized> {
99
Variant(&'a T),
1010
}
1111

12-
#[derive(SmartPointer)]
13-
//~^ ERROR: At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits
14-
#[repr(transparent)]
15-
struct NoPointee<'a, T: ?Sized> {
16-
ptr: &'a T,
17-
}
18-
1912
#[derive(SmartPointer)]
2013
//~^ ERROR: `SmartPointer` can only be derived on `struct`s with at least one field
2114
#[repr(transparent)]
@@ -30,6 +23,16 @@ struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
3023
//~^ ERROR: lifetime parameter `'a` is never used
3124
//~| ERROR: type parameter `T` is never used
3225

26+
#[derive(SmartPointer)]
27+
//~^ ERROR: `SmartPointer` can only be derived on `struct`s that are generic over at least one type
28+
#[repr(transparent)]
29+
struct NoGeneric<'a>(&'a u8);
30+
31+
#[derive(SmartPointer)]
32+
#[repr(transparent)]
33+
struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
34+
//~^ ERROR: `SmartPointer` can only admit one type as pointee
35+
3336
#[derive(SmartPointer)]
3437
//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
3538
struct NotTransparent<'a, #[pointee] T: ?Sized> {

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

+15-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | #[derive(SmartPointer)]
66
|
77
= note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
88

9-
error: At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits
9+
error: `SmartPointer` can only be derived on `struct`s with at least one field
1010
--> $DIR/deriving-smart-pointer-neg.rs:12:10
1111
|
1212
LL | #[derive(SmartPointer)]
@@ -22,60 +22,66 @@ LL | #[derive(SmartPointer)]
2222
|
2323
= note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
2424

25-
error: `SmartPointer` can only be derived on `struct`s with at least one field
25+
error: `SmartPointer` can only be derived on `struct`s that are generic over at least one type
2626
--> $DIR/deriving-smart-pointer-neg.rs:26:10
2727
|
2828
LL | #[derive(SmartPointer)]
2929
| ^^^^^^^^^^^^
3030
|
3131
= note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
3232

33+
error: `SmartPointer` can only admit one type as pointee
34+
--> $DIR/deriving-smart-pointer-neg.rs:33:39
35+
|
36+
LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
37+
| ^ ^
38+
3339
error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
34-
--> $DIR/deriving-smart-pointer-neg.rs:33:10
40+
--> $DIR/deriving-smart-pointer-neg.rs:36:10
3541
|
3642
LL | #[derive(SmartPointer)]
3743
| ^^^^^^^^^^^^
3844
|
3945
= note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
4046

4147
error: `derive(SmartPointer)` requires T to be marked `?Sized`
42-
--> $DIR/deriving-smart-pointer-neg.rs:41:36
48+
--> $DIR/deriving-smart-pointer-neg.rs:44:36
4349
|
4450
LL | struct NoMaybeSized<'a, #[pointee] T> {
4551
| ^
4652

4753
error[E0392]: lifetime parameter `'a` is never used
48-
--> $DIR/deriving-smart-pointer-neg.rs:22:16
54+
--> $DIR/deriving-smart-pointer-neg.rs:15:16
4955
|
5056
LL | struct NoField<'a, #[pointee] T: ?Sized> {}
5157
| ^^ unused lifetime parameter
5258
|
5359
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
5460

5561
error[E0392]: type parameter `T` is never used
56-
--> $DIR/deriving-smart-pointer-neg.rs:22:31
62+
--> $DIR/deriving-smart-pointer-neg.rs:15:31
5763
|
5864
LL | struct NoField<'a, #[pointee] T: ?Sized> {}
5965
| ^ unused type parameter
6066
|
6167
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
6268

6369
error[E0392]: lifetime parameter `'a` is never used
64-
--> $DIR/deriving-smart-pointer-neg.rs:29:20
70+
--> $DIR/deriving-smart-pointer-neg.rs:22:20
6571
|
6672
LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
6773
| ^^ unused lifetime parameter
6874
|
6975
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
7076

7177
error[E0392]: type parameter `T` is never used
72-
--> $DIR/deriving-smart-pointer-neg.rs:29:35
78+
--> $DIR/deriving-smart-pointer-neg.rs:22:35
7379
|
7480
LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
7581
| ^ unused type parameter
7682
|
7783
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
7884

79-
error: aborting due to 10 previous errors
85+
error: aborting due to 11 previous errors
8086

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

0 commit comments

Comments
 (0)