@@ -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 ,
@@ -20,7 +21,7 @@ use rustc::ty::layout::{
2021 HasDataLayout , HasTyCtxt , LayoutError , LayoutOf , Size , TargetDataLayout , TyLayout ,
2122} ;
2223use rustc:: ty:: subst:: InternalSubsts ;
23- use rustc:: ty:: { self , Instance , ParamEnv , Ty , TyCtxt } ;
24+ use rustc:: ty:: { self , Instance , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
2425use rustc_data_structures:: fx:: FxHashMap ;
2526use rustc_index:: vec:: IndexVec ;
2627use syntax:: ast:: Mutability ;
@@ -260,6 +261,9 @@ struct ConstPropagator<'mir, 'tcx> {
260261 source_scopes : IndexVec < SourceScope , SourceScopeData > ,
261262 local_decls : IndexVec < Local , LocalDecl < ' tcx > > ,
262263 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 > ,
263267}
264268
265269impl < ' mir , ' tcx > LayoutOf for ConstPropagator < ' mir , ' tcx > {
@@ -293,13 +297,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
293297 source : MirSource < ' tcx > ,
294298 ) -> ConstPropagator < ' mir , ' tcx > {
295299 let def_id = source. def_id ( ) ;
296- let param_env = tcx. param_env ( def_id) ;
300+ let substs = & InternalSubsts :: identity_for_item ( tcx, def_id) ;
301+ let mut param_env = tcx. param_env ( def_id) ;
302+
303+ // If we're evaluating inside a monomorphic function, then use `Reveal::All` because
304+ // we want to see the same instances that codegen will see. This allows us to `resolve()`
305+ // specializations.
306+ if !substs. needs_subst ( ) {
307+ param_env = param_env. with_reveal_all ( ) ;
308+ }
309+
297310 let span = tcx. def_span ( def_id) ;
298311 let mut ecx = InterpCx :: new ( tcx. at ( span) , param_env, ConstPropMachine , ( ) ) ;
299312 let can_const_prop = CanConstProp :: check ( body) ;
300313
301- let substs = & InternalSubsts :: identity_for_item ( tcx, def_id) ;
302-
303314 let ret = ecx
304315 . layout_of ( body. return_ty ( ) . subst ( tcx, substs) )
305316 . ok ( )
@@ -331,6 +342,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
331342 //FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
332343 local_decls : body. local_decls . clone ( ) ,
333344 ret : ret. map ( Into :: into) ,
345+ source_info : None ,
334346 }
335347 }
336348
@@ -352,6 +364,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
352364 LocalState { value : LocalValue :: Uninitialized , layout : Cell :: new ( None ) } ;
353365 }
354366
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+
355374 fn use_ecx < F , T > ( & mut self , source_info : SourceInfo , f : F ) -> Option < T >
356375 where
357376 F : FnOnce ( & mut Self ) -> InterpResult < ' tcx , T > ,
@@ -360,10 +379,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
360379 // FIXME(eddyb) move this to the `Panic(_)` error case, so that
361380 // `f(self)` is always called, and that the only difference when the
362381 // scope's `local_data` is missing, is that the lint isn't emitted.
363- let lint_root = match & self . source_scopes [ source_info. scope ] . local_data {
364- ClearCrossCrate :: Set ( data) => data. lint_root ,
365- ClearCrossCrate :: Clear => return None ,
366- } ;
382+ let lint_root = self . lint_root ( source_info) ?;
367383 let r = match f ( self ) {
368384 Ok ( val) => Some ( val) ,
369385 Err ( error) => {
@@ -409,13 +425,31 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
409425 r
410426 }
411427
412- fn eval_constant ( & mut self , c : & Constant < ' tcx > ) -> Option < Const < ' tcx > > {
428+ fn eval_constant (
429+ & mut self ,
430+ c : & Constant < ' tcx > ,
431+ source_info : SourceInfo ,
432+ ) -> Option < Const < ' tcx > > {
413433 self . ecx . tcx . span = c. span ;
414434 match self . ecx . eval_const_to_op ( c. literal , None ) {
415435 Ok ( op) => Some ( op) ,
416436 Err ( error) => {
417437 let err = error_to_const_error ( & self . ecx , error) ;
418- 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+ }
419453 None
420454 }
421455 }
@@ -428,7 +462,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
428462
429463 fn eval_operand ( & mut self , op : & Operand < ' tcx > , source_info : SourceInfo ) -> Option < Const < ' tcx > > {
430464 match * op {
431- Operand :: Constant ( ref c) => self . eval_constant ( c) ,
465+ Operand :: Constant ( ref c) => self . eval_constant ( c, source_info ) ,
432466 Operand :: Move ( ref place) | Operand :: Copy ( ref place) => {
433467 self . eval_place ( place, source_info)
434468 }
@@ -495,10 +529,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
495529 let right_size = r. layout . size ;
496530 let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
497531 if r_bits. map_or ( false , |b| b >= left_bits as u128 ) {
498- let lint_root = match & self . source_scopes [ source_info. scope ] . local_data {
499- ClearCrossCrate :: Set ( data) => data. lint_root ,
500- ClearCrossCrate :: Clear => return None ,
501- } ;
532+ let lint_root = self . lint_root ( source_info) ?;
502533 let dir = if * op == BinOp :: Shr { "right" } else { "left" } ;
503534 self . tcx . lint_hir (
504535 :: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
@@ -748,18 +779,19 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
748779 fn visit_constant ( & mut self , constant : & mut Constant < ' tcx > , location : Location ) {
749780 trace ! ( "visit_constant: {:?}" , constant) ;
750781 self . super_constant ( constant, location) ;
751- self . eval_constant ( constant) ;
782+ self . eval_constant ( constant, self . source_info . unwrap ( ) ) ;
752783 }
753784
754785 fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
755786 trace ! ( "visit_statement: {:?}" , statement) ;
787+ let source_info = statement. source_info ;
788+ self . source_info = Some ( source_info) ;
756789 if let StatementKind :: Assign ( box ( ref place, ref mut rval) ) = statement. kind {
757790 let place_ty: Ty < ' tcx > = place. ty ( & self . local_decls , self . tcx ) . ty ;
758791 if let Ok ( place_layout) = self . tcx . layout_of ( self . param_env . and ( place_ty) ) {
759792 if let Some ( local) = place. as_local ( ) {
760- let source = statement. source_info ;
761793 let can_const_prop = self . can_const_prop [ local] ;
762- if let Some ( ( ) ) = self . const_prop ( rval, place_layout, source , place) {
794+ if let Some ( ( ) ) = self . const_prop ( rval, place_layout, source_info , place) {
763795 if can_const_prop == ConstPropMode :: FullConstProp
764796 || can_const_prop == ConstPropMode :: OnlyPropagateInto
765797 {
@@ -802,8 +834,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
802834 }
803835
804836 fn visit_terminator ( & mut self , terminator : & mut Terminator < ' tcx > , location : Location ) {
805- self . super_terminator ( terminator, location) ;
806837 let source_info = terminator. source_info ;
838+ self . source_info = Some ( source_info) ;
839+ self . super_terminator ( terminator, location) ;
807840 match & mut terminator. kind {
808841 TerminatorKind :: Assert { expected, ref msg, ref mut cond, .. } => {
809842 if let Some ( value) = self . eval_operand ( & cond, source_info) {
0 commit comments