Skip to content

Commit 704e47f

Browse files
committed
Auto merge of rust-lang#78407 - oli-obk:ub_checkable_ctfe, r=RalfJung,pnkfelix
Make CTFE able to check for UB... ... by not doing any optimizations on the `const fn` MIR used in CTFE. This means we duplicate all `const fn`'s MIR now, once for CTFE, once for runtime. This PR is for checking the perf effect, so we have some data when talking about https://github.com/rust-lang/const-eval/blob/master/rfcs/0000-const-ub.md To do this, we now have two queries for obtaining mir: `optimized_mir` and `mir_for_ctfe`. It is now illegal to invoke `optimized_mir` to obtain the MIR of a const/static item's initializer, an array length, an inline const expression or an enum discriminant initializer. For `const fn`, both `optimized_mir` and `mir_for_ctfe` work, the former returning the MIR that LLVM should use if the function is called at runtime. Similarly it is illegal to invoke `mir_for_ctfe` on regular functions. This is all checked via appropriate assertions and I don't think it is easy to get wrong, as there should be no `mir_for_ctfe` calls outside the const evaluator or metadata encoding. Almost all rustc devs should keep using `optimized_mir` (or `instance_mir` for that matter).
2 parents 497c9a2 + 53e3a23 commit 704e47f

40 files changed

+556
-220
lines changed

compiler/rustc_metadata/src/rmeta/decoder.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1160,6 +1160,10 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
11601160
}
11611161
}
11621162

1163+
fn is_ctfe_mir_available(&self, id: DefIndex) -> bool {
1164+
self.root.tables.mir_for_ctfe.get(self, id).is_some()
1165+
}
1166+
11631167
fn is_item_mir_available(&self, id: DefIndex) -> bool {
11641168
self.root.tables.mir.get(self, id).is_some()
11651169
}
@@ -1183,6 +1187,17 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
11831187
.decode((self, tcx))
11841188
}
11851189

1190+
fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
1191+
self.root
1192+
.tables
1193+
.mir_for_ctfe
1194+
.get(self, id)
1195+
.unwrap_or_else(|| {
1196+
bug!("get_mir_for_ctfe: missing MIR for `{:?}`", self.local_def_id(id))
1197+
})
1198+
.decode((self, tcx))
1199+
}
1200+
11861201
fn get_mir_abstract_const(
11871202
&self,
11881203
tcx: TyCtxt<'tcx>,

compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs

+2
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
115115
})
116116
}
117117
optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(tcx, def_id.index)) }
118+
mir_for_ctfe => { tcx.arena.alloc(cdata.get_mir_for_ctfe(tcx, def_id.index)) }
118119
promoted_mir => { tcx.arena.alloc(cdata.get_promoted_mir(tcx, def_id.index)) }
119120
mir_abstract_const => { cdata.get_mir_abstract_const(tcx, def_id.index) }
120121
unused_generic_params => { cdata.get_unused_generic_params(def_id.index) }
@@ -145,6 +146,7 @@ provide! { <'tcx> tcx, def_id, other, cdata,
145146
impl_parent => { cdata.get_parent_impl(def_id.index) }
146147
trait_of_item => { cdata.get_trait_of_item(def_id.index) }
147148
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
149+
is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
148150

149151
dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) }
150152
is_panic_runtime => { cdata.root.panic_runtime }

compiler/rustc_metadata/src/rmeta/encoder.rs

+87-33
Original file line numberDiff line numberDiff line change
@@ -758,8 +758,6 @@ impl EncodeContext<'a, 'tcx> {
758758
self.encode_generics(def_id);
759759
self.encode_explicit_predicates(def_id);
760760
self.encode_inferred_outlives(def_id);
761-
self.encode_optimized_mir(def_id.expect_local());
762-
self.encode_promoted_mir(def_id.expect_local());
763761
}
764762

765763
fn encode_enum_variant_ctor(&mut self, def: &ty::AdtDef, index: VariantIdx) {
@@ -789,6 +787,7 @@ impl EncodeContext<'a, 'tcx> {
789787
self.encode_generics(def_id);
790788
self.encode_explicit_predicates(def_id);
791789
self.encode_inferred_outlives(def_id);
790+
self.encode_mir_for_ctfe(def_id.expect_local());
792791
self.encode_optimized_mir(def_id.expect_local());
793792
self.encode_promoted_mir(def_id.expect_local());
794793
}
@@ -897,6 +896,7 @@ impl EncodeContext<'a, 'tcx> {
897896
self.encode_explicit_predicates(def_id);
898897
self.encode_inferred_outlives(def_id);
899898
self.encode_optimized_mir(def_id.expect_local());
899+
self.encode_mir_for_ctfe(def_id.expect_local());
900900
self.encode_promoted_mir(def_id.expect_local());
901901
}
902902

@@ -1015,8 +1015,21 @@ impl EncodeContext<'a, 'tcx> {
10151015
self.encode_inferred_outlives(def_id);
10161016

10171017
// This should be kept in sync with `PrefetchVisitor.visit_trait_item`.
1018-
self.encode_optimized_mir(def_id.expect_local());
1019-
self.encode_promoted_mir(def_id.expect_local());
1018+
match trait_item.kind {
1019+
ty::AssocKind::Type => {}
1020+
ty::AssocKind::Const => {
1021+
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
1022+
self.encode_mir_for_ctfe(def_id.expect_local());
1023+
self.encode_promoted_mir(def_id.expect_local());
1024+
}
1025+
}
1026+
ty::AssocKind::Fn => {
1027+
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
1028+
self.encode_optimized_mir(def_id.expect_local());
1029+
self.encode_promoted_mir(def_id.expect_local());
1030+
}
1031+
}
1032+
}
10201033
}
10211034

10221035
fn metadata_output_only(&self) -> bool {
@@ -1089,23 +1102,28 @@ impl EncodeContext<'a, 'tcx> {
10891102

10901103
// The following part should be kept in sync with `PrefetchVisitor.visit_impl_item`.
10911104

1092-
let mir = match ast_item.kind {
1093-
hir::ImplItemKind::Const(..) => true,
1105+
let (mir, mir_const) = match ast_item.kind {
1106+
hir::ImplItemKind::Const(..) => (false, true),
10941107
hir::ImplItemKind::Fn(ref sig, _) => {
10951108
let generics = self.tcx.generics_of(def_id);
10961109
let needs_inline = (generics.requires_monomorphization(self.tcx)
10971110
|| tcx.codegen_fn_attrs(def_id).requests_inline())
10981111
&& !self.metadata_output_only();
10991112
let is_const_fn = sig.header.constness == hir::Constness::Const;
11001113
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
1101-
needs_inline || is_const_fn || always_encode_mir
1114+
(needs_inline || always_encode_mir, is_const_fn)
11021115
}
1103-
hir::ImplItemKind::TyAlias(..) => false,
1116+
hir::ImplItemKind::TyAlias(..) => (false, false),
11041117
};
11051118
if mir {
11061119
self.encode_optimized_mir(def_id.expect_local());
1120+
}
1121+
if mir || mir_const {
11071122
self.encode_promoted_mir(def_id.expect_local());
11081123
}
1124+
if mir_const {
1125+
self.encode_mir_for_ctfe(def_id.expect_local());
1126+
}
11091127
}
11101128

11111129
fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> {
@@ -1116,28 +1134,34 @@ impl EncodeContext<'a, 'tcx> {
11161134
self.lazy(param_names.iter())
11171135
}
11181136

1119-
fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
1120-
debug!("EntryBuilder::encode_mir({:?})", def_id);
1121-
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
1122-
record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
1137+
fn encode_mir_for_ctfe(&mut self, def_id: LocalDefId) {
1138+
debug!("EntryBuilder::encode_mir_for_ctfe({:?})", def_id);
1139+
record!(self.tables.mir_for_ctfe[def_id.to_def_id()] <- self.tcx.mir_for_ctfe(def_id));
11231140

1124-
let unused = self.tcx.unused_generic_params(def_id);
1125-
if !unused.is_empty() {
1126-
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
1127-
}
1141+
let unused = self.tcx.unused_generic_params(def_id);
1142+
if !unused.is_empty() {
1143+
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
1144+
}
11281145

1129-
let abstract_const = self.tcx.mir_abstract_const(def_id);
1130-
if let Ok(Some(abstract_const)) = abstract_const {
1131-
record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
1132-
}
1146+
let abstract_const = self.tcx.mir_abstract_const(def_id);
1147+
if let Ok(Some(abstract_const)) = abstract_const {
1148+
record!(self.tables.mir_abstract_consts[def_id.to_def_id()] <- abstract_const);
1149+
}
1150+
}
1151+
1152+
fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
1153+
debug!("EntryBuilder::encode_optimized_mir({:?})", def_id);
1154+
record!(self.tables.mir[def_id.to_def_id()] <- self.tcx.optimized_mir(def_id));
1155+
1156+
let unused = self.tcx.unused_generic_params(def_id);
1157+
if !unused.is_empty() {
1158+
record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused);
11331159
}
11341160
}
11351161

11361162
fn encode_promoted_mir(&mut self, def_id: LocalDefId) {
11371163
debug!("EncodeContext::encode_promoted_mir({:?})", def_id);
1138-
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id) {
1139-
record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
1140-
}
1164+
record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
11411165
}
11421166

11431167
// Encodes the inherent implementations of a structure, enumeration, or trait.
@@ -1406,22 +1430,31 @@ impl EncodeContext<'a, 'tcx> {
14061430

14071431
// The following part should be kept in sync with `PrefetchVisitor.visit_item`.
14081432

1409-
let mir = match item.kind {
1410-
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true,
1433+
let (mir, const_mir) = match item.kind {
1434+
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => (false, true),
14111435
hir::ItemKind::Fn(ref sig, ..) => {
14121436
let generics = tcx.generics_of(def_id);
14131437
let needs_inline = (generics.requires_monomorphization(tcx)
14141438
|| tcx.codegen_fn_attrs(def_id).requests_inline())
14151439
&& !self.metadata_output_only();
1440+
1441+
let is_const_fn = sig.header.constness == hir::Constness::Const;
14161442
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
1417-
needs_inline || sig.header.constness == hir::Constness::Const || always_encode_mir
1443+
let mir = needs_inline || always_encode_mir;
1444+
// We don't need the optimized MIR for const fns.
1445+
(mir, is_const_fn)
14181446
}
1419-
_ => false,
1447+
_ => (false, false),
14201448
};
14211449
if mir {
14221450
self.encode_optimized_mir(def_id.expect_local());
1451+
}
1452+
if mir || const_mir {
14231453
self.encode_promoted_mir(def_id.expect_local());
14241454
}
1455+
if const_mir {
1456+
self.encode_mir_for_ctfe(def_id.expect_local());
1457+
}
14251458
}
14261459

14271460
/// Serialize the text of exported macros
@@ -1486,7 +1519,7 @@ impl EncodeContext<'a, 'tcx> {
14861519
self.encode_generics(def_id.to_def_id());
14871520
self.encode_explicit_predicates(def_id.to_def_id());
14881521
self.encode_inferred_outlives(def_id.to_def_id());
1489-
self.encode_optimized_mir(def_id);
1522+
self.encode_mir_for_ctfe(def_id);
14901523
self.encode_promoted_mir(def_id);
14911524
}
14921525

@@ -1951,6 +1984,12 @@ struct PrefetchVisitor<'tcx> {
19511984
}
19521985

19531986
impl<'tcx> PrefetchVisitor<'tcx> {
1987+
fn prefetch_ctfe_mir(&self, def_id: LocalDefId) {
1988+
if self.mir_keys.contains(&def_id) {
1989+
self.tcx.ensure().mir_for_ctfe(def_id);
1990+
self.tcx.ensure().promoted_mir(def_id);
1991+
}
1992+
}
19541993
fn prefetch_mir(&self, def_id: LocalDefId) {
19551994
if self.mir_keys.contains(&def_id) {
19561995
self.tcx.ensure().optimized_mir(def_id);
@@ -1965,42 +2004,57 @@ impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
19652004
let tcx = self.tcx;
19662005
match item.kind {
19672006
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
1968-
self.prefetch_mir(tcx.hir().local_def_id(item.hir_id))
2007+
self.prefetch_ctfe_mir(tcx.hir().local_def_id(item.hir_id))
19692008
}
19702009
hir::ItemKind::Fn(ref sig, ..) => {
19712010
let def_id = tcx.hir().local_def_id(item.hir_id);
19722011
let generics = tcx.generics_of(def_id.to_def_id());
19732012
let needs_inline = generics.requires_monomorphization(tcx)
19742013
|| tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
1975-
if needs_inline || sig.header.constness == hir::Constness::Const {
2014+
if needs_inline {
19762015
self.prefetch_mir(def_id)
19772016
}
2017+
if sig.header.constness == hir::Constness::Const {
2018+
self.prefetch_ctfe_mir(def_id);
2019+
}
19782020
}
19792021
_ => (),
19802022
}
19812023
}
19822024

19832025
fn visit_trait_item(&self, trait_item: &'v hir::TraitItem<'v>) {
19842026
// This should be kept in sync with `encode_info_for_trait_item`.
1985-
self.prefetch_mir(self.tcx.hir().local_def_id(trait_item.hir_id));
2027+
let def_id = self.tcx.hir().local_def_id(trait_item.hir_id);
2028+
match trait_item.kind {
2029+
hir::TraitItemKind::Type(..) => {}
2030+
hir::TraitItemKind::Const(..) => {
2031+
self.prefetch_ctfe_mir(def_id);
2032+
}
2033+
hir::TraitItemKind::Fn(..) => {
2034+
self.prefetch_mir(def_id);
2035+
}
2036+
}
19862037
}
19872038

19882039
fn visit_impl_item(&self, impl_item: &'v hir::ImplItem<'v>) {
19892040
// This should be kept in sync with `encode_info_for_impl_item`.
19902041
let tcx = self.tcx;
19912042
match impl_item.kind {
19922043
hir::ImplItemKind::Const(..) => {
1993-
self.prefetch_mir(tcx.hir().local_def_id(impl_item.hir_id))
2044+
self.prefetch_ctfe_mir(tcx.hir().local_def_id(impl_item.hir_id))
19942045
}
19952046
hir::ImplItemKind::Fn(ref sig, _) => {
19962047
let def_id = tcx.hir().local_def_id(impl_item.hir_id);
19972048
let generics = tcx.generics_of(def_id.to_def_id());
19982049
let needs_inline = generics.requires_monomorphization(tcx)
19992050
|| tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
20002051
let is_const_fn = sig.header.constness == hir::Constness::Const;
2001-
if needs_inline || is_const_fn {
2052+
if needs_inline {
20022053
self.prefetch_mir(def_id)
20032054
}
2055+
if is_const_fn {
2056+
self.prefetch_ctfe_mir(def_id);
2057+
}
20042058
}
20052059
hir::ImplItemKind::TyAlias(..) => (),
20062060
}

compiler/rustc_metadata/src/rmeta/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@ define_tables! {
302302
// As an optimization, a missing entry indicates an empty `&[]`.
303303
explicit_item_bounds: Table<DefIndex, Lazy!([(ty::Predicate<'tcx>, Span)])>,
304304
mir: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
305+
mir_for_ctfe: Table<DefIndex, Lazy!(mir::Body<'tcx>)>,
305306
promoted_mir: Table<DefIndex, Lazy!(IndexVec<mir::Promoted, mir::Body<'tcx>>)>,
306307
mir_abstract_consts: Table<DefIndex, Lazy!(&'tcx [mir::abstract_const::Node<'tcx>])>,
307308
unused_generic_params: Table<DefIndex, Lazy<FiniteBitSet<u32>>>,

compiler/rustc_middle/src/mir/query.rs

+11-2
Original file line numberDiff line numberDiff line change
@@ -439,17 +439,26 @@ impl<'tcx> TyCtxt<'tcx> {
439439
}
440440

441441
#[inline]
442-
pub fn optimized_mir_opt_const_arg(
442+
pub fn optimized_mir_or_const_arg_mir(
443443
self,
444444
def: ty::WithOptConstParam<DefId>,
445445
) -> &'tcx Body<'tcx> {
446446
if let Some((did, param_did)) = def.as_const_arg() {
447-
self.optimized_mir_of_const_arg((did, param_did))
447+
self.mir_for_ctfe_of_const_arg((did, param_did))
448448
} else {
449449
self.optimized_mir(def.did)
450450
}
451451
}
452452

453+
#[inline]
454+
pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> {
455+
if let Some((did, param_did)) = def.as_const_arg() {
456+
self.mir_for_ctfe_of_const_arg((did, param_did))
457+
} else {
458+
self.mir_for_ctfe(def.did)
459+
}
460+
}
461+
453462
#[inline]
454463
pub fn mir_abstract_const_opt_const_arg(
455464
self,

compiler/rustc_middle/src/query/mod.rs

+17-6
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,20 @@ rustc_queries! {
312312
desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
313313
}
314314

315+
query mir_for_ctfe(
316+
key: DefId
317+
) -> &'tcx mir::Body<'tcx> {
318+
desc { |tcx| "caching mir of `{}` for CTFE", tcx.def_path_str(key) }
319+
cache_on_disk_if { key.is_local() }
320+
}
321+
322+
query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
323+
desc {
324+
|tcx| "MIR for CTFE of the const argument `{}`",
325+
tcx.def_path_str(key.0.to_def_id())
326+
}
327+
}
328+
315329
query mir_promoted(key: ty::WithOptConstParam<LocalDefId>) ->
316330
(
317331
&'tcx Steal<mir::Body<'tcx>>,
@@ -331,12 +345,6 @@ rustc_queries! {
331345
desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
332346
cache_on_disk_if { key.is_local() }
333347
}
334-
query optimized_mir_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
335-
desc {
336-
|tcx| "optimizing MIR for the const argument `{}`",
337-
tcx.def_path_str(key.0.to_def_id())
338-
}
339-
}
340348

341349
/// Returns coverage summary info for a function, after executing the `InstrumentCoverage`
342350
/// MIR pass (assuming the -Zinstrument-coverage option is enabled).
@@ -927,6 +935,9 @@ rustc_queries! {
927935
}
928936

929937
Codegen {
938+
query is_ctfe_mir_available(key: DefId) -> bool {
939+
desc { |tcx| "checking if item has ctfe mir available: `{}`", tcx.def_path_str(key) }
940+
}
930941
query is_mir_available(key: DefId) -> bool {
931942
desc { |tcx| "checking if item has mir available: `{}`", tcx.def_path_str(key) }
932943
}

compiler/rustc_middle/src/ty/mod.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -3010,7 +3010,16 @@ impl<'tcx> TyCtxt<'tcx> {
30103010
/// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
30113011
pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
30123012
match instance {
3013-
ty::InstanceDef::Item(def) => self.optimized_mir_opt_const_arg(def),
3013+
ty::InstanceDef::Item(def) => match self.def_kind(def.did) {
3014+
DefKind::Const
3015+
| DefKind::Static
3016+
| DefKind::AssocConst
3017+
| DefKind::Ctor(..)
3018+
| DefKind::AnonConst => self.mir_for_ctfe_opt_const_arg(def),
3019+
// If the caller wants `mir_for_ctfe` of a function they should not be using
3020+
// `instance_mir`, so we'll assume const fn also wants the optimized version.
3021+
_ => self.optimized_mir_or_const_arg_mir(def),
3022+
},
30143023
ty::InstanceDef::VtableShim(..)
30153024
| ty::InstanceDef::ReifyShim(..)
30163025
| ty::InstanceDef::Intrinsic(..)

0 commit comments

Comments
 (0)