12
12
//! initialization and can otherwise silence errors, if
13
13
//! move analysis runs after promotion on broken MIR.
14
14
15
- use rustc_ast:: LitKind ;
16
15
use rustc_hir as hir;
17
- use rustc_hir:: def_id:: DefId ;
18
16
use rustc_middle:: mir:: traversal:: ReversePostorder ;
19
17
use rustc_middle:: mir:: visit:: { MutVisitor , MutatingUseContext , PlaceContext , Visitor } ;
20
18
use rustc_middle:: mir:: * ;
21
19
use rustc_middle:: ty:: cast:: CastTy ;
22
20
use rustc_middle:: ty:: subst:: InternalSubsts ;
23
21
use rustc_middle:: ty:: { self , List , TyCtxt , TypeFoldable } ;
24
- use rustc_span:: symbol:: sym;
25
22
use rustc_span:: Span ;
26
23
27
24
use rustc_index:: vec:: { Idx , IndexVec } ;
28
- use rustc_target:: spec:: abi:: Abi ;
29
25
30
26
use std:: cell:: Cell ;
31
27
use std:: { cmp, iter, mem} ;
@@ -101,47 +97,16 @@ impl TempState {
101
97
pub enum Candidate {
102
98
/// Borrow of a constant temporary, candidate for lifetime extension.
103
99
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 } ,
111
100
}
112
101
113
102
impl 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
-
122
103
fn source_info ( & self , body : & Body < ' _ > ) -> SourceInfo {
123
104
match self {
124
105
Candidate :: Ref ( location) => * body. source_info ( * location) ,
125
- Candidate :: Argument { bb, .. } => * body. source_info ( body. terminator_loc ( * bb) ) ,
126
106
}
127
107
}
128
108
}
129
109
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
-
145
110
struct Collector < ' a , ' tcx > {
146
111
ccx : & ' a ConstCx < ' a , ' tcx > ,
147
112
temps : IndexVec < Local , TempState > ,
@@ -208,31 +173,6 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> {
208
173
_ => { }
209
174
}
210
175
}
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
- }
236
176
}
237
177
238
178
pub fn collect_temps_and_candidates (
@@ -256,14 +196,6 @@ pub fn collect_temps_and_candidates(
256
196
struct Validator < ' a , ' tcx > {
257
197
ccx : & ' a ConstCx < ' a , ' tcx > ,
258
198
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 ,
267
199
}
268
200
269
201
impl std:: ops:: Deref for Validator < ' a , ' tcx > {
@@ -280,8 +212,6 @@ impl<'tcx> Validator<'_, 'tcx> {
280
212
fn validate_candidate ( & self , candidate : Candidate ) -> Result < ( ) , Unpromotable > {
281
213
match candidate {
282
214
Candidate :: Ref ( loc) => {
283
- assert ! ( !self . explicit) ;
284
-
285
215
let statement = & self . body [ loc. block ] . statements [ loc. statement_index ] ;
286
216
match & statement. kind {
287
217
StatementKind :: Assign ( box ( _, Rvalue :: Ref ( _, kind, place) ) ) => {
@@ -310,15 +240,6 @@ impl<'tcx> Validator<'_, 'tcx> {
310
240
_ => bug ! ( ) ,
311
241
}
312
242
}
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
- }
322
243
}
323
244
}
324
245
@@ -448,12 +369,10 @@ impl<'tcx> Validator<'_, 'tcx> {
448
369
ProjectionElem :: ConstantIndex { .. } | ProjectionElem :: Subslice { .. } => { }
449
370
450
371
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] {
457
376
let block = & self . body [ loc. block ] ;
458
377
if loc. statement_index < block. statements . len ( ) {
459
378
let statement = & block. statements [ loc. statement_index ] ;
@@ -470,28 +389,27 @@ impl<'tcx> Validator<'_, 'tcx> {
470
389
} else {
471
390
None
472
391
} ;
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 ;
486
403
}
487
404
}
488
- _ => { }
489
405
}
406
+ _ => { }
490
407
}
491
- if !promotable {
492
- return Err ( Unpromotable ) ;
493
- }
494
408
}
409
+ if !promotable {
410
+ return Err ( Unpromotable ) ;
411
+ }
412
+
495
413
self . validate_local ( local) ?;
496
414
}
497
415
@@ -636,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> {
636
554
637
555
match op {
638
556
BinOp :: Div | BinOp :: Rem => {
639
- if ! self . explicit && lhs_ty. is_integral ( ) {
557
+ if lhs_ty. is_integral ( ) {
640
558
// Integer division: the RHS must be a non-zero const.
641
559
let const_val = match rhs {
642
560
Operand :: Constant ( c) => {
@@ -721,13 +639,12 @@ impl<'tcx> Validator<'_, 'tcx> {
721
639
) -> Result < ( ) , Unpromotable > {
722
640
let fn_ty = callee. ty ( self . body , self . tcx ) ;
723
641
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.
725
643
// 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
+ ) ;
731
648
if !promote_all_const_fn {
732
649
if let ty:: FnDef ( def_id, _) = * fn_ty. kind ( ) {
733
650
// Never promote runtime `const fn` calls of
@@ -765,41 +682,12 @@ pub fn validate_candidates(
765
682
temps : & IndexVec < Local , TempState > ,
766
683
candidates : & [ Candidate ] ,
767
684
) -> Vec < Candidate > {
768
- let mut validator = Validator { ccx, temps, explicit : false } ;
685
+ let validator = Validator { ccx, temps } ;
769
686
770
687
candidates
771
688
. iter ( )
772
689
. 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 ( ) )
803
691
. collect ( )
804
692
}
805
693
@@ -1039,26 +927,6 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
1039
927
_ => bug ! ( ) ,
1040
928
}
1041
929
}
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
- }
1062
930
}
1063
931
} ;
1064
932
@@ -1113,7 +981,6 @@ pub fn promote_candidates<'tcx>(
1113
981
}
1114
982
}
1115
983
}
1116
- Candidate :: Argument { .. } => { }
1117
984
}
1118
985
1119
986
// Declare return place local so that `mir::Body::new` doesn't complain.
0 commit comments