@@ -6,6 +6,7 @@ use std::cell::Cell;
66
77use rustc:: hir:: def:: DefKind ;
88use rustc:: hir:: def_id:: DefId ;
9+ use rustc:: hir:: HirId ;
910use rustc:: mir:: interpret:: { InterpResult , PanicInfo , Scalar } ;
1011use rustc:: mir:: visit:: {
1112 MutVisitor , MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor ,
@@ -33,7 +34,6 @@ use crate::interpret::{
3334 ScalarMaybeUndef , StackPopCleanup ,
3435} ;
3536use crate :: rustc:: ty:: subst:: Subst ;
36- use crate :: rustc:: ty:: TypeFoldable ;
3737use crate :: transform:: { MirPass , MirSource } ;
3838
3939/// The maximum number of bytes that we'll allocate space for a return value.
@@ -261,6 +261,9 @@ struct ConstPropagator<'mir, 'tcx> {
261261 source_scopes : IndexVec < SourceScope , SourceScopeData > ,
262262 local_decls : IndexVec < Local , LocalDecl < ' tcx > > ,
263263 ret : Option < OpTy < ' tcx , ( ) > > ,
264+ // Because we have `MutVisitor` we can't obtain the `SourceInfo` from a `Location`. So we store
265+ // the last known `SourceInfo` here and just keep revisiting it.
266+ source_info : Option < SourceInfo > ,
264267}
265268
266269impl < ' mir , ' tcx > LayoutOf for ConstPropagator < ' mir , ' tcx > {
@@ -339,6 +342,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
339342 //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
340343 local_decls : body. local_decls . clone ( ) ,
341344 ret : ret. map ( Into :: into) ,
345+ source_info : None ,
342346 }
343347 }
344348
@@ -360,6 +364,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
360364 LocalState { value : LocalValue :: Uninitialized , layout : Cell :: new ( None ) } ;
361365 }
362366
367+ fn lint_root ( & self , source_info : SourceInfo ) -> Option < HirId > {
368+ match & self . source_scopes [ source_info. scope ] . local_data {
369+ ClearCrossCrate :: Set ( data) => Some ( data. lint_root ) ,
370+ ClearCrossCrate :: Clear => None ,
371+ }
372+ }
373+
363374 fn use_ecx < F , T > ( & mut self , source_info : SourceInfo , f : F ) -> Option < T >
364375 where
365376 F : FnOnce ( & mut Self ) -> InterpResult < ' tcx , T > ,
@@ -368,10 +379,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
368379 // FIXME(eddyb) move this to the `Panic(_)` error case, so that
369380 // `f(self)` is always called, and that the only difference when the
370381 // scope's `local_data` is missing, is that the lint isn't emitted.
371- let lint_root = match & self . source_scopes [ source_info. scope ] . local_data {
372- ClearCrossCrate :: Set ( data) => data. lint_root ,
373- ClearCrossCrate :: Clear => return None ,
374- } ;
382+ let lint_root = self . lint_root ( source_info) ?;
375383 let r = match f ( self ) {
376384 Ok ( val) => Some ( val) ,
377385 Err ( error) => {
@@ -417,19 +425,31 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
417425 r
418426 }
419427
420- fn eval_constant ( & mut self , c : & Constant < ' tcx > ) -> Option < Const < ' tcx > > {
421- // `eval_const_to_op` uses `Instance::resolve` which still has a bug (#66901) in the
422- // presence of trait items with a default body. So we just bail out if we aren't 100%
423- // monomorphic.
424- if c. literal . needs_subst ( ) {
425- return None ;
426- }
428+ fn eval_constant (
429+ & mut self ,
430+ c : & Constant < ' tcx > ,
431+ source_info : SourceInfo ,
432+ ) -> Option < Const < ' tcx > > {
427433 self . ecx . tcx . span = c. span ;
428434 match self . ecx . eval_const_to_op ( c. literal , None ) {
429435 Ok ( op) => Some ( op) ,
430436 Err ( error) => {
431437 let err = error_to_const_error ( & self . ecx , error) ;
432- err. report_as_error ( self . ecx . tcx , "erroneous constant used" ) ;
438+ match self . lint_root ( source_info) {
439+ Some ( lint_root) if c. literal . needs_subst ( ) => {
440+ // Out of backwards compatibility we cannot report hard errors in unused
441+ // generic functions using associated constants of the generic parameters.
442+ err. report_as_lint (
443+ self . ecx . tcx ,
444+ "erroneous constant used" ,
445+ lint_root,
446+ Some ( c. span ) ,
447+ ) ;
448+ }
449+ _ => {
450+ err. report_as_error ( self . ecx . tcx , "erroneous constant used" ) ;
451+ }
452+ }
433453 None
434454 }
435455 }
@@ -442,7 +462,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
442462
443463 fn eval_operand ( & mut self , op : & Operand < ' tcx > , source_info : SourceInfo ) -> Option < Const < ' tcx > > {
444464 match * op {
445- Operand :: Constant ( ref c) => self . eval_constant ( c) ,
465+ Operand :: Constant ( ref c) => self . eval_constant ( c, source_info ) ,
446466 Operand :: Move ( ref place) | Operand :: Copy ( ref place) => {
447467 self . eval_place ( place, source_info)
448468 }
@@ -509,10 +529,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
509529 let right_size = r. layout . size ;
510530 let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
511531 if r_bits. map_or ( false , |b| b >= left_bits as u128 ) {
512- let lint_root = match & self . source_scopes [ source_info. scope ] . local_data {
513- ClearCrossCrate :: Set ( data) => data. lint_root ,
514- ClearCrossCrate :: Clear => return None ,
515- } ;
532+ let lint_root = self . lint_root ( source_info) ?;
516533 let dir = if * op == BinOp :: Shr { "right" } else { "left" } ;
517534 self . tcx . lint_hir (
518535 :: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
@@ -570,13 +587,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
570587 _ => { }
571588 }
572589
573- // `eval_rvalue_into_place` uses `Instance::resolve` for constants which still has a bug
574- // (#66901) in the presence of trait items with a default body. So we just bail out if we
575- // aren't 100% monomorphic.
576- if rvalue. needs_subst ( ) {
577- return None ;
578- }
579-
580590 self . use_ecx ( source_info, |this| {
581591 trace ! ( "calling eval_rvalue_into_place(rvalue = {:?}, place = {:?})" , rvalue, place) ;
582592 this. ecx . eval_rvalue_into_place ( rvalue, place) ?;
@@ -769,18 +779,19 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
769779 fn visit_constant ( & mut self , constant : & mut Constant < ' tcx > , location : Location ) {
770780 trace ! ( "visit_constant: {:?}" , constant) ;
771781 self . super_constant ( constant, location) ;
772- self . eval_constant ( constant) ;
782+ self . eval_constant ( constant, self . source_info . unwrap ( ) ) ;
773783 }
774784
775785 fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
776786 trace ! ( "visit_statement: {:?}" , statement) ;
787+ let source_info = statement. source_info ;
788+ self . source_info = Some ( source_info) ;
777789 if let StatementKind :: Assign ( box ( ref place, ref mut rval) ) = statement. kind {
778790 let place_ty: Ty < ' tcx > = place. ty ( & self . local_decls , self . tcx ) . ty ;
779791 if let Ok ( place_layout) = self . tcx . layout_of ( self . param_env . and ( place_ty) ) {
780792 if let Some ( local) = place. as_local ( ) {
781- let source = statement. source_info ;
782793 let can_const_prop = self . can_const_prop [ local] ;
783- if let Some ( ( ) ) = self . const_prop ( rval, place_layout, source , place) {
794+ if let Some ( ( ) ) = self . const_prop ( rval, place_layout, source_info , place) {
784795 if can_const_prop == ConstPropMode :: FullConstProp
785796 || can_const_prop == ConstPropMode :: OnlyPropagateInto
786797 {
@@ -823,8 +834,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
823834 }
824835
825836 fn visit_terminator ( & mut self , terminator : & mut Terminator < ' tcx > , location : Location ) {
826- self . super_terminator ( terminator, location) ;
827837 let source_info = terminator. source_info ;
838+ self . source_info = Some ( source_info) ;
839+ self . super_terminator ( terminator, location) ;
828840 match & mut terminator. kind {
829841 TerminatorKind :: Assert { expected, ref msg, ref mut cond, .. } => {
830842 if let Some ( value) = self . eval_operand ( & cond, source_info) {
0 commit comments