@@ -20,8 +20,8 @@ use rustc_span::{DUMMY_SP, Span, Symbol, sym};
2020use rustc_trait_selection:: infer:: InferCtxtExt ;
2121use tracing:: { debug, instrument} ;
2222
23- use crate :: builder:: Builder ;
2423use crate :: builder:: matches:: { Candidate , MatchPairTree , Test , TestBranch , TestCase , TestKind } ;
24+ use crate :: builder:: { Builder , PlaceBuilder } ;
2525
2626impl < ' a , ' tcx > Builder < ' a , ' tcx > {
2727 /// Identifies what test is needed to decide if `match_pair` is applicable.
@@ -36,7 +36,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3636
3737 TestCase :: Constant { .. } if match_pair. pattern . ty . is_bool ( ) => TestKind :: If ,
3838 TestCase :: Constant { .. } if is_switch_ty ( match_pair. pattern . ty ) => TestKind :: SwitchInt ,
39- TestCase :: Constant { value } => TestKind :: Eq { value, ty : match_pair. pattern . ty } ,
39+ TestCase :: Constant { value, ref range } => {
40+ TestKind :: Eq { value, ty : match_pair. pattern . ty , range : range. clone ( ) }
41+ }
4042
4143 TestCase :: Range ( range) => {
4244 assert_eq ! ( range. ty, match_pair. pattern. ty) ;
@@ -142,7 +144,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
142144 self . cfg . terminate ( block, self . source_info ( match_start_span) , terminator) ;
143145 }
144146
145- TestKind :: Eq { value, ty } => {
147+ TestKind :: Eq { value, ref range , ty } => {
146148 let tcx = self . tcx ;
147149 let success_block = target_block ( TestBranch :: Success ) ;
148150 let fail_block = target_block ( TestBranch :: Failure ) ;
@@ -179,15 +181,37 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
179181 ref_str_ty,
180182 ) ;
181183 } else if !ty. is_scalar ( ) {
184+ let new_place;
185+ let cmp_block;
186+ if let Some ( range) = range {
187+ assert_eq ! ( range. start, 0 ) ;
188+ let elem_ty = ty. sequence_element_type ( tcx) ;
189+ cmp_block = self . cfg . start_new_block ( ) ;
190+ let subslice_ptr = self . subslice (
191+ block,
192+ cmp_block,
193+ place,
194+ place_ty. ty ,
195+ test. span ,
196+ elem_ty,
197+ range. end ,
198+ ) ;
199+
200+ new_place = PlaceBuilder :: from ( subslice_ptr) . deref ( ) . to_place ( self ) ;
201+ } else {
202+ cmp_block = block;
203+ new_place = place;
204+ }
205+
182206 // Use `PartialEq::eq` instead of `BinOp::Eq`
183207 // (the binop can only handle primitives)
184208 self . non_scalar_compare (
185- block ,
209+ cmp_block ,
186210 success_block,
187211 fail_block,
188212 source_info,
189213 value,
190- place ,
214+ new_place ,
191215 ty,
192216 ) ;
193217 } else {
@@ -290,6 +314,66 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
290314 }
291315 }
292316
317+ fn subslice (
318+ & mut self ,
319+ block : BasicBlock ,
320+ target_block : BasicBlock ,
321+ input : Place < ' tcx > ,
322+ input_ty : Ty < ' tcx > ,
323+ span : Span ,
324+ elem_ty : Ty < ' tcx > ,
325+ new_len : u64 ,
326+ ) -> Place < ' tcx > {
327+ let tcx = self . tcx ;
328+ let source_info = self . source_info ( span) ;
329+
330+ let temp_source_ptr = self . temp ( Ty :: new_ptr ( tcx, input_ty, Mutability :: Not ) , span) ;
331+ self . cfg . push_assign (
332+ block,
333+ source_info,
334+ temp_source_ptr,
335+ Rvalue :: RawPtr ( Mutability :: Not , input) ,
336+ ) ;
337+
338+ let elem_ptr_ty = Ty :: new_ptr ( tcx, elem_ty, Mutability :: Not ) ;
339+ let slice_ptr_ty = Ty :: new_ptr ( tcx, Ty :: new_slice ( tcx, elem_ty) , Mutability :: Not ) ;
340+
341+ let temp_elem_ptr = self . temp ( elem_ptr_ty, span) ;
342+ self . cfg . push_assign (
343+ block,
344+ source_info,
345+ temp_elem_ptr,
346+ Rvalue :: Cast ( CastKind :: PtrToPtr , Operand :: Copy ( temp_source_ptr) , elem_ptr_ty) ,
347+ ) ;
348+
349+ let temp_len = self . push_usize ( block, source_info, new_len) ;
350+
351+ let aggregate_raw_ptr = Operand :: function_handle (
352+ tcx,
353+ tcx. require_lang_item ( LangItem :: AggregateRawPtr , Some ( span) ) ,
354+ [ slice_ptr_ty. into ( ) , elem_ptr_ty. into ( ) , tcx. types . usize . into ( ) ] ,
355+ span,
356+ ) ;
357+
358+ let subslice_ptr = self . temp ( slice_ptr_ty, span) ;
359+
360+ self . cfg . terminate ( block, source_info, TerminatorKind :: Call {
361+ func : aggregate_raw_ptr,
362+ args : [ Spanned { node : Operand :: Move ( temp_elem_ptr) , span } , Spanned {
363+ node : Operand :: Move ( temp_len) ,
364+ span,
365+ } ]
366+ . into ( ) ,
367+ destination : subslice_ptr,
368+ target : Some ( target_block) ,
369+ unwind : UnwindAction :: Continue ,
370+ call_source : CallSource :: Misc ,
371+ fn_span : source_info. span ,
372+ } ) ;
373+
374+ subslice_ptr
375+ }
376+
293377 /// Perform `let temp = <ty as Deref>::deref(&place)`.
294378 /// or `let temp = <ty as DerefMut>::deref_mut(&mut place)`.
295379 pub ( super ) fn call_deref (
@@ -582,7 +666,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
582666 //
583667 // FIXME(#29623) we could use PatKind::Range to rule
584668 // things out here, in some cases.
585- ( TestKind :: SwitchInt , & TestCase :: Constant { value } )
669+ ( TestKind :: SwitchInt , & TestCase :: Constant { value, .. } )
586670 if is_switch_ty ( match_pair. pattern . ty ) =>
587671 {
588672 // An important invariant of candidate sorting is that a candidate
@@ -636,7 +720,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
636720 } )
637721 }
638722
639- ( TestKind :: If , TestCase :: Constant { value } ) => {
723+ ( TestKind :: If , TestCase :: Constant { value, .. } ) => {
640724 fully_matched = true ;
641725 let value = value. try_eval_bool ( self . tcx , self . typing_env ( ) ) . unwrap_or_else ( || {
642726 span_bug ! ( test. span, "expected boolean value but got {value:?}" )
@@ -725,7 +809,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
725809 }
726810 }
727811 }
728- ( TestKind :: Range ( range) , & TestCase :: Constant { value } ) => {
812+ ( TestKind :: Range ( range) , & TestCase :: Constant { value, .. } ) => {
729813 fully_matched = false ;
730814 if !range. contains ( value, self . tcx , self . typing_env ( ) ) ? {
731815 // `value` is not contained in the testing range,
@@ -736,7 +820,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
736820 }
737821 }
738822
739- ( TestKind :: Eq { value : test_val, .. } , TestCase :: Constant { value : case_val } ) => {
823+ ( TestKind :: Eq { value : test_val, .. } , TestCase :: Constant { value : case_val, .. } ) => {
740824 if test_val == case_val {
741825 fully_matched = true ;
742826 Some ( TestBranch :: Success )
0 commit comments