@@ -687,7 +687,6 @@ impl<'tcx> Validator<'_, 'tcx> {
687687 }
688688}
689689
690- // FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
691690fn validate_candidates (
692691 ccx : & ConstCx < ' _ , ' _ > ,
693692 temps : & mut IndexSlice < Local , TempState > ,
@@ -712,6 +711,10 @@ struct Promoter<'a, 'tcx> {
712711 /// If true, all nested temps are also kept in the
713712 /// source MIR, not moved to the promoted MIR.
714713 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 ,
715718}
716719
717720impl < ' a , ' tcx > Promoter < ' a , ' tcx > {
@@ -814,6 +817,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
814817 TerminatorKind :: Call {
815818 mut func, mut args, call_source : desugar, fn_span, ..
816819 } => {
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+
817824 self . visit_operand ( & mut func, loc) ;
818825 for arg in & mut args {
819826 self . visit_operand ( & mut arg. node , loc) ;
@@ -848,7 +855,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
848855
849856 fn promote_candidate ( mut self , candidate : Candidate , next_promoted_id : usize ) -> Body < ' tcx > {
850857 let def = self . source . source . def_id ( ) ;
851- let mut rvalue = {
858+ let ( mut rvalue, promoted_op ) = {
852859 let promoted = & mut self . promoted ;
853860 let promoted_id = Promoted :: new ( next_promoted_id) ;
854861 let tcx = self . tcx ;
@@ -858,11 +865,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
858865 let args = tcx. erase_regions ( GenericArgs :: identity_for_item ( tcx, def) ) ;
859866 let uneval = mir:: UnevaluatedConst { def, args, promoted : Some ( promoted_id) } ;
860867
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) }
866869 } ;
867870
868871 let blocks = self . source . basic_blocks . as_mut ( ) ;
@@ -895,22 +898,26 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
895898 let promoted_ref = local_decls. push ( promoted_ref) ;
896899 assert_eq ! ( self . temps. push( TempState :: Unpromotable ) , promoted_ref) ;
897900
901+ let promoted_operand = promoted_operand ( ref_ty, span) ;
898902 let promoted_ref_statement = Statement {
899903 source_info : statement. source_info ,
900904 kind : StatementKind :: Assign ( Box :: new ( (
901905 Place :: from ( promoted_ref) ,
902- Rvalue :: Use ( promoted_operand ( ref_ty , span ) ) ,
906+ Rvalue :: Use ( Operand :: Constant ( Box :: new ( promoted_operand ) ) ) ,
903907 ) ) ) ,
904908 } ;
905909 self . extra_statements . push ( ( loc, promoted_ref_statement) ) ;
906910
907- Rvalue :: Ref (
908- tcx. lifetimes . re_erased ,
909- * borrow_kind,
910- Place {
911- local : mem:: replace ( & mut place. local , promoted_ref) ,
912- projection : List :: empty ( ) ,
913- } ,
911+ (
912+ Rvalue :: Ref (
913+ tcx. lifetimes . re_erased ,
914+ * borrow_kind,
915+ Place {
916+ local : mem:: replace ( & mut place. local , promoted_ref) ,
917+ projection : List :: empty ( ) ,
918+ } ,
919+ ) ,
920+ promoted_operand,
914921 )
915922 } ;
916923
@@ -922,6 +929,12 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
922929
923930 let span = self . promoted . span ;
924931 self . assign ( RETURN_PLACE , rvalue, span) ;
932+
933+ // Now that we did promotion, we know whether we'll want to add this to `required_consts`.
934+ if self . add_to_required {
935+ self . source . required_consts . push ( promoted_op) ;
936+ }
937+
925938 self . promoted
926939 }
927940}
@@ -981,6 +994,11 @@ fn promote_candidates<'tcx>(
981994 None ,
982995 body. tainted_by_errors ,
983996 ) ;
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.
9841002 promoted. phase = MirPhase :: Analysis ( AnalysisPhase :: Initial ) ;
9851003
9861004 let promoter = Promoter {
@@ -990,6 +1008,7 @@ fn promote_candidates<'tcx>(
9901008 temps : & mut temps,
9911009 extra_statements : & mut extra_statements,
9921010 keep_original : false ,
1011+ add_to_required : false ,
9931012 } ;
9941013
9951014 let mut promoted = promoter. promote_candidate ( candidate, promotions. len ( ) ) ;
0 commit comments