@@ -545,75 +545,137 @@ pub fn try_evaluate_const<'tcx>(
545
545
| ty:: ConstKind :: Expr ( _) => Err ( EvaluateConstErr :: HasGenericsOrInfers ) ,
546
546
ty:: ConstKind :: Unevaluated ( uv) => {
547
547
// Postpone evaluation of constants that depend on generic parameters or
548
- // inference variables.
548
+ // inference variables. Also ensure that constants are wf before passing
549
+ // them onto CTFE.
549
550
//
550
- // We use `TypingMode::PostAnalysis` here which is not *technically* correct
551
+ // We use `TypingMode::PostAnalysis` here which is not *technically* correct
551
552
// to be revealing opaque types here as borrowcheck has not run yet. However,
552
553
// CTFE itself uses `TypingMode::PostAnalysis` unconditionally even during
553
554
// typeck and not doing so has a lot of (undesirable) fallout (#101478, #119821).
554
555
// As a result we always use a revealed env when resolving the instance to evaluate.
555
556
//
556
557
// FIXME: `const_eval_resolve_for_typeck` should probably just modify the env itself
557
558
// instead of having this logic here
558
- let ( args, typing_env) = if tcx. features ( ) . generic_const_exprs ( )
559
- && uv. has_non_region_infer ( )
560
- {
561
- // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
562
- // inference variables and generic parameters to show up in `ty::Const` even though the anon const
563
- // does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
564
- match tcx. thir_abstract_const ( uv. def ) {
565
- Ok ( Some ( ct) ) => {
566
- let ct = tcx. expand_abstract_consts ( ct. instantiate ( tcx, uv. args ) ) ;
567
- if let Err ( e) = ct. error_reported ( ) {
568
- return Err ( EvaluateConstErr :: EvaluationFailure ( e) ) ;
569
- } else if ct. has_non_region_infer ( ) || ct. has_non_region_param ( ) {
570
- // If the anon const *does* actually use generic parameters or inference variables from
571
- // the generic arguments provided for it, then we should *not* attempt to evaluate it.
572
- return Err ( EvaluateConstErr :: HasGenericsOrInfers ) ;
573
- } else {
574
- let args = replace_param_and_infer_args_with_placeholder ( tcx, uv. args ) ;
575
- let typing_env = infcx
576
- . typing_env ( tcx. erase_regions ( param_env) )
577
- . with_post_analysis_normalized ( tcx) ;
559
+ let ( args, typing_env) = if tcx. features ( ) . generic_const_exprs ( ) {
560
+ // We handle `generic_const_exprs` separately as reasonable ways of handling constants in the type system
561
+ // completely fall apart under `generic_const_exprs` and makes this whole function Really hard to reason
562
+ // about if you have to consider gce whatsoever.
563
+ //
564
+ // We don't bother trying to ensure GCE constants are WF before passing them to CTFE as it would cause
565
+ // query cycles on almost every single call to this function.
566
+
567
+ if uv. has_non_region_infer ( ) || uv. has_non_region_param ( ) {
568
+ // `feature(generic_const_exprs)` causes anon consts to inherit all parent generics. This can cause
569
+ // inference variables and generic parameters to show up in `ty::Const` even though the anon const
570
+ // does not actually make use of them. We handle this case specially and attempt to evaluate anyway.
571
+ match tcx. thir_abstract_const ( uv. def ) {
572
+ Ok ( Some ( ct) ) => {
573
+ let ct = tcx. expand_abstract_consts ( ct. instantiate ( tcx, uv. args ) ) ;
574
+ if let Err ( e) = ct. error_reported ( ) {
575
+ return Err ( EvaluateConstErr :: EvaluationFailure ( e) ) ;
576
+ } else if ct. has_non_region_infer ( ) || ct. has_non_region_param ( ) {
577
+ // If the anon const *does* actually use generic parameters or inference variables from
578
+ // the generic arguments provided for it, then we should *not* attempt to evaluate it.
579
+ return Err ( EvaluateConstErr :: HasGenericsOrInfers ) ;
580
+ } else {
581
+ let args =
582
+ replace_param_and_infer_args_with_placeholder ( tcx, uv. args ) ;
583
+ let typing_env = infcx
584
+ . typing_env ( tcx. erase_regions ( param_env) )
585
+ . with_post_analysis_normalized ( tcx) ;
586
+ ( args, typing_env)
587
+ }
588
+ }
589
+ Err ( _) | Ok ( None ) => {
590
+ let args = GenericArgs :: identity_for_item ( tcx, uv. def ) ;
591
+ let typing_env = ty:: TypingEnv :: post_analysis ( tcx, uv. def ) ;
578
592
( args, typing_env)
579
593
}
580
594
}
581
- Err ( _ ) | Ok ( None ) => {
582
- let args = GenericArgs :: identity_for_item ( tcx , uv . def ) ;
583
- let typing_env = ty :: TypingEnv :: post_analysis ( tcx, uv . def ) ;
584
- ( args , typing_env )
585
- }
595
+ } else {
596
+ let typing_env = infcx
597
+ . typing_env ( tcx. erase_regions ( param_env ) )
598
+ . with_post_analysis_normalized ( tcx ) ;
599
+ ( uv . args , typing_env )
586
600
}
587
- } else if tcx. def_kind ( uv. def ) == DefKind :: AnonConst && uv. has_non_region_infer ( ) {
601
+ } else if !tcx. features ( ) . min_generic_const_args ( )
602
+ && !tcx. features ( ) . associated_const_equality ( )
603
+ // We check for anon consts so that when `associated_const_equality` bounds are
604
+ // lowered on stable we still handle them correctly to avoid ICEs in CTFE.
605
+ && tcx. def_kind ( uv. def ) == DefKind :: AnonConst
606
+ {
588
607
// FIXME: remove this when `const_evaluatable_unchecked` is a hard error.
589
608
//
590
- // Diagnostics will sometimes replace the identity args of anon consts in
591
- // array repeat expr counts with inference variables so we have to handle this
592
- // even though it is not something we should ever actually encounter.
593
- //
594
- // Array repeat expr counts are allowed to syntactically use generic parameters
595
- // but must not actually depend on them in order to evalaute successfully. This means
596
- // that it is actually fine to evalaute them in their own environment rather than with
597
- // the actually provided generic arguments.
598
- tcx. dcx ( ) . delayed_bug (
599
- "Encountered anon const with inference variable args but no error reported" ,
600
- ) ;
609
+ // Under `min_const_generics` the only place we can encounter generics in type system
610
+ // consts is for the `const_evaluatable_unchecked` future compat lint. We don't care
611
+ // to handle them in important ways (e.g. deferring evaluation) so we handle it separately.
612
+
613
+ if uv. has_non_region_infer ( ) {
614
+ // Diagnostics will sometimes replace the identity args of anon consts in
615
+ // array repeat expr counts with inference variables so we have to handle this
616
+ // even though it is not something we should ever actually encounter.
617
+ //
618
+ // Array repeat expr counts are allowed to syntactically use generic parameters
619
+ // but must not actually depend on them in order to evalaute successfully. This means
620
+ // that it is actually fine to evalaute them in their own environment rather than with
621
+ // the actually provided generic arguments.
622
+ tcx. dcx ( ) . delayed_bug (
623
+ "Encountered anon const with inference variable args but no error reported" ,
624
+ ) ;
625
+ }
601
626
627
+ // Generic arguments to anon consts in the type system are never meaningful under mcg,
628
+ // there either are no arguments or its a repeat count and the arguments must not be
629
+ // depended on for evaluation.
602
630
let args = GenericArgs :: identity_for_item ( tcx, uv. def ) ;
603
631
let typing_env = ty:: TypingEnv :: post_analysis ( tcx, uv. def ) ;
604
632
( args, typing_env)
605
633
} else {
606
- // FIXME: This codepath is reachable under `associated_const_equality` and in the
607
- // future will be reachable by `min_generic_const_args`. We should handle inference
608
- // variables and generic parameters properly instead of doing nothing.
634
+ // We are only dealing with "truly" generic/uninferred constants here:
635
+ // - `generic_const_exprs` has been handled separately in the first if
636
+ // - `min_const_generics` repeat expr count hacks have been handled in the previous if
637
+ //
638
+ // So we are free to simply defer evaluation here. This does assume that `uv.args` has
639
+ // already been normalized.
640
+ if uv. args . has_non_region_param ( ) || uv. args . has_non_region_infer ( ) {
641
+ return Err ( EvaluateConstErr :: HasGenericsOrInfers ) ;
642
+ }
643
+
644
+ // If we are dealing with a fully monomorphic constant then we should ensure that
645
+ // it is well formed as otherwise CTFE will ICE. For the same reasons as with
646
+ // deferring evaluation of generic/uninferred constants, we do not have to worry
647
+ // about `generic_const_expr`
648
+ //
649
+ // This check is done in an empty environment which is a little weird, however, mir
650
+ // bodies with impossible predicates (in an empty environment) are sometimes built as
651
+ // only an `unreachable` terminator which makes evaluating them incorrect even if the
652
+ // impossible pred is satsifiable in this environment.
653
+ if tcx. instantiate_and_check_impossible_predicates ( (
654
+ uv. def ,
655
+ tcx. erase_regions ( uv. args ) ,
656
+ ) ) {
657
+ // We treat these consts as rigid instead of an error or delaying a bug as we may
658
+ // be checking a constant with a trivialy-false where clause that is satisfied from
659
+ // a trivially-false clause in the environment.
660
+ //
661
+ // Delaying a bug would ICE the compiler as we may be in an environment where the
662
+ // impossible pred actually holds.
663
+ //
664
+ // Emitting an error would be wrong as we may be normalizing inside of a probe where
665
+ // an inference variable was inferred to a concrete value resulting in an impossible
666
+ // predicate.
667
+ return Ok ( ct) ;
668
+ }
669
+
609
670
let typing_env = infcx
610
671
. typing_env ( tcx. erase_regions ( param_env) )
611
672
. with_post_analysis_normalized ( tcx) ;
612
673
( uv. args , typing_env)
613
674
} ;
614
- let uv = ty:: UnevaluatedConst :: new ( uv. def , args) ;
615
675
676
+ let uv = ty:: UnevaluatedConst :: new ( uv. def , args) ;
616
677
let erased_uv = tcx. erase_regions ( uv) ;
678
+
617
679
use rustc_middle:: mir:: interpret:: ErrorHandled ;
618
680
match tcx. const_eval_resolve_for_typeck ( typing_env, erased_uv, DUMMY_SP ) {
619
681
Ok ( Ok ( val) ) => Ok ( ty:: Const :: new_value (
@@ -697,7 +759,7 @@ fn replace_param_and_infer_args_with_placeholder<'tcx>(
697
759
args. fold_with ( & mut ReplaceParamAndInferWithPlaceholder { tcx, idx : 0 } )
698
760
}
699
761
700
- /// Normalizes the predicates and checks whether they hold in an empty environment . If this
762
+ /// Normalizes the predicates and checks whether they hold in a given empty . If this
701
763
/// returns true, then either normalize encountered an error or one of the predicates did not
702
764
/// hold. Used when creating vtables to check for unsatisfiable methods. This should not be
703
765
/// used during analysis.
@@ -738,7 +800,7 @@ fn instantiate_and_check_impossible_predicates<'tcx>(
738
800
// Specifically check trait fulfillment to avoid an error when trying to resolve
739
801
// associated items.
740
802
if let Some ( trait_def_id) = tcx. trait_of_item ( key. 0 ) {
741
- let trait_ref = ty:: TraitRef :: from_method ( tcx, trait_def_id, key. 1 ) ;
803
+ let trait_ref = ty:: TraitRef :: from_assoc_args ( tcx, trait_def_id, key. 1 ) ;
742
804
predicates. push ( trait_ref. upcast ( tcx) ) ;
743
805
}
744
806
0 commit comments