Replace tuples in DropTree
with named structs · rust-lang/rust@5ba70bd (original) (raw)
`@@ -203,16 +203,31 @@ const ROOT_NODE: DropIdx = DropIdx::from_u32(0);
`
203
203
`` /// in build_mir
.
``
204
204
`#[derive(Debug)]
`
205
205
`struct DropTree {
`
206
``
`-
/// Drops in the tree.
`
207
``
`-
drops: IndexVec<DropIdx, (DropData, DropIdx)>,
`
208
``
`` -
/// Map for finding the inverse of the next_drop
relation:
``
209
``
`-
///
`
210
``
`` -
/// previous_drops[(drops[i].1, drops[i].0.local, drops[i].0.kind)] == i
``
211
``
`-
previous_drops: FxHashMap<(DropIdx, Local, DropKind), DropIdx>,
`
``
206
`+
/// Nodes in the drop tree, containing drop data and a link to the next node.
`
``
207
`+
drops: IndexVec<DropIdx, DropNode>,
`
``
208
`+
/// Map for finding the index of an existing node, given its contents.
`
``
209
`+
existing_drops_map: FxHashMap<DropNodeKey, DropIdx>,
`
212
210
`` /// Edges into the DropTree
that need to be added once it's lowered.
``
213
211
`entry_points: Vec<(DropIdx, BasicBlock)>,
`
214
212
`}
`
215
213
``
``
214
`+
/// A single node in the drop tree.
`
``
215
`+
#[derive(Debug)]
`
``
216
`+
struct DropNode {
`
``
217
`+
/// Info about the drop to be performed at this node in the drop tree.
`
``
218
`+
data: DropData,
`
``
219
`+
/// Index of the "next" drop to perform (in drop order, not declaration order).
`
``
220
`+
next: DropIdx,
`
``
221
`+
}
`
``
222
+
``
223
`` +
/// Subset of [DropNode
] used for reverse lookup in a hash table.
``
``
224
`+
#[derive(Debug, PartialEq, Eq, Hash)]
`
``
225
`+
struct DropNodeKey {
`
``
226
`+
next: DropIdx,
`
``
227
`+
local: Local,
`
``
228
`+
kind: DropKind,
`
``
229
`+
}
`
``
230
+
216
231
`impl Scope {
`
217
232
`/// Whether there's anything to do for the cleanup path, that is,
`
218
233
`/// when unwinding through this scope. This includes destructors,
`
`@@ -258,17 +273,22 @@ impl DropTree {
`
258
273
`let fake_source_info = SourceInfo::outermost(DUMMY_SP);
`
259
274
`let fake_data =
`
260
275
`DropData { source_info: fake_source_info, local: Local::MAX, kind: DropKind::Storage };
`
261
``
`-
let drop_idx = DropIdx::MAX;
`
262
``
`-
let drops = IndexVec::from_elem_n((fake_data, drop_idx), 1);
`
263
``
`-
Self { drops, entry_points: Vec::new(), previous_drops: FxHashMap::default() }
`
``
276
`+
let drops = IndexVec::from_raw(vec![DropNode { data: fake_data, next: DropIdx::MAX }]);
`
``
277
`+
Self { drops, entry_points: Vec::new(), existing_drops_map: FxHashMap::default() }
`
264
278
`}
`
265
279
``
266
``
`-
fn add_drop(&mut self, drop: DropData, next: DropIdx) -> DropIdx {
`
``
280
`+
/// Adds a node to the drop tree, consisting of drop data and the index of
`
``
281
`` +
/// the "next" drop (in drop order), which could be the sentinel [ROOT_NODE
].
``
``
282
`+
///
`
``
283
`+
/// If there is already an equivalent node in the tree, nothing is added, and
`
``
284
`+
/// that node's index is returned. Otherwise, the new node's index is returned.
`
``
285
`+
fn add_drop(&mut self, data: DropData, next: DropIdx) -> DropIdx {
`
267
286
`let drops = &mut self.drops;
`
268
287
`*self
`
269
``
`-
.previous_drops
`
270
``
`-
.entry((next, drop.local, drop.kind))
`
271
``
`-
.or_insert_with(|| drops.push((drop, next)))
`
``
288
`+
.existing_drops_map
`
``
289
`+
.entry(DropNodeKey { next, local: data.local, kind: data.kind })
`
``
290
`+
// Create a new node, and also add its index to the map.
`
``
291
`+
.or_insert_with(|| drops.push(DropNode { data, next }))
`
272
292
`}
`
273
293
``
274
294
`` /// Registers from
as an entry point to this drop tree, at to
.
``
`@@ -330,7 +350,7 @@ impl DropTree {
`
330
350
`let entry_points = &mut self.entry_points;
`
331
351
` entry_points.sort();
`
332
352
``
333
``
`-
for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
`
``
353
`+
for (drop_idx, drop_node) in self.drops.iter_enumerated().rev() {
`
334
354
`if entry_points.last().is_some_and(|entry_point| entry_point.0 == drop_idx) {
`
335
355
`let block = *blocks[drop_idx].get_or_insert_with(|| T::make_block(cfg));
`
336
356
` needs_block[drop_idx] = Block::Own;
`
`@@ -348,10 +368,10 @@ impl DropTree {
`
348
368
` blocks[drop_idx] = blocks[pred];
`
349
369
`}
`
350
370
`}
`
351
``
`-
if let DropKind::Value = drop_data.0.kind {
`
352
``
`-
needs_block[drop_data.1] = Block::Own;
`
``
371
`+
if let DropKind::Value = drop_node.data.kind {
`
``
372
`+
needs_block[drop_node.next] = Block::Own;
`
353
373
`} else if drop_idx != ROOT_NODE {
`
354
``
`-
match &mut needs_block[drop_data.1] {
`
``
374
`+
match &mut needs_block[drop_node.next] {
`
355
375
` pred @ Block::None => *pred = Block::Shares(drop_idx),
`
356
376
` pred @ Block::Shares(_) => *pred = Block::Own,
`
357
377
`Block::Own => (),
`
`@@ -368,34 +388,35 @@ impl DropTree {
`
368
388
`cfg: &mut CFG<'tcx>,
`
369
389
`blocks: &IndexSlice<DropIdx, Option>,
`
370
390
`) {
`
371
``
`-
for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
`
``
391
`+
for (drop_idx, drop_node) in self.drops.iter_enumerated().rev() {
`
372
392
`let Some(block) = blocks[drop_idx] else { continue };
`
373
``
`-
match drop_data.0.kind {
`
``
393
`+
match drop_node.data.kind {
`
374
394
`DropKind::Value => {
`
375
395
`let terminator = TerminatorKind::Drop {
`
376
``
`-
target: blocks[drop_data.1].unwrap(),
`
``
396
`+
target: blocks[drop_node.next].unwrap(),
`
377
397
`// The caller will handle this if needed.
`
378
398
`unwind: UnwindAction::Terminate(UnwindTerminateReason::InCleanup),
`
379
``
`-
place: drop_data.0.local.into(),
`
``
399
`+
place: drop_node.data.local.into(),
`
380
400
`replace: false,
`
381
401
`};
`
382
``
`-
cfg.terminate(block, drop_data.0.source_info, terminator);
`
``
402
`+
cfg.terminate(block, drop_node.data.source_info, terminator);
`
383
403
`}
`
384
404
`// Root nodes don't correspond to a drop.
`
385
405
`DropKind::Storage if drop_idx == ROOT_NODE => {}
`
386
406
`DropKind::Storage => {
`
387
407
`let stmt = Statement {
`
388
``
`-
source_info: drop_data.0.source_info,
`
389
``
`-
kind: StatementKind::StorageDead(drop_data.0.local),
`
``
408
`+
source_info: drop_node.data.source_info,
`
``
409
`+
kind: StatementKind::StorageDead(drop_node.data.local),
`
390
410
`};
`
391
411
` cfg.push(block, stmt);
`
392
``
`-
let target = blocks[drop_data.1].unwrap();
`
``
412
`+
let target = blocks[drop_node.next].unwrap();
`
393
413
`if target != block {
`
394
414
`` // Diagnostics don't use this Span
but debuginfo
``
395
415
`// might. Since we don't want breakpoints to be placed
`
396
416
`// here, especially when this is on an unwind path, we
`
397
417
`` // use DUMMY_SP
.
``
398
``
`-
let source_info = SourceInfo { span: DUMMY_SP, ..drop_data.0.source_info };
`
``
418
`+
let source_info =
`
``
419
`+
SourceInfo { span: DUMMY_SP, ..drop_node.data.source_info };
`
399
420
`let terminator = TerminatorKind::Goto { target };
`
400
421
` cfg.terminate(block, source_info, terminator);
`
401
422
`}
`
`@@ -1277,9 +1298,9 @@ fn build_scope_drops<'tcx>(
`
1277
1298
`` // unwind_to
should drop the value that we're about to
``
1278
1299
`// schedule. If dropping this value panics, then we continue
`
1279
1300
`// with the next value on the unwind path.
`
1280
``
`-
debug_assert_eq!(unwind_drops.drops[unwind_to].0.local, drop_data.local);
`
1281
``
`-
debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind);
`
1282
``
`-
unwind_to = unwind_drops.drops[unwind_to].1;
`
``
1301
`+
debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local);
`
``
1302
`+
debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
`
``
1303
`+
unwind_to = unwind_drops.drops[unwind_to].next;
`
1283
1304
``
1284
1305
`// If the operand has been moved, and we are not on an unwind
`
1285
1306
`// path, then don't generate the drop. (We only take this into
`
`@@ -1306,9 +1327,9 @@ fn build_scope_drops<'tcx>(
`
1306
1327
`}
`
1307
1328
`DropKind::Storage => {
`
1308
1329
`if storage_dead_on_unwind {
`
1309
``
`-
debug_assert_eq!(unwind_drops.drops[unwind_to].0.local, drop_data.local);
`
1310
``
`-
debug_assert_eq!(unwind_drops.drops[unwind_to].0.kind, drop_data.kind);
`
1311
``
`-
unwind_to = unwind_drops.drops[unwind_to].1;
`
``
1330
`+
debug_assert_eq!(unwind_drops.drops[unwind_to].data.local, drop_data.local);
`
``
1331
`+
debug_assert_eq!(unwind_drops.drops[unwind_to].data.kind, drop_data.kind);
`
``
1332
`+
unwind_to = unwind_drops.drops[unwind_to].next;
`
1312
1333
`}
`
1313
1334
`// Only temps and vars need their storage dead.
`
1314
1335
`assert!(local.index() > arg_count);
`
`@@ -1338,30 +1359,30 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
`
1338
1359
`let is_coroutine = self.coroutine.is_some();
`
1339
1360
``
1340
1361
`// Link the exit drop tree to unwind drop tree.
`
1341
``
`-
if drops.drops.iter().any(|(drop, _)| drop.kind == DropKind::Value) {
`
``
1362
`+
if drops.drops.iter().any(|drop_node| drop_node.data.kind == DropKind::Value) {
`
1342
1363
`let unwind_target = self.diverge_cleanup_target(else_scope, span);
`
1343
1364
`let mut unwind_indices = IndexVec::from_elem_n(unwind_target, 1);
`
1344
``
`-
for (drop_idx, drop_data) in drops.drops.iter_enumerated().skip(1) {
`
1345
``
`-
match drop_data.0.kind {
`
``
1365
`+
for (drop_idx, drop_node) in drops.drops.iter_enumerated().skip(1) {
`
``
1366
`+
match drop_node.data.kind {
`
1346
1367
`DropKind::Storage => {
`
1347
1368
`if is_coroutine {
`
1348
1369
`let unwind_drop = self
`
1349
1370
`.scopes
`
1350
1371
`.unwind_drops
`
1351
``
`-
.add_drop(drop_data.0, unwind_indices[drop_data.1]);
`
``
1372
`+
.add_drop(drop_node.data, unwind_indices[drop_node.next]);
`
1352
1373
` unwind_indices.push(unwind_drop);
`
1353
1374
`} else {
`
1354
``
`-
unwind_indices.push(unwind_indices[drop_data.1]);
`
``
1375
`+
unwind_indices.push(unwind_indices[drop_node.next]);
`
1355
1376
`}
`
1356
1377
`}
`
1357
1378
`DropKind::Value => {
`
1358
1379
`let unwind_drop = self
`
1359
1380
`.scopes
`
1360
1381
`.unwind_drops
`
1361
``
`-
.add_drop(drop_data.0, unwind_indices[drop_data.1]);
`
``
1382
`+
.add_drop(drop_node.data, unwind_indices[drop_node.next]);
`
1362
1383
`self.scopes.unwind_drops.add_entry_point(
`
1363
1384
` blocks[drop_idx].unwrap(),
`
1364
``
`-
unwind_indices[drop_data.1],
`
``
1385
`+
unwind_indices[drop_node.next],
`
1365
1386
`);
`
1366
1387
` unwind_indices.push(unwind_drop);
`
1367
1388
`}
`
`@@ -1412,10 +1433,10 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
`
1412
1433
`// prevent drop elaboration from creating drop flags that would have
`
1413
1434
`// to be captured by the coroutine. I'm not sure how important this
`
1414
1435
`// optimization is, but it is here.
`
1415
``
`-
for (drop_idx, drop_data) in drops.drops.iter_enumerated() {
`
1416
``
`-
if let DropKind::Value = drop_data.0.kind {
`
1417
``
`-
debug_assert!(drop_data.1 < drops.drops.next_index());
`
1418
``
`-
drops.entry_points.push((drop_data.1, blocks[drop_idx].unwrap()));
`
``
1436
`+
for (drop_idx, drop_node) in drops.drops.iter_enumerated() {
`
``
1437
`+
if let DropKind::Value = drop_node.data.kind {
`
``
1438
`+
debug_assert!(drop_node.next < drops.drops.next_index());
`
``
1439
`+
drops.entry_points.push((drop_node.next, blocks[drop_idx].unwrap()));
`
1419
1440
`}
`
1420
1441
`}
`
1421
1442
`Self::build_unwind_tree(cfg, drops, fn_span, resume_block);
`