1515//! diagnostics as to why a constant rvalue wasn't promoted.
1616
1717use rustc_data_structures:: bitvec:: BitVector ;
18+ use rustc_data_structures:: indexed_set:: IdxSetBuf ;
1819use rustc_data_structures:: indexed_vec:: { IndexVec , Idx } ;
1920use rustc:: hir;
2021use rustc:: hir:: map as hir_map;
@@ -33,6 +34,7 @@ use syntax::feature_gate::UnstableFeatures;
3334use syntax_pos:: { Span , DUMMY_SP } ;
3435
3536use std:: fmt;
37+ use std:: rc:: Rc ;
3638use std:: usize;
3739
3840use super :: promote_consts:: { self , Candidate , TempState } ;
@@ -127,7 +129,6 @@ struct Qualifier<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
127129
128130impl < ' a , ' tcx > Qualifier < ' a , ' tcx , ' tcx > {
129131 fn new ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
130- param_env : ty:: ParamEnv < ' tcx > ,
131132 def_id : DefId ,
132133 mir : & ' a Mir < ' tcx > ,
133134 mode : Mode )
@@ -142,7 +143,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
142143 mir,
143144 rpo,
144145 tcx,
145- param_env,
146+ param_env : tcx . param_env ( def_id ) ,
146147 temp_qualif : IndexVec :: from_elem ( None , & mir. local_decls ) ,
147148 return_qualif : None ,
148149 qualif : Qualif :: empty ( ) ,
@@ -368,7 +369,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
368369 }
369370
370371 /// 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 > > ) {
372373 debug ! ( "qualifying {} {:?}" , self . mode, self . def_id) ;
373374
374375 let mir = self . mir ;
@@ -390,7 +391,7 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
390391
391392 // Non-terminating calls cannot produce any value.
392393 TerminatorKind :: Call { destination : None , .. } => {
393- return Qualif :: empty ( ) ;
394+ break ;
394395 }
395396
396397 TerminatorKind :: SwitchInt { ..} |
@@ -472,7 +473,25 @@ impl<'a, 'tcx> Qualifier<'a, 'tcx, 'tcx> {
472473 }
473474 }
474475 }
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) )
476495 }
477496}
478497
@@ -516,6 +535,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
516535 span_err ! ( self . tcx. sess, self . span, E0625 ,
517536 "thread-local statics cannot be \
518537 accessed at compile-time") ;
538+ self . add ( Qualif :: NOT_CONST ) ;
519539 return ;
520540 }
521541 }
@@ -598,7 +618,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
598618 if self . tcx . trait_of_item ( def_id) . is_some ( ) {
599619 self . add_type ( constant. ty ) ;
600620 } 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) ;
602622
603623 let qualif = Qualif :: from_bits ( bits) . expect ( "invalid mir_const_qualif" ) ;
604624 self . add ( qualif) ;
@@ -702,13 +722,11 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
702722
703723 // We might have a candidate for promotion.
704724 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) ;
712730 }
713731 }
714732 }
@@ -999,21 +1017,21 @@ pub fn provide(providers: &mut Providers) {
9991017
10001018fn mir_const_qualif < ' a , ' tcx > ( tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
10011019 def_id : DefId )
1002- -> u8 {
1020+ -> ( u8 , Rc < IdxSetBuf < Local > > ) {
10031021 // NB: This `borrow()` is guaranteed to be valid (i.e., the value
10041022 // cannot yet be stolen), because `mir_validated()`, which steals
10051023 // from `mir_const(), forces this query to execute before
10061024 // performing the steal.
10071025 let mir = & tcx. mir_const ( def_id) . borrow ( ) ;
10081026
10091027 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 ) ) ) ;
10111030 }
10121031
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)
10171035}
10181036
10191037pub struct QualifyAndPromoteConstants ;
@@ -1023,8 +1041,15 @@ impl MirPass for QualifyAndPromoteConstants {
10231041 tcx : TyCtxt < ' a , ' tcx , ' tcx > ,
10241042 src : MirSource ,
10251043 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+
10261050 let id = src. item_id ( ) ;
10271051 let def_id = tcx. hir . local_def_id ( id) ;
1052+ let mut const_promoted_temps = None ;
10281053 let mode = match src {
10291054 MirSource :: Fn ( _) => {
10301055 if tcx. is_const_fn ( def_id) {
@@ -1033,20 +1058,21 @@ impl MirPass for QualifyAndPromoteConstants {
10331058 Mode :: Fn
10341059 }
10351060 }
1061+ MirSource :: Const ( _) => {
1062+ const_promoted_temps = Some ( tcx. mir_const_qualif ( def_id) . 1 ) ;
1063+ Mode :: Const
1064+ }
10361065 MirSource :: Static ( _, hir:: MutImmutable ) => Mode :: Static ,
10371066 MirSource :: Static ( _, hir:: MutMutable ) => Mode :: StaticMut ,
10381067 MirSource :: GeneratorDrop ( _) |
1039- MirSource :: Const ( _) |
10401068 MirSource :: Promoted ( ..) => return
10411069 } ;
1042- let param_env = tcx. param_env ( def_id) ;
10431070
10441071 if mode == Mode :: Fn || mode == Mode :: ConstFn {
10451072 // This is ugly because Qualifier holds onto mir,
10461073 // which can't be mutated until its scope ends.
10471074 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) ;
10501076 if mode == Mode :: ConstFn {
10511077 // Enforce a constant-like CFG for `const fn`.
10521078 qualifier. qualify_const ( ) ;
@@ -1062,8 +1088,37 @@ impl MirPass for QualifyAndPromoteConstants {
10621088 // Do the actual promotion, now that we know what's viable.
10631089 promote_consts:: promote_candidates ( mir, tcx, temps, candidates) ;
10641090 } 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+ }
10671122 }
10681123
10691124 // Statics must be Sync.
0 commit comments