Module rustc_mir::build::scope [−][src]
🔬 This is a nightly-only experimental API. (rustc_private
)
this crate is being loaded from the sysroot, an unstable location; did you mean to load this crate from crates.io via Cargo.toml
instead?
Managing the scope stack. The scopes are tied to lexical scopes, so as
we descend the HAIR, we push a scope on the stack, build its
contents, and then pop it off. Every scope is named by a
region::Scope
.
SEME Regions
When pushing a new scope, we record the current point in the graph (a
basic block); this marks the entry to the scope. We then generate more
stuff in the control-flow graph. Whenever the scope is exited, either
via a break
or return
or just by fallthrough, that marks an exit
from the scope. Each lexical scope thus corresponds to a single-entry,
multiple-exit (SEME) region in the control-flow graph.
For now, we keep a mapping from each region::Scope
to its
corresponding SEME region for later reference (see caveat in next
paragraph). This is because region scopes are tied to
them. Eventually, when we shift to non-lexical lifetimes, there should
be no need to remember this mapping.
There is one additional wrinkle, actually, that I wanted to hide from you but duty compels me to mention. In the course of building matches, it sometimes happen that certain code (namely guards) gets executed multiple times. This means that the scope lexical scope may in fact correspond to multiple, disjoint SEME regions. So in fact our mapping is from one scope to a vector of SEME regions.
Drops
The primary purpose for scopes is to insert drops: while building
the contents, we also accumulate places that need to be dropped upon
exit from each scope. This is done by calling schedule_drop
. Once a
drop is scheduled, whenever we branch out we will insert drops of all
those places onto the outgoing edge. Note that we don't know the full
set of scheduled drops up front, and so whenever we exit from the
scope we only drop the values scheduled thus far. For example, consider
the scope S corresponding to this loop:
loop { let x = ..; if cond { break; } let y = ..; }
When processing the let x
, we will add one drop to the scope for
x
. The break will then insert a drop for x
. When we process let y
, we will add another drop (in fact, to a subscope, but let's ignore
that for now); any later drops would also drop y
.
Early exit
There are numerous "normal" ways to early exit a scope: break
,
continue
, return
(panics are handled separately). Whenever an
early exit occurs, the method exit_scope
is called. It is given the
current point in execution where the early exit occurs, as well as the
scope you want to branch to (note that all early exits from to some
other enclosing scope). exit_scope
will record this exit point and
also add all drops.
Panics are handled in a similar fashion, except that a panic always
returns out to the DIVERGE_BLOCK
. To trigger a panic, simply call
panic(p)
with the current point p
. Or else you can call
diverge_cleanup
, which will produce a block that you can branch to
which does the appropriate cleanup and then diverges. panic(p)
simply calls diverge_cleanup()
and adds an edge from p
to the
result.
Loop scopes
In addition to the normal scope stack, we track a loop scope stack
that contains only loops. It tracks where a break
and continue
should go to.
Re-exports
use build::BlockAnd; |
use build::BlockAndExtension; |
use build::Builder; |
use build::CFG; |
use hair::LintLevel; |
use rustc::middle::region; |
use rustc::ty::Ty; |
use rustc::ty::TyCtxt; |
use rustc::hir; |
use rustc::hir::def_id::LOCAL_CRATE; |
use rustc::mir::*; |
use syntax_pos::Span; |
use rustc_data_structures::indexed_vec::Idx; |
use rustc_data_structures::fx::FxHashMap; |
use rustc_data_structures::fx::FxHashMap; |
Structs
BreakableScope |
[ Experimental ]
|
CachedBlock |
[ Experimental ]
|
DropData |
[ Experimental ]
|
Scope |
[ Experimental ]
|
Enums
DropKind |
[ Experimental ]
|
Functions
build_diverge_scope |
[ Experimental ]
|
build_scope_drops |
[ Experimental ] Builds drops for pop_scope and exit_scope. |