mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 21:13:37 +00:00
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).
This commit is contained in:
parent
5982d9c420
commit
13f853464c
1 changed files with 67 additions and 58 deletions
|
@ -386,82 +386,91 @@ fn ever_initialized_map(
|
||||||
fn dfs(
|
fn dfs(
|
||||||
db: &dyn HirDatabase,
|
db: &dyn HirDatabase,
|
||||||
body: &MirBody,
|
body: &MirBody,
|
||||||
b: BasicBlockId,
|
|
||||||
l: LocalId,
|
l: LocalId,
|
||||||
|
stack: &mut Vec<BasicBlockId>,
|
||||||
result: &mut ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>>,
|
result: &mut ArenaMap<BasicBlockId, ArenaMap<LocalId, bool>>,
|
||||||
) {
|
) {
|
||||||
let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs
|
while let Some(b) = stack.pop() {
|
||||||
let block = &body.basic_blocks[b];
|
let mut is_ever_initialized = result[b][l]; // It must be filled, as we use it as mark for dfs
|
||||||
for statement in &block.statements {
|
let block = &body.basic_blocks[b];
|
||||||
match &statement.kind {
|
for statement in &block.statements {
|
||||||
StatementKind::Assign(p, _) => {
|
match &statement.kind {
|
||||||
if p.projection.lookup(&body.projection_store).is_empty() && p.local == l {
|
StatementKind::Assign(p, _) => {
|
||||||
|
if p.projection.lookup(&body.projection_store).is_empty() && p.local == l {
|
||||||
|
is_ever_initialized = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StatementKind::StorageDead(p) => {
|
||||||
|
if *p == l {
|
||||||
|
is_ever_initialized = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StatementKind::Deinit(_)
|
||||||
|
| StatementKind::FakeRead(_)
|
||||||
|
| StatementKind::Nop
|
||||||
|
| StatementKind::StorageLive(_) => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let Some(terminator) = &block.terminator else {
|
||||||
|
never!(
|
||||||
|
"Terminator should be none only in construction.\nThe body:\n{}",
|
||||||
|
body.pretty_print(db)
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let mut process = |target, is_ever_initialized| {
|
||||||
|
if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
|
||||||
|
result[target].insert(l, is_ever_initialized);
|
||||||
|
stack.push(target);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match &terminator.kind {
|
||||||
|
TerminatorKind::Goto { target } => process(*target, is_ever_initialized),
|
||||||
|
TerminatorKind::SwitchInt { targets, .. } => {
|
||||||
|
targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized));
|
||||||
|
}
|
||||||
|
TerminatorKind::UnwindResume
|
||||||
|
| TerminatorKind::Abort
|
||||||
|
| TerminatorKind::Return
|
||||||
|
| TerminatorKind::Unreachable => (),
|
||||||
|
TerminatorKind::Call { target, cleanup, destination, .. } => {
|
||||||
|
if destination.projection.lookup(&body.projection_store).is_empty()
|
||||||
|
&& destination.local == l
|
||||||
|
{
|
||||||
is_ever_initialized = true;
|
is_ever_initialized = true;
|
||||||
}
|
}
|
||||||
|
target.iter().chain(cleanup).for_each(|&it| process(it, is_ever_initialized));
|
||||||
}
|
}
|
||||||
StatementKind::StorageDead(p) => {
|
TerminatorKind::Drop { target, unwind, place: _ } => {
|
||||||
if *p == l {
|
iter::once(target)
|
||||||
is_ever_initialized = false;
|
.chain(unwind)
|
||||||
}
|
.for_each(|&it| process(it, is_ever_initialized));
|
||||||
}
|
}
|
||||||
StatementKind::Deinit(_)
|
TerminatorKind::DropAndReplace { .. }
|
||||||
| StatementKind::FakeRead(_)
|
| TerminatorKind::Assert { .. }
|
||||||
| StatementKind::Nop
|
| TerminatorKind::Yield { .. }
|
||||||
| StatementKind::StorageLive(_) => (),
|
| TerminatorKind::CoroutineDrop
|
||||||
}
|
| TerminatorKind::FalseEdge { .. }
|
||||||
}
|
| TerminatorKind::FalseUnwind { .. } => {
|
||||||
let Some(terminator) = &block.terminator else {
|
never!("We don't emit these MIR terminators yet");
|
||||||
never!(
|
|
||||||
"Terminator should be none only in construction.\nThe body:\n{}",
|
|
||||||
body.pretty_print(db)
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
let mut process = |target, is_ever_initialized| {
|
|
||||||
if !result[target].contains_idx(l) || !result[target][l] && is_ever_initialized {
|
|
||||||
result[target].insert(l, is_ever_initialized);
|
|
||||||
dfs(db, body, target, l, result);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match &terminator.kind {
|
|
||||||
TerminatorKind::Goto { target } => process(*target, is_ever_initialized),
|
|
||||||
TerminatorKind::SwitchInt { targets, .. } => {
|
|
||||||
targets.all_targets().iter().for_each(|&it| process(it, is_ever_initialized));
|
|
||||||
}
|
|
||||||
TerminatorKind::UnwindResume
|
|
||||||
| TerminatorKind::Abort
|
|
||||||
| TerminatorKind::Return
|
|
||||||
| TerminatorKind::Unreachable => (),
|
|
||||||
TerminatorKind::Call { target, cleanup, destination, .. } => {
|
|
||||||
if destination.projection.lookup(&body.projection_store).is_empty()
|
|
||||||
&& destination.local == l
|
|
||||||
{
|
|
||||||
is_ever_initialized = true;
|
|
||||||
}
|
}
|
||||||
target.iter().chain(cleanup).for_each(|&it| process(it, is_ever_initialized));
|
|
||||||
}
|
|
||||||
TerminatorKind::Drop { target, unwind, place: _ } => {
|
|
||||||
iter::once(target).chain(unwind).for_each(|&it| process(it, is_ever_initialized));
|
|
||||||
}
|
|
||||||
TerminatorKind::DropAndReplace { .. }
|
|
||||||
| TerminatorKind::Assert { .. }
|
|
||||||
| TerminatorKind::Yield { .. }
|
|
||||||
| TerminatorKind::CoroutineDrop
|
|
||||||
| TerminatorKind::FalseEdge { .. }
|
|
||||||
| TerminatorKind::FalseUnwind { .. } => {
|
|
||||||
never!("We don't emit these MIR terminators yet");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let mut stack = Vec::new();
|
||||||
for &l in &body.param_locals {
|
for &l in &body.param_locals {
|
||||||
result[body.start_block].insert(l, true);
|
result[body.start_block].insert(l, true);
|
||||||
dfs(db, body, body.start_block, l, &mut result);
|
stack.clear();
|
||||||
|
stack.push(body.start_block);
|
||||||
|
dfs(db, body, l, &mut stack, &mut result);
|
||||||
}
|
}
|
||||||
for l in body.locals.iter().map(|it| it.0) {
|
for l in body.locals.iter().map(|it| it.0) {
|
||||||
db.unwind_if_cancelled();
|
db.unwind_if_cancelled();
|
||||||
if !result[body.start_block].contains_idx(l) {
|
if !result[body.start_block].contains_idx(l) {
|
||||||
result[body.start_block].insert(l, false);
|
result[body.start_block].insert(l, false);
|
||||||
dfs(db, body, body.start_block, l, &mut result);
|
stack.clear();
|
||||||
|
stack.push(body.start_block);
|
||||||
|
dfs(db, body, l, &mut stack, &mut result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
|
|
Loading…
Reference in a new issue