@@ -61,7 +61,7 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
61
61
62
62
let promotable_candidates = validate_candidates ( & ccx, & mut temps, & all_candidates) ;
63
63
64
- let promoted = promote_candidates ( body, tcx, temps, promotable_candidates) ;
64
+ let promoted = promote_candidates ( body, tcx, ccx . const_kind , temps, promotable_candidates) ;
65
65
self . promoted_fragments . set ( promoted) ;
66
66
}
67
67
}
@@ -657,15 +657,9 @@ impl<'tcx> Validator<'_, 'tcx> {
657
657
}
658
658
}
659
659
660
- // Ideally, we'd stop here and reject the rest.
661
- // But for backward compatibility, we have to accept some promotion in const/static
662
- // initializers. Inline consts are explicitly excluded, they are more recent so we have no
663
- // backwards compatibility reason to allow more promotion inside of them.
664
- let promote_all_fn = matches ! (
665
- self . const_kind,
666
- Some ( hir:: ConstContext :: Static ( _) | hir:: ConstContext :: Const { inline: false } )
667
- ) ;
668
- if !promote_all_fn {
660
+ // Ideally, we'd stop here and reject the rest. But for backward compatibility, we have to
661
+ // accept some promotion in const/static initializers.
662
+ if !promote_all_fn ( self . ccx . const_kind ) {
669
663
return Err ( Unpromotable ) ;
670
664
}
671
665
// Make sure the callee is a `const fn`.
@@ -687,6 +681,18 @@ impl<'tcx> Validator<'_, 'tcx> {
687
681
}
688
682
}
689
683
684
+ /// Decides whether in this context we are okay with promoting all functions (and not just
685
+ /// `#[rustc_promotable]`).
686
+ /// For backwards compatibility, we do that in static/const initializers.
687
+ fn promote_all_fn ( const_kind : Option < hir:: ConstContext > ) -> bool {
688
+ // Inline consts are explicitly excluded, they are more recent so we have no
689
+ // backwards compatibility reason to allow more promotion inside of them.
690
+ matches ! (
691
+ const_kind,
692
+ Some ( hir:: ConstContext :: Static ( _) | hir:: ConstContext :: Const { inline: false } )
693
+ )
694
+ }
695
+
690
696
// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
691
697
fn validate_candidates (
692
698
ccx : & ConstCx < ' _ , ' _ > ,
@@ -712,6 +718,9 @@ struct Promoter<'a, 'tcx> {
712
718
/// If true, all nested temps are also kept in the
713
719
/// source MIR, not moved to the promoted MIR.
714
720
keep_original : bool ,
721
+
722
+ /// If true, add the new const (the promoted) to the required_consts of the parent MIR.
723
+ add_to_required : bool ,
715
724
}
716
725
717
726
impl < ' a , ' tcx > Promoter < ' a , ' tcx > {
@@ -858,11 +867,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
858
867
let args = tcx. erase_regions ( GenericArgs :: identity_for_item ( tcx, def) ) ;
859
868
let uneval = mir:: UnevaluatedConst { def, args, promoted : Some ( promoted_id) } ;
860
869
861
- Operand :: Constant ( Box :: new ( ConstOperand {
862
- span,
863
- user_ty : None ,
864
- const_ : Const :: Unevaluated ( uneval, ty) ,
865
- } ) )
870
+ ConstOperand { span, user_ty : None , const_ : Const :: Unevaluated ( uneval, ty) }
866
871
} ;
867
872
868
873
let blocks = self . source . basic_blocks . as_mut ( ) ;
@@ -898,11 +903,15 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
898
903
let promoted_ref = local_decls. push ( promoted_ref) ;
899
904
assert_eq ! ( self . temps. push( TempState :: Unpromotable ) , promoted_ref) ;
900
905
906
+ let promoted_operand = promoted_operand ( ref_ty, span) ;
907
+ if self . add_to_required {
908
+ self . source . required_consts . push ( promoted_operand) ;
909
+ }
901
910
let promoted_ref_statement = Statement {
902
911
source_info : statement. source_info ,
903
912
kind : StatementKind :: Assign ( Box :: new ( (
904
913
Place :: from ( promoted_ref) ,
905
- Rvalue :: Use ( promoted_operand ( ref_ty , span ) ) ,
914
+ Rvalue :: Use ( Operand :: Constant ( Box :: new ( promoted_operand ) ) ) ,
906
915
) ) ) ,
907
916
} ;
908
917
self . extra_statements . push ( ( loc, promoted_ref_statement) ) ;
@@ -945,6 +954,7 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Promoter<'a, 'tcx> {
945
954
fn promote_candidates < ' tcx > (
946
955
body : & mut Body < ' tcx > ,
947
956
tcx : TyCtxt < ' tcx > ,
957
+ ccx_const_kind : Option < hir:: ConstContext > ,
948
958
mut temps : IndexVec < Local , TempState > ,
949
959
candidates : Vec < Candidate > ,
950
960
) -> IndexVec < Promoted , Body < ' tcx > > {
@@ -984,6 +994,11 @@ fn promote_candidates<'tcx>(
984
994
None ,
985
995
body. tainted_by_errors ,
986
996
) ;
997
+ // We keep `required_consts` of the new MIR body empty. All consts mentioned here have
998
+ // already been added to the parent MIR's `required_consts` (that is computed before
999
+ // promotion), and no matter where this promoted const ends up, our parent MIR must be
1000
+ // somewhere in the reachable dependency chain so we can rely on its required consts being
1001
+ // evaluated.
987
1002
promoted. phase = MirPhase :: Analysis ( AnalysisPhase :: Initial ) ;
988
1003
989
1004
let promoter = Promoter {
@@ -993,6 +1008,10 @@ fn promote_candidates<'tcx>(
993
1008
temps : & mut temps,
994
1009
extra_statements : & mut extra_statements,
995
1010
keep_original : false ,
1011
+ // If we promote all functions, some of these promoteds could fail, so we better make
1012
+ // sure they get all checked as `required_consts`. Otherwise, as an optimization we
1013
+ // *don't* add the promoteds to the parent's `required_consts`.
1014
+ add_to_required : promote_all_fn ( ccx_const_kind) ,
996
1015
} ;
997
1016
998
1017
let mut promoted = promoter. promote_candidate ( candidate, promotions. len ( ) ) ;
0 commit comments