@@ -11,7 +11,6 @@ use std::sync::Arc;
1111use rustc_data_structures:: fx:: FxIndexMap ;
1212use rustc_hir:: { LangItem , RangeEnd } ;
1313use rustc_middle:: mir:: * ;
14- use rustc_middle:: ty:: adjustment:: PointerCoercion ;
1514use rustc_middle:: ty:: util:: IntTypeExt ;
1615use rustc_middle:: ty:: { self , GenericArg , Ty , TyCtxt } ;
1716use rustc_middle:: { bug, span_bug} ;
@@ -178,21 +177,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
178177 _ => { }
179178 }
180179
180+ assert_eq ! ( expect_ty, ty) ;
181181 if !ty. is_scalar ( ) {
182182 // Use `PartialEq::eq` instead of `BinOp::Eq`
183183 // (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 (
185196 block,
186197 success_block,
187198 fail_block,
188199 source_info,
189200 expect,
190- expect_ty,
191201 Operand :: Copy ( place) ,
192- ty,
193202 ) ;
194203 } else {
195- assert_eq ! ( expect_ty, ty) ;
196204 self . compare (
197205 block,
198206 success_block,
@@ -370,97 +378,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
370378 ) ;
371379 }
372380
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 (
377383 & mut self ,
378384 block : BasicBlock ,
379385 success_block : BasicBlock ,
380386 fail_block : BasicBlock ,
381387 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 > ,
386390 ) {
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_ ;
462392 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 ] ) ;
464394
465395 let bool_ty = self . tcx . types . bool ;
466396 let eq_result = self . temp ( bool_ty, source_info. span ) ;
0 commit comments