Skip to content

Commit 964af99

Browse files
Double-check conditional constness in MIR
To prevent any conditional constness from leaking through during MIR lowering
1 parent 9f57edf commit 964af99

File tree

3 files changed

+72
-29
lines changed

3 files changed

+72
-29
lines changed

compiler/rustc_const_eval/src/check_consts/check.rs

+62-26
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ use rustc_hir::def_id::DefId;
1111
use rustc_hir::{self as hir, LangItem};
1212
use rustc_index::bit_set::BitSet;
1313
use rustc_infer::infer::TyCtxtInferExt;
14-
use rustc_infer::traits::ObligationCause;
1514
use rustc_middle::mir::visit::Visitor;
1615
use rustc_middle::mir::*;
1716
use rustc_middle::span_bug;
@@ -20,9 +19,11 @@ use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TypeVisitableExt};
2019
use rustc_mir_dataflow::Analysis;
2120
use rustc_mir_dataflow::impls::MaybeStorageLive;
2221
use rustc_mir_dataflow::storage::always_storage_live_locals;
23-
use rustc_span::{DUMMY_SP, Span, Symbol, sym};
22+
use rustc_span::{Span, Symbol, sym};
2423
use rustc_trait_selection::error_reporting::InferCtxtErrorExt;
25-
use rustc_trait_selection::traits::{self, ObligationCauseCode, ObligationCtxt};
24+
use rustc_trait_selection::traits::{
25+
Obligation, ObligationCause, ObligationCauseCode, ObligationCtxt,
26+
};
2627
use tracing::{debug, instrument, trace};
2728

2829
use super::ops::{self, NonConstOp, Status};
@@ -364,6 +365,60 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
364365
// end of evaluation.
365366
!is_transient
366367
}
368+
369+
fn revalidate_conditional_constness(
370+
&self,
371+
callee: DefId,
372+
callee_args: ty::GenericArgsRef<'tcx>,
373+
call_source: CallSource,
374+
call_span: Span,
375+
) {
376+
let tcx = self.tcx;
377+
if !tcx.is_conditionally_const(callee) {
378+
return;
379+
}
380+
381+
let infcx = tcx.infer_ctxt().build();
382+
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
383+
384+
let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
385+
386+
let body_id = self.body.source.def_id().expect_local();
387+
let host_polarity = match self.const_kind() {
388+
hir::ConstContext::ConstFn => ty::HostPolarity::Maybe,
389+
hir::ConstContext::Static(_) | hir::ConstContext::Const { .. } => {
390+
ty::HostPolarity::Const
391+
}
392+
};
393+
let const_conditions = ocx.normalize(
394+
&ObligationCause::misc(call_span, body_id),
395+
self.param_env,
396+
const_conditions,
397+
);
398+
ocx.register_obligations(const_conditions.into_iter().map(|(trait_ref, span)| {
399+
Obligation::new(
400+
tcx,
401+
ObligationCause::new(
402+
call_span,
403+
body_id,
404+
ObligationCauseCode::WhereClause(callee, span),
405+
),
406+
self.param_env,
407+
trait_ref.to_host_effect_clause(tcx, host_polarity),
408+
)
409+
}));
410+
411+
let errors = ocx.select_all_or_error();
412+
if !errors.is_empty() {
413+
// FIXME(effects): Soon this should be unconditionally delaying a bug.
414+
if matches!(call_source, CallSource::Normal) && tcx.features().effects() {
415+
tcx.dcx()
416+
.span_delayed_bug(call_span, "this should have reported a ~const error in HIR");
417+
} else {
418+
infcx.err_ctxt().report_fulfillment_errors(errors);
419+
}
420+
}
421+
}
367422
}
368423

369424
impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
@@ -588,31 +643,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
588643
}
589644
};
590645

591-
// Check that all trait bounds that are marked as `~const` can be satisfied.
592-
//
593-
// Typeck only does a "non-const" check since it operates on HIR and cannot distinguish
594-
// which path expressions are getting called on and which path expressions are only used
595-
// as function pointers. This is required for correctness.
596-
let infcx = tcx.infer_ctxt().build();
597-
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
598-
599-
let predicates = tcx.predicates_of(callee).instantiate(tcx, fn_args);
600-
let cause = ObligationCause::new(
646+
self.revalidate_conditional_constness(
647+
callee,
648+
fn_args,
649+
call_source,
601650
terminator.source_info.span,
602-
self.body.source.def_id().expect_local(),
603-
ObligationCauseCode::WhereClause(callee, DUMMY_SP),
604651
);
605-
let normalized_predicates = ocx.normalize(&cause, param_env, predicates);
606-
ocx.register_obligations(traits::predicates_for_generics(
607-
|_, _| cause.clone(),
608-
self.param_env,
609-
normalized_predicates,
610-
));
611-
612-
let errors = ocx.select_all_or_error();
613-
if !errors.is_empty() {
614-
infcx.err_ctxt().report_fulfillment_errors(errors);
615-
}
616652

617653
let mut is_trait = false;
618654
// Attempting to call a trait method?

tests/ui/traits/const-traits/cross-crate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ const fn const_context() {
1818
#[cfg(any(stocknc, gatednc))]
1919
NonConst.func();
2020
//[stocknc]~^ ERROR: cannot call
21-
//[gatednc]~^^ ERROR: the trait bound
21+
//[stocknc,gatednc]~^^ ERROR: the trait bound
2222
Const.func();
2323
//[stock]~^ ERROR: cannot call
2424
//[stocknc]~^^ ERROR: cannot call

tests/ui/traits/const-traits/cross-crate.stocknc.stderr

+9-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
error[E0277]: the trait bound `cross_crate::NonConst: ~const cross_crate::MyTrait` is not satisfied
2+
--> $DIR/cross-crate.rs:19:5
3+
|
4+
LL | NonConst.func();
5+
| ^^^^^^^^^^^^^^^
6+
17
error[E0015]: cannot call non-const fn `<cross_crate::NonConst as cross_crate::MyTrait>::func` in constant functions
28
--> $DIR/cross-crate.rs:19:14
39
|
@@ -22,6 +28,7 @@ help: add `#![feature(const_trait_impl)]` to the crate attributes to enable
2228
LL + #![feature(const_trait_impl)]
2329
|
2430

25-
error: aborting due to 2 previous errors
31+
error: aborting due to 3 previous errors
2632

27-
For more information about this error, try `rustc --explain E0015`.
33+
Some errors have detailed explanations: E0015, E0277.
34+
For more information about an error, try `rustc --explain E0015`.

0 commit comments

Comments
 (0)