1212//! initialization and can otherwise silence errors, if
1313//! move analysis runs after promotion on broken MIR.
1414
15- use rustc_ast:: LitKind ;
1615use rustc_hir as hir;
17- use rustc_hir:: def_id:: DefId ;
1816use rustc_middle:: mir:: traversal:: ReversePostorder ;
1917use rustc_middle:: mir:: visit:: { MutVisitor , MutatingUseContext , PlaceContext , Visitor } ;
2018use rustc_middle:: mir:: * ;
2119use rustc_middle:: ty:: cast:: CastTy ;
2220use rustc_middle:: ty:: subst:: InternalSubsts ;
2321use rustc_middle:: ty:: { self , List , TyCtxt , TypeFoldable } ;
24- use rustc_span:: symbol:: sym;
2522use rustc_span:: Span ;
2623
2724use rustc_index:: vec:: { Idx , IndexVec } ;
28- use rustc_target:: spec:: abi:: Abi ;
2925
3026use std:: cell:: Cell ;
3127use std:: { cmp, iter, mem} ;
@@ -101,47 +97,16 @@ impl TempState {
10197pub enum Candidate {
10298 /// Borrow of a constant temporary, candidate for lifetime extension.
10399 Ref ( Location ) ,
104-
105- /// Currently applied to function calls where the callee has the unstable
106- /// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle
107- /// intrinsic. The intrinsic requires the arguments are indeed constant and
108- /// the attribute currently provides the semantic requirement that arguments
109- /// must be constant.
110- Argument { bb : BasicBlock , index : usize } ,
111100}
112101
113102impl Candidate {
114- /// Returns `true` if we should use the "explicit" rules for promotability for this `Candidate`.
115- fn forces_explicit_promotion ( & self ) -> bool {
116- match self {
117- Candidate :: Ref ( _) => false ,
118- Candidate :: Argument { .. } => true ,
119- }
120- }
121-
122103 fn source_info ( & self , body : & Body < ' _ > ) -> SourceInfo {
123104 match self {
124105 Candidate :: Ref ( location) => * body. source_info ( * location) ,
125- Candidate :: Argument { bb, .. } => * body. source_info ( body. terminator_loc ( * bb) ) ,
126106 }
127107 }
128108}
129109
130- fn args_required_const ( tcx : TyCtxt < ' _ > , def_id : DefId ) -> Option < Vec < usize > > {
131- let attrs = tcx. get_attrs ( def_id) ;
132- let attr = attrs. iter ( ) . find ( |a| tcx. sess . check_name ( a, sym:: rustc_args_required_const) ) ?;
133- let mut ret = vec ! [ ] ;
134- for meta in attr. meta_item_list ( ) ? {
135- match meta. literal ( ) ?. kind {
136- LitKind :: Int ( a, _) => {
137- ret. push ( a as usize ) ;
138- }
139- _ => bug ! ( "invalid arg index" ) ,
140- }
141- }
142- Some ( ret)
143- }
144-
145110struct Collector < ' a , ' tcx > {
146111 ccx : & ' a ConstCx < ' a , ' tcx > ,
147112 temps : IndexVec < Local , TempState > ,
@@ -208,31 +173,6 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
208173 _ => { }
209174 }
210175 }
211-
212- fn visit_terminator ( & mut self , terminator : & Terminator < ' tcx > , location : Location ) {
213- self . super_terminator ( terminator, location) ;
214-
215- if let TerminatorKind :: Call { ref func, .. } = terminator. kind {
216- if let ty:: FnDef ( def_id, _) = * func. ty ( self . ccx . body , self . ccx . tcx ) . kind ( ) {
217- let fn_sig = self . ccx . tcx . fn_sig ( def_id) ;
218- if let Abi :: RustIntrinsic | Abi :: PlatformIntrinsic = fn_sig. abi ( ) {
219- let name = self . ccx . tcx . item_name ( def_id) ;
220- // FIXME(eddyb) use `#[rustc_args_required_const(2)]` for shuffles.
221- if name. as_str ( ) . starts_with ( "simd_shuffle" ) {
222- self . candidates . push ( Candidate :: Argument { bb : location. block , index : 2 } ) ;
223-
224- return ; // Don't double count `simd_shuffle` candidates
225- }
226- }
227-
228- if let Some ( constant_args) = args_required_const ( self . ccx . tcx , def_id) {
229- for index in constant_args {
230- self . candidates . push ( Candidate :: Argument { bb : location. block , index } ) ;
231- }
232- }
233- }
234- }
235- }
236176}
237177
238178pub fn collect_temps_and_candidates (
@@ -256,14 +196,6 @@ pub fn collect_temps_and_candidates(
256196struct Validator < ' a , ' tcx > {
257197 ccx : & ' a ConstCx < ' a , ' tcx > ,
258198 temps : & ' a IndexVec < Local , TempState > ,
259-
260- /// Explicit promotion happens e.g. for constant arguments declared via
261- /// `rustc_args_required_const`.
262- /// Implicit promotion has almost the same rules, except that disallows `const fn`
263- /// except for those marked `#[rustc_promotable]`. This is to avoid changing
264- /// a legitimate run-time operation into a failing compile-time operation
265- /// e.g. due to addresses being compared inside the function.
266- explicit : bool ,
267199}
268200
269201impl std:: ops:: Deref for Validator < ' a , ' tcx > {
@@ -280,8 +212,6 @@ impl<'tcx> Validator<'_, 'tcx> {
280212 fn validate_candidate ( & self , candidate : Candidate ) -> Result < ( ) , Unpromotable > {
281213 match candidate {
282214 Candidate :: Ref ( loc) => {
283- assert ! ( !self . explicit) ;
284-
285215 let statement = & self . body [ loc. block ] . statements [ loc. statement_index ] ;
286216 match & statement. kind {
287217 StatementKind :: Assign ( box ( _, Rvalue :: Ref ( _, kind, place) ) ) => {
@@ -310,15 +240,6 @@ impl<'tcx> Validator<'_, 'tcx> {
310240 _ => bug ! ( ) ,
311241 }
312242 }
313- Candidate :: Argument { bb, index } => {
314- assert ! ( self . explicit) ;
315-
316- let terminator = self . body [ bb] . terminator ( ) ;
317- match & terminator. kind {
318- TerminatorKind :: Call { args, .. } => self . validate_operand ( & args[ index] ) ,
319- _ => bug ! ( ) ,
320- }
321- }
322243 }
323244 }
324245
@@ -448,12 +369,10 @@ impl<'tcx> Validator<'_, 'tcx> {
448369 ProjectionElem :: ConstantIndex { .. } | ProjectionElem :: Subslice { .. } => { }
449370
450371 ProjectionElem :: Index ( local) => {
451- if !self . explicit {
452- let mut promotable = false ;
453- // Only accept if we can predict the index and are indexing an array.
454- let val = if let TempState :: Defined { location : loc, .. } =
455- self . temps [ local]
456- {
372+ let mut promotable = false ;
373+ // Only accept if we can predict the index and are indexing an array.
374+ let val =
375+ if let TempState :: Defined { location : loc, .. } = self . temps [ local] {
457376 let block = & self . body [ loc. block ] ;
458377 if loc. statement_index < block. statements . len ( ) {
459378 let statement = & block. statements [ loc. statement_index ] ;
@@ -470,28 +389,27 @@ impl<'tcx> Validator<'_, 'tcx> {
470389 } else {
471390 None
472391 } ;
473- if let Some ( idx) = val {
474- // Determine the type of the thing we are indexing.
475- let ty = place_base. ty ( self . body , self . tcx ) . ty ;
476- match ty. kind ( ) {
477- ty:: Array ( _, len) => {
478- // It's an array; determine its length.
479- if let Some ( len) =
480- len. try_eval_usize ( self . tcx , self . param_env )
481- {
482- // If the index is in-bounds, go ahead.
483- if idx < len {
484- promotable = true ;
485- }
392+ if let Some ( idx) = val {
393+ // Determine the type of the thing we are indexing.
394+ let ty = place_base. ty ( self . body , self . tcx ) . ty ;
395+ match ty. kind ( ) {
396+ ty:: Array ( _, len) => {
397+ // It's an array; determine its length.
398+ if let Some ( len) = len. try_eval_usize ( self . tcx , self . param_env )
399+ {
400+ // If the index is in-bounds, go ahead.
401+ if idx < len {
402+ promotable = true ;
486403 }
487404 }
488- _ => { }
489405 }
406+ _ => { }
490407 }
491- if !promotable {
492- return Err ( Unpromotable ) ;
493- }
494408 }
409+ if !promotable {
410+ return Err ( Unpromotable ) ;
411+ }
412+
495413 self . validate_local ( local) ?;
496414 }
497415
@@ -636,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> {
636554
637555 match op {
638556 BinOp :: Div | BinOp :: Rem => {
639- if ! self . explicit && lhs_ty. is_integral ( ) {
557+ if lhs_ty. is_integral ( ) {
640558 // Integer division: the RHS must be a non-zero const.
641559 let const_val = match rhs {
642560 Operand :: Constant ( c) => {
@@ -721,13 +639,12 @@ impl<'tcx> Validator<'_, 'tcx> {
721639 ) -> Result < ( ) , Unpromotable > {
722640 let fn_ty = callee. ty ( self . body , self . tcx ) ;
723641
724- // When doing explicit promotion and inside const/static items, we promote all (eligible) function calls.
642+ // Inside const/static items, we promote all (eligible) function calls.
725643 // Everywhere else, we require `#[rustc_promotable]` on the callee.
726- let promote_all_const_fn = self . explicit
727- || matches ! (
728- self . const_kind,
729- Some ( hir:: ConstContext :: Static ( _) | hir:: ConstContext :: Const )
730- ) ;
644+ let promote_all_const_fn = matches ! (
645+ self . const_kind,
646+ Some ( hir:: ConstContext :: Static ( _) | hir:: ConstContext :: Const )
647+ ) ;
731648 if !promote_all_const_fn {
732649 if let ty:: FnDef ( def_id, _) = * fn_ty. kind ( ) {
733650 // Never promote runtime `const fn` calls of
@@ -765,41 +682,12 @@ pub fn validate_candidates(
765682 temps : & IndexVec < Local , TempState > ,
766683 candidates : & [ Candidate ] ,
767684) -> Vec < Candidate > {
768- let mut validator = Validator { ccx, temps, explicit : false } ;
685+ let validator = Validator { ccx, temps } ;
769686
770687 candidates
771688 . iter ( )
772689 . copied ( )
773- . filter ( |& candidate| {
774- validator. explicit = candidate. forces_explicit_promotion ( ) ;
775-
776- // FIXME(eddyb) also emit the errors for shuffle indices
777- // and `#[rustc_args_required_const]` arguments here.
778-
779- let is_promotable = validator. validate_candidate ( candidate) . is_ok ( ) ;
780-
781- // If we use explicit validation, we carry the risk of turning a legitimate run-time
782- // operation into a failing compile-time operation. Make sure that does not happen
783- // by asserting that there is no possible run-time behavior here in case promotion
784- // fails.
785- if validator. explicit && !is_promotable {
786- ccx. tcx . sess . delay_span_bug (
787- ccx. body . span ,
788- "Explicit promotion requested, but failed to promote" ,
789- ) ;
790- }
791-
792- match candidate {
793- Candidate :: Argument { bb, index } if !is_promotable => {
794- let span = ccx. body [ bb] . terminator ( ) . source_info . span ;
795- let msg = format ! ( "argument {} is required to be a constant" , index + 1 ) ;
796- ccx. tcx . sess . span_err ( span, & msg) ;
797- }
798- _ => ( ) ,
799- }
800-
801- is_promotable
802- } )
690+ . filter ( |& candidate| validator. validate_candidate ( candidate) . is_ok ( ) )
803691 . collect ( )
804692}
805693
@@ -1039,26 +927,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
1039927 _ => bug ! ( ) ,
1040928 }
1041929 }
1042- Candidate :: Argument { bb, index } => {
1043- let terminator = blocks[ bb] . terminator_mut ( ) ;
1044- match terminator. kind {
1045- TerminatorKind :: Call { ref mut args, .. } => {
1046- let ty = args[ index] . ty ( local_decls, self . tcx ) ;
1047- let span = terminator. source_info . span ;
1048-
1049- Rvalue :: Use ( mem:: replace ( & mut args[ index] , promoted_operand ( ty, span) ) )
1050- }
1051- // We expected a `TerminatorKind::Call` for which we'd like to promote an
1052- // argument. `qualify_consts` saw a `TerminatorKind::Call` here, but
1053- // we are seeing a `Goto`. That means that the `promote_temps` method
1054- // already promoted this call away entirely. This case occurs when calling
1055- // a function requiring a constant argument and as that constant value
1056- // providing a value whose computation contains another call to a function
1057- // requiring a constant argument.
1058- TerminatorKind :: Goto { .. } => return None ,
1059- _ => bug ! ( ) ,
1060- }
1061- }
1062930 }
1063931 } ;
1064932
@@ -1113,7 +981,6 @@ pub fn promote_candidates<'tcx>(
1113981 }
1114982 }
1115983 }
1116- Candidate :: Argument { .. } => { }
1117984 }
1118985
1119986 // Declare return place local so that `mir::Body::new` doesn't complain.
0 commit comments