@@ -11,7 +11,6 @@ use std::sync::Arc;
11
11
use rustc_data_structures:: fx:: FxIndexMap ;
12
12
use rustc_hir:: { LangItem , RangeEnd } ;
13
13
use rustc_middle:: mir:: * ;
14
- use rustc_middle:: ty:: adjustment:: PointerCoercion ;
15
14
use rustc_middle:: ty:: util:: IntTypeExt ;
16
15
use rustc_middle:: ty:: { self , GenericArg , Ty , TyCtxt } ;
17
16
use rustc_middle:: { bug, span_bug} ;
@@ -178,21 +177,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
178
177
_ => { }
179
178
}
180
179
180
+ assert_eq ! ( expect_ty, ty) ;
181
181
if !ty. is_scalar ( ) {
182
182
// Use `PartialEq::eq` instead of `BinOp::Eq`
183
183
// (the binop can only handle primitives)
184
- self . non_scalar_compare (
184
+ // Make sure that we do *not* call any user-defined code here.
185
+ // The only type that can end up here is string literals, which have their
186
+ // comparison defined in `core`.
187
+ // (Interestingly this means that exhaustiveness analysis relies, for soundness,
188
+ // on the `PartialEq` impl for `str` to b correct!)
189
+ match * ty. kind ( ) {
190
+ ty:: Ref ( _, deref_ty, _) if deref_ty == self . tcx . types . str_ => { }
191
+ _ => {
192
+ span_bug ! ( source_info. span, "invalid type for non-scalar compare: {ty}" )
193
+ }
194
+ } ;
195
+ self . string_compare (
185
196
block,
186
197
success_block,
187
198
fail_block,
188
199
source_info,
189
200
expect,
190
- expect_ty,
191
201
Operand :: Copy ( place) ,
192
- ty,
193
202
) ;
194
203
} else {
195
- assert_eq ! ( expect_ty, ty) ;
196
204
self . compare (
197
205
block,
198
206
success_block,
@@ -370,97 +378,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
370
378
) ;
371
379
}
372
380
373
- /// Compare two values using `<T as std::compare::PartialEq>::eq`.
374
- /// If the values are already references, just call it directly, otherwise
375
- /// take a reference to the values first and then call it.
376
- fn non_scalar_compare (
381
+ /// Compare two values of type `&str` using `<str as std::cmp::PartialEq>::eq`.
382
+ fn string_compare (
377
383
& mut self ,
378
384
block : BasicBlock ,
379
385
success_block : BasicBlock ,
380
386
fail_block : BasicBlock ,
381
387
source_info : SourceInfo ,
382
- mut expect : Operand < ' tcx > ,
383
- expect_ty : Ty < ' tcx > ,
384
- mut val : Operand < ' tcx > ,
385
- mut ty : Ty < ' tcx > ,
388
+ expect : Operand < ' tcx > ,
389
+ val : Operand < ' tcx > ,
386
390
) {
387
- // If we're using `b"..."` as a pattern, we need to insert an
388
- // unsizing coercion, as the byte string has the type `&[u8; N]`.
389
- //
390
- // We want to do this even when the scrutinee is a reference to an
391
- // array, so we can call `<[u8]>::eq` rather than having to find an
392
- // `<[u8; N]>::eq`.
393
- let unsize = |ty : Ty < ' tcx > | match ty. kind ( ) {
394
- ty:: Ref ( region, rty, _) => match rty. kind ( ) {
395
- ty:: Array ( inner_ty, n) => Some ( ( region, inner_ty, n) ) ,
396
- _ => None ,
397
- } ,
398
- _ => None ,
399
- } ;
400
- let opt_ref_ty = unsize ( ty) ;
401
- let opt_ref_test_ty = unsize ( expect_ty) ;
402
- match ( opt_ref_ty, opt_ref_test_ty) {
403
- // nothing to do, neither is an array
404
- ( None , None ) => { }
405
- ( Some ( ( region, elem_ty, _) ) , _) | ( None , Some ( ( region, elem_ty, _) ) ) => {
406
- let tcx = self . tcx ;
407
- // make both a slice
408
- ty = Ty :: new_imm_ref ( tcx, * region, Ty :: new_slice ( tcx, * elem_ty) ) ;
409
- if opt_ref_ty. is_some ( ) {
410
- let temp = self . temp ( ty, source_info. span ) ;
411
- self . cfg . push_assign (
412
- block,
413
- source_info,
414
- temp,
415
- Rvalue :: Cast (
416
- CastKind :: PointerCoercion (
417
- PointerCoercion :: Unsize ,
418
- CoercionSource :: Implicit ,
419
- ) ,
420
- val,
421
- ty,
422
- ) ,
423
- ) ;
424
- val = Operand :: Copy ( temp) ;
425
- }
426
- if opt_ref_test_ty. is_some ( ) {
427
- let slice = self . temp ( ty, source_info. span ) ;
428
- self . cfg . push_assign (
429
- block,
430
- source_info,
431
- slice,
432
- Rvalue :: Cast (
433
- CastKind :: PointerCoercion (
434
- PointerCoercion :: Unsize ,
435
- CoercionSource :: Implicit ,
436
- ) ,
437
- expect,
438
- ty,
439
- ) ,
440
- ) ;
441
- expect = Operand :: Move ( slice) ;
442
- }
443
- }
444
- }
445
-
446
- // Figure out the type on which we are calling `PartialEq`. This involves an extra wrapping
447
- // reference: we can only compare two `&T`, and then compare_ty will be `T`.
448
- // Make sure that we do *not* call any user-defined code here.
449
- // The only types that can end up here are string and byte literals,
450
- // which have their comparison defined in `core`.
451
- // (Interestingly this means that exhaustiveness analysis relies, for soundness,
452
- // on the `PartialEq` impls for `str` and `[u8]` to b correct!)
453
- let compare_ty = match * ty. kind ( ) {
454
- ty:: Ref ( _, deref_ty, _)
455
- if deref_ty == self . tcx . types . str_ || deref_ty != self . tcx . types . u8 =>
456
- {
457
- deref_ty
458
- }
459
- _ => span_bug ! ( source_info. span, "invalid type for non-scalar compare: {}" , ty) ,
460
- } ;
461
-
391
+ let str_ty = self . tcx . types . str_ ;
462
392
let eq_def_id = self . tcx . require_lang_item ( LangItem :: PartialEq , Some ( source_info. span ) ) ;
463
- let method = trait_method ( self . tcx , eq_def_id, sym:: eq, [ compare_ty , compare_ty ] ) ;
393
+ let method = trait_method ( self . tcx , eq_def_id, sym:: eq, [ str_ty , str_ty ] ) ;
464
394
465
395
let bool_ty = self . tcx . types . bool ;
466
396
let eq_result = self . temp ( bool_ty, source_info. span ) ;
0 commit comments