@@ -24,7 +24,6 @@ use syntax::symbol::sym;
24
24
use syntax_pos::{Span, DUMMY_SP};
25
25
26
26
use rustc_index::vec::{IndexVec, Idx};
27
- use rustc_index::bit_set::HybridBitSet;
28
27
use rustc_target::spec::abi::Abi;
29
28
30
29
use std::cell::Cell;
@@ -35,10 +34,8 @@ use crate::transform::check_consts::{qualifs, Item, ConstKind, is_lang_panic_fn}
35
34
36
35
/// A `MirPass` for promotion.
37
36
///
38
- /// In this case, "promotion" entails the following:
39
- /// - Extract promotable temps in `fn` and `const fn` into their own MIR bodies.
40
- /// - Extend lifetimes in `const` and `static` by removing `Drop` and `StorageDead`.
41
- /// - Emit errors if the requirements of `#[rustc_args_required_const]` are not met.
37
+ /// Promotion is the extraction of promotable temps into separate MIR bodies. This pass also emits
38
+ /// errors when promotion of `#[rustc_args_required_const]` arguments fails.
42
39
///
43
40
/// After this pass is run, `promoted_fragments` will hold the MIR body corresponding to each
44
41
/// newly created `StaticKind::Promoted`.
@@ -63,26 +60,13 @@ impl<'tcx> MirPass<'tcx> for PromoteTemps<'tcx> {
63
60
64
61
let def_id = src.def_id();
65
62
66
- let item = Item::new(tcx, def_id, body);
67
63
let mut rpo = traversal::reverse_postorder(body);
68
64
let (temps, all_candidates) = collect_temps_and_candidates(tcx, body, &mut rpo);
69
65
70
66
let promotable_candidates = validate_candidates(tcx, body, def_id, &temps, &all_candidates);
71
67
72
- // For now, lifetime extension is done in `const` and `static`s without creating promoted
73
- // MIR fragments by removing `Drop` and `StorageDead` for each referent. However, this will
74
- // not work inside loops when they are allowed in `const`s.
75
- //
76
- // FIXME: use promoted MIR fragments everywhere?
77
- let promoted_fragments = if should_create_promoted_mir_fragments(item.const_kind) {
78
- promote_candidates(def_id, body, tcx, temps, promotable_candidates)
79
- } else {
80
- // FIXME: promote const array initializers in consts.
81
- remove_drop_and_storage_dead_on_promoted_locals(tcx, body, &promotable_candidates);
82
- IndexVec::new()
83
- };
84
-
85
- self.promoted_fragments.set(promoted_fragments);
68
+ let promoted = promote_candidates(def_id, body, tcx, temps, promotable_candidates);
69
+ self.promoted_fragments.set(promoted);
86
70
}
87
71
}
88
72
@@ -1178,83 +1162,3 @@ crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>(
1178
1162
should_promote={:?} feature_flag={:?}", mir_def_id, should_promote, feature_flag);
1179
1163
should_promote && !feature_flag
1180
1164
}
1181
-
1182
- fn should_create_promoted_mir_fragments(const_kind: Option<ConstKind>) -> bool {
1183
- match const_kind {
1184
- Some(ConstKind::ConstFn) | None => true,
1185
- Some(ConstKind::Const) | Some(ConstKind::Static) | Some(ConstKind::StaticMut) => false,
1186
- }
1187
- }
1188
-
1189
- /// In `const` and `static` everything without `StorageDead`
1190
- /// is `'static`, we don't have to create promoted MIR fragments,
1191
- /// just remove `Drop` and `StorageDead` on "promoted" locals.
1192
- fn remove_drop_and_storage_dead_on_promoted_locals(
1193
- tcx: TyCtxt<'tcx>,
1194
- body: &mut Body<'tcx>,
1195
- promotable_candidates: &[Candidate],
1196
- ) {
1197
- debug!("run_pass: promotable_candidates={:?}", promotable_candidates);
1198
-
1199
- // Removing `StorageDead` will cause errors for temps declared inside a loop body. For now we
1200
- // simply skip promotion if a loop exists, since loops are not yet allowed in a `const`.
1201
- //
1202
- // FIXME: Just create MIR fragments for `const`s instead of using this hackish approach?
1203
- if body.is_cfg_cyclic() {
1204
- tcx.sess.delay_span_bug(body.span, "Control-flow cycle detected in `const`");
1205
- return;
1206
- }
1207
-
1208
- // The underlying local for promotion contexts like `&temp` and `&(temp.proj)`.
1209
- let mut requires_lifetime_extension = HybridBitSet::new_empty(body.local_decls.len());
1210
-
1211
- promotable_candidates
1212
- .iter()
1213
- .filter_map(|c| {
1214
- match c {
1215
- Candidate::Ref(loc) => Some(loc),
1216
- Candidate::Repeat(_) | Candidate::Argument { .. } => None,
1217
- }
1218
- })
1219
- .map(|&Location { block, statement_index }| {
1220
- // FIXME: store the `Local` for each `Candidate` when it is created.
1221
- let place = match &body[block].statements[statement_index].kind {
1222
- StatementKind::Assign(box ( _, Rvalue::Ref(_, _, place))) => place,
1223
- _ => bug!("`Candidate::Ref` without corresponding assignment"),
1224
- };
1225
-
1226
- match place.base {
1227
- PlaceBase::Local(local) => local,
1228
- PlaceBase::Static(_) => bug!("`Candidate::Ref` for a non-local"),
1229
- }
1230
- })
1231
- .for_each(|local| {
1232
- requires_lifetime_extension.insert(local);
1233
- });
1234
-
1235
- // Remove `Drop` terminators and `StorageDead` statements for all promotable temps that require
1236
- // lifetime extension.
1237
- for block in body.basic_blocks_mut() {
1238
- block.statements.retain(|statement| {
1239
- match statement.kind {
1240
- StatementKind::StorageDead(index) => !requires_lifetime_extension.contains(index),
1241
- _ => true
1242
- }
1243
- });
1244
- let terminator = block.terminator_mut();
1245
- match &terminator.kind {
1246
- TerminatorKind::Drop {
1247
- location,
1248
- target,
1249
- ..
1250
- } => {
1251
- if let Some(index) = location.as_local() {
1252
- if requires_lifetime_extension.contains(index) {
1253
- terminator.kind = TerminatorKind::Goto { target: *target };
1254
- }
1255
- }
1256
- }
1257
- _ => {}
1258
- }
1259
- }
1260
- }
0 commit comments