Keep an unoptimized duplicate of const fn
around
This allows CTFE to reliably detect UB, as otherwise optimizations may hide UB.
This commit is contained in:
parent
8e4fe6647f
commit
cccd40f9b5
25 changed files with 312 additions and 112 deletions
|
@ -1162,6 +1162,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
|
||||
fn is_item_mir_available(&self, id: DefIndex) -> bool {
|
||||
self.root.tables.mir.get(self, id).is_some()
|
||||
|| self.root.tables.mir_for_ctfe.get(self, id).is_some()
|
||||
}
|
||||
|
||||
fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
|
||||
|
@ -1183,6 +1184,17 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
|
|||
.decode((self, tcx))
|
||||
}
|
||||
|
||||
fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
|
||||
self.root
|
||||
.tables
|
||||
.mir_for_ctfe
|
||||
.get(self, id)
|
||||
.unwrap_or_else(|| {
|
||||
bug!("get_mir_for_ctfe: missing MIR for `{:?}`", self.local_def_id(id))
|
||||
})
|
||||
.decode((self, tcx))
|
||||
}
|
||||
|
||||
fn get_mir_abstract_const(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
|
|
@ -115,6 +115,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
|
|||
})
|
||||
}
|
||||
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
|
||||
mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) }
|
||||
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
|
||||
mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
|
||||
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
|
||||
|
|
|
@ -787,6 +787,7 @@ impl EncodeContext<'a, 'tcx> {
|
|||
self.encode_generics(def_id);
|
||||
self.encode_explicit_predicates(def_id);
|
||||
self.encode_inferred_outlives(def_id);
|
||||
self.encode_mir_for_ctfe(def_id.expect_local());
|
||||
self.encode_optimized_mir(def_id.expect_local());
|
||||
self.encode_promoted_mir(def_id.expect_local());
|
||||
}
|
||||
|
@ -895,6 +896,7 @@ impl EncodeContext<'a, 'tcx> {
|
|||
self.encode_explicit_predicates(def_id);
|
||||
self.encode_inferred_outlives(def_id);
|
||||
self.encode_optimized_mir(def_id.expect_local());
|
||||
self.encode_mir_for_ctfe(def_id.expect_local());
|
||||
self.encode_promoted_mir(def_id.expect_local());
|
||||
}
|
||||
|
||||
|
@ -1015,7 +1017,13 @@ impl EncodeContext<'a, 'tcx> {
|
|||
// This should be kept in sync with `PrefetchVisitor.visit_trait_item`.
|
||||
match trait_item.kind {
|
||||
ty::AssocKind::Type => {}
|
||||
ty::AssocKind::Const | ty::AssocKind::Fn => {
|
||||
ty::AssocKind::Const => {
|
||||
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
|
||||
self.encode_mir_for_ctfe(def_id.expect_local());
|
||||
self.encode_promoted_mir(def_id.expect_local());
|
||||
}
|
||||
}
|
||||
ty::AssocKind::Fn => {
|
||||
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
|
||||
self.encode_optimized_mir(def_id.expect_local());
|
||||
self.encode_promoted_mir(def_id.expect_local());
|
||||
|
@ -1094,8 +1102,8 @@ impl EncodeContext<'a, 'tcx> {
|
|||
|
||||
// The following part should be kept in sync with `PrefetchVisitor.visit_impl_item`.
|
||||
|
||||
let mir = match ast_item.kind {
|
||||
hir::ImplItemKind::Const(..) => true,
|
||||
let (mir, mir_const) = match ast_item.kind {
|
||||
hir::ImplItemKind::Const(..) => (false, true),
|
||||
hir::ImplItemKind::Fn(ref sig, _) => {
|
||||
let generics = self.tcx.generics_of(def_id);
|
||||
let needs_inline = (generics.requires_monomorphization(self.tcx)
|
||||
|
@ -1103,14 +1111,19 @@ impl EncodeContext<'a, 'tcx> {
|
|||
&& !self.metadata_output_only();
|
||||
let is_const_fn = sig.header.constness == hir::Constness::Const;
|
||||
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
|
||||
needs_inline || is_const_fn || always_encode_mir
|
||||
(needs_inline || always_encode_mir, is_const_fn)
|
||||
}
|
||||
hir::ImplItemKind::TyAlias(..) => false,
|
||||
hir::ImplItemKind::TyAlias(..) => (false, false),
|
||||
};
|
||||
if mir {
|
||||
self.encode_optimized_mir(def_id.expect_local());
|
||||
}
|
||||
if mir || mir_const {
|
||||
self.encode_promoted_mir(def_id.expect_local());
|
||||
}
|
||||
if mir_const {
|
||||
self.encode_mir_for_ctfe(def_id.expect_local());
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> {
|
||||
|
@ -1121,9 +1134,9 @@ impl EncodeContext<'a, 'tcx> {
|
|||
self.lazy(param_names.iter())
|
||||
}
|
||||
|
||||
fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
|
||||
debug!("EntryBuilder::encode_mir({:?})", def_id);
|
||||
record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
|
||||
fn encode_mir_for_ctfe(&mut self, def_id: LocalDefId) {
|
||||
debug!("EntryBuilder::encode_mir_for_ctfe({:?})", def_id);
|
||||
record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
|
||||
|
||||
let unused = self.tcx.unused_generic_params(def_id);
|
||||
if !unused.is_empty() {
|
||||
|
@ -1136,6 +1149,16 @@ impl EncodeContext<'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
|
||||
debug!("EntryBuilder::encode_optimized_mir({:?})", def_id);
|
||||
record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
|
||||
|
||||
let unused = self.tcx.unused_generic_params(def_id);
|
||||
if !unused.is_empty() {
|
||||
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
|
||||
}
|
||||
}
|
||||
|
||||
fn encode_promoted_mir(&mut self, def_id: LocalDefId) {
|
||||
debug!("EncodeContext::encode_promoted_mir({:?})", def_id);
|
||||
record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
|
||||
|
@ -1407,8 +1430,8 @@ impl EncodeContext<'a, 'tcx> {
|
|||
|
||||
// The following part should be kept in sync with `PrefetchVisitor.visit_item`.
|
||||
|
||||
let mir = match item.kind {
|
||||
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true,
|
||||
let (mir, const_mir) = match item.kind {
|
||||
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => (false, true),
|
||||
hir::ItemKind::Fn(ref sig, ..) => {
|
||||
let generics = tcx.generics_of(def_id);
|
||||
let needs_inline = (generics.requires_monomorphization(tcx)
|
||||
|
@ -1417,14 +1440,21 @@ impl EncodeContext<'a, 'tcx> {
|
|||
|
||||
let is_const_fn = sig.header.constness == hir::Constness::Const;
|
||||
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
|
||||
needs_inline || is_const_fn || always_encode_mir
|
||||
let mir = needs_inline || always_encode_mir;
|
||||
// We don't need the optimized MIR for const fns.
|
||||
(mir, is_const_fn)
|
||||
}
|
||||
_ => false,
|
||||
_ => (false, false),
|
||||
};
|
||||
if mir {
|
||||
self.encode_optimized_mir(def_id.expect_local());
|
||||
}
|
||||
if mir || const_mir {
|
||||
self.encode_promoted_mir(def_id.expect_local());
|
||||
}
|
||||
if const_mir {
|
||||
self.encode_mir_for_ctfe(def_id.expect_local());
|
||||
}
|
||||
}
|
||||
|
||||
/// Serialize the text of exported macros
|
||||
|
@ -1489,7 +1519,7 @@ impl EncodeContext<'a, 'tcx> {
|
|||
self.encode_generics(def_id.to_def_id());
|
||||
self.encode_explicit_predicates(def_id.to_def_id());
|
||||
self.encode_inferred_outlives(def_id.to_def_id());
|
||||
self.encode_optimized_mir(def_id);
|
||||
self.encode_mir_for_ctfe(def_id);
|
||||
self.encode_promoted_mir(def_id);
|
||||
}
|
||||
|
||||
|
@ -1954,6 +1984,12 @@ struct PrefetchVisitor<'tcx> {
|
|||
}
|
||||
|
||||
impl<'tcx> PrefetchVisitor<'tcx> {
|
||||
fn prefetch_ctfe_mir(&self, def_id: LocalDefId) {
|
||||
if self.mir_keys.contains(&def_id) {
|
||||
self.tcx.ensure().mir_for_ctfe(def_id);
|
||||
self.tcx.ensure().promoted_mir(def_id);
|
||||
}
|
||||
}
|
||||
fn prefetch_mir(&self, def_id: LocalDefId) {
|
||||
if self.mir_keys.contains(&def_id) {
|
||||
self.tcx.ensure().optimized_mir(def_id);
|
||||
|
@ -1968,16 +2004,19 @@ impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
|
|||
let tcx = self.tcx;
|
||||
match item.kind {
|
||||
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
|
||||
self.prefetch_mir(tcx.hir().local_def_id(item.hir_id))
|
||||
self.prefetch_ctfe_mir(tcx.hir().local_def_id(item.hir_id))
|
||||
}
|
||||
hir::ItemKind::Fn(ref sig, ..) => {
|
||||
let def_id = tcx.hir().local_def_id(item.hir_id);
|
||||
let generics = tcx.generics_of(def_id.to_def_id());
|
||||
let needs_inline = generics.requires_monomorphization(tcx)
|
||||
|| tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
|
||||
if needs_inline || sig.header.constness == hir::Constness::Const {
|
||||
if needs_inline {
|
||||
self.prefetch_mir(def_id)
|
||||
}
|
||||
if sig.header.constness == hir::Constness::Const {
|
||||
self.prefetch_ctfe_mir(def_id);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
@ -1985,7 +2024,16 @@ impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
|
|||
|
||||
fn visit_trait_item(&self, trait_item: &'v hir::TraitItem<'v>) {
|
||||
// This should be kept in sync with `encode_info_for_trait_item`.
|
||||
self.prefetch_mir(self.tcx.hir().local_def_id(trait_item.hir_id));
|
||||
let def_id = self.tcx.hir().local_def_id(trait_item.hir_id);
|
||||
match trait_item.kind {
|
||||
hir::TraitItemKind::Type(..) => {}
|
||||
hir::TraitItemKind::Const(..) => {
|
||||
self.prefetch_ctfe_mir(def_id);
|
||||
}
|
||||
hir::TraitItemKind::Fn(..) => {
|
||||
self.prefetch_mir(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_impl_item(&self, impl_item: &'v hir::ImplItem<'v>) {
|
||||
|
@ -1993,7 +2041,7 @@ impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
|
|||
let tcx = self.tcx;
|
||||
match impl_item.kind {
|
||||
hir::ImplItemKind::Const(..) => {
|
||||
self.prefetch_mir(tcx.hir().local_def_id(impl_item.hir_id))
|
||||
self.prefetch_ctfe_mir(tcx.hir().local_def_id(impl_item.hir_id))
|
||||
}
|
||||
hir::ImplItemKind::Fn(ref sig, _) => {
|
||||
let def_id = tcx.hir().local_def_id(impl_item.hir_id);
|
||||
|
@ -2001,9 +2049,12 @@ impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
|
|||
let needs_inline = generics.requires_monomorphization(tcx)
|
||||
|| tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
|
||||
let is_const_fn = sig.header.constness == hir::Constness::Const;
|
||||
if needs_inline || is_const_fn {
|
||||
if needs_inline {
|
||||
self.prefetch_mir(def_id)
|
||||
}
|
||||
if is_const_fn {
|
||||
self.prefetch_ctfe_mir(def_id);
|
||||
}
|
||||
}
|
||||
hir::ImplItemKind::TyAlias(..) => (),
|
||||
}
|
||||
|
|
|
@ -302,6 +302,7 @@ define_tables! {
|
|||
// As an optimization, a missing entry indicates an empty `&[]`.
|
||||
explicit_item_bounds: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
|
||||
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
|
||||
mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
|
||||
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
|
||||
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
|
||||
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,
|
||||
|
|
|
@ -450,6 +450,15 @@ impl<'tcx> TyCtxt<'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> {
|
||||
if let Some((did, param_did)) = def.as_const_arg() {
|
||||
self.mir_for_ctfe_of_const_arg((did, param_did))
|
||||
} else {
|
||||
self.mir_for_ctfe(def.did)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn mir_abstract_const_opt_const_arg(
|
||||
self,
|
||||
|
|
|
@ -312,6 +312,20 @@ rustc_queries! {
|
|||
desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
|
||||
}
|
||||
|
||||
query mir_for_ctfe(
|
||||
key: DefId
|
||||
) -> &'tcx mir::Body<'tcx> {
|
||||
desc { |tcx| "caching mir for `{}` for CTFE", tcx.def_path_str(key) }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
|
||||
desc {
|
||||
|tcx| "MIR for CTFE of the const argument `{}`",
|
||||
tcx.def_path_str(key.0.to_def_id())
|
||||
}
|
||||
}
|
||||
|
||||
query mir_promoted(key: ty::WithOptConstParam<LocalDefId>) ->
|
||||
(
|
||||
&'tcx Steal<mir::Body<'tcx>>,
|
||||
|
@ -331,6 +345,9 @@ rustc_queries! {
|
|||
desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
|
||||
cache_on_disk_if { key.is_local() }
|
||||
}
|
||||
|
||||
// FIXME: now that we have `mir_for_ctfe_of_const_arg` can we get
|
||||
// rid of this query?
|
||||
query optimized_mir_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
|
||||
desc {
|
||||
|tcx| "optimizing MIR for the const argument `{}`",
|
||||
|
|
|
@ -480,7 +480,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||
match instance {
|
||||
ty::InstanceDef::Item(def) => {
|
||||
if self.tcx.is_mir_available(def.did) {
|
||||
Ok(self.tcx.optimized_mir_opt_const_arg(def))
|
||||
Ok(self.tcx.mir_for_ctfe_opt_const_arg(def))
|
||||
} else {
|
||||
throw_unsup!(NoMirFor(def.did))
|
||||
}
|
||||
|
|
|
@ -69,7 +69,10 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
|
|||
debug!("unused_generic_params: (after default) unused_parameters={:?}", unused_parameters);
|
||||
|
||||
// Visit MIR and accumululate used generic parameters.
|
||||
let body = tcx.optimized_mir(def_id);
|
||||
let body = match tcx.hir().body_const_context(def_id.expect_local()) {
|
||||
None => tcx.optimized_mir(def_id),
|
||||
Some(_) => tcx.mir_for_ctfe(def_id),
|
||||
};
|
||||
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
|
||||
vis.visit_body(body);
|
||||
debug!("unused_generic_params: (after visitor) unused_parameters={:?}", unused_parameters);
|
||||
|
|
|
@ -71,6 +71,8 @@ pub(crate) fn provide(providers: &mut Providers) {
|
|||
},
|
||||
mir_promoted,
|
||||
mir_drops_elaborated_and_const_checked,
|
||||
mir_for_ctfe,
|
||||
mir_for_ctfe_of_const_arg,
|
||||
optimized_mir,
|
||||
optimized_mir_of_const_arg,
|
||||
is_mir_available,
|
||||
|
@ -319,6 +321,63 @@ fn mir_promoted(
|
|||
(tcx.alloc_steal_mir(body), tcx.alloc_steal_promoted(promoted))
|
||||
}
|
||||
|
||||
fn mir_for_ctfe<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx Body<'tcx> {
|
||||
let did = def_id.expect_local();
|
||||
if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
|
||||
tcx.mir_for_ctfe_of_const_arg(def)
|
||||
} else {
|
||||
tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(did)))
|
||||
}
|
||||
}
|
||||
|
||||
fn mir_for_ctfe_of_const_arg<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
(did, param_did): (LocalDefId, DefId),
|
||||
) -> &'tcx Body<'tcx> {
|
||||
tcx.arena.alloc(inner_mir_for_ctfe(
|
||||
tcx,
|
||||
ty::WithOptConstParam { did, const_param_did: Some(param_did) },
|
||||
))
|
||||
}
|
||||
|
||||
fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
|
||||
// FIXME: don't duplicate this between the optimized_mir/mir_for_ctfe queries
|
||||
if tcx.is_constructor(def.did.to_def_id()) {
|
||||
// There's no reason to run all of the MIR passes on constructors when
|
||||
// we can just output the MIR we want directly. This also saves const
|
||||
// qualification and borrow checking the trouble of special casing
|
||||
// constructors.
|
||||
return shim::build_adt_ctor(tcx, def.did.to_def_id());
|
||||
}
|
||||
|
||||
assert_ne!(
|
||||
tcx.hir().body_const_context(def.did),
|
||||
None,
|
||||
"mir_for_ctfe should not be used for runtime functions"
|
||||
);
|
||||
|
||||
let mut body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
|
||||
|
||||
#[rustfmt::skip]
|
||||
let optimizations: &[&dyn MirPass<'_>] = &[
|
||||
&const_prop::ConstProp,
|
||||
];
|
||||
|
||||
#[rustfmt::skip]
|
||||
run_passes(
|
||||
tcx,
|
||||
&mut body,
|
||||
MirPhase::Optimization,
|
||||
&[
|
||||
optimizations,
|
||||
],
|
||||
);
|
||||
|
||||
debug_assert!(!body.has_free_regions(), "Free regions in MIR for CTFE");
|
||||
|
||||
body
|
||||
}
|
||||
|
||||
fn mir_drops_elaborated_and_const_checked<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
def: ty::WithOptConstParam<LocalDefId>,
|
||||
|
@ -484,6 +543,17 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>)
|
|||
return shim::build_adt_ctor(tcx, def.did.to_def_id());
|
||||
}
|
||||
|
||||
match tcx.hir().body_const_context(def.did) {
|
||||
Some(hir::ConstContext::ConstFn) => {
|
||||
if let Some((did, param_did)) = def.to_global().as_const_arg() {
|
||||
tcx.ensure().mir_for_ctfe_of_const_arg((did, param_did))
|
||||
} else {
|
||||
tcx.ensure().mir_for_ctfe(def.did)
|
||||
}
|
||||
}
|
||||
None => {}
|
||||
Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other),
|
||||
}
|
||||
let mut body = tcx.mir_drops_elaborated_and_const_checked(def).steal();
|
||||
run_optimization_passes(tcx, &mut body);
|
||||
|
||||
|
|
|
@ -273,7 +273,11 @@ pub fn write_mir_pretty<'tcx>(
|
|||
|
||||
let mut first = true;
|
||||
for def_id in dump_mir_def_ids(tcx, single) {
|
||||
let body = &tcx.optimized_mir(def_id);
|
||||
let body = match tcx.hir().body_const_context(def_id.expect_local()) {
|
||||
// FIXME: print both MIRs for `const fn`?
|
||||
None | Some(rustc_hir::ConstContext::ConstFn) => tcx.optimized_mir(def_id),
|
||||
Some(_) => tcx.mir_for_ctfe(def_id),
|
||||
};
|
||||
|
||||
if first {
|
||||
first = false;
|
||||
|
|
|
@ -152,7 +152,7 @@ pub fn is_const_evaluatable<'cx, 'tcx>(
|
|||
if concrete.is_ok() && substs.has_param_types_or_consts() {
|
||||
match infcx.tcx.def_kind(def.did) {
|
||||
DefKind::AnonConst => {
|
||||
let mir_body = infcx.tcx.optimized_mir_opt_const_arg(def);
|
||||
let mir_body = infcx.tcx.mir_for_ctfe_opt_const_arg(def);
|
||||
|
||||
if mir_body.is_polymorphic {
|
||||
future_compat_lint();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue