Add a fast path for lowering trivial consts
This commit is contained in:
@@ -7,7 +7,7 @@ use rustc_hir::def::DefKind;
|
|||||||
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo};
|
use rustc_middle::mir::interpret::{AllocId, ErrorHandled, InterpErrorInfo, ReportedErrorInfo};
|
||||||
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
|
use rustc_middle::mir::{self, ConstAlloc, ConstValue};
|
||||||
use rustc_middle::query::TyCtxtAt;
|
use rustc_middle::query::TyCtxtAt;
|
||||||
use rustc_middle::ty::layout::HasTypingEnv;
|
use rustc_middle::ty::layout::{HasTypingEnv, TyAndLayout};
|
||||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||||
use rustc_middle::{bug, throw_inval};
|
use rustc_middle::{bug, throw_inval};
|
||||||
@@ -24,13 +24,11 @@ use crate::interpret::{
|
|||||||
};
|
};
|
||||||
use crate::{CTRL_C_RECEIVED, errors};
|
use crate::{CTRL_C_RECEIVED, errors};
|
||||||
|
|
||||||
// Returns a pointer to where the result lives
|
fn setup_for_eval<'tcx>(
|
||||||
#[instrument(level = "trace", skip(ecx, body))]
|
|
||||||
fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
|
|
||||||
ecx: &mut CompileTimeInterpCx<'tcx>,
|
ecx: &mut CompileTimeInterpCx<'tcx>,
|
||||||
cid: GlobalId<'tcx>,
|
cid: GlobalId<'tcx>,
|
||||||
body: &'tcx mir::Body<'tcx>,
|
layout: TyAndLayout<'tcx>,
|
||||||
) -> InterpResult<'tcx, R> {
|
) -> InterpResult<'tcx, (InternKind, MPlaceTy<'tcx>)> {
|
||||||
let tcx = *ecx.tcx;
|
let tcx = *ecx.tcx;
|
||||||
assert!(
|
assert!(
|
||||||
cid.promoted.is_some()
|
cid.promoted.is_some()
|
||||||
@@ -46,7 +44,6 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
|
|||||||
"Unexpected DefKind: {:?}",
|
"Unexpected DefKind: {:?}",
|
||||||
ecx.tcx.def_kind(cid.instance.def_id())
|
ecx.tcx.def_kind(cid.instance.def_id())
|
||||||
);
|
);
|
||||||
let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?;
|
|
||||||
assert!(layout.is_sized());
|
assert!(layout.is_sized());
|
||||||
|
|
||||||
let intern_kind = if cid.promoted.is_some() {
|
let intern_kind = if cid.promoted.is_some() {
|
||||||
@@ -58,12 +55,25 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let ret = if let InternKind::Static(_) = intern_kind {
|
let return_place = if let InternKind::Static(_) = intern_kind {
|
||||||
create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout)?
|
create_static_alloc(ecx, cid.instance.def_id().expect_local(), layout)
|
||||||
} else {
|
} else {
|
||||||
ecx.allocate(layout, MemoryKind::Stack)?
|
ecx.allocate(layout, MemoryKind::Stack)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return_place.map(|ret| (intern_kind, ret))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(ecx, body))]
|
||||||
|
fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
|
||||||
|
ecx: &mut CompileTimeInterpCx<'tcx>,
|
||||||
|
cid: GlobalId<'tcx>,
|
||||||
|
body: &'tcx mir::Body<'tcx>,
|
||||||
|
) -> InterpResult<'tcx, R> {
|
||||||
|
let tcx = *ecx.tcx;
|
||||||
|
let layout = ecx.layout_of(body.bound_return_ty().instantiate(tcx, cid.instance.args))?;
|
||||||
|
let (intern_kind, ret) = setup_for_eval(ecx, cid, layout)?;
|
||||||
|
|
||||||
trace!(
|
trace!(
|
||||||
"eval_body_using_ecx: pushing stack frame for global: {}{}",
|
"eval_body_using_ecx: pushing stack frame for global: {}{}",
|
||||||
with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())),
|
with_no_trimmed_paths!(ecx.tcx.def_path_str(cid.instance.def_id())),
|
||||||
@@ -87,6 +97,31 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
intern_and_validate(ecx, cid, intern_kind, ret)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(ecx))]
|
||||||
|
fn eval_trivial_const_using_ecx<'tcx, R: InterpretationResult<'tcx>>(
|
||||||
|
ecx: &mut CompileTimeInterpCx<'tcx>,
|
||||||
|
cid: GlobalId<'tcx>,
|
||||||
|
val: ConstValue,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
) -> InterpResult<'tcx, R> {
|
||||||
|
let layout = ecx.layout_of(ty)?;
|
||||||
|
let (intern_kind, return_place) = setup_for_eval(ecx, cid, layout)?;
|
||||||
|
|
||||||
|
let opty = ecx.const_val_to_op(val, ty, Some(layout))?;
|
||||||
|
ecx.copy_op(&opty, &return_place)?;
|
||||||
|
|
||||||
|
intern_and_validate(ecx, cid, intern_kind, return_place)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn intern_and_validate<'tcx, R: InterpretationResult<'tcx>>(
|
||||||
|
ecx: &mut CompileTimeInterpCx<'tcx>,
|
||||||
|
cid: GlobalId<'tcx>,
|
||||||
|
intern_kind: InternKind,
|
||||||
|
ret: MPlaceTy<'tcx>,
|
||||||
|
) -> InterpResult<'tcx, R> {
|
||||||
// Intern the result
|
// Intern the result
|
||||||
let intern_result = intern_const_alloc_recursive(ecx, intern_kind, &ret);
|
let intern_result = intern_const_alloc_recursive(ecx, intern_kind, &ret);
|
||||||
|
|
||||||
@@ -292,6 +327,9 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
|
|||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
|
key: ty::PseudoCanonicalInput<'tcx, GlobalId<'tcx>>,
|
||||||
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
|
) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> {
|
||||||
|
if let Some((value, _ty)) = tcx.trivial_const(key.value.instance.def_id()) {
|
||||||
|
return Ok(value);
|
||||||
|
}
|
||||||
tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
|
tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,10 +406,14 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>(
|
|||||||
// so we have to reject reading mutable global memory.
|
// so we have to reject reading mutable global memory.
|
||||||
CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error),
|
CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error),
|
||||||
);
|
);
|
||||||
let res = ecx.load_mir(cid.instance.def, cid.promoted);
|
|
||||||
res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body))
|
let result = if let Some((value, ty)) = tcx.trivial_const(def) {
|
||||||
.report_err()
|
eval_trivial_const_using_ecx(&mut ecx, cid, value, ty)
|
||||||
.map_err(|error| report_eval_error(&ecx, cid, error))
|
} else {
|
||||||
|
ecx.load_mir(cid.instance.def, cid.promoted)
|
||||||
|
.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body))
|
||||||
|
};
|
||||||
|
result.report_err().map_err(|error| report_eval_error(&ecx, cid, error))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|||||||
@@ -1088,9 +1088,15 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
|
|||||||
|
|
||||||
sess.time("MIR_borrow_checking", || {
|
sess.time("MIR_borrow_checking", || {
|
||||||
tcx.par_hir_body_owners(|def_id| {
|
tcx.par_hir_body_owners(|def_id| {
|
||||||
if !tcx.is_typeck_child(def_id.to_def_id()) {
|
let not_typeck_child = !tcx.is_typeck_child(def_id.to_def_id());
|
||||||
|
if not_typeck_child {
|
||||||
// Child unsafety and borrowck happens together with the parent
|
// Child unsafety and borrowck happens together with the parent
|
||||||
tcx.ensure_ok().check_unsafety(def_id);
|
tcx.ensure_ok().check_unsafety(def_id);
|
||||||
|
}
|
||||||
|
if tcx.is_trivial_const(def_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if not_typeck_child {
|
||||||
tcx.ensure_ok().mir_borrowck(def_id);
|
tcx.ensure_ok().mir_borrowck(def_id);
|
||||||
tcx.ensure_ok().check_transmutes(def_id);
|
tcx.ensure_ok().check_transmutes(def_id);
|
||||||
}
|
}
|
||||||
@@ -1198,7 +1204,9 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
|
|||||||
if tcx.sess.opts.unstable_opts.validate_mir {
|
if tcx.sess.opts.unstable_opts.validate_mir {
|
||||||
sess.time("ensuring_final_MIR_is_computable", || {
|
sess.time("ensuring_final_MIR_is_computable", || {
|
||||||
tcx.par_hir_body_owners(|def_id| {
|
tcx.par_hir_body_owners(|def_id| {
|
||||||
|
if !tcx.is_trivial_const(def_id) {
|
||||||
tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
|
tcx.instance_mir(ty::InstanceKind::Item(def_id.into()));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ provide! { tcx, def_id, other, cdata,
|
|||||||
thir_abstract_const => { table }
|
thir_abstract_const => { table }
|
||||||
optimized_mir => { table }
|
optimized_mir => { table }
|
||||||
mir_for_ctfe => { table }
|
mir_for_ctfe => { table }
|
||||||
|
trivial_const => { table }
|
||||||
closure_saved_names_of_captured_variables => { table }
|
closure_saved_names_of_captured_variables => { table }
|
||||||
mir_coroutine_witnesses => { table }
|
mir_coroutine_witnesses => { table }
|
||||||
promoted_mir => { table }
|
promoted_mir => { table }
|
||||||
|
|||||||
@@ -1791,8 +1791,15 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||||||
record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses);
|
record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mut is_trivial = false;
|
||||||
if encode_const {
|
if encode_const {
|
||||||
|
if let Some((val, ty)) = tcx.trivial_const(def_id) {
|
||||||
|
is_trivial = true;
|
||||||
|
record!(self.tables.trivial_const[def_id.to_def_id()] <- (val, ty));
|
||||||
|
} else {
|
||||||
|
is_trivial = false;
|
||||||
record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id));
|
record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- tcx.mir_for_ctfe(def_id));
|
||||||
|
}
|
||||||
|
|
||||||
// FIXME(generic_const_exprs): this feels wrong to have in `encode_mir`
|
// FIXME(generic_const_exprs): this feels wrong to have in `encode_mir`
|
||||||
let abstract_const = tcx.thir_abstract_const(def_id);
|
let abstract_const = tcx.thir_abstract_const(def_id);
|
||||||
@@ -1810,7 +1817,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if !is_trivial {
|
||||||
record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id));
|
record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id));
|
||||||
|
}
|
||||||
|
|
||||||
if self.tcx.is_coroutine(def_id.to_def_id())
|
if self.tcx.is_coroutine(def_id.to_def_id())
|
||||||
&& let Some(witnesses) = tcx.mir_coroutine_witnesses(def_id)
|
&& let Some(witnesses) = tcx.mir_coroutine_witnesses(def_id)
|
||||||
@@ -2234,6 +2243,9 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
|
|||||||
|
|
||||||
let reachable_set = tcx.reachable_set(());
|
let reachable_set = tcx.reachable_set(());
|
||||||
par_for_each_in(tcx.mir_keys(()), |&&def_id| {
|
par_for_each_in(tcx.mir_keys(()), |&&def_id| {
|
||||||
|
if tcx.is_trivial_const(def_id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
|
let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id);
|
||||||
|
|
||||||
if encode_const {
|
if encode_const {
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
|
|||||||
use rustc_middle::middle::lib_features::FeatureStability;
|
use rustc_middle::middle::lib_features::FeatureStability;
|
||||||
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
|
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
|
use rustc_middle::mir::ConstValue;
|
||||||
use rustc_middle::ty::fast_reject::SimplifiedType;
|
use rustc_middle::ty::fast_reject::SimplifiedType;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, UnusedGenericParams};
|
use rustc_middle::ty::{self, Ty, TyCtxt, UnusedGenericParams};
|
||||||
use rustc_middle::util::Providers;
|
use rustc_middle::util::Providers;
|
||||||
@@ -426,6 +427,7 @@ define_tables! {
|
|||||||
object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
|
object_lifetime_default: Table<DefIndex, LazyValue<ObjectLifetimeDefault>>,
|
||||||
optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
optimized_mir: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
||||||
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
|
||||||
|
trivial_const: Table<DefIndex, LazyValue<(ConstValue, Ty<'static>)>>,
|
||||||
closure_saved_names_of_captured_variables: Table<DefIndex, LazyValue<IndexVec<FieldIdx, Symbol>>>,
|
closure_saved_names_of_captured_variables: Table<DefIndex, LazyValue<IndexVec<FieldIdx, Symbol>>>,
|
||||||
mir_coroutine_witnesses: Table<DefIndex, LazyValue<mir::CoroutineLayout<'static>>>,
|
mir_coroutine_witnesses: Table<DefIndex, LazyValue<mir::CoroutineLayout<'static>>>,
|
||||||
promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
|
promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
|
||||||
|
|||||||
@@ -102,6 +102,7 @@ trivially_parameterized_over_tcx! {
|
|||||||
rustc_middle::middle::lib_features::FeatureStability,
|
rustc_middle::middle::lib_features::FeatureStability,
|
||||||
rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault,
|
rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault,
|
||||||
rustc_middle::mir::ConstQualifs,
|
rustc_middle::mir::ConstQualifs,
|
||||||
|
rustc_middle::mir::ConstValue,
|
||||||
rustc_middle::ty::AnonConstKind,
|
rustc_middle::ty::AnonConstKind,
|
||||||
rustc_middle::ty::AssocContainer,
|
rustc_middle::ty::AssocContainer,
|
||||||
rustc_middle::ty::AsyncDestructor,
|
rustc_middle::ty::AsyncDestructor,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ where
|
|||||||
|
|
||||||
let mirs = def_ids
|
let mirs = def_ids
|
||||||
.iter()
|
.iter()
|
||||||
|
.filter(|def_id| !tcx.is_trivial_const(*def_id))
|
||||||
.flat_map(|def_id| {
|
.flat_map(|def_id| {
|
||||||
if tcx.is_const_fn(*def_id) {
|
if tcx.is_const_fn(*def_id) {
|
||||||
vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
|
vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
|
||||||
|
|||||||
@@ -352,11 +352,19 @@ pub fn write_mir_pretty<'tcx>(
|
|||||||
// Do not use `render_body`, as that would render the promoteds again, but these
|
// Do not use `render_body`, as that would render the promoteds again, but these
|
||||||
// are shared between mir_for_ctfe and optimized_mir
|
// are shared between mir_for_ctfe and optimized_mir
|
||||||
writer.write_mir_fn(tcx.mir_for_ctfe(def_id), w)?;
|
writer.write_mir_fn(tcx.mir_for_ctfe(def_id), w)?;
|
||||||
|
} else {
|
||||||
|
if let Some((val, ty)) = tcx.trivial_const(def_id) {
|
||||||
|
ty::print::with_forced_impl_filename_line! {
|
||||||
|
// see notes on #41697 elsewhere
|
||||||
|
write!(w, "const {}", tcx.def_path_str(def_id))?
|
||||||
|
}
|
||||||
|
writeln!(w, ": {} = const {};", ty, Const::Val(val, ty))?;
|
||||||
} else {
|
} else {
|
||||||
let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id));
|
let instance_mir = tcx.instance_mir(ty::InstanceKind::Item(def_id));
|
||||||
render_body(w, instance_mir)?;
|
render_body(w, instance_mir)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -160,6 +160,10 @@ impl EraseType for Result<mir::ConstValue, mir::interpret::ErrorHandled> {
|
|||||||
type Result = [u8; size_of::<Result<mir::ConstValue, mir::interpret::ErrorHandled>>()];
|
type Result = [u8; size_of::<Result<mir::ConstValue, mir::interpret::ErrorHandled>>()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl EraseType for Option<(mir::ConstValue, Ty<'_>)> {
|
||||||
|
type Result = [u8; size_of::<Option<(mir::ConstValue, Ty<'_>)>>()];
|
||||||
|
}
|
||||||
|
|
||||||
impl EraseType for EvalToValTreeResult<'_> {
|
impl EraseType for EvalToValTreeResult<'_> {
|
||||||
type Result = [u8; size_of::<EvalToValTreeResult<'static>>()];
|
type Result = [u8; size_of::<EvalToValTreeResult<'static>>()];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2719,6 +2719,12 @@ rustc_queries! {
|
|||||||
separate_provide_extern
|
separate_provide_extern
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query trivial_const(def_id: DefId) -> Option<(mir::ConstValue, Ty<'tcx>)> {
|
||||||
|
desc { |tcx| "checking if `{}` is a trivial const", tcx.def_path_str(def_id) }
|
||||||
|
cache_on_disk_if { def_id.is_local() }
|
||||||
|
separate_provide_extern
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks for the nearest `#[sanitize(xyz = "off")]` or
|
/// Checks for the nearest `#[sanitize(xyz = "off")]` or
|
||||||
/// `#[sanitize(xyz = "on")]` on this def and any enclosing defs, up to the
|
/// `#[sanitize(xyz = "on")]` on this def and any enclosing defs, up to the
|
||||||
/// crate root.
|
/// crate root.
|
||||||
|
|||||||
@@ -3546,6 +3546,13 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||||||
self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some()
|
self.get_diagnostic_attr(def_id, sym::do_not_recommend).is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_trivial_const<P>(self, def_id: P) -> bool
|
||||||
|
where
|
||||||
|
P: IntoQueryParam<DefId>,
|
||||||
|
{
|
||||||
|
self.trivial_const(def_id).is_some()
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether this def is one of the special bin crate entrypoint functions that must have a
|
/// Whether this def is one of the special bin crate entrypoint functions that must have a
|
||||||
/// monomorphization and also not be internalized in the bin crate.
|
/// monomorphization and also not be internalized in the bin crate.
|
||||||
pub fn is_entrypoint(self, def_id: DefId) -> bool {
|
pub fn is_entrypoint(self, def_id: DefId) -> bool {
|
||||||
|
|||||||
@@ -23,11 +23,11 @@ use rustc_hir::def::{CtorKind, DefKind};
|
|||||||
use rustc_hir::def_id::LocalDefId;
|
use rustc_hir::def_id::LocalDefId;
|
||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, LocalDecl,
|
AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs, ConstValue,
|
||||||
MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, START_BLOCK,
|
LocalDecl, MirPhase, Operand, Place, ProjectionElem, Promoted, RETURN_PLACE, RuntimePhase,
|
||||||
SourceInfo, Statement, StatementKind, TerminatorKind,
|
Rvalue, START_BLOCK, SourceInfo, Statement, StatementKind, TerminatorKind,
|
||||||
};
|
};
|
||||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
|
||||||
use rustc_middle::util::Providers;
|
use rustc_middle::util::Providers;
|
||||||
use rustc_middle::{bug, query, span_bug};
|
use rustc_middle::{bug, query, span_bug};
|
||||||
use rustc_mir_build::builder::build_mir;
|
use rustc_mir_build::builder::build_mir;
|
||||||
@@ -226,6 +226,7 @@ pub fn provide(providers: &mut Providers) {
|
|||||||
promoted_mir,
|
promoted_mir,
|
||||||
deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
|
deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
|
||||||
coroutine_by_move_body_def_id: coroutine::coroutine_by_move_body_def_id,
|
coroutine_by_move_body_def_id: coroutine::coroutine_by_move_body_def_id,
|
||||||
|
trivial_const: trivial_const_provider,
|
||||||
..providers.queries
|
..providers.queries
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -376,9 +377,71 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
|
|||||||
validator.qualifs_in_return_place()
|
validator.qualifs_in_return_place()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn def_kind_compatible_with_trivial_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> bool {
|
||||||
|
// Static and InlineConst are the obvious additions, but
|
||||||
|
// * Statics need additional type-checking to taint `static A: _ = 0;`, currently we'd ICE.
|
||||||
|
// * The MIR for InlineConst is used by the borrow checker, and not easy to skip over.
|
||||||
|
matches!(tcx.def_kind(def), DefKind::AssocConst | DefKind::Const | DefKind::AnonConst)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trivial_const_provider<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
def: LocalDefId,
|
||||||
|
) -> Option<(ConstValue, Ty<'tcx>)> {
|
||||||
|
if def_kind_compatible_with_trivial_mir(tcx, def) {
|
||||||
|
trivial_const(&tcx.mir_built(def).borrow())
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn trivial_const<'tcx>(body: &Body<'tcx>) -> Option<(ConstValue, Ty<'tcx>)> {
|
||||||
|
if body.has_opaque_types() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if body.basic_blocks.len() != 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let block = &body.basic_blocks[START_BLOCK];
|
||||||
|
if block.statements.len() != 1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if block.terminator().kind != TerminatorKind::Return {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let StatementKind::Assign(box (place, rvalue)) = &block.statements[0].kind else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
if *place != Place::from(RETURN_PLACE) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Rvalue::Use(Operand::Constant(c)) = rvalue {
|
||||||
|
if let rustc_middle::mir::Const::Val(v, ty) = c.const_ {
|
||||||
|
return Some((v, ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
|
fn mir_built(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
|
||||||
let mut body = build_mir(tcx, def);
|
let mut body = build_mir(tcx, def);
|
||||||
|
|
||||||
|
// Identifying trivial consts based on their mir_built is easy, but a little wasteful.
|
||||||
|
// Trying to push this logic earlier in the compiler and never even produce the Body would
|
||||||
|
// probably improve compile time.
|
||||||
|
if def_kind_compatible_with_trivial_mir(tcx, def) && trivial_const(&body).is_some() {
|
||||||
|
let body = tcx.alloc_steal_mir(body);
|
||||||
|
pass_manager::dump_mir_for_phase_change(tcx, &body.borrow());
|
||||||
|
return body;
|
||||||
|
}
|
||||||
|
|
||||||
pass_manager::dump_mir_for_phase_change(tcx, &body);
|
pass_manager::dump_mir_for_phase_change(tcx, &body);
|
||||||
|
|
||||||
pm::run_passes(
|
pm::run_passes(
|
||||||
@@ -409,6 +472,8 @@ fn mir_promoted(
|
|||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'_>,
|
||||||
def: LocalDefId,
|
def: LocalDefId,
|
||||||
) -> (&Steal<Body<'_>>, &Steal<IndexVec<Promoted, Body<'_>>>) {
|
) -> (&Steal<Body<'_>>, &Steal<IndexVec<Promoted, Body<'_>>>) {
|
||||||
|
debug_assert!(!tcx.is_trivial_const(def), "Tried to get mir_promoted of a trivial const");
|
||||||
|
|
||||||
// Ensure that we compute the `mir_const_qualif` for constants at
|
// Ensure that we compute the `mir_const_qualif` for constants at
|
||||||
// this point, before we steal the mir-const result.
|
// this point, before we steal the mir-const result.
|
||||||
// Also this means promotion can rely on all const checks having been done.
|
// Also this means promotion can rely on all const checks having been done.
|
||||||
@@ -436,6 +501,9 @@ fn mir_promoted(
|
|||||||
tcx.ensure_done().coroutine_by_move_body_def_id(def);
|
tcx.ensure_done().coroutine_by_move_body_def_id(def);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// the `trivial_const` query uses mir_built, so make sure it is run.
|
||||||
|
tcx.ensure_done().trivial_const(def);
|
||||||
|
|
||||||
let mut body = tcx.mir_built(def).steal();
|
let mut body = tcx.mir_built(def).steal();
|
||||||
if let Some(error_reported) = const_qualifs.tainted_by_errors {
|
if let Some(error_reported) = const_qualifs.tainted_by_errors {
|
||||||
body.tainted_by_errors = Some(error_reported);
|
body.tainted_by_errors = Some(error_reported);
|
||||||
@@ -463,6 +531,7 @@ fn mir_promoted(
|
|||||||
|
|
||||||
/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
|
/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
|
||||||
fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> {
|
fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> {
|
||||||
|
debug_assert!(!tcx.is_trivial_const(def_id), "Tried to get mir_for_ctfe of a trivial const");
|
||||||
tcx.arena.alloc(inner_mir_for_ctfe(tcx, def_id))
|
tcx.arena.alloc(inner_mir_for_ctfe(tcx, def_id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,8 @@ impl<'tcx, B: Bridge> CompilerCtxt<'tcx, B> {
|
|||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
};
|
};
|
||||||
!must_override && self.tcx.is_mir_available(def_id)
|
// FIXME: A good reason to make is_mir_available or mir_keys change behavior
|
||||||
|
!must_override && self.tcx.is_mir_available(def_id) && !self.tcx.is_trivial_const(def_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter_fn_def(&self, def_id: DefId) -> Option<DefId> {
|
fn filter_fn_def(&self, def_id: DefId) -> Option<DefId> {
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ impl Tr for str {
|
|||||||
type Arr = [u8; 8];
|
type Arr = [u8; 8];
|
||||||
#[cfg(cfail)]
|
#[cfg(cfail)]
|
||||||
type Arr = [u8; Self::C];
|
type Arr = [u8; Self::C];
|
||||||
//[cfail]~^ ERROR cycle detected when caching mir
|
//[cfail]~^ ERROR cycle detected when
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|||||||
@@ -397,13 +397,6 @@ fn operands(_1: u8) -> () {
|
|||||||
_89 = core::panicking::assert_failed::<usize, usize>(move _90, move _91, move _93, move _95) -> unwind unreachable;
|
_89 = core::panicking::assert_failed::<usize, usize>(move _90, move _91, move _93, move _95) -> unwind unreachable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn operands::{constant#0}() -> usize {
|
|
||||||
let mut _0: usize;
|
|
||||||
bb0: {
|
|
||||||
_0 = 10_usize;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn more_operands() -> [Ctors; 3] {
|
fn more_operands() -> [Ctors; 3] {
|
||||||
let mut _0: [Ctors; 3];
|
let mut _0: [Ctors; 3];
|
||||||
let _1: Dummy;
|
let _1: Dummy;
|
||||||
@@ -447,13 +440,6 @@ fn more_operands() -> [Ctors; 3] {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn more_operands::{constant#0}() -> usize {
|
|
||||||
let mut _0: usize;
|
|
||||||
bb0: {
|
|
||||||
_0 = 3_usize;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn closures(_1: bool, _2: bool) -> {closure@$DIR/operands.rs:47:5: 47:19} {
|
fn closures(_1: bool, _2: bool) -> {closure@$DIR/operands.rs:47:5: 47:19} {
|
||||||
let mut _0: {closure@$DIR/operands.rs:47:5: 47:19};
|
let mut _0: {closure@$DIR/operands.rs:47:5: 47:19};
|
||||||
debug x => _1;
|
debug x => _1;
|
||||||
|
|||||||
@@ -17,27 +17,7 @@ note: ...which requires const-evaluating + checking `accept0::{constant#0}`...
|
|||||||
|
|
|
|
||||||
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
note: ...which requires caching mir of `accept0::{constant#0}` for CTFE...
|
note: ...which requires checking if `accept0::{constant#0}` is a trivial const...
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
|
||||||
|
|
|
||||||
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
note: ...which requires elaborating drops for `accept0::{constant#0}`...
|
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
|
||||||
|
|
|
||||||
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
note: ...which requires borrow-checking `accept0::{constant#0}`...
|
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
|
||||||
|
|
|
||||||
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
note: ...which requires promoting constants in MIR for `accept0::{constant#0}`...
|
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
|
||||||
|
|
|
||||||
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
note: ...which requires const checking `accept0::{constant#0}`...
|
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
--> $DIR/unsatisfied-const-trait-bound.rs:29:35
|
||||||
|
|
|
|
||||||
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
||||||
@@ -70,32 +50,12 @@ LL | fn accept0<T: Trait>(_: Container<{ T::make() }>) {}
|
|||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
|
||||||
|
|
||||||
error[E0391]: cycle detected when caching mir of `accept1::{constant#0}` for CTFE
|
error[E0391]: cycle detected when checking if `accept1::{constant#0}` is a trivial const
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
||||||
|
|
|
|
||||||
LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
|
LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
|
|
|
|
||||||
note: ...which requires elaborating drops for `accept1::{constant#0}`...
|
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
|
||||||
|
|
|
||||||
LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
note: ...which requires borrow-checking `accept1::{constant#0}`...
|
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
|
||||||
|
|
|
||||||
LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
note: ...which requires promoting constants in MIR for `accept1::{constant#0}`...
|
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
|
||||||
|
|
|
||||||
LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
note: ...which requires const checking `accept1::{constant#0}`...
|
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
|
||||||
|
|
|
||||||
LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
note: ...which requires building MIR for `accept1::{constant#0}`...
|
note: ...which requires building MIR for `accept1::{constant#0}`...
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
||||||
|
|
|
|
||||||
@@ -126,7 +86,7 @@ note: ...which requires const-evaluating + checking `accept1::{constant#0}`...
|
|||||||
|
|
|
|
||||||
LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
|
LL | const fn accept1<T: [const] Trait>(_: Container<{ T::make() }>) {}
|
||||||
| ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^
|
||||||
= note: ...which again requires caching mir of `accept1::{constant#0}` for CTFE, completing the cycle
|
= note: ...which again requires checking if `accept1::{constant#0}` is a trivial const, completing the cycle
|
||||||
note: cycle used when const-evaluating + checking `accept1::{constant#0}`
|
note: cycle used when const-evaluating + checking `accept1::{constant#0}`
|
||||||
--> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
--> $DIR/unsatisfied-const-trait-bound.rs:33:49
|
||||||
|
|
|
|
||||||
|
|||||||
Reference in New Issue
Block a user