12
12
//! initialization and can otherwise silence errors, if
13
13
//! move analysis runs after promotion on broken MIR.
14
14
15
- use rustc:: hir;
16
15
use rustc:: hir:: def_id:: DefId ;
17
16
use rustc:: mir:: * ;
18
17
use rustc:: mir:: interpret:: ConstValue ;
@@ -30,7 +29,7 @@ use rustc_target::spec::abi::Abi;
30
29
31
30
use std:: { iter, mem, usize} ;
32
31
33
- use crate :: transform:: check_consts:: { qualifs, Item as ConstCx } ;
32
+ use crate :: transform:: check_consts:: { qualifs, Item , ConstKind } ;
34
33
35
34
/// State of a temporary during collection and promotion.
36
35
#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
@@ -224,18 +223,13 @@ pub fn collect_temps_and_candidates(
224
223
( collector. temps , collector. candidates )
225
224
}
226
225
226
+ /// Checks whether locals that appear in a promotion context (`Candidate`) are actually promotable.
227
+ ///
228
+ /// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion.
227
229
struct Validator < ' a , ' tcx > {
228
- tcx : TyCtxt < ' tcx > ,
229
- param_env : ty:: ParamEnv < ' tcx > ,
230
- body : & ' a Body < ' tcx > ,
231
- is_static : bool ,
232
- is_static_mut : bool ,
233
- is_non_const_fn : bool ,
230
+ item : Item < ' a , ' tcx > ,
234
231
temps : & ' a IndexVec < Local , TempState > ,
235
232
236
- // FIXME(eddyb) deduplicate the data in this vs other fields.
237
- const_cx : ConstCx < ' a , ' tcx > ,
238
-
239
233
/// Explicit promotion happens e.g. for constant arguments declared via
240
234
/// `rustc_args_required_const`.
241
235
/// Implicit promotion has almost the same rules, except that disallows `const fn`
@@ -245,6 +239,14 @@ struct Validator<'a, 'tcx> {
245
239
explicit : bool ,
246
240
}
247
241
242
+ impl std:: ops:: Deref for Validator < ' a , ' tcx > {
243
+ type Target = Item < ' a , ' tcx > ;
244
+
245
+ fn deref ( & self ) -> & Self :: Target {
246
+ & self . item
247
+ }
248
+ }
249
+
248
250
struct Unpromotable ;
249
251
250
252
impl < ' tcx > Validator < ' _ , ' tcx > {
@@ -317,13 +319,14 @@ impl<'tcx> Validator<'_, 'tcx> {
317
319
if self . qualif_local :: < qualifs:: NeedsDrop > ( base) {
318
320
return Err ( Unpromotable ) ;
319
321
}
322
+
320
323
if let BorrowKind :: Mut { .. } = kind {
321
324
let ty = place. ty ( self . body , self . tcx ) . ty ;
322
325
323
326
// In theory, any zero-sized value could be borrowed
324
327
// mutably without consequences. However, only &mut []
325
328
// is allowed right now, and only in functions.
326
- if self . is_static_mut {
329
+ if self . const_kind == Some ( ConstKind :: StaticMut ) {
327
330
// Inside a `static mut`, &mut [...] is also allowed.
328
331
match ty. kind {
329
332
ty:: Array ( ..) | ty:: Slice ( _) => { }
@@ -333,7 +336,7 @@ impl<'tcx> Validator<'_, 'tcx> {
333
336
// FIXME(eddyb) the `self.is_non_const_fn` condition
334
337
// seems unnecessary, given that this is merely a ZST.
335
338
match len. try_eval_usize ( self . tcx , self . param_env ) {
336
- Some ( 0 ) if self . is_non_const_fn => { } ,
339
+ Some ( 0 ) if self . const_kind . is_none ( ) => { } ,
337
340
_ => return Err ( Unpromotable ) ,
338
341
}
339
342
} else {
@@ -386,7 +389,7 @@ impl<'tcx> Validator<'_, 'tcx> {
386
389
let statement = & self . body [ loc. block ] . statements [ loc. statement_index ] ;
387
390
match & statement. kind {
388
391
StatementKind :: Assign ( box( _, rhs) ) => {
389
- Q :: in_rvalue ( & self . const_cx , per_local, rhs)
392
+ Q :: in_rvalue ( & self . item , per_local, rhs)
390
393
}
391
394
_ => {
392
395
span_bug ! ( statement. source_info. span, "{:?} is not an assignment" ,
@@ -398,7 +401,7 @@ impl<'tcx> Validator<'_, 'tcx> {
398
401
match & terminator. kind {
399
402
TerminatorKind :: Call { func, args, .. } => {
400
403
let return_ty = self . body . local_decls [ local] . ty ;
401
- Q :: in_call ( & self . const_cx , per_local, func, args, return_ty)
404
+ Q :: in_call ( & self . item , per_local, func, args, return_ty)
402
405
}
403
406
kind => {
404
407
span_bug ! ( terminator. source_info. span, "{:?} not promotable" , kind) ;
@@ -462,8 +465,8 @@ impl<'tcx> Validator<'_, 'tcx> {
462
465
} => {
463
466
// Only allow statics (not consts) to refer to other statics.
464
467
// FIXME(eddyb) does this matter at all for promotion?
465
- let allowed = self . is_static || self . is_static_mut ;
466
- if !allowed {
468
+ let is_static = self . const_kind . map_or ( false , |k| k . is_static ( ) ) ;
469
+ if !is_static {
467
470
return Err ( Unpromotable ) ;
468
471
}
469
472
@@ -490,7 +493,7 @@ impl<'tcx> Validator<'_, 'tcx> {
490
493
}
491
494
492
495
ProjectionElem :: Field ( ..) => {
493
- if self . is_non_const_fn {
496
+ if self . const_kind . is_none ( ) {
494
497
let base_ty =
495
498
Place :: ty_from ( place. base , proj_base, self . body , self . tcx ) . ty ;
496
499
if let Some ( def) = base_ty. ty_adt_def ( ) {
@@ -545,7 +548,7 @@ impl<'tcx> Validator<'_, 'tcx> {
545
548
546
549
fn validate_rvalue ( & self , rvalue : & Rvalue < ' tcx > ) -> Result < ( ) , Unpromotable > {
547
550
match * rvalue {
548
- Rvalue :: Cast ( CastKind :: Misc , ref operand, cast_ty) if self . is_non_const_fn => {
551
+ Rvalue :: Cast ( CastKind :: Misc , ref operand, cast_ty) if self . const_kind . is_none ( ) => {
549
552
let operand_ty = operand. ty ( self . body , self . tcx ) ;
550
553
let cast_in = CastTy :: from_ty ( operand_ty) . expect ( "bad input type for cast" ) ;
551
554
let cast_out = CastTy :: from_ty ( cast_ty) . expect ( "bad output type for cast" ) ;
@@ -559,7 +562,7 @@ impl<'tcx> Validator<'_, 'tcx> {
559
562
}
560
563
}
561
564
562
- Rvalue :: BinaryOp ( op, ref lhs, _) if self . is_non_const_fn => {
565
+ Rvalue :: BinaryOp ( op, ref lhs, _) if self . const_kind . is_none ( ) => {
563
566
if let ty:: RawPtr ( _) | ty:: FnPtr ( ..) = lhs. ty ( self . body , self . tcx ) . kind {
564
567
assert ! ( op == BinOp :: Eq || op == BinOp :: Ne ||
565
568
op == BinOp :: Le || op == BinOp :: Lt ||
@@ -600,17 +603,17 @@ impl<'tcx> Validator<'_, 'tcx> {
600
603
// In theory, any zero-sized value could be borrowed
601
604
// mutably without consequences. However, only &mut []
602
605
// is allowed right now, and only in functions.
603
- if self . is_static_mut {
606
+ if self . const_kind == Some ( ConstKind :: StaticMut ) {
604
607
// Inside a `static mut`, &mut [...] is also allowed.
605
608
match ty. kind {
606
609
ty:: Array ( ..) | ty:: Slice ( _) => { }
607
610
_ => return Err ( Unpromotable ) ,
608
611
}
609
612
} else if let ty:: Array ( _, len) = ty. kind {
610
- // FIXME(eddyb) the `self.is_non_const_fn` condition
611
- // seems unnecessary, given that this is merely a ZST.
613
+ // FIXME(eddyb): We only return `Unpromotable` for `&mut []` inside a
614
+ // const context which seems unnecessary given that this is merely a ZST.
612
615
match len. try_eval_usize ( self . tcx , self . param_env ) {
613
- Some ( 0 ) if self . is_non_const_fn => { } ,
616
+ Some ( 0 ) if self . const_kind . is_none ( ) => { } ,
614
617
_ => return Err ( Unpromotable ) ,
615
618
}
616
619
} else {
@@ -683,7 +686,7 @@ impl<'tcx> Validator<'_, 'tcx> {
683
686
) -> Result < ( ) , Unpromotable > {
684
687
let fn_ty = callee. ty ( self . body , self . tcx ) ;
685
688
686
- if !self . explicit && self . is_non_const_fn {
689
+ if !self . explicit && self . const_kind . is_none ( ) {
687
690
if let ty:: FnDef ( def_id, _) = fn_ty. kind {
688
691
// Never promote runtime `const fn` calls of
689
692
// functions without `#[rustc_promotable]`.
@@ -714,6 +717,7 @@ impl<'tcx> Validator<'_, 'tcx> {
714
717
}
715
718
}
716
719
720
+ // FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
717
721
pub fn validate_candidates (
718
722
tcx : TyCtxt < ' tcx > ,
719
723
body : & Body < ' tcx > ,
@@ -722,33 +726,11 @@ pub fn validate_candidates(
722
726
candidates : & [ Candidate ] ,
723
727
) -> Vec < Candidate > {
724
728
let mut validator = Validator {
725
- tcx,
726
- param_env : tcx. param_env ( def_id) ,
727
- body,
728
- is_static : false ,
729
- is_static_mut : false ,
730
- is_non_const_fn : false ,
729
+ item : Item :: new ( tcx, def_id, body) ,
731
730
temps,
732
-
733
- const_cx : ConstCx :: new ( tcx, def_id, body) ,
734
-
735
731
explicit : false ,
736
732
} ;
737
733
738
- // FIXME(eddyb) remove the distinctions that make this necessary.
739
- let id = tcx. hir ( ) . as_local_hir_id ( def_id) . unwrap ( ) ;
740
- match tcx. hir ( ) . body_owner_kind ( id) {
741
- hir:: BodyOwnerKind :: Closure => validator. is_non_const_fn = true ,
742
- hir:: BodyOwnerKind :: Fn => {
743
- if !tcx. is_const_fn ( def_id) {
744
- validator. is_non_const_fn = true ;
745
- }
746
- } ,
747
- hir:: BodyOwnerKind :: Static ( hir:: MutImmutable ) => validator. is_static = true ,
748
- hir:: BodyOwnerKind :: Static ( hir:: MutMutable ) => validator. is_static_mut = true ,
749
- _ => { }
750
- }
751
-
752
734
candidates. iter ( ) . copied ( ) . filter ( |& candidate| {
753
735
validator. explicit = match candidate {
754
736
Candidate :: Ref ( _) |
0 commit comments