Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit cccd40f

Browse files
olioli-obk
authored andcommitted
Keep an unoptimized duplicate of const fn around
This allows CTFE to reliably detect UB, as otherwise optimizations may hide UB.
1 parent 8e4fe66 commit cccd40f

25 files changed

+312
-112
lines changed

compiler/rustc_metadata/src/rmeta/decoder.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,6 +1162,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
11621162

11631163
fn is_item_mir_available(&self, id: DefIndex) -> bool {
11641164
self.root.tables.mir.get(self, id).is_some()
1165+
|| self.root.tables.mir_for_ctfe.get(self, id).is_some()
11651166
}
11661167

11671168
fn module_expansion(&self, id: DefIndex, sess: &Session) -> ExpnId {
@@ -1183,6 +1184,17 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
11831184
.decode((self, tcx))
11841185
}
11851186

1187+
fn get_mir_for_ctfe(&self, tcx: TyCtxt<'tcx>, id: DefIndex) -> Body<'tcx> {
1188+
self.root
1189+
.tables
1190+
.mir_for_ctfe
1191+
.get(self, id)
1192+
.unwrap_or_else(|| {
1193+
bug!("get_mir_for_ctfe: missing MIR for `{:?}`", self.local_def_id(id))
1194+
})
1195+
.decode((self, tcx))
1196+
}
1197+
11861198
fn get_mir_abstract_const(
11871199
&self,
11881200
tcx: TyCtxt<'tcx>,

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

Lines changed: 1 addition & 0 deletions
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) }

compiler/rustc_metadata/src/rmeta/encoder.rs

Lines changed: 69 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ impl EncodeContext<'a, 'tcx> {
787787
self.encode_generics(def_id);
788788
self.encode_explicit_predicates(def_id);
789789
self.encode_inferred_outlives(def_id);
790+
self.encode_mir_for_ctfe(def_id.expect_local());
790791
self.encode_optimized_mir(def_id.expect_local());
791792
self.encode_promoted_mir(def_id.expect_local());
792793
}
@@ -895,6 +896,7 @@ impl EncodeContext<'a, 'tcx> {
895896
self.encode_explicit_predicates(def_id);
896897
self.encode_inferred_outlives(def_id);
897898
self.encode_optimized_mir(def_id.expect_local());
899+
self.encode_mir_for_ctfe(def_id.expect_local());
898900
self.encode_promoted_mir(def_id.expect_local());
899901
}
900902

@@ -1015,7 +1017,13 @@ impl EncodeContext<'a, 'tcx> {
10151017
// This should be kept in sync with `PrefetchVisitor.visit_trait_item`.
10161018
match trait_item.kind {
10171019
ty::AssocKind::Type => {}
1018-
ty::AssocKind::Const | ty::AssocKind::Fn => {
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 => {
10191027
if self.tcx.mir_keys(LOCAL_CRATE).contains(&def_id.expect_local()) {
10201028
self.encode_optimized_mir(def_id.expect_local());
10211029
self.encode_promoted_mir(def_id.expect_local());
@@ -1094,23 +1102,28 @@ impl EncodeContext<'a, 'tcx> {
10941102

10951103
// The following part should be kept in sync with `PrefetchVisitor.visit_impl_item`.
10961104

1097-
let mir = match ast_item.kind {
1098-
hir::ImplItemKind::Const(..) => true,
1105+
let (mir, mir_const) = match ast_item.kind {
1106+
hir::ImplItemKind::Const(..) => (false, true),
10991107
hir::ImplItemKind::Fn(ref sig, _) => {
11001108
let generics = self.tcx.generics_of(def_id);
11011109
let needs_inline = (generics.requires_monomorphization(self.tcx)
11021110
|| tcx.codegen_fn_attrs(def_id).requests_inline())
11031111
&& !self.metadata_output_only();
11041112
let is_const_fn = sig.header.constness == hir::Constness::Const;
11051113
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
1106-
needs_inline || is_const_fn || always_encode_mir
1114+
(needs_inline || always_encode_mir, is_const_fn)
11071115
}
1108-
hir::ImplItemKind::TyAlias(..) => false,
1116+
hir::ImplItemKind::TyAlias(..) => (false, false),
11091117
};
11101118
if mir {
11111119
self.encode_optimized_mir(def_id.expect_local());
1120+
}
1121+
if mir || mir_const {
11121122
self.encode_promoted_mir(def_id.expect_local());
11131123
}
1124+
if mir_const {
1125+
self.encode_mir_for_ctfe(def_id.expect_local());
1126+
}
11141127
}
11151128

11161129
fn encode_fn_param_names_for_body(&mut self, body_id: hir::BodyId) -> Lazy<[Ident]> {
@@ -1121,9 +1134,9 @@ impl EncodeContext<'a, 'tcx> {
11211134
self.lazy(param_names.iter())
11221135
}
11231136

1124-
fn encode_optimized_mir(&mut self, def_id: LocalDefId) {
1125-
debug!("EntryBuilder::encode_mir({:?})", def_id);
1126-
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));
11271140

11281141
let unused = self.tcx.unused_generic_params(def_id);
11291142
if !unused.is_empty() {
@@ -1136,6 +1149,16 @@ impl EncodeContext<'a, 'tcx> {
11361149
}
11371150
}
11381151

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);
1159+
}
1160+
}
1161+
11391162
fn encode_promoted_mir(&mut self, def_id: LocalDefId) {
11401163
debug!("EncodeContext::encode_promoted_mir({:?})", def_id);
11411164
record!(self.tables.promoted_mir[def_id.to_def_id()] <- self.tcx.promoted_mir(def_id));
@@ -1407,8 +1430,8 @@ impl EncodeContext<'a, 'tcx> {
14071430

14081431
// The following part should be kept in sync with `PrefetchVisitor.visit_item`.
14091432

1410-
let mir = match item.kind {
1411-
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => true,
1433+
let (mir, const_mir) = match item.kind {
1434+
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => (false, true),
14121435
hir::ItemKind::Fn(ref sig, ..) => {
14131436
let generics = tcx.generics_of(def_id);
14141437
let needs_inline = (generics.requires_monomorphization(tcx)
@@ -1417,14 +1440,21 @@ impl EncodeContext<'a, 'tcx> {
14171440

14181441
let is_const_fn = sig.header.constness == hir::Constness::Const;
14191442
let always_encode_mir = self.tcx.sess.opts.debugging_opts.always_encode_mir;
1420-
needs_inline || is_const_fn || 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)
14211446
}
1422-
_ => false,
1447+
_ => (false, false),
14231448
};
14241449
if mir {
14251450
self.encode_optimized_mir(def_id.expect_local());
1451+
}
1452+
if mir || const_mir {
14261453
self.encode_promoted_mir(def_id.expect_local());
14271454
}
1455+
if const_mir {
1456+
self.encode_mir_for_ctfe(def_id.expect_local());
1457+
}
14281458
}
14291459

14301460
/// Serialize the text of exported macros
@@ -1489,7 +1519,7 @@ impl EncodeContext<'a, 'tcx> {
14891519
self.encode_generics(def_id.to_def_id());
14901520
self.encode_explicit_predicates(def_id.to_def_id());
14911521
self.encode_inferred_outlives(def_id.to_def_id());
1492-
self.encode_optimized_mir(def_id);
1522+
self.encode_mir_for_ctfe(def_id);
14931523
self.encode_promoted_mir(def_id);
14941524
}
14951525

@@ -1954,6 +1984,12 @@ struct PrefetchVisitor<'tcx> {
19541984
}
19551985

19561986
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+
}
19571993
fn prefetch_mir(&self, def_id: LocalDefId) {
19581994
if self.mir_keys.contains(&def_id) {
19591995
self.tcx.ensure().optimized_mir(def_id);
@@ -1968,42 +2004,57 @@ impl<'tcx, 'v> ParItemLikeVisitor<'v> for PrefetchVisitor<'tcx> {
19682004
let tcx = self.tcx;
19692005
match item.kind {
19702006
hir::ItemKind::Static(..) | hir::ItemKind::Const(..) => {
1971-
self.prefetch_mir(tcx.hir().local_def_id(item.hir_id))
2007+
self.prefetch_ctfe_mir(tcx.hir().local_def_id(item.hir_id))
19722008
}
19732009
hir::ItemKind::Fn(ref sig, ..) => {
19742010
let def_id = tcx.hir().local_def_id(item.hir_id);
19752011
let generics = tcx.generics_of(def_id.to_def_id());
19762012
let needs_inline = generics.requires_monomorphization(tcx)
19772013
|| tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
1978-
if needs_inline || sig.header.constness == hir::Constness::Const {
2014+
if needs_inline {
19792015
self.prefetch_mir(def_id)
19802016
}
2017+
if sig.header.constness == hir::Constness::Const {
2018+
self.prefetch_ctfe_mir(def_id);
2019+
}
19812020
}
19822021
_ => (),
19832022
}
19842023
}
19852024

19862025
fn visit_trait_item(&self, trait_item: &'v hir::TraitItem<'v>) {
19872026
// This should be kept in sync with `encode_info_for_trait_item`.
1988-
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+
}
19892037
}
19902038

19912039
fn visit_impl_item(&self, impl_item: &'v hir::ImplItem<'v>) {
19922040
// This should be kept in sync with `encode_info_for_impl_item`.
19932041
let tcx = self.tcx;
19942042
match impl_item.kind {
19952043
hir::ImplItemKind::Const(..) => {
1996-
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))
19972045
}
19982046
hir::ImplItemKind::Fn(ref sig, _) => {
19992047
let def_id = tcx.hir().local_def_id(impl_item.hir_id);
20002048
let generics = tcx.generics_of(def_id.to_def_id());
20012049
let needs_inline = generics.requires_monomorphization(tcx)
20022050
|| tcx.codegen_fn_attrs(def_id.to_def_id()).requests_inline();
20032051
let is_const_fn = sig.header.constness == hir::Constness::Const;
2004-
if needs_inline || is_const_fn {
2052+
if needs_inline {
20052053
self.prefetch_mir(def_id)
20062054
}
2055+
if is_const_fn {
2056+
self.prefetch_ctfe_mir(def_id);
2057+
}
20072058
}
20082059
hir::ImplItemKind::TyAlias(..) => (),
20092060
}

compiler/rustc_metadata/src/rmeta/mod.rs

Lines changed: 1 addition & 0 deletions
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

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,15 @@ impl<'tcx> TyCtxt<'tcx> {
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

Lines changed: 17 additions & 0 deletions
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 for `{}` 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,6 +345,9 @@ rustc_queries! {
331345
desc { |tcx| "optimizing MIR for `{}`", tcx.def_path_str(key) }
332346
cache_on_disk_if { key.is_local() }
333347
}
348+
349+
// FIXME: now that we have `mir_for_ctfe_of_const_arg` can we get
350+
// rid of this query?
334351
query optimized_mir_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
335352
desc {
336353
|tcx| "optimizing MIR for the const argument `{}`",

compiler/rustc_mir/src/interpret/eval_context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
480480
match instance {
481481
ty::InstanceDef::Item(def) => {
482482
if self.tcx.is_mir_available(def.did) {
483-
Ok(self.tcx.optimized_mir_opt_const_arg(def))
483+
Ok(self.tcx.mir_for_ctfe_opt_const_arg(def))
484484
} else {
485485
throw_unsup!(NoMirFor(def.did))
486486
}

compiler/rustc_mir/src/monomorphize/polymorphize.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,10 @@ fn unused_generic_params(tcx: TyCtxt<'_>, def_id: DefId) -> FiniteBitSet<u32> {
6969
debug!("unused_generic_params: (after default) unused_parameters={:?}", unused_parameters);
7070

7171
// Visit MIR and accumululate used generic parameters.
72-
let body = tcx.optimized_mir(def_id);
72+
let body = match tcx.hir().body_const_context(def_id.expect_local()) {
73+
None => tcx.optimized_mir(def_id),
74+
Some(_) => tcx.mir_for_ctfe(def_id),
75+
};
7376
let mut vis = MarkUsedGenericParams { tcx, def_id, unused_parameters: &mut unused_parameters };
7477
vis.visit_body(body);
7578
debug!("unused_generic_params: (after visitor) unused_parameters={:?}", unused_parameters);

0 commit comments

Comments
 (0)