@@ -687,7 +687,6 @@ impl<'tcx> Validator<'_, 'tcx> {
687
687
}
688
688
}
689
689
690
- // FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
691
690
fn validate_candidates (
692
691
ccx : & ConstCx < ' _ , ' _ > ,
693
692
temps : & mut IndexSlice < Local , TempState > ,
@@ -712,6 +711,10 @@ struct Promoter<'a, 'tcx> {
712
711
/// If true, all nested temps are also kept in the
713
712
/// source MIR, not moved to the promoted MIR.
714
713
keep_original : bool ,
714
+
715
+ /// If true, add the new const (the promoted) to the required_consts of the parent MIR.
716
+ /// This is initially false and then set by the visitor when it encounters a `Call` terminator.
717
+ add_to_required : bool ,
715
718
}
716
719
717
720
impl < ' a , ' tcx > Promoter < ' a , ' tcx > {
@@ -814,6 +817,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
814
817
TerminatorKind :: Call {
815
818
mut func, mut args, call_source : desugar, fn_span, ..
816
819
} => {
820
+ // This promoted involves a function call, so it may fail to evaluate.
821
+ // Let's make sure it is added to `required_consts` so that that failure cannot get lost.
822
+ self . add_to_required = true ;
823
+
817
824
self . visit_operand ( & mut func, loc) ;
818
825
for arg in & mut args {
819
826
self . visit_operand ( & mut arg. node , loc) ;
@@ -848,7 +855,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
848
855
849
856
fn promote_candidate ( mut self , candidate : Candidate , next_promoted_id : usize ) -> Body < ' tcx > {
850
857
let def = self . source . source . def_id ( ) ;
851
- let mut rvalue = {
858
+ let ( mut rvalue, promoted_op ) = {
852
859
let promoted = & mut self . promoted ;
853
860
let promoted_id = Promoted :: new ( next_promoted_id) ;
854
861
let tcx = self . tcx ;
@@ -858,11 +865,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
858
865
let args = tcx. erase_regions ( GenericArgs :: identity_for_item ( tcx, def) ) ;
859
866
let uneval = mir:: UnevaluatedConst { def, args, promoted : Some ( promoted_id) } ;
860
867
861
- Operand :: Constant ( Box :: new ( ConstOperand {
862
- span,
863
- user_ty : None ,
864
- const_ : Const :: Unevaluated ( uneval, ty) ,
865
- } ) )
868
+ ConstOperand { span, user_ty : None , const_ : Const :: Unevaluated ( uneval, ty) }
866
869
} ;
867
870
868
871
let blocks = self . source . basic_blocks . as_mut ( ) ;
@@ -898,22 +901,26 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
898
901
let promoted_ref = local_decls. push ( promoted_ref) ;
899
902
assert_eq ! ( self . temps. push( TempState :: Unpromotable ) , promoted_ref) ;
900
903
904
+ let promoted_operand = promoted_operand ( ref_ty, span) ;
901
905
let promoted_ref_statement = Statement {
902
906
source_info : statement. source_info ,
903
907
kind : StatementKind :: Assign ( Box :: new ( (
904
908
Place :: from ( promoted_ref) ,
905
- Rvalue :: Use ( promoted_operand ( ref_ty , span ) ) ,
909
+ Rvalue :: Use ( Operand :: Constant ( Box :: new ( promoted_operand ) ) ) ,
906
910
) ) ) ,
907
911
} ;
908
912
self . extra_statements . push ( ( loc, promoted_ref_statement) ) ;
909
913
910
- Rvalue :: Ref (
911
- tcx. lifetimes . re_erased ,
912
- * borrow_kind,
913
- Place {
914
- local : mem:: replace ( & mut place. local , promoted_ref) ,
915
- projection : List :: empty ( ) ,
916
- } ,
914
+ (
915
+ Rvalue :: Ref (
916
+ tcx. lifetimes . re_erased ,
917
+ * borrow_kind,
918
+ Place {
919
+ local : mem:: replace ( & mut place. local , promoted_ref) ,
920
+ projection : List :: empty ( ) ,
921
+ } ,
922
+ ) ,
923
+ promoted_operand,
917
924
)
918
925
} ;
919
926
@@ -925,6 +932,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
925
932
926
933
let span = self . promoted . span ;
927
934
self . assign ( RETURN_PLACE , rvalue, span) ;
935
+
936
+ // Now that we did promotion, we know whether we'll want to add this to `required_consts`.
937
+ if self . add_to_required {
938
+ self . source . required_consts . push ( promoted_op) ;
939
+ }
940
+
928
941
self . promoted
929
942
}
930
943
}
@@ -984,6 +997,11 @@ fn promote_candidates<'tcx>(
984
997
None ,
985
998
body. tainted_by_errors ,
986
999
) ;
1000
+ // We keep `required_consts` of the new MIR body empty. All consts mentioned here have
1001
+ // already been added to the parent MIR's `required_consts` (that is computed before
1002
+ // promotion), and no matter where this promoted const ends up, our parent MIR must be
1003
+ // somewhere in the reachable dependency chain so we can rely on its required consts being
1004
+ // evaluated.
987
1005
promoted. phase = MirPhase :: Analysis ( AnalysisPhase :: Initial ) ;
988
1006
989
1007
let promoter = Promoter {
@@ -993,6 +1011,7 @@ fn promote_candidates<'tcx>(
993
1011
temps : & mut temps,
994
1012
extra_statements : & mut extra_statements,
995
1013
keep_original : false ,
1014
+ add_to_required : false ,
996
1015
} ;
997
1016
998
1017
let mut promoted = promoter. promote_candidate ( candidate, promotions. len ( ) ) ;
0 commit comments