Skip to content

Commit d5984c7

Browse files
committed
Auto merge of rust-lang#18255 - ChayimFriedman2:stack-overflow, r=HKalbasi
Use external stack in borrowck DFS Because damnit, it can crash r-a. Why do people make this stupid DFSes anyway (I get it, it's easier until it blows). Fixes rust-lang#18223 (who thought DFS will be the problem).
2 parents fe2b453 + 0e96fd0 commit d5984c7

File tree

1 file changed

+67
-58
lines changed
  • src/tools/rust-analyzer/crates/hir-ty/src/mir

1 file changed

+67
-58
lines changed

src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs

+67-58
Original file line numberDiff line numberDiff line change
@@ -386,82 +386,91 @@ fn ever_initialized_map(
386386
fn dfs(
387387
db: &dyn HirDatabase,
388388
body: &MirBody,
389-
b: BasicBlockId,
390389
l: LocalId,
390+
stack: &mut Vec<BasicBlockId>,
391391
result: &mut ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>>,
392392
) {
393-
let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs
394-
let block = &body.basic_blocks[b];
395-
for statement in &block.statements {
396-
match &statement.kind {
397-
StatementKind::Assign(p, _) => {
398-
if p.projection.lookup(&body.projection_store).is_empty() && p.local == l {
399-
is_ever_initialized = true;
393+
while let Some(b) = stack.pop() {
394+
let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs
395+
let block = &body.basic_blocks[b];
396+
for statement in &block.statements {
397+
match &statement.kind {
398+
StatementKind::Assign(p, _) => {
399+
if p.projection.lookup(&body.projection_store).is_empty() && p.local == l {
400+
is_ever_initialized = true;
401+
}
400402
}
401-
}
402-
StatementKind::StorageDead(p) => {
403-
if *p == l {
404-
is_ever_initialized = false;
403+
StatementKind::StorageDead(p) => {
404+
if *p == l {
405+
is_ever_initialized = false;
406+
}
405407
}
408+
StatementKind::Deinit(_)
409+
| StatementKind::FakeRead(_)
410+
| StatementKind::Nop
411+
| StatementKind::StorageLive(_) => (),
406412
}
407-
StatementKind::Deinit(_)
408-
| StatementKind::FakeRead(_)
409-
| StatementKind::Nop
410-
| StatementKind::StorageLive(_) => (),
411-
}
412-
}
413-
let Some(terminator) = &block.terminator else {
414-
never!(
415-
"Terminator should be none only in construction.\nThe body:\n{}",
416-
body.pretty_print(db)
417-
);
418-
return;
419-
};
420-
let mut process = |target, is_ever_initialized| {
421-
if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
422-
result[target].insert(l, is_ever_initialized);
423-
dfs(db, body, target, l, result);
424-
}
425-
};
426-
match &terminator.kind {
427-
TerminatorKind::Goto { target } => process(*target, is_ever_initialized),
428-
TerminatorKind::SwitchInt { targets, .. } => {
429-
targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized));
430413
}
431-
TerminatorKind::UnwindResume
432-
| TerminatorKind::Abort
433-
| TerminatorKind::Return
434-
| TerminatorKind::Unreachable => (),
435-
TerminatorKind::Call { target, cleanup, destination, .. } => {
436-
if destination.projection.lookup(&body.projection_store).is_empty()
437-
&& destination.local == l
438-
{
439-
is_ever_initialized = true;
414+
let Some(terminator) = &block.terminator else {
415+
never!(
416+
"Terminator should be none only in construction.\nThe body:\n{}",
417+
body.pretty_print(db)
418+
);
419+
return;
420+
};
421+
let mut process = |target, is_ever_initialized| {
422+
if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
423+
result[target].insert(l, is_ever_initialized);
424+
stack.push(target);
425+
}
426+
};
427+
match &terminator.kind {
428+
TerminatorKind::Goto { target } => process(*target, is_ever_initialized),
429+
TerminatorKind::SwitchInt { targets, .. } => {
430+
targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized));
431+
}
432+
TerminatorKind::UnwindResume
433+
| TerminatorKind::Abort
434+
| TerminatorKind::Return
435+
| TerminatorKind::Unreachable => (),
436+
TerminatorKind::Call { target, cleanup, destination, .. } => {
437+
if destination.projection.lookup(&body.projection_store).is_empty()
438+
&& destination.local == l
439+
{
440+
is_ever_initialized = true;
441+
}
442+
target.iter().chain(cleanup).for_each(|&it| process(it, is_ever_initialized));
443+
}
444+
TerminatorKind::Drop { target, unwind, place: _ } => {
445+
iter::once(target)
446+
.chain(unwind)
447+
.for_each(|&it| process(it, is_ever_initialized));
448+
}
449+
TerminatorKind::DropAndReplace { .. }
450+
| TerminatorKind::Assert { .. }
451+
| TerminatorKind::Yield { .. }
452+
| TerminatorKind::CoroutineDrop
453+
| TerminatorKind::FalseEdge { .. }
454+
| TerminatorKind::FalseUnwind { .. } => {
455+
never!("We don't emit these MIR terminators yet");
440456
}
441-
target.iter().chain(cleanup).for_each(|&it| process(it, is_ever_initialized));
442-
}
443-
TerminatorKind::Drop { target, unwind, place: _ } => {
444-
iter::once(target).chain(unwind).for_each(|&it| process(it, is_ever_initialized));
445-
}
446-
TerminatorKind::DropAndReplace { .. }
447-
| TerminatorKind::Assert { .. }
448-
| TerminatorKind::Yield { .. }
449-
| TerminatorKind::CoroutineDrop
450-
| TerminatorKind::FalseEdge { .. }
451-
| TerminatorKind::FalseUnwind { .. } => {
452-
never!("We don't emit these MIR terminators yet");
453457
}
454458
}
455459
}
460+
let mut stack = Vec::new();
456461
for &l in &body.param_locals {
457462
result[body.start_block].insert(l, true);
458-
dfs(db, body, body.start_block, l, &mut result);
463+
stack.clear();
464+
stack.push(body.start_block);
465+
dfs(db, body, l, &mut stack, &mut result);
459466
}
460467
for l in body.locals.iter().map(|it| it.0) {
461468
db.unwind_if_cancelled();
462469
if !result[body.start_block].contains_idx(l) {
463470
result[body.start_block].insert(l, false);
464-
dfs(db, body, body.start_block, l, &mut result);
471+
stack.clear();
472+
stack.push(body.start_block);
473+
dfs(db, body, l, &mut stack, &mut result);
465474
}
466475
}
467476
result

0 commit comments

Comments
 (0)