Skip to content

Commit f3b4c67

Browse files
committed
Auto merge of #111555 - cjgillot:elaborate-drops, r=tmiasko
Only run MaybeInitializedPlaces dataflow once to elaborate drops This pass allows forward dataflow analyses to modify the CFG depending on the dataflow state. This possibility is used for the `MaybeInitializedPlace` analysis in drop elaboration, to skip the dataflow effect of dead unwinds without having to compute dataflow twice.
2 parents 07438b0 + 5b2524e commit f3b4c67

25 files changed

+1420
-1288
lines changed

compiler/rustc_borrowck/src/dataflow.rs

+13-6
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
#![deny(rustc::diagnostic_outside_of_impl)]
33
use rustc_data_structures::fx::FxIndexMap;
44
use rustc_index::bit_set::BitSet;
5-
use rustc_middle::mir::{self, BasicBlock, Body, Location, Place};
5+
use rustc_middle::mir::{
6+
self, BasicBlock, Body, CallReturnPlaces, Location, Place, TerminatorEdges,
7+
};
68
use rustc_middle::ty::RegionVid;
79
use rustc_middle::ty::TyCtxt;
810
use rustc_mir_dataflow::impls::{EverInitializedPlaces, MaybeUninitializedPlaces};
911
use rustc_mir_dataflow::ResultsVisitable;
10-
use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
12+
use rustc_mir_dataflow::{self, fmt::DebugWithContext, GenKill};
1113
use rustc_mir_dataflow::{Analysis, Direction, Results};
1214
use std::fmt;
1315

@@ -334,6 +336,10 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
334336
impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
335337
type Idx = BorrowIndex;
336338

339+
fn domain_size(&self, _: &mir::Body<'tcx>) -> usize {
340+
self.borrow_set.len()
341+
}
342+
337343
fn before_statement_effect(
338344
&mut self,
339345
trans: &mut impl GenKill<Self::Idx>,
@@ -400,12 +406,12 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
400406
self.kill_loans_out_of_scope_at_location(trans, location);
401407
}
402408

403-
fn terminator_effect(
409+
fn terminator_effect<'mir>(
404410
&mut self,
405-
trans: &mut impl GenKill<Self::Idx>,
406-
terminator: &mir::Terminator<'tcx>,
411+
trans: &mut Self::Domain,
412+
terminator: &'mir mir::Terminator<'tcx>,
407413
_location: Location,
408-
) {
414+
) -> TerminatorEdges<'mir, 'tcx> {
409415
if let mir::TerminatorKind::InlineAsm { operands, .. } = &terminator.kind {
410416
for op in operands {
411417
if let mir::InlineAsmOperand::Out { place: Some(place), .. }
@@ -415,6 +421,7 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
415421
}
416422
}
417423
}
424+
terminator.edges()
418425
}
419426

420427
fn call_return_effect(

compiler/rustc_const_eval/src/transform/check_consts/resolver.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
55
use rustc_index::bit_set::BitSet;
66
use rustc_middle::mir::visit::Visitor;
7-
use rustc_middle::mir::{self, BasicBlock, Local, Location, Statement, StatementKind};
7+
use rustc_middle::mir::{
8+
self, BasicBlock, CallReturnPlaces, Local, Location, Statement, StatementKind, TerminatorEdges,
9+
};
810
use rustc_mir_dataflow::fmt::DebugWithContext;
911
use rustc_mir_dataflow::JoinSemiLattice;
10-
use rustc_mir_dataflow::{Analysis, AnalysisDomain, CallReturnPlaces};
12+
use rustc_mir_dataflow::{Analysis, AnalysisDomain};
1113

1214
use std::fmt;
1315
use std::marker::PhantomData;
@@ -345,13 +347,14 @@ where
345347
self.transfer_function(state).visit_statement(statement, location);
346348
}
347349

348-
fn apply_terminator_effect(
350+
fn apply_terminator_effect<'mir>(
349351
&mut self,
350352
state: &mut Self::Domain,
351-
terminator: &mir::Terminator<'tcx>,
353+
terminator: &'mir mir::Terminator<'tcx>,
352354
location: Location,
353-
) {
355+
) -> TerminatorEdges<'mir, 'tcx> {
354356
self.transfer_function(state).visit_terminator(terminator, location);
357+
terminator.edges()
355358
}
356359

357360
fn apply_call_return_effect(

compiler/rustc_middle/src/mir/terminator.rs

+106
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use std::iter;
1010
use std::slice;
1111

1212
pub use super::query::*;
13+
use super::*;
1314

1415
#[derive(Debug, Clone, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
1516
pub struct SwitchTargets {
@@ -430,3 +431,108 @@ impl<'tcx> TerminatorKind<'tcx> {
430431
}
431432
}
432433
}
434+
435+
#[derive(Copy, Clone, Debug)]
436+
pub enum TerminatorEdges<'mir, 'tcx> {
437+
/// For terminators that have no successor, like `return`.
438+
None,
439+
/// For terminators that a single successor, like `goto`, and `assert` without cleanup block.
440+
Single(BasicBlock),
441+
/// For terminators that two successors, `assert` with cleanup block and `falseEdge`.
442+
Double(BasicBlock, BasicBlock),
443+
/// Special action for `Yield`, `Call` and `InlineAsm` terminators.
444+
AssignOnReturn {
445+
return_: Option<BasicBlock>,
446+
unwind: UnwindAction,
447+
place: CallReturnPlaces<'mir, 'tcx>,
448+
},
449+
/// Special edge for `SwitchInt`.
450+
SwitchInt { targets: &'mir SwitchTargets, discr: &'mir Operand<'tcx> },
451+
}
452+
453+
/// List of places that are written to after a successful (non-unwind) return
454+
/// from a `Call`, `Yield` or `InlineAsm`.
455+
#[derive(Copy, Clone, Debug)]
456+
pub enum CallReturnPlaces<'a, 'tcx> {
457+
Call(Place<'tcx>),
458+
Yield(Place<'tcx>),
459+
InlineAsm(&'a [InlineAsmOperand<'tcx>]),
460+
}
461+
462+
impl<'tcx> CallReturnPlaces<'_, 'tcx> {
463+
pub fn for_each(&self, mut f: impl FnMut(Place<'tcx>)) {
464+
match *self {
465+
Self::Call(place) | Self::Yield(place) => f(place),
466+
Self::InlineAsm(operands) => {
467+
for op in operands {
468+
match *op {
469+
InlineAsmOperand::Out { place: Some(place), .. }
470+
| InlineAsmOperand::InOut { out_place: Some(place), .. } => f(place),
471+
_ => {}
472+
}
473+
}
474+
}
475+
}
476+
}
477+
}
478+
479+
impl<'tcx> Terminator<'tcx> {
480+
pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
481+
self.kind.edges()
482+
}
483+
}
484+
485+
impl<'tcx> TerminatorKind<'tcx> {
486+
pub fn edges(&self) -> TerminatorEdges<'_, 'tcx> {
487+
use TerminatorKind::*;
488+
match *self {
489+
Return | Resume | Terminate | GeneratorDrop | Unreachable => TerminatorEdges::None,
490+
491+
Goto { target } => TerminatorEdges::Single(target),
492+
493+
Assert { target, unwind, expected: _, msg: _, cond: _ }
494+
| Drop { target, unwind, place: _, replace: _ }
495+
| FalseUnwind { real_target: target, unwind } => match unwind {
496+
UnwindAction::Cleanup(unwind) => TerminatorEdges::Double(target, unwind),
497+
UnwindAction::Continue | UnwindAction::Terminate | UnwindAction::Unreachable => {
498+
TerminatorEdges::Single(target)
499+
}
500+
},
501+
502+
FalseEdge { real_target, imaginary_target } => {
503+
TerminatorEdges::Double(real_target, imaginary_target)
504+
}
505+
506+
Yield { resume: target, drop, resume_arg, value: _ } => {
507+
TerminatorEdges::AssignOnReturn {
508+
return_: Some(target),
509+
unwind: drop.map_or(UnwindAction::Terminate, UnwindAction::Cleanup),
510+
place: CallReturnPlaces::Yield(resume_arg),
511+
}
512+
}
513+
514+
Call { unwind, destination, target, func: _, args: _, fn_span: _, call_source: _ } => {
515+
TerminatorEdges::AssignOnReturn {
516+
return_: target,
517+
unwind,
518+
place: CallReturnPlaces::Call(destination),
519+
}
520+
}
521+
522+
InlineAsm {
523+
template: _,
524+
ref operands,
525+
options: _,
526+
line_spans: _,
527+
destination,
528+
unwind,
529+
} => TerminatorEdges::AssignOnReturn {
530+
return_: destination,
531+
unwind,
532+
place: CallReturnPlaces::InlineAsm(operands),
533+
},
534+
535+
SwitchInt { ref targets, ref discr } => TerminatorEdges::SwitchInt { targets, discr },
536+
}
537+
}
538+
}

0 commit comments

Comments
 (0)