Skip to content

Commit 6880fea

Browse files
Double-check conditional constness in MIR
To prevent any conditional constness from leaking through during MIR lowering
1 parent 20c909f commit 6880fea

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

365420
impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
@@ -584,31 +639,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
584639
}
585640
};
586641

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

613649
let mut is_trait = false;
614650
// 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)