Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 447ca81

Browse files
committedAug 28, 2024··
derive(SmartPointer): assume pointee from the single generic and better error messages
1 parent 1a94d83 commit 447ca81

File tree

5 files changed

+109
-44
lines changed

5 files changed

+109
-44
lines changed
 

‎compiler/rustc_builtin_macros/src/deriving/smart_ptr.rs

+48-28
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ 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 {
@@ -68,43 +67,64 @@ pub fn expand_deriving_smart_ptr(
6867
};
6968

7069
// Convert generic parameters (from the struct) into generic args.
71-
let mut pointee_param = None;
72-
let mut multiple_pointee_diag: SmallVec<[_; 2]> = smallvec![];
73-
let self_params = generics
70+
let self_params: Vec<_> = generics
7471
.params
7572
.iter()
76-
.enumerate()
77-
.map(|(idx, p)| match p.kind {
73+
.map(|p| match p.kind {
7874
GenericParamKind::Lifetime => GenericArg::Lifetime(cx.lifetime(p.span(), p.ident)),
79-
GenericParamKind::Type { .. } => {
80-
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);
88-
}
89-
}
90-
GenericArg::Type(cx.ty_ident(p.span(), p.ident))
91-
}
75+
GenericParamKind::Type { .. } => GenericArg::Type(cx.ty_ident(p.span(), p.ident)),
9276
GenericParamKind::Const { .. } => GenericArg::Const(cx.const_ident(p.span(), p.ident)),
9377
})
94-
.collect::<Vec<_>>();
95-
let Some(pointee_param_idx) = pointee_param else {
78+
.collect();
79+
let type_params: Vec<_> = generics
80+
.params
81+
.iter()
82+
.enumerate()
83+
.filter_map(|(idx, p)| {
84+
if let GenericParamKind::Type { .. } = p.kind {
85+
Some((idx, p.span(), p.attrs().iter().any(|attr| attr.has_name(sym::pointee))))
86+
} else {
87+
None
88+
}
89+
})
90+
.collect();
91+
92+
let pointee_param_idx = if type_params.is_empty() {
93+
// `#[derive(SmartPointer)]` requires at least one generic type on the target `struct`
9694
cx.dcx().struct_span_err(
9795
span,
98-
"At least one generic type should be designated as `#[pointee]` in order to derive `SmartPointer` traits",
96+
"`SmartPointer` can only be derived on `struct`s that are generic over at least one type",
9997
).emit();
10098
return;
101-
};
102-
if !multiple_pointee_diag.is_empty() {
103-
for diag in multiple_pointee_diag {
104-
diag.emit();
99+
} else if type_params.len() == 1 {
100+
// Regardless of the only type param being designed as `#[pointee]` or not, we can just use it as such
101+
type_params[0].0
102+
} else {
103+
let mut pointees = type_params
104+
.iter()
105+
.filter_map(|&(idx, span, is_pointee)| is_pointee.then_some((idx, span)))
106+
.fuse();
107+
match (pointees.next(), pointees.next()) {
108+
(Some((idx, _span)), None) => idx,
109+
(None, _) => {
110+
cx.dcx().struct_span_err(
111+
span,
112+
"exactly one generic parameters when there are at least two generic type parameters \
113+
should be designated as `#[pointee]` in order to derive `SmartPointer` traits",
114+
).emit();
115+
return;
116+
}
117+
(Some((_, one)), Some((_, another))) => {
118+
cx.dcx()
119+
.struct_span_err(
120+
vec![one, another],
121+
"only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits",
122+
)
123+
.emit();
124+
return;
125+
}
105126
}
106-
return;
107-
}
127+
};
108128

109129
// Create the type of `self`.
110130
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

+17-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,23 @@ 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+
//~^ ERROR: exactly one generic parameters when there are at least two generic type parameters should be designated as `#[pointee]` in order to derive `SmartPointer` traits
33+
#[repr(transparent)]
34+
struct AmbiguousPointee<'a, T1: ?Sized, T2: ?Sized> {
35+
a: (&'a T1, &'a T2),
36+
}
37+
38+
#[derive(SmartPointer)]
39+
#[repr(transparent)]
40+
struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
41+
//~^ ERROR: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits
42+
3343
#[derive(SmartPointer)]
3444
//~^ ERROR: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
3545
struct NotTransparent<'a, #[pointee] T: ?Sized> {

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

+23-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,74 @@ 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: exactly one generic parameters when there are at least two generic type parameters should be designated as `#[pointee]` in order to derive `SmartPointer` traits
34+
--> $DIR/deriving-smart-pointer-neg.rs:31: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: only one type parameter can be marked as `#[pointee]` when deriving SmartPointer traits
42+
--> $DIR/deriving-smart-pointer-neg.rs:40:39
43+
|
44+
LL | struct TooManyPointees<'a, #[pointee] A: ?Sized, #[pointee] B: ?Sized>((&'a A, &'a B));
45+
| ^ ^
46+
3347
error: `SmartPointer` can only be derived on `struct`s with `#[repr(transparent)]`
34-
--> $DIR/deriving-smart-pointer-neg.rs:33:10
48+
--> $DIR/deriving-smart-pointer-neg.rs:43:10
3549
|
3650
LL | #[derive(SmartPointer)]
3751
| ^^^^^^^^^^^^
3852
|
3953
= note: this error originates in the derive macro `SmartPointer` (in Nightly builds, run with -Z macro-backtrace for more info)
4054

4155
error: `derive(SmartPointer)` requires T to be marked `?Sized`
42-
--> $DIR/deriving-smart-pointer-neg.rs:41:36
56+
--> $DIR/deriving-smart-pointer-neg.rs:51:36
4357
|
4458
LL | struct NoMaybeSized<'a, #[pointee] T> {
4559
| ^
4660

4761
error[E0392]: lifetime parameter `'a` is never used
48-
--> $DIR/deriving-smart-pointer-neg.rs:22:16
62+
--> $DIR/deriving-smart-pointer-neg.rs:15:16
4963
|
5064
LL | struct NoField<'a, #[pointee] T: ?Sized> {}
5165
| ^^ unused lifetime parameter
5266
|
5367
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
5468

5569
error[E0392]: type parameter `T` is never used
56-
--> $DIR/deriving-smart-pointer-neg.rs:22:31
70+
--> $DIR/deriving-smart-pointer-neg.rs:15:31
5771
|
5872
LL | struct NoField<'a, #[pointee] T: ?Sized> {}
5973
| ^ unused type parameter
6074
|
6175
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
6276

6377
error[E0392]: lifetime parameter `'a` is never used
64-
--> $DIR/deriving-smart-pointer-neg.rs:29:20
78+
--> $DIR/deriving-smart-pointer-neg.rs:22:20
6579
|
6680
LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
6781
| ^^ unused lifetime parameter
6882
|
6983
= help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData`
7084

7185
error[E0392]: type parameter `T` is never used
72-
--> $DIR/deriving-smart-pointer-neg.rs:29:35
86+
--> $DIR/deriving-smart-pointer-neg.rs:22:35
7387
|
7488
LL | struct NoFieldUnit<'a, #[pointee] T: ?Sized>();
7589
| ^ unused type parameter
7690
|
7791
= help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData`
7892

79-
error: aborting due to 10 previous errors
93+
error: aborting due to 12 previous errors
8094

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

0 commit comments

Comments
 (0)
Please sign in to comment.