1- use rustc_ast:: { BinOpKind , BorrowKind , Expr , ExprKind , MetaItem , Mutability , Safety } ;
1+ use rustc_ast:: { BinOpKind , BorrowKind , Expr , ExprKind , GenericArg , MetaItem , Mutability , Safety } ;
22use rustc_expand:: base:: { Annotatable , ExtCtxt } ;
3- use rustc_span:: { Span , sym} ;
3+ use rustc_span:: { Ident , Span , kw , sym} ;
44use thin_vec:: thin_vec;
55
66use crate :: deriving:: generic:: ty:: * ;
@@ -125,7 +125,7 @@ fn get_substructure_equality_expr(
125125) -> Box < Expr > {
126126 use SubstructureFields :: * ;
127127
128- match substructure. fields {
128+ let field_comparison = match substructure. fields {
129129 EnumMatching ( .., fields) | Struct ( .., fields) => {
130130 let combine = move |acc, field| {
131131 let rhs = get_field_equality_expr ( cx, field) ;
@@ -138,23 +138,35 @@ fn get_substructure_equality_expr(
138138 Some ( rhs)
139139 } ;
140140
141- // First compare scalar fields, then compound fields, combining all
142- // with logical AND.
143- return fields
144- . iter ( )
145- . filter ( |field| !field. maybe_scalar )
146- . fold ( fields. iter ( ) . filter ( |field| field. maybe_scalar ) . fold ( None , combine) , combine)
147- // If there are no fields, treat as always equal.
148- . unwrap_or_else ( || cx. expr_bool ( span, true ) ) ;
141+ // If there are no fields, return true immediately.
142+ // If there is just one, compare it.
143+ // Otherwise, try to do a bitwise comparison.
144+ match & fields[ ..] {
145+ [ ] => return cx. expr_bool ( span, true ) ,
146+ [ field] => return get_field_equality_expr ( cx, field) ,
147+ _ => {
148+ // First compare scalar fields, then compound fields, combining all
149+ // with logical AND.
150+ fields
151+ . iter ( )
152+ . filter ( |field| !field. maybe_scalar )
153+ . fold (
154+ fields. iter ( ) . filter ( |field| field. maybe_scalar ) . fold ( None , combine) ,
155+ combine,
156+ )
157+ . unwrap ( )
158+ }
159+ }
149160 }
150161 EnumDiscr ( disc, match_expr) => {
151162 let lhs = get_field_equality_expr ( cx, disc) ;
152- let Some ( match_expr) = match_expr else {
153- return lhs;
154- } ;
155- // Compare the discriminant first (cheaper), then the rest of the
156- // fields.
157- return cx. expr_binary ( disc. span , BinOpKind :: And , lhs, match_expr. clone ( ) ) ;
163+ if let Some ( match_expr) = match_expr {
164+ // Compare the discriminant first (cheaper), then the rest of the
165+ // fields.
166+ cx. expr_binary ( disc. span , BinOpKind :: And , lhs, match_expr. clone ( ) )
167+ } else {
168+ lhs
169+ }
158170 }
159171 StaticEnum ( ..) => cx. dcx ( ) . span_bug (
160172 span,
@@ -168,6 +180,31 @@ fn get_substructure_equality_expr(
168180 span,
169181 "unexpected all-fieldless enum encountered during `derive(PartialEq)` expansion" ,
170182 ) ,
183+ } ;
184+
185+ if matches ! ( substructure. fields, Struct ( ..) ) {
186+ // Construct intrinsics::can_compare_bitwise<Self>()
187+ let self_ty = cx. ty_path ( cx. path_ident ( span, Ident :: with_dummy_span ( kw:: SelfUpper ) ) ) ;
188+ let path = cx. expr_path ( cx. path_all (
189+ span,
190+ true ,
191+ cx. std_path ( & [ sym:: intrinsics, sym:: can_compare_bitwise] ) ,
192+ vec ! [ GenericArg :: Type ( self_ty) ] ,
193+ ) ) ;
194+ let cond = cx. expr_call ( span, path, thin_vec ! [ ] ) ;
195+
196+ let [ _self, rhs] = & substructure. selflike_args [ ..] else {
197+ cx. dcx ( ) . span_bug ( span, "not exactly 2 arguments in `derive(PartialEq)`" ) ;
198+ } ;
199+
200+ // Construct intrinsics::compare_bitwise(self, other)
201+ let compare_bitwise = cx. std_path ( & [ sym:: intrinsics, sym:: compare_bitwise] ) ;
202+ let call_compare_bitwise =
203+ cx. expr_call_global ( span, compare_bitwise, thin_vec ! [ cx. expr_self( span) , rhs. clone( ) ] ) ;
204+
205+ cx. expr_if ( span, cond, call_compare_bitwise, Some ( field_comparison) )
206+ } else {
207+ field_comparison
171208 }
172209}
173210
0 commit comments