@@ -18,6 +18,7 @@ use rustc_const_eval::check_consts::{ConstCx, qualifs};
1818use rustc_data_structures:: assert_matches;
1919use rustc_data_structures:: fx:: FxHashSet ;
2020use rustc_hir as hir;
21+ use rustc_hir:: def:: DefKind ;
2122use rustc_index:: { IndexSlice , IndexVec } ;
2223use rustc_middle:: mir:: visit:: { MutVisitor , MutatingUseContext , PlaceContext , Visitor } ;
2324use rustc_middle:: mir:: * ;
@@ -329,6 +330,7 @@ impl<'tcx> Validator<'_, 'tcx> {
329330 if let TempState :: Defined { location : loc, .. } = self . temps [ local]
330331 && let Left ( statement) = self . body . stmt_at ( loc)
331332 && let Some ( ( _, Rvalue :: Use ( Operand :: Constant ( c) ) ) ) = statement. kind . as_assign ( )
333+ && self . should_evaluate_for_promotion_checks ( c. const_ )
332334 && let Some ( idx) = c. const_ . try_eval_target_usize ( self . tcx , self . typing_env )
333335 // Determine the type of the thing we are indexing.
334336 && let ty:: Array ( _, len) = place_base. ty ( self . body , self . tcx ) . ty . kind ( )
@@ -484,7 +486,9 @@ impl<'tcx> Validator<'_, 'tcx> {
484486 let sz = lhs_ty. primitive_size ( self . tcx ) ;
485487 // Integer division: the RHS must be a non-zero const.
486488 let rhs_val = match rhs {
487- Operand :: Constant ( c) => {
489+ Operand :: Constant ( c)
490+ if self . should_evaluate_for_promotion_checks ( c. const_ ) =>
491+ {
488492 c. const_ . try_eval_scalar_int ( self . tcx , self . typing_env )
489493 }
490494 _ => None ,
@@ -502,9 +506,14 @@ impl<'tcx> Validator<'_, 'tcx> {
502506 // The RHS is -1 or unknown, so we have to be careful.
503507 // But is the LHS int::MIN?
504508 let lhs_val = match lhs {
505- Operand :: Constant ( c) => c
506- . const_
507- . try_eval_scalar_int ( self . tcx , self . typing_env ) ,
509+ Operand :: Constant ( c)
510+ if self . should_evaluate_for_promotion_checks (
511+ c. const_ ,
512+ ) =>
513+ {
514+ c. const_
515+ . try_eval_scalar_int ( self . tcx , self . typing_env )
516+ }
508517 _ => None ,
509518 } ;
510519 let lhs_min = sz. signed_int_min ( ) ;
@@ -683,6 +692,28 @@ impl<'tcx> Validator<'_, 'tcx> {
683692 // This passed all checks, so let's accept.
684693 Ok ( ( ) )
685694 }
695+
696+ /// Can we try to evaluate a given constant at this point in compilation? Attempting to evaluate
697+ /// a const block before borrow-checking will result in a query cycle (#150464).
698+ fn should_evaluate_for_promotion_checks ( & self , constant : Const < ' tcx > ) -> bool {
699+ match constant {
700+ // `Const::Ty` is always a `ConstKind::Param` right now and that can never be turned
701+ // into a mir value for promotion
702+ // FIXME(mgca): do we want uses of type_const to be normalized during promotion?
703+ Const :: Ty ( ..) => false ,
704+ Const :: Val ( ..) => true ,
705+ // Evaluating a MIR constant requires borrow-checking it. For inline consts, as of
706+ // #138499, this means borrow-checking its typeck root. Since borrow-checking the
707+ // typeck root requires promoting its constants, trying to evaluate an inline const here
708+ // will result in a query cycle. To avoid the cycle, we can't evaluate const blocks yet.
709+ // Other kinds of unevaluated's can cause query cycles too when they arise from
710+ // self-reference in user code; e.g. evaluating a constant can require evaluating a
711+ // const function that uses that constant, again requiring evaluation of the constant.
712+ // However, this form of cycle renders both the constant and function unusable in
713+ // general, so we don't need to special-case it here.
714+ Const :: Unevaluated ( uc, _) => self . tcx . def_kind ( uc. def ) != DefKind :: InlineConst ,
715+ }
716+ }
686717}
687718
688719fn validate_candidates (
0 commit comments