Completely deny calling functions with const conditions in MIR const check unless const_trait_impl is enabled
This will help us make sure that we never leak any conditionally const functions into stable.
This commit is contained in:
parent
e319838e8d
commit
57f2e12f4a
13 changed files with 132 additions and 44 deletions
|
@ -363,7 +363,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
fn revalidate_conditional_constness(
|
||||
&self,
|
||||
&mut self,
|
||||
callee: DefId,
|
||||
callee_args: ty::GenericArgsRef<'tcx>,
|
||||
call_source: CallSource,
|
||||
|
@ -374,11 +374,24 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
|
|||
return;
|
||||
}
|
||||
|
||||
let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
|
||||
// If there are any const conditions on this fn and `const_trait_impl`
|
||||
// is not enabled, simply bail. We shouldn't be able to call conditionally
|
||||
// const functions on stable.
|
||||
if !const_conditions.is_empty() && !tcx.features().const_trait_impl() {
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
callee,
|
||||
args: callee_args,
|
||||
span: call_span,
|
||||
call_source,
|
||||
feature: Some(sym::const_trait_impl),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let infcx = tcx.infer_ctxt().build(self.body.typing_mode(tcx));
|
||||
let ocx = ObligationCtxt::new_with_diagnostics(&infcx);
|
||||
|
||||
let const_conditions = tcx.const_conditions(callee).instantiate(tcx, callee_args);
|
||||
|
||||
let body_id = self.body.source.def_id().expect_local();
|
||||
let host_polarity = match self.const_kind() {
|
||||
hir::ConstContext::ConstFn => ty::BoundConstness::Maybe,
|
||||
|
@ -621,7 +634,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
};
|
||||
|
||||
let ConstCx { tcx, body, param_env, .. } = *self.ccx;
|
||||
let caller = self.def_id();
|
||||
|
||||
let fn_ty = func.ty(body, tcx);
|
||||
|
||||
|
@ -639,12 +651,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
}
|
||||
};
|
||||
|
||||
self.revalidate_conditional_constness(
|
||||
callee,
|
||||
fn_args,
|
||||
call_source,
|
||||
terminator.source_info.span,
|
||||
);
|
||||
self.revalidate_conditional_constness(callee, fn_args, call_source, *fn_span);
|
||||
|
||||
let mut is_trait = false;
|
||||
// Attempting to call a trait method?
|
||||
|
@ -684,7 +691,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
None
|
||||
};
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
caller,
|
||||
callee,
|
||||
args: fn_args,
|
||||
span: *fn_span,
|
||||
|
@ -774,7 +780,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
|||
// Trait functions are not `const fn` so we have to skip them here.
|
||||
if !tcx.is_const_fn(callee) && !is_trait {
|
||||
self.check_op(ops::FnCallNonConst {
|
||||
caller,
|
||||
callee,
|
||||
args: fn_args,
|
||||
span: *fn_span,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
//! Concrete error types for all operations which may be invalid in a certain const context.
|
||||
|
||||
use hir::def_id::LocalDefId;
|
||||
use hir::{ConstContext, LangItem};
|
||||
use rustc_errors::Diag;
|
||||
use rustc_errors::codes::*;
|
||||
|
@ -74,7 +73,6 @@ impl<'tcx> NonConstOp<'tcx> for FnCallIndirect {
|
|||
/// A function call where the callee is not marked as `const`.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub(crate) struct FnCallNonConst<'tcx> {
|
||||
pub caller: LocalDefId,
|
||||
pub callee: DefId,
|
||||
pub args: GenericArgsRef<'tcx>,
|
||||
pub span: Span,
|
||||
|
@ -87,8 +85,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
#[allow(rustc::diagnostic_outside_of_impl)]
|
||||
#[allow(rustc::untranslatable_diagnostic)]
|
||||
fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, _: Span) -> Diag<'tcx> {
|
||||
let FnCallNonConst { caller, callee, args, span, call_source, feature } = *self;
|
||||
let ConstCx { tcx, param_env, body, .. } = *ccx;
|
||||
let FnCallNonConst { callee, args, span, call_source, feature } = *self;
|
||||
let ConstCx { tcx, param_env, .. } = *ccx;
|
||||
let caller = ccx.def_id();
|
||||
|
||||
let diag_trait = |err, self_ty: Ty<'_>, trait_id| {
|
||||
let trait_ref = TraitRef::from_method(tcx, trait_id, args);
|
||||
|
@ -116,7 +115,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
let obligation =
|
||||
Obligation::new(tcx, ObligationCause::dummy(), param_env, trait_ref);
|
||||
|
||||
let infcx = tcx.infer_ctxt().build(body.typing_mode(tcx));
|
||||
let infcx = tcx.infer_ctxt().build(ccx.body.typing_mode(tcx));
|
||||
let mut selcx = SelectionContext::new(&infcx);
|
||||
let implsrc = selcx.select(&obligation);
|
||||
|
||||
|
@ -289,7 +288,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
|
|||
if let Some(feature) = feature {
|
||||
ccx.tcx.disabled_nightly_features(
|
||||
&mut err,
|
||||
body.source.def_id().as_local().map(|local| ccx.tcx.local_def_id_to_hir_id(local)),
|
||||
Some(ccx.tcx.local_def_id_to_hir_id(caller)),
|
||||
[(String::new(), feature)],
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue