11//! Propagates constants for early reporting of statically known
22//! assertion failures
33
4- use either:: { Left , Right } ;
4+ use either:: Left ;
55
66use rustc_const_eval:: interpret:: Immediate ;
77use rustc_const_eval:: interpret:: {
@@ -129,9 +129,6 @@ struct ConstPropagator<'mir, 'tcx> {
129129 ecx : InterpCx < ' mir , ' tcx , ConstPropMachine < ' mir , ' tcx > > ,
130130 tcx : TyCtxt < ' tcx > ,
131131 param_env : ParamEnv < ' tcx > ,
132- // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
133- // the last known `SourceInfo` here and just keep revisiting it.
134- source_info : Option < SourceInfo > ,
135132}
136133
137134impl < ' tcx > LayoutOfHelpers < ' tcx > for ConstPropagator < ' _ , ' tcx > {
@@ -206,7 +203,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
206203 )
207204 . expect ( "failed to push initial stack frame" ) ;
208205
209- ConstPropagator { ecx, tcx, param_env, source_info : None }
206+ ConstPropagator { ecx, tcx, param_env }
210207 }
211208
212209 fn body ( & self ) -> & ' mir Body < ' tcx > {
@@ -252,12 +249,12 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
252249 source_info. scope . lint_root ( & self . body ( ) . source_scopes )
253250 }
254251
255- fn use_ecx < F , T > ( & mut self , source_info : SourceInfo , f : F ) -> Option < T >
252+ fn use_ecx < F , T > ( & mut self , location : Location , f : F ) -> Option < T >
256253 where
257254 F : FnOnce ( & mut Self ) -> InterpResult < ' tcx , T > ,
258255 {
259256 // Overwrite the PC -- whatever the interpreter does to it does not make any sense anyway.
260- self . ecx . frame_mut ( ) . loc = Right ( source_info . span ) ;
257+ self . ecx . frame_mut ( ) . loc = Left ( location ) ;
261258 match f ( self ) {
262259 Ok ( val) => Some ( val) ,
263260 Err ( error) => {
@@ -276,7 +273,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
276273 }
277274
278275 /// Returns the value, if any, of evaluating `c`.
279- fn eval_constant ( & mut self , c : & Constant < ' tcx > , source_info : SourceInfo ) -> Option < OpTy < ' tcx > > {
276+ fn eval_constant ( & mut self , c : & Constant < ' tcx > , location : Location ) -> Option < OpTy < ' tcx > > {
280277 // FIXME we need to revisit this for #67176
281278 if c. needs_subst ( ) {
282279 return None ;
@@ -290,45 +287,41 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
290287 // manually normalized.
291288 let val = self . tcx . try_normalize_erasing_regions ( self . param_env , c. literal ) . ok ( ) ?;
292289
293- self . use_ecx ( source_info , |this| this. ecx . eval_mir_constant ( & val, Some ( c. span ) , None ) )
290+ self . use_ecx ( location , |this| this. ecx . eval_mir_constant ( & val, Some ( c. span ) , None ) )
294291 }
295292
296293 /// Returns the value, if any, of evaluating `place`.
297- fn eval_place ( & mut self , place : Place < ' tcx > , source_info : SourceInfo ) -> Option < OpTy < ' tcx > > {
294+ fn eval_place ( & mut self , place : Place < ' tcx > , location : Location ) -> Option < OpTy < ' tcx > > {
298295 trace ! ( "eval_place(place={:?})" , place) ;
299- self . use_ecx ( source_info , |this| this. ecx . eval_place_to_op ( place, None ) )
296+ self . use_ecx ( location , |this| this. ecx . eval_place_to_op ( place, None ) )
300297 }
301298
302299 /// Returns the value, if any, of evaluating `op`. Calls upon `eval_constant`
303300 /// or `eval_place`, depending on the variant of `Operand` used.
304- fn eval_operand ( & mut self , op : & Operand < ' tcx > , source_info : SourceInfo ) -> Option < OpTy < ' tcx > > {
301+ fn eval_operand ( & mut self , op : & Operand < ' tcx > , location : Location ) -> Option < OpTy < ' tcx > > {
305302 match * op {
306- Operand :: Constant ( ref c) => self . eval_constant ( c, source_info ) ,
307- Operand :: Move ( place) | Operand :: Copy ( place) => self . eval_place ( place, source_info ) ,
303+ Operand :: Constant ( ref c) => self . eval_constant ( c, location ) ,
304+ Operand :: Move ( place) | Operand :: Copy ( place) => self . eval_place ( place, location ) ,
308305 }
309306 }
310307
311308 fn report_assert_as_lint (
312309 & self ,
313310 lint : & ' static lint:: Lint ,
314- source_info : SourceInfo ,
311+ location : Location ,
315312 message : & ' static str ,
316313 panic : AssertKind < impl std:: fmt:: Debug > ,
317314 ) {
318- if let Some ( lint_root) = self . lint_root ( source_info) {
315+ let source_info = self . body ( ) . source_info ( location) ;
316+ if let Some ( lint_root) = self . lint_root ( * source_info) {
319317 self . tcx . struct_span_lint_hir ( lint, lint_root, source_info. span , message, |lint| {
320318 lint. span_label ( source_info. span , format ! ( "{:?}" , panic) )
321319 } ) ;
322320 }
323321 }
324322
325- fn check_unary_op (
326- & mut self ,
327- op : UnOp ,
328- arg : & Operand < ' tcx > ,
329- source_info : SourceInfo ,
330- ) -> Option < ( ) > {
331- if let ( val, true ) = self . use_ecx ( source_info, |this| {
323+ fn check_unary_op ( & mut self , op : UnOp , arg : & Operand < ' tcx > , location : Location ) -> Option < ( ) > {
324+ if let ( val, true ) = self . use_ecx ( location, |this| {
332325 let val = this. ecx . read_immediate ( & this. ecx . eval_operand ( arg, None ) ?) ?;
333326 let ( _res, overflow, _ty) = this. ecx . overflowing_unary_op ( op, & val) ?;
334327 Ok ( ( val, overflow) )
@@ -338,7 +331,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
338331 assert_eq ! ( op, UnOp :: Neg , "Neg is the only UnOp that can overflow" ) ;
339332 self . report_assert_as_lint (
340333 lint:: builtin:: ARITHMETIC_OVERFLOW ,
341- source_info ,
334+ location ,
342335 "this arithmetic operation will overflow" ,
343336 AssertKind :: OverflowNeg ( val. to_const_int ( ) ) ,
344337 ) ;
@@ -353,14 +346,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
353346 op : BinOp ,
354347 left : & Operand < ' tcx > ,
355348 right : & Operand < ' tcx > ,
356- source_info : SourceInfo ,
349+ location : Location ,
357350 ) -> Option < ( ) > {
358- let r = self . use_ecx ( source_info , |this| {
351+ let r = self . use_ecx ( location , |this| {
359352 this. ecx . read_immediate ( & this. ecx . eval_operand ( right, None ) ?)
360353 } ) ;
361- let l = self . use_ecx ( source_info, |this| {
362- this. ecx . read_immediate ( & this. ecx . eval_operand ( left, None ) ?)
363- } ) ;
354+ let l = self
355+ . use_ecx ( location, |this| this. ecx . read_immediate ( & this. ecx . eval_operand ( left, None ) ?) ) ;
364356 // Check for exceeding shifts *even if* we cannot evaluate the LHS.
365357 if matches ! ( op, BinOp :: Shr | BinOp :: Shl ) {
366358 let r = r. clone ( ) ?;
@@ -371,10 +363,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
371363 let right_size = r. layout . size ;
372364 let r_bits = r. to_scalar ( ) . to_bits ( right_size) . ok ( ) ;
373365 if r_bits. map_or ( false , |b| b >= left_size. bits ( ) as u128 ) {
374- debug ! ( "check_binary_op: reporting assert for {:?}" , source_info ) ;
366+ debug ! ( "check_binary_op: reporting assert for {:?}" , location ) ;
375367 self . report_assert_as_lint (
376368 lint:: builtin:: ARITHMETIC_OVERFLOW ,
377- source_info ,
369+ location ,
378370 "this arithmetic operation will overflow" ,
379371 AssertKind :: Overflow (
380372 op,
@@ -396,13 +388,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
396388
397389 if let ( Some ( l) , Some ( r) ) = ( l, r) {
398390 // The remaining operators are handled through `overflowing_binary_op`.
399- if self . use_ecx ( source_info , |this| {
391+ if self . use_ecx ( location , |this| {
400392 let ( _res, overflow, _ty) = this. ecx . overflowing_binary_op ( op, & l, & r) ?;
401393 Ok ( overflow)
402394 } ) ? {
403395 self . report_assert_as_lint (
404396 lint:: builtin:: ARITHMETIC_OVERFLOW ,
405- source_info ,
397+ location ,
406398 "this arithmetic operation will overflow" ,
407399 AssertKind :: Overflow ( op, l. to_const_int ( ) , r. to_const_int ( ) ) ,
408400 ) ;
@@ -412,7 +404,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
412404 Some ( ( ) )
413405 }
414406
415- fn check_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > , source_info : SourceInfo ) -> Option < ( ) > {
407+ fn check_rvalue ( & mut self , rvalue : & Rvalue < ' tcx > , location : Location ) -> Option < ( ) > {
416408 // Perform any special handling for specific Rvalue types.
417409 // Generally, checks here fall into one of two categories:
418410 // 1. Additional checking to provide useful lints to the user
@@ -427,11 +419,11 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
427419 // lint.
428420 Rvalue :: UnaryOp ( op, arg) => {
429421 trace ! ( "checking UnaryOp(op = {:?}, arg = {:?})" , op, arg) ;
430- self . check_unary_op ( * op, arg, source_info ) ?;
422+ self . check_unary_op ( * op, arg, location ) ?;
431423 }
432424 Rvalue :: BinaryOp ( op, box ( left, right) ) => {
433425 trace ! ( "checking BinaryOp(op = {:?}, left = {:?}, right = {:?})" , op, left, right) ;
434- self . check_binary_op ( * op, left, right, source_info ) ?;
426+ self . check_binary_op ( * op, left, right, location ) ?;
435427 }
436428 Rvalue :: CheckedBinaryOp ( op, box ( left, right) ) => {
437429 trace ! (
@@ -440,7 +432,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
440432 left,
441433 right
442434 ) ;
443- self . check_binary_op ( * op, left, right, source_info ) ?;
435+ self . check_binary_op ( * op, left, right, location ) ?;
444436 }
445437
446438 // Do not try creating references (#67862)
@@ -516,22 +508,21 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
516508 fn visit_constant ( & mut self , constant : & Constant < ' tcx > , location : Location ) {
517509 trace ! ( "visit_constant: {:?}" , constant) ;
518510 self . super_constant ( constant, location) ;
519- self . eval_constant ( constant, self . source_info . unwrap ( ) ) ;
511+ self . eval_constant ( constant, location ) ;
520512 }
521513
522514 fn visit_assign ( & mut self , place : & Place < ' tcx > , rvalue : & Rvalue < ' tcx > , location : Location ) {
523515 self . super_assign ( place, rvalue, location) ;
524516
525- let source_info = self . source_info . unwrap ( ) ;
526- let Some ( ( ) ) = self . check_rvalue ( rvalue, source_info) else { return } ;
517+ let Some ( ( ) ) = self . check_rvalue ( rvalue, location) else { return } ;
527518
528519 match self . ecx . machine . can_const_prop [ place. local ] {
529520 // Do nothing if the place is indirect.
530521 _ if place. is_indirect ( ) => { }
531522 ConstPropMode :: NoPropagation => self . ensure_not_propagated ( place. local ) ,
532523 ConstPropMode :: OnlyInsideOwnBlock | ConstPropMode :: FullConstProp => {
533524 if self
534- . use_ecx ( source_info , |this| this. ecx . eval_rvalue_into_place ( rvalue, * place) )
525+ . use_ecx ( location , |this| this. ecx . eval_rvalue_into_place ( rvalue, * place) )
535526 . is_none ( )
536527 {
537528 // Const prop failed, so erase the destination, ensuring that whatever happens
@@ -557,8 +548,6 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
557548
558549 fn visit_statement ( & mut self , statement : & Statement < ' tcx > , location : Location ) {
559550 trace ! ( "visit_statement: {:?}" , statement) ;
560- let source_info = statement. source_info ;
561- self . source_info = Some ( source_info) ;
562551
563552 // We want to evaluate operands before any change to the assigned-to value,
564553 // so we recurse first.
@@ -571,8 +560,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
571560 _ if place. is_indirect ( ) => { }
572561 ConstPropMode :: NoPropagation => self . ensure_not_propagated ( place. local ) ,
573562 ConstPropMode :: FullConstProp | ConstPropMode :: OnlyInsideOwnBlock => {
574- if self . use_ecx ( source_info, |this| this. ecx . statement ( statement) ) . is_some ( )
575- {
563+ if self . use_ecx ( location, |this| this. ecx . statement ( statement) ) . is_some ( ) {
576564 trace ! ( "propped discriminant into {:?}" , place) ;
577565 } else {
578566 Self :: remove_const ( & mut self . ecx , place. local ) ;
@@ -594,12 +582,10 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
594582 }
595583
596584 fn visit_terminator ( & mut self , terminator : & Terminator < ' tcx > , location : Location ) {
597- let source_info = terminator. source_info ;
598- self . source_info = Some ( source_info) ;
599585 self . super_terminator ( terminator, location) ;
600586 match & terminator. kind {
601587 TerminatorKind :: Assert { expected, ref msg, ref cond, .. } => {
602- if let Some ( ref value) = self . eval_operand ( & cond, source_info ) {
588+ if let Some ( ref value) = self . eval_operand ( & cond, location ) {
603589 trace ! ( "assertion on {:?} should be {:?}" , value, expected) ;
604590 let expected = Scalar :: from_bool ( * expected) ;
605591 let Ok ( value_const) = self . ecx . read_scalar ( & value) else {
@@ -623,7 +609,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
623609 let mut eval_to_int = |op| {
624610 // This can be `None` if the lhs wasn't const propagated and we just
625611 // triggered the assert on the value of the rhs.
626- self . eval_operand ( op, source_info )
612+ self . eval_operand ( op, location )
627613 . and_then ( |op| self . ecx . read_immediate ( & op) . ok ( ) )
628614 . map_or ( DbgVal :: Underscore , |op| DbgVal :: Val ( op. to_const_int ( ) ) )
629615 } ;
@@ -664,7 +650,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
664650 if let Some ( msg) = msg {
665651 self . report_assert_as_lint (
666652 lint:: builtin:: UNCONDITIONAL_PANIC ,
667- source_info ,
653+ location ,
668654 "this operation will panic at runtime" ,
669655 msg,
670656 ) ;
0 commit comments