1
Fork 0

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:
oli 2020-10-26 19:00:40 +00:00 committed by oli
parent 8e4fe6647f
commit cccd40f9b5
25 changed files with 312 additions and 112 deletions

View file

@ -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>,

View file

@ -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) }

View file

@ -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(..) => (),
}

View file

@ -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>>>,