@@ -15,7 +15,7 @@ use rustc_middle::mir::visit::Visitor;
15
15
use rustc_middle::mir::*;
16
16
use rustc_middle::span_bug;
17
17
use rustc_middle::ty::adjustment::PointerCoercion;
18
- use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
18
+ use rustc_middle::ty::{self, Ty, TypeVisitableExt};
19
19
use rustc_mir_dataflow::Analysis;
20
20
use rustc_mir_dataflow::impls::MaybeStorageLive;
21
21
use rustc_mir_dataflow::storage::always_storage_live_locals;
@@ -361,31 +361,21 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
361
361
!is_transient
362
362
}
363
363
364
+ /// Returns whether there are const-conditions.
364
365
fn revalidate_conditional_constness(
365
366
&mut self,
366
367
callee: DefId,
367
368
callee_args: ty::GenericArgsRef<'tcx>,
368
- call_source: CallSource,
369
369
call_span: Span,
370
- ) {
370
+ ) -> bool {
371
371
let tcx = self.tcx;
372
372
if !tcx.is_conditionally_const(callee) {
373
- return;
373
+ return false ;
374
374
}
375
375
376
376
let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
377
- // If there are any const conditions on this fn and `const_trait_impl`
378
- // is not enabled, simply bail. We shouldn't be able to call conditionally
379
- // const functions on stable.
380
- if !const_conditions.is_empty() && !tcx.features().const_trait_impl() {
381
- self.check_op(ops::FnCallNonConst {
382
- callee,
383
- args: callee_args,
384
- span: call_span,
385
- call_source,
386
- feature: Some(sym::const_trait_impl),
387
- });
388
- return;
377
+ if const_conditions.is_empty() {
378
+ return false;
389
379
}
390
380
391
381
let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx));
@@ -421,6 +411,8 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
421
411
tcx.dcx()
422
412
.span_delayed_bug(call_span, "this should have reported a ~const error in HIR");
423
413
}
414
+
415
+ true
424
416
}
425
417
}
426
418
@@ -627,11 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
627
619
_ => unreachable!(),
628
620
};
629
621
630
- let ConstCx { tcx, body, param_env, .. } = *self.ccx;
622
+ let ConstCx { tcx, body, .. } = *self.ccx;
631
623
632
624
let fn_ty = func.ty(body, tcx);
633
625
634
- let (mut callee, mut fn_args) = match *fn_ty.kind() {
626
+ let (callee, fn_args) = match *fn_ty.kind() {
635
627
ty::FnDef(def_id, fn_args) => (def_id, fn_args),
636
628
637
629
ty::FnPtr(..) => {
@@ -645,57 +637,38 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
645
637
}
646
638
};
647
639
648
- self.revalidate_conditional_constness(callee, fn_args, call_source, *fn_span);
640
+ let has_const_conditions =
641
+ self.revalidate_conditional_constness(callee, fn_args, *fn_span);
649
642
650
- let mut is_trait = false;
651
643
// Attempting to call a trait method?
652
644
if let Some(trait_did) = tcx.trait_of_item(callee) {
653
- trace!("attempting to call a trait method");
645
+ // We can't determine the actual callee here, so we have to do different checks
646
+ // than usual.
654
647
648
+ trace!("attempting to call a trait method");
655
649
let trait_is_const = tcx.is_const_trait(trait_did);
656
- // trait method calls are only permitted when `effects` is enabled.
657
- // typeck ensures the conditions for calling a const trait method are met,
658
- // so we only error if the trait isn't const. We try to resolve the trait
659
- // into the concrete method, and uses that for const stability checks.
660
- // FIXME(const_trait_impl) we might consider moving const stability checks
661
- // to typeck as well.
662
- if tcx.features().const_trait_impl() && trait_is_const {
663
- // This skips the check below that ensures we only call `const fn`.
664
- is_trait = true;
665
-
666
- if let Ok(Some(instance)) =
667
- Instance::try_resolve(tcx, param_env, callee, fn_args)
668
- && let InstanceKind::Item(def) = instance.def
669
- {
670
- // Resolve a trait method call to its concrete implementation, which may be in a
671
- // `const` trait impl. This is only used for the const stability check below, since
672
- // we want to look at the concrete impl's stability.
673
- fn_args = instance.args;
674
- callee = def;
675
- }
650
+
651
+ if trait_is_const {
652
+ // Trait calls are always conditionally-const.
653
+ self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
654
+ // FIXME(const_trait_impl): do a more fine-grained check whether this
655
+ // particular trait can be const-stably called.
676
656
} else {
677
- // if the trait is const but the user has not enabled the feature(s),
678
- // suggest them.
679
- let feature = if trait_is_const {
680
- Some(if tcx.features().const_trait_impl() {
681
- sym::effects
682
- } else {
683
- sym::const_trait_impl
684
- })
685
- } else {
686
- None
687
- };
657
+ // Not even a const trait.
688
658
self.check_op(ops::FnCallNonConst {
689
659
callee,
690
660
args: fn_args,
691
661
span: *fn_span,
692
662
call_source,
693
- feature,
694
663
});
695
- // If we allowed this, we're in miri-unleashed mode, so we might
696
- // as well skip the remaining checks.
697
- return;
698
664
}
665
+ // That's all we can check here.
666
+ return;
667
+ }
668
+
669
+ // Even if we know the callee, ensure we can use conditionally-const calls.
670
+ if has_const_conditions {
671
+ self.check_op(ops::ConditionallyConstCall { callee, args: fn_args });
699
672
}
700
673
701
674
// At this point, we are calling a function, `callee`, whose `DefId` is known...
@@ -783,14 +756,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
783
756
return;
784
757
}
785
758
786
- // Trait functions are not `const fn` so we have to skip them here.
787
- if !tcx.is_const_fn(callee) && !is_trait {
759
+ if !tcx.is_const_fn(callee) {
788
760
self.check_op(ops::FnCallNonConst {
789
761
callee,
790
762
args: fn_args,
791
763
span: *fn_span,
792
764
call_source,
793
- feature: None,
794
765
});
795
766
// If we allowed this, we're in miri-unleashed mode, so we might
796
767
// as well skip the remaining checks.
0 commit comments