Skip to content

Commit ed9f230

Browse files
committed
Don't evaluate constants depending on infers or params
1 parent 3a95d63 commit ed9f230

File tree

1 file changed

+64
-42
lines changed
  • compiler/rustc_trait_selection/src/traits

1 file changed

+64
-42
lines changed

compiler/rustc_trait_selection/src/traits/mod.rs

+64-42
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ pub fn try_evaluate_const<'tcx>(
545545
// Postpone evaluation of constants that depend on generic parameters or
546546
// inference variables.
547547
//
548-
// We use `TypingMode::PostAnalysis` here which is not *technically* correct
548+
// We use `TypingMode::PostAnalysis` here which is not *technically* correct
549549
// to be revealing opaque types here as borrowcheck has not run yet. However,
550550
// CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during
551551
// typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821).
@@ -555,68 +555,90 @@ pub fn try_evaluate_const<'tcx>(
555555
// instead of having this logic here
556556
let (args, typing_env) = if tcx.def_kind(uv.def) == DefKind::AnonConst
557557
&& let ty::AnonConstKind::GCEConst = tcx.anon_const_kind(uv.def)
558-
&& uv.has_non_region_infer()
559558
{
560-
// `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
561-
// inference variables and generic parameters to show up in `ty::Const` even though the anon const
562-
// does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
563-
match tcx.thir_abstract_const(uv.def) {
564-
Ok(Some(ct)) => {
565-
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
566-
if let Err(e) = ct.error_reported() {
567-
return Err(EvaluateConstErr::EvaluationFailure(e));
568-
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
569-
// If the anon const *does* actually use generic parameters or inference variables from
570-
// the generic arguments provided for it, then we should *not* attempt to evaluate it.
571-
return Err(EvaluateConstErr::HasGenericsOrInfers);
572-
} else {
573-
let args = replace_param_and_infer_args_with_placeholder(tcx, uv.args);
574-
let typing_env = infcx
575-
.typing_env(tcx.erase_regions(param_env))
576-
.with_post_analysis_normalized(tcx);
559+
// We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system
560+
// completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason
561+
// about if you have to consider gce whatsoever.
562+
563+
if uv.has_non_region_infer() || uv.has_non_region_param() {
564+
// `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
565+
// inference variables and generic parameters to show up in `ty::Const` even though the anon const
566+
// does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
567+
match tcx.thir_abstract_const(uv.def) {
568+
Ok(Some(ct)) => {
569+
let ct = tcx.expand_abstract_consts(ct.instantiate(tcx, uv.args));
570+
if let Err(e) = ct.error_reported() {
571+
return Err(EvaluateConstErr::EvaluationFailure(e));
572+
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
573+
// If the anon const *does* actually use generic parameters or inference variables from
574+
// the generic arguments provided for it, then we should *not* attempt to evaluate it.
575+
return Err(EvaluateConstErr::HasGenericsOrInfers);
576+
} else {
577+
let args =
578+
replace_param_and_infer_args_with_placeholder(tcx, uv.args);
579+
let typing_env = infcx
580+
.typing_env(tcx.erase_regions(param_env))
581+
.with_post_analysis_normalized(tcx);
582+
(args, typing_env)
583+
}
584+
}
585+
Err(_) | Ok(None) => {
586+
let args = GenericArgs::identity_for_item(tcx, uv.def);
587+
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
577588
(args, typing_env)
578589
}
579590
}
580-
Err(_) | Ok(None) => {
581-
let args = GenericArgs::identity_for_item(tcx, uv.def);
582-
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
583-
(args, typing_env)
584-
}
591+
} else {
592+
let typing_env = infcx
593+
.typing_env(tcx.erase_regions(param_env))
594+
.with_post_analysis_normalized(tcx);
595+
(uv.args, typing_env)
585596
}
586597
} else if tcx.def_kind(uv.def) == DefKind::AnonConst
587598
&& let ty::AnonConstKind::RepeatExprCount = tcx.anon_const_kind(uv.def)
588-
&& uv.has_non_region_infer()
589599
{
590-
// FIXME: remove this when `const_evaluatable_unchecked` is a hard error.
591-
//
592-
// Diagnostics will sometimes replace the identity args of anon consts in
593-
// array repeat expr counts with inference variables so we have to handle this
594-
// even though it is not something we should ever actually encounter.
595-
//
596-
// Array repeat expr counts are allowed to syntactically use generic parameters
597-
// but must not actually depend on them in order to evalaute successfully. This means
598-
// that it is actually fine to evalaute them in their own environment rather than with
599-
// the actually provided generic arguments.
600-
tcx.dcx().delayed_bug(
601-
"Encountered anon const with inference variable args but no error reported",
602-
);
600+
if uv.has_non_region_infer() {
601+
// Diagnostics will sometimes replace the identity args of anon consts in
602+
// array repeat expr counts with inference variables so we have to handle this
603+
// even though it is not something we should ever actually encounter.
604+
//
605+
// Array repeat expr counts are allowed to syntactically use generic parameters
606+
// but must not actually depend on them in order to evalaute successfully. This means
607+
// that it is actually fine to evalaute them in their own environment rather than with
608+
// the actually provided generic arguments.
609+
tcx.dcx().delayed_bug(
610+
"Encountered anon const with inference variable args but no error reported",
611+
);
612+
}
603613

614+
// The generic args of repeat expr counts under `min_const_generics` are not supposed to
615+
// affect evaluation of the constant as this would make it a "truly" generic const arg.
616+
// To prevent this we discard all the generic arguments and evalaute with identity args
617+
// and in its own environment instead of the current environment we are normalizing in.
604618
let args = GenericArgs::identity_for_item(tcx, uv.def);
605619
let typing_env = ty::TypingEnv::post_analysis(tcx, uv.def);
606620

607621
(args, typing_env)
608622
} else {
609-
// FIXME: This codepath is reachable under `associated_const_equality` and in the
610-
// future will be reachable by `min_generic_const_args`. We should handle inference
611-
// variables and generic parameters properly instead of doing nothing.
623+
// We are only dealing with "truly" generic/uninferred constants here:
624+
// - GCEConsts have been handled separately
625+
// - Repeat expr count back compat consts have also been handled separately
626+
// So we are free to simply defer evaluation here.
627+
//
628+
// FIXME: This assumes that `args` are normalized which is not necessarily true
629+
if uv.args.has_non_region_param() || uv.args.has_non_region_infer() {
630+
return Err(EvaluateConstErr::HasGenericsOrInfers);
631+
}
632+
612633
let typing_env = infcx
613634
.typing_env(tcx.erase_regions(param_env))
614635
.with_post_analysis_normalized(tcx);
615636
(uv.args, typing_env)
616637
};
617-
let uv = ty::UnevaluatedConst::new(uv.def, args);
618638

639+
let uv = ty::UnevaluatedConst::new(uv.def, args);
619640
let erased_uv = tcx.erase_regions(uv);
641+
620642
use rustc_middle::mir::interpret::ErrorHandled;
621643
match tcx.const_eval_resolve_for_typeck(typing_env, erased_uv, DUMMY_SP) {
622644
Ok(Ok(val)) => Ok(ty::Const::new_value(

0 commit comments

Comments
 (0)