@@ -6,6 +6,7 @@ use std::cell::Cell;
6
6
7
7
use rustc:: hir:: def:: DefKind ;
8
8
use rustc:: hir:: def_id:: DefId ;
9
+ use rustc:: hir:: HirId ;
9
10
use rustc:: mir:: interpret:: { InterpResult , PanicInfo , Scalar } ;
10
11
use rustc:: mir:: visit:: {
11
12
MutVisitor , MutatingUseContext , NonMutatingUseContext , PlaceContext , Visitor ,
@@ -20,7 +21,7 @@ use rustc::ty::layout::{
20
21
HasDataLayout , HasTyCtxt , LayoutError , LayoutOf , Size , TargetDataLayout , TyLayout ,
21
22
} ;
22
23
use rustc:: ty:: subst:: InternalSubsts ;
23
- use rustc:: ty:: { self , Instance , ParamEnv , Ty , TyCtxt } ;
24
+ use rustc:: ty:: { self , Instance , ParamEnv , Ty , TyCtxt , TypeFoldable } ;
24
25
use rustc_data_structures:: fx:: FxHashMap ;
25
26
use rustc_index:: vec:: IndexVec ;
26
27
use syntax:: ast:: Mutability ;
@@ -260,6 +261,9 @@ struct ConstPropagator<'mir, 'tcx> {
260
261
source_scopes : IndexVec < SourceScope , SourceScopeData > ,
261
262
local_decls : IndexVec < Local , LocalDecl < ' tcx > > ,
262
263
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 > ,
263
267
}
264
268
265
269
impl < ' mir , ' tcx > LayoutOf for ConstPropagator < ' mir , ' tcx > {
@@ -293,13 +297,20 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
293
297
source : MirSource < ' tcx > ,
294
298
) -> ConstPropagator < ' mir , ' tcx > {
295
299
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
+
297
310
let span = tcx. def_span ( def_id) ;
298
311
let mut ecx = InterpCx :: new ( tcx. at ( span) , param_env, ConstPropMachine , ( ) ) ;
299
312
let can_const_prop = CanConstProp :: check ( body) ;
300
313
301
- let substs = & InternalSubsts :: identity_for_item ( tcx, def_id) ;
302
-
303
314
let ret = ecx
304
315
. layout_of ( body. return_ty ( ) . subst ( tcx, substs) )
305
316
. ok ( )
@@ -331,6 +342,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
331
342
//FIXME(wesleywiser) we can't steal this because `Visitor::super_visit_body()` needs it
332
343
local_decls : body. local_decls . clone ( ) ,
333
344
ret : ret. map ( Into :: into) ,
345
+ source_info : None ,
334
346
}
335
347
}
336
348
@@ -352,6 +364,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
352
364
LocalState { value : LocalValue :: Uninitialized , layout : Cell :: new ( None ) } ;
353
365
}
354
366
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
+
355
374
fn use_ecx < F , T > ( & mut self , source_info : SourceInfo , f : F ) -> Option < T >
356
375
where
357
376
F : FnOnce ( & mut Self ) -> InterpResult < ' tcx , T > ,
@@ -360,10 +379,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
360
379
// FIXME(eddyb) move this to the `Panic(_)` error case, so that
361
380
// `f(self)` is always called, and that the only difference when the
362
381
// 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) ?;
367
383
let r = match f ( self ) {
368
384
Ok ( val) => Some ( val) ,
369
385
Err ( error) => {
@@ -409,13 +425,31 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
409
425
r
410
426
}
411
427
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 > > {
413
433
self . ecx . tcx . span = c. span ;
414
434
match self . ecx . eval_const_to_op ( c. literal , None ) {
415
435
Ok ( op) => Some ( op) ,
416
436
Err ( error) => {
417
437
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
+ }
419
453
None
420
454
}
421
455
}
@@ -428,7 +462,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
428
462
429
463
fn eval_operand ( & mut self , op : & Operand < ' tcx > , source_info : SourceInfo ) -> Option < Const < ' tcx > > {
430
464
match * op {
431
- Operand :: Constant ( ref c) => self . eval_constant ( c) ,
465
+ Operand :: Constant ( ref c) => self . eval_constant ( c, source_info ) ,
432
466
Operand :: Move ( ref place) | Operand :: Copy ( ref place) => {
433
467
self . eval_place ( place, source_info)
434
468
}
@@ -495,10 +529,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
495
529
let right_size = r. layout . size ;
496
530
let r_bits = r. to_scalar ( ) . and_then ( |r| r. to_bits ( right_size) ) ;
497
531
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) ?;
502
533
let dir = if * op == BinOp :: Shr { "right" } else { "left" } ;
503
534
self . tcx . lint_hir (
504
535
:: rustc:: lint:: builtin:: EXCEEDING_BITSHIFTS ,
@@ -748,18 +779,19 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
748
779
fn visit_constant ( & mut self , constant : & mut Constant < ' tcx > , location : Location ) {
749
780
trace ! ( "visit_constant: {:?}" , constant) ;
750
781
self . super_constant ( constant, location) ;
751
- self . eval_constant ( constant) ;
782
+ self . eval_constant ( constant, self . source_info . unwrap ( ) ) ;
752
783
}
753
784
754
785
fn visit_statement ( & mut self , statement : & mut Statement < ' tcx > , location : Location ) {
755
786
trace ! ( "visit_statement: {:?}" , statement) ;
787
+ let source_info = statement. source_info ;
788
+ self . source_info = Some ( source_info) ;
756
789
if let StatementKind :: Assign ( box ( ref place, ref mut rval) ) = statement. kind {
757
790
let place_ty: Ty < ' tcx > = place. ty ( & self . local_decls , self . tcx ) . ty ;
758
791
if let Ok ( place_layout) = self . tcx . layout_of ( self . param_env . and ( place_ty) ) {
759
792
if let Some ( local) = place. as_local ( ) {
760
- let source = statement. source_info ;
761
793
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) {
763
795
if can_const_prop == ConstPropMode :: FullConstProp
764
796
|| can_const_prop == ConstPropMode :: OnlyPropagateInto
765
797
{
@@ -802,8 +834,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
802
834
}
803
835
804
836
fn visit_terminator ( & mut self , terminator : & mut Terminator < ' tcx > , location : Location ) {
805
- self . super_terminator ( terminator, location) ;
806
837
let source_info = terminator. source_info ;
838
+ self . source_info = Some ( source_info) ;
839
+ self . super_terminator ( terminator, location) ;
807
840
match & mut terminator. kind {
808
841
TerminatorKind :: Assert { expected, ref msg, ref mut cond, .. } => {
809
842
if let Some ( value) = self . eval_operand ( & cond, source_info) {
0 commit comments