@@ -11,7 +11,6 @@ use rustc_data_structures::flat_map_in_place::FlatMapInPlace;
1111use rustc_expand:: base:: { Annotatable , ExtCtxt } ;
1212use rustc_span:: symbol:: { sym, Ident } ;
1313use rustc_span:: { Span , Symbol } ;
14- use smallvec:: { smallvec, SmallVec } ;
1514use thin_vec:: { thin_vec, ThinVec } ;
1615
1716macro_rules! path {
@@ -68,43 +67,65 @@ 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+ // `#[derive(SmartPointer)]` requires at least one generic type on the target `struct`
93+ if type_params. is_empty ( ) {
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 ( ) ;
105- }
106- return ;
10799 }
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+ } ;
108129
109130 // Create the type of `self`.
110131 let path = cx. path_all ( span, false , vec ! [ name_ident] , self_params. clone ( ) ) ;
0 commit comments