1212//! initialization and can otherwise silence errors, if
1313//! move analysis runs after promotion on broken MIR.
1414
15- use rustc:: hir;
1615use rustc:: hir:: def_id:: DefId ;
1716use rustc:: mir:: * ;
1817use rustc:: mir:: interpret:: ConstValue ;
@@ -30,7 +29,7 @@ use rustc_target::spec::abi::Abi;
3029
3130use std:: { iter, mem, usize} ;
3231
33- use crate :: transform:: check_consts:: { qualifs, Item as ConstCx } ;
32+ use crate :: transform:: check_consts:: { qualifs, Item , ConstKind } ;
3433
3534/// State of a temporary during collection and promotion.
3635#[ derive( Copy , Clone , PartialEq , Eq , Debug ) ]
@@ -224,18 +223,13 @@ pub fn collect_temps_and_candidates(
224223 ( collector. temps , collector. candidates )
225224}
226225
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.
227229struct 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 > ,
234231 temps : & ' a IndexVec < Local , TempState > ,
235232
236- // FIXME(eddyb) deduplicate the data in this vs other fields.
237- const_cx : ConstCx < ' a , ' tcx > ,
238-
239233 /// Explicit promotion happens e.g. for constant arguments declared via
240234 /// `rustc_args_required_const`.
241235 /// Implicit promotion has almost the same rules, except that disallows `const fn`
@@ -245,6 +239,14 @@ struct Validator<'a, 'tcx> {
245239 explicit : bool ,
246240}
247241
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+
248250struct Unpromotable ;
249251
250252impl < ' tcx > Validator < ' _ , ' tcx > {
@@ -317,13 +319,14 @@ impl<'tcx> Validator<'_, 'tcx> {
317319 if self . qualif_local :: < qualifs:: NeedsDrop > ( base) {
318320 return Err ( Unpromotable ) ;
319321 }
322+
320323 if let BorrowKind :: Mut { .. } = kind {
321324 let ty = place. ty ( self . body , self . tcx ) . ty ;
322325
323326 // In theory, any zero-sized value could be borrowed
324327 // mutably without consequences. However, only &mut []
325328 // is allowed right now, and only in functions.
326- if self . is_static_mut {
329+ if self . const_kind == Some ( ConstKind :: StaticMut ) {
327330 // Inside a `static mut`, &mut [...] is also allowed.
328331 match ty. kind {
329332 ty:: Array ( ..) | ty:: Slice ( _) => { }
@@ -333,7 +336,7 @@ impl<'tcx> Validator<'_, 'tcx> {
333336 // FIXME(eddyb) the `self.is_non_const_fn` condition
334337 // seems unnecessary, given that this is merely a ZST.
335338 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 ( ) => { } ,
337340 _ => return Err ( Unpromotable ) ,
338341 }
339342 } else {
@@ -386,7 +389,7 @@ impl<'tcx> Validator<'_, 'tcx> {
386389 let statement = & self . body [ loc. block ] . statements [ loc. statement_index ] ;
387390 match & statement. kind {
388391 StatementKind :: Assign ( box( _, rhs) ) => {
389- Q :: in_rvalue ( & self . const_cx , per_local, rhs)
392+ Q :: in_rvalue ( & self . item , per_local, rhs)
390393 }
391394 _ => {
392395 span_bug ! ( statement. source_info. span, "{:?} is not an assignment" ,
@@ -398,7 +401,7 @@ impl<'tcx> Validator<'_, 'tcx> {
398401 match & terminator. kind {
399402 TerminatorKind :: Call { func, args, .. } => {
400403 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)
402405 }
403406 kind => {
404407 span_bug ! ( terminator. source_info. span, "{:?} not promotable" , kind) ;
@@ -462,8 +465,8 @@ impl<'tcx> Validator<'_, 'tcx> {
462465 } => {
463466 // Only allow statics (not consts) to refer to other statics.
464467 // 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 {
467470 return Err ( Unpromotable ) ;
468471 }
469472
@@ -490,7 +493,7 @@ impl<'tcx> Validator<'_, 'tcx> {
490493 }
491494
492495 ProjectionElem :: Field ( ..) => {
493- if self . is_non_const_fn {
496+ if self . const_kind . is_none ( ) {
494497 let base_ty =
495498 Place :: ty_from ( place. base , proj_base, self . body , self . tcx ) . ty ;
496499 if let Some ( def) = base_ty. ty_adt_def ( ) {
@@ -545,7 +548,7 @@ impl<'tcx> Validator<'_, 'tcx> {
545548
546549 fn validate_rvalue ( & self , rvalue : & Rvalue < ' tcx > ) -> Result < ( ) , Unpromotable > {
547550 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 ( ) => {
549552 let operand_ty = operand. ty ( self . body , self . tcx ) ;
550553 let cast_in = CastTy :: from_ty ( operand_ty) . expect ( "bad input type for cast" ) ;
551554 let cast_out = CastTy :: from_ty ( cast_ty) . expect ( "bad output type for cast" ) ;
@@ -559,7 +562,7 @@ impl<'tcx> Validator<'_, 'tcx> {
559562 }
560563 }
561564
562- Rvalue :: BinaryOp ( op, ref lhs, _) if self . is_non_const_fn => {
565+ Rvalue :: BinaryOp ( op, ref lhs, _) if self . const_kind . is_none ( ) => {
563566 if let ty:: RawPtr ( _) | ty:: FnPtr ( ..) = lhs. ty ( self . body , self . tcx ) . kind {
564567 assert ! ( op == BinOp :: Eq || op == BinOp :: Ne ||
565568 op == BinOp :: Le || op == BinOp :: Lt ||
@@ -600,17 +603,17 @@ impl<'tcx> Validator<'_, 'tcx> {
600603 // In theory, any zero-sized value could be borrowed
601604 // mutably without consequences. However, only &mut []
602605 // is allowed right now, and only in functions.
603- if self . is_static_mut {
606+ if self . const_kind == Some ( ConstKind :: StaticMut ) {
604607 // Inside a `static mut`, &mut [...] is also allowed.
605608 match ty. kind {
606609 ty:: Array ( ..) | ty:: Slice ( _) => { }
607610 _ => return Err ( Unpromotable ) ,
608611 }
609612 } 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.
612615 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 ( ) => { } ,
614617 _ => return Err ( Unpromotable ) ,
615618 }
616619 } else {
@@ -683,7 +686,7 @@ impl<'tcx> Validator<'_, 'tcx> {
683686 ) -> Result < ( ) , Unpromotable > {
684687 let fn_ty = callee. ty ( self . body , self . tcx ) ;
685688
686- if !self . explicit && self . is_non_const_fn {
689+ if !self . explicit && self . const_kind . is_none ( ) {
687690 if let ty:: FnDef ( def_id, _) = fn_ty. kind {
688691 // Never promote runtime `const fn` calls of
689692 // functions without `#[rustc_promotable]`.
@@ -714,6 +717,7 @@ impl<'tcx> Validator<'_, 'tcx> {
714717 }
715718}
716719
720+ // FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
717721pub fn validate_candidates (
718722 tcx : TyCtxt < ' tcx > ,
719723 body : & Body < ' tcx > ,
@@ -722,33 +726,11 @@ pub fn validate_candidates(
722726 candidates : & [ Candidate ] ,
723727) -> Vec < Candidate > {
724728 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) ,
731730 temps,
732-
733- const_cx : ConstCx :: new ( tcx, def_id, body) ,
734-
735731 explicit : false ,
736732 } ;
737733
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-
752734 candidates. iter ( ) . copied ( ) . filter ( |& candidate| {
753735 validator. explicit = match candidate {
754736 Candidate :: Ref ( _) |
0 commit comments