@@ -11,13 +11,20 @@ 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 {
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+
2128pub 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 ( ) ) ;
0 commit comments