15
15
//! diagnostics as to why a constant rvalue wasn't promoted.
16
16
17
17
use rustc_data_structures:: bitvec:: BitVector ;
18
+ use rustc_data_structures:: indexed_set:: IdxSetBuf ;
18
19
use rustc_data_structures:: indexed_vec:: { IndexVec , Idx } ;
19
20
use rustc:: hir;
20
21
use rustc:: hir:: map as hir_map;
@@ -33,6 +34,7 @@ use syntax::feature_gate::UnstableFeatures;
33
34
use syntax_pos:: { Span , DUMMY_SP } ;
34
35
35
36
use std:: fmt;
37
+ use std:: rc:: Rc ;
36
38
use std:: usize;
37
39
38
40
use super :: promote_consts:: { self , Candidate , TempState } ;
@@ -127,7 +129,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
127
129
128
130
impl < ' a , ' tcx > Qualifier < ' a , ' tcx , ' tcx > {
129
131
fn new ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
130
- param_env : ty:: ParamEnv < ' tcx > ,
131
132
def_id : DefId ,
132
133
mir : & ' a Mir < ' tcx > ,
133
134
mode : Mode )
@@ -142,7 +143,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
142
143
mir,
143
144
rpo,
144
145
tcx,
145
- param_env,
146
+ param_env : tcx . param_env ( def_id ) ,
146
147
temp_qualif : IndexVec :: from_elem ( None , & mir. local_decls ) ,
147
148
return_qualif : None ,
148
149
qualif : Qualif :: empty ( ) ,
@@ -368,7 +369,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
368
369
}
369
370
370
371
/// Qualify a whole const, static initializer or const fn.
371
- fn qualify_const ( & mut self ) -> Qualif {
372
+ fn qualify_const ( & mut self ) -> ( Qualif , Rc < IdxSetBuf < Local > > ) {
372
373
debug ! ( "qualifying {} {:?}" , self . mode, self . def_id) ;
373
374
374
375
let mir = self . mir ;
@@ -390,7 +391,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
390
391
391
392
// Non-terminating calls cannot produce any value.
392
393
TerminatorKind :: Call { destination : None , .. } => {
393
- return Qualif :: empty ( ) ;
394
+ break ;
394
395
}
395
396
396
397
TerminatorKind :: SwitchInt { ..} |
@@ -472,7 +473,25 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
472
473
}
473
474
}
474
475
}
475
- self . qualif
476
+
477
+ // Collect all the temps we need to promote.
478
+ let mut promoted_temps = IdxSetBuf :: new_empty ( self . temp_promotion_state . len ( ) ) ;
479
+
480
+ for candidate in & self . promotion_candidates {
481
+ match * candidate {
482
+ Candidate :: Ref ( Location { block : bb, statement_index : stmt_idx } ) => {
483
+ match self . mir [ bb] . statements [ stmt_idx] . kind {
484
+ StatementKind :: Assign ( _, Rvalue :: Ref ( _, _, Lvalue :: Local ( index) ) ) => {
485
+ promoted_temps. add ( & index) ;
486
+ }
487
+ _ => { }
488
+ }
489
+ }
490
+ Candidate :: ShuffleIndices ( _) => { }
491
+ }
492
+ }
493
+
494
+ ( self . qualif , Rc :: new ( promoted_temps) )
476
495
}
477
496
}
478
497
@@ -516,6 +535,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
516
535
span_err ! ( self . tcx. sess, self . span, E0625 ,
517
536
"thread-local statics cannot be \
518
537
accessed at compile-time") ;
538
+ self . add ( Qualif :: NOT_CONST ) ;
519
539
return ;
520
540
}
521
541
}
@@ -598,7 +618,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
598
618
if self . tcx . trait_of_item ( def_id) . is_some ( ) {
599
619
self . add_type ( constant. ty ) ;
600
620
} else {
601
- let bits = self . tcx . at ( constant. span ) . mir_const_qualif ( def_id) ;
621
+ let ( bits, _ ) = self . tcx . at ( constant. span ) . mir_const_qualif ( def_id) ;
602
622
603
623
let qualif = Qualif :: from_bits ( bits) . expect ( "invalid mir_const_qualif" ) ;
604
624
self . add ( qualif) ;
@@ -702,13 +722,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
702
722
703
723
// We might have a candidate for promotion.
704
724
let candidate = Candidate :: Ref ( location) ;
705
- if self . mode == Mode :: Fn || self . mode == Mode :: ConstFn {
706
- if !self . qualif . intersects ( Qualif :: NEVER_PROMOTE ) {
707
- // We can only promote direct borrows of temps.
708
- if let Lvalue :: Local ( local) = * lvalue {
709
- if self . mir . local_kind ( local) == LocalKind :: Temp {
710
- self . promotion_candidates . push ( candidate) ;
711
- }
725
+ if !self . qualif . intersects ( Qualif :: NEVER_PROMOTE ) {
726
+ // We can only promote direct borrows of temps.
727
+ if let Lvalue :: Local ( local) = * lvalue {
728
+ if self . mir . local_kind ( local) == LocalKind :: Temp {
729
+ self . promotion_candidates . push ( candidate) ;
712
730
}
713
731
}
714
732
}
@@ -999,21 +1017,21 @@ pub fn provide(providers: &mut Providers) {
999
1017
1000
1018
fn mir_const_qualif < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
1001
1019
def_id : DefId )
1002
- -> u8 {
1020
+ -> ( u8 , Rc < IdxSetBuf < Local > > ) {
1003
1021
// NB: This `borrow()` is guaranteed to be valid (i.e., the value
1004
1022
// cannot yet be stolen), because `mir_validated()`, which steals
1005
1023
// from `mir_const(), forces this query to execute before
1006
1024
// performing the steal.
1007
1025
let mir = & tcx. mir_const ( def_id) . borrow ( ) ;
1008
1026
1009
1027
if mir. return_ty . references_error ( ) {
1010
- return Qualif :: NOT_CONST . bits ( ) ;
1028
+ tcx. sess . delay_span_bug ( mir. span , "mir_const_qualif: Mir had errors" ) ;
1029
+ return ( Qualif :: NOT_CONST . bits ( ) , Rc :: new ( IdxSetBuf :: new_empty ( 0 ) ) ) ;
1011
1030
}
1012
1031
1013
- let param_env = tcx. param_env ( def_id) ;
1014
-
1015
- let mut qualifier = Qualifier :: new ( tcx, param_env, def_id, mir, Mode :: Const ) ;
1016
- qualifier. qualify_const ( ) . bits ( )
1032
+ let mut qualifier = Qualifier :: new ( tcx, def_id, mir, Mode :: Const ) ;
1033
+ let ( qualif, promoted_temps) = qualifier. qualify_const ( ) ;
1034
+ ( qualif. bits ( ) , promoted_temps)
1017
1035
}
1018
1036
1019
1037
pub struct QualifyAndPromoteConstants ;
@@ -1023,8 +1041,15 @@ impl MirPass for QualifyAndPromoteConstants {
1023
1041
tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
1024
1042
src : MirSource ,
1025
1043
mir : & mut Mir < ' tcx > ) {
1044
+ // There's not really any point in promoting errorful MIR.
1045
+ if mir. return_ty . references_error ( ) {
1046
+ tcx. sess . delay_span_bug ( mir. span , "QualifyAndPromoteConstants: Mir had errors" ) ;
1047
+ return ;
1048
+ }
1049
+
1026
1050
let id = src. item_id ( ) ;
1027
1051
let def_id = tcx. hir . local_def_id ( id) ;
1052
+ let mut const_promoted_temps = None ;
1028
1053
let mode = match src {
1029
1054
MirSource :: Fn ( _) => {
1030
1055
if tcx. is_const_fn ( def_id) {
@@ -1033,20 +1058,21 @@ impl MirPass for QualifyAndPromoteConstants {
1033
1058
Mode :: Fn
1034
1059
}
1035
1060
}
1061
+ MirSource :: Const ( _) => {
1062
+ const_promoted_temps = Some ( tcx. mir_const_qualif ( def_id) . 1 ) ;
1063
+ Mode :: Const
1064
+ }
1036
1065
MirSource :: Static ( _, hir:: MutImmutable ) => Mode :: Static ,
1037
1066
MirSource :: Static ( _, hir:: MutMutable ) => Mode :: StaticMut ,
1038
1067
MirSource :: GeneratorDrop ( _) |
1039
- MirSource :: Const ( _) |
1040
1068
MirSource :: Promoted ( ..) => return
1041
1069
} ;
1042
- let param_env = tcx. param_env ( def_id) ;
1043
1070
1044
1071
if mode == Mode :: Fn || mode == Mode :: ConstFn {
1045
1072
// This is ugly because Qualifier holds onto mir,
1046
1073
// which can't be mutated until its scope ends.
1047
1074
let ( temps, candidates) = {
1048
- let mut qualifier = Qualifier :: new ( tcx, param_env,
1049
- def_id, mir, mode) ;
1075
+ let mut qualifier = Qualifier :: new ( tcx, def_id, mir, mode) ;
1050
1076
if mode == Mode :: ConstFn {
1051
1077
// Enforce a constant-like CFG for `const fn`.
1052
1078
qualifier. qualify_const ( ) ;
@@ -1062,8 +1088,37 @@ impl MirPass for QualifyAndPromoteConstants {
1062
1088
// Do the actual promotion, now that we know what's viable.
1063
1089
promote_consts:: promote_candidates ( mir, tcx, temps, candidates) ;
1064
1090
} else {
1065
- let mut qualifier = Qualifier :: new ( tcx, param_env, def_id, mir, mode) ;
1066
- qualifier. qualify_const ( ) ;
1091
+ let promoted_temps = if mode == Mode :: Const {
1092
+ // Already computed by `mir_const_qualif`.
1093
+ const_promoted_temps. unwrap ( )
1094
+ } else {
1095
+ Qualifier :: new ( tcx, def_id, mir, mode) . qualify_const ( ) . 1
1096
+ } ;
1097
+
1098
+ // In `const` and `static` everything without `StorageDead`
1099
+ // is `'static`, we don't have to create promoted MIR fragments,
1100
+ // just remove `Drop` and `StorageDead` on "promoted" locals.
1101
+ for block in mir. basic_blocks_mut ( ) {
1102
+ block. statements . retain ( |statement| {
1103
+ match statement. kind {
1104
+ StatementKind :: StorageDead ( Lvalue :: Local ( index) ) => {
1105
+ !promoted_temps. contains ( & index)
1106
+ }
1107
+ _ => true
1108
+ }
1109
+ } ) ;
1110
+ let terminator = block. terminator_mut ( ) ;
1111
+ match terminator. kind {
1112
+ TerminatorKind :: Drop { location : Lvalue :: Local ( index) , target, .. } => {
1113
+ if promoted_temps. contains ( & index) {
1114
+ terminator. kind = TerminatorKind :: Goto {
1115
+ target,
1116
+ } ;
1117
+ }
1118
+ }
1119
+ _ => { }
1120
+ }
1121
+ }
1067
1122
}
1068
1123
1069
1124
// Statics must be Sync.
0 commit comments