@@ -11,7 +11,6 @@ use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
11
11
use rustc_expand:: base:: { Annotatable , ExtCtxt } ;
12
12
use rustc_span:: symbol:: { sym, Ident } ;
13
13
use rustc_span:: { Span , Symbol } ;
14
- use smallvec:: { smallvec, SmallVec } ;
15
14
use thin_vec:: { thin_vec, ThinVec } ;
16
15
17
16
macro_rules! path {
@@ -68,43 +67,65 @@ pub fn expand_deriving_smart_ptr(
68
67
} ;
69
68
70
69
// 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
74
71
. params
75
72
. iter ( )
76
- . enumerate ( )
77
- . map ( |( idx, p) | match p. kind {
73
+ . map ( |p| match p. kind {
78
74
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 ) ) ,
92
76
GenericParamKind :: Const { .. } => GenericArg :: Const ( cx. const_ident ( p. span ( ) , p. ident ) ) ,
93
77
} )
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
+ // `#[derive(SmartPointer)]` requires at least one generic type on the target `struct`
93
+ if type_params. is_empty ( ) {
96
94
cx. dcx ( ) . struct_span_err (
97
95
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 " ,
99
97
) . emit ( ) ;
100
98
return ;
101
- } ;
102
- if !multiple_pointee_diag. is_empty ( ) {
103
- for diag in multiple_pointee_diag {
104
- diag. emit ( ) ;
105
- }
106
- return ;
107
99
}
100
+ let pointee_param_idx = if type_params. len ( ) == 1 {
101
+ // Regardless of the only type param being designed as `#[pointee]` or not, we can just use it as such
102
+ type_params[ 0 ] . 0
103
+ } else {
104
+ let mut pointees = type_params
105
+ . iter ( )
106
+ . filter_map ( |& ( idx, span, is_pointee) | is_pointee. then_some ( ( idx, span) ) )
107
+ . fuse ( ) ;
108
+ match ( pointees. next ( ) , pointees. next ( ) ) {
109
+ ( Some ( ( idx, _span) ) , None ) => idx,
110
+ ( None , _) => {
111
+ cx. dcx ( ) . struct_span_err (
112
+ span,
113
+ "Exactly one generic parameters when there are at least two generic type parameters \
114
+ should be designated as `#[pointee]` in order to derive `SmartPointer` traits",
115
+ ) . emit ( ) ;
116
+ return ;
117
+ }
118
+ ( Some ( ( _, one) ) , Some ( ( _, another) ) ) => {
119
+ cx. dcx ( )
120
+ . struct_span_err (
121
+ vec ! [ one, another] ,
122
+ "`SmartPointer` can only admit one type as pointee" ,
123
+ )
124
+ . emit ( ) ;
125
+ return ;
126
+ }
127
+ }
128
+ } ;
108
129
109
130
// Create the type of `self`.
110
131
let path = cx. path_all ( span, false , vec ! [ name_ident] , self_params. clone ( ) ) ;
0 commit comments