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);

`