rust/compiler/rustc_middle/src/mir/visit.rs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

1383 lines
50 KiB
Rust
Raw Normal View History

//! # The MIR Visitor
//!
//! ## Overview
//!
//! There are two visitors, one for immutable and one for mutable references,
//! but both are generated by the `make_mir_visitor` macro.
//! The code is written according to the following conventions:
//!
//! - introduce a `visit_foo` and a `super_foo` method for every MIR type
//! - `visit_foo`, by default, calls `super_foo`
//! - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
//!
//! This allows you to override `visit_foo` for types you are
//! interested in, and invoke (within that method call)
//! `self.super_foo` to get the default behavior. Just as in an OO
//! language, you should never call `super` methods ordinarily except
//! in that circumstance.
//!
//! For the most part, we do not destructure things external to the
//! MIR, e.g., types, spans, etc, but simply visit them and stop. This
//! avoids duplication with other visitors like `TypeFoldable`.
//!
//! ## Updating
//!
//! The code is written in a very deliberate style intended to minimize
//! the chance of things being overlooked. You'll notice that we always
//! use pattern matching to reference fields and we ensure that all
//! matches are exhaustive.
//!
//! For example, the `super_basic_block_data` method begins like this:
//!
2022-04-15 15:04:34 -07:00
//! ```ignore (pseudo-rust)
//! fn super_basic_block_data(
//! &mut self,
//! block: BasicBlock,
//! data: & $($mutability)? BasicBlockData<'tcx>
//! ) {
//! let BasicBlockData {
//! statements,
//! terminator,
//! is_cleanup: _
//! } = *data;
//!
//! for statement in statements {
//! self.visit_statement(block, statement);
//! }
//!
//! ...
//! }
//! ```
//!
//! Here we used `let BasicBlockData { <fields> } = *data` deliberately,
//! rather than writing `data.statements` in the body. This is because if one
//! adds a new field to `BasicBlockData`, one will be forced to revise this code,
//! and hence one will (hopefully) invoke the correct visit methods (if any).
//!
//! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
//! That means you never write `..` to skip over fields, nor do you write `_`
//! to skip over variants in a `match`.
//!
//! The only place that `_` is acceptable is to match a field (or
//! variant argument) that does not require visiting, as in
//! `is_cleanup` above.
2019-02-05 11:20:45 -06:00
use crate::mir::*;
use crate::ty::GenericArgsRef;
use crate::ty::{self, CanonicalUserTypeAnnotation, Ty};
use rustc_span::Span;
2015-11-03 06:33:59 -05:00
macro_rules! make_mir_visitor {
2019-02-09 16:29:31 +00:00
($visitor_trait_name:ident, $($mutability:ident)?) => {
pub trait $visitor_trait_name<'tcx> {
// Override these, and call `self.super_xxx` to revert back to the
// default behavior.
2015-11-03 06:33:59 -05:00
fn visit_body(
&mut self,
2020-04-12 10:31:00 -07:00
body: &$($mutability)? Body<'tcx>,
) {
self.super_body(body);
2015-11-03 06:33:59 -05:00
}
extra_body_methods!($($mutability)?);
fn visit_basic_block_data(
&mut self,
block: BasicBlock,
data: & $($mutability)? BasicBlockData<'tcx>,
) {
self.super_basic_block_data(block, data);
2015-11-03 06:33:59 -05:00
}
fn visit_source_scope_data(
&mut self,
scope_data: & $($mutability)? SourceScopeData<'tcx>,
) {
self.super_source_scope_data(scope_data);
}
fn visit_statement(
&mut self,
statement: & $($mutability)? Statement<'tcx>,
location: Location,
) {
self.super_statement(statement, location);
2015-11-03 06:33:59 -05:00
}
fn visit_assign(
&mut self,
place: & $($mutability)? Place<'tcx>,
rvalue: & $($mutability)? Rvalue<'tcx>,
location: Location,
) {
self.super_assign(place, rvalue, location);
2015-11-03 06:33:59 -05:00
}
fn visit_terminator(
&mut self,
terminator: & $($mutability)? Terminator<'tcx>,
location: Location,
) {
self.super_terminator(terminator, location);
}
fn visit_assert_message(
&mut self,
msg: & $($mutability)? AssertMessage<'tcx>,
location: Location,
) {
self.super_assert_message(msg, location);
}
fn visit_rvalue(
&mut self,
rvalue: & $($mutability)? Rvalue<'tcx>,
location: Location,
) {
self.super_rvalue(rvalue, location);
2015-11-03 06:33:59 -05:00
}
fn visit_operand(
&mut self,
operand: & $($mutability)? Operand<'tcx>,
location: Location,
) {
self.super_operand(operand, location);
}
2015-11-03 06:33:59 -05:00
fn visit_ascribe_user_ty(
&mut self,
place: & $($mutability)? Place<'tcx>,
2022-07-04 09:40:58 +02:00
variance: $(& $mutability)? ty::Variance,
user_ty: & $($mutability)? UserTypeProjection,
location: Location,
) {
2018-10-10 17:07:10 -04:00
self.super_ascribe_user_ty(place, variance, user_ty, location);
2018-02-23 20:52:05 +00:00
}
fn visit_coverage(
&mut self,
coverage: & $($mutability)? Coverage,
location: Location,
) {
self.super_coverage(coverage, location);
}
fn visit_retag(
&mut self,
2022-07-04 09:40:58 +02:00
kind: $(& $mutability)? RetagKind,
place: & $($mutability)? Place<'tcx>,
location: Location,
) {
self.super_retag(kind, place, location);
}
fn visit_place(
&mut self,
place: & $($mutability)? Place<'tcx>,
context: PlaceContext,
location: Location,
) {
self.super_place(place, context, location);
2015-11-03 06:33:59 -05:00
}
visit_place_fns!($($mutability)?);
fn visit_constant(
&mut self,
constant: & $($mutability)? Constant<'tcx>,
location: Location,
) {
self.super_constant(constant, location);
2015-11-03 06:33:59 -05:00
}
2023-05-02 18:04:52 +01:00
fn visit_ty_const(
&mut self,
2023-05-04 11:22:11 +01:00
ct: $( & $mutability)? ty::Const<'tcx>,
2023-05-02 18:04:52 +01:00
location: Location,
) {
self.super_ty_const(ct, location);
}
fn visit_span(
&mut self,
span: $(& $mutability)? Span,
) {
self.super_span(span);
2015-11-03 06:33:59 -05:00
}
fn visit_source_info(
&mut self,
source_info: & $($mutability)? SourceInfo,
) {
self.super_source_info(source_info);
}
fn visit_ty(
&mut self,
ty: $(& $mutability)? Ty<'tcx>,
_: TyContext,
) {
self.super_ty(ty);
}
fn visit_user_type_projection(
&mut self,
ty: & $($mutability)? UserTypeProjection,
) {
self.super_user_type_projection(ty);
}
2018-10-15 09:31:38 -04:00
fn visit_user_type_annotation(
&mut self,
index: UserTypeAnnotationIndex,
2019-02-09 16:29:31 +00:00
ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
2018-10-15 09:31:38 -04:00
) {
self.super_user_type_annotation(index, ty);
}
fn visit_region(
&mut self,
region: $(& $mutability)? ty::Region<'tcx>,
_: Location,
) {
self.super_region(region);
}
fn visit_args(
&mut self,
args: & $($mutability)? GenericArgsRef<'tcx>,
_: Location,
) {
self.super_args(args);
}
fn visit_local_decl(
&mut self,
local: Local,
local_decl: & $($mutability)? LocalDecl<'tcx>,
) {
self.super_local_decl(local, local_decl);
}
fn visit_var_debug_info(
&mut self,
var_debug_info: & $($mutability)* VarDebugInfo<'tcx>,
) {
self.super_var_debug_info(var_debug_info);
}
fn visit_local(
&mut self,
_local: $(& $mutability)? Local,
_context: PlaceContext,
_location: Location,
) {}
2016-12-26 14:34:03 +01:00
fn visit_source_scope(
&mut self,
scope: $(& $mutability)? SourceScope,
) {
self.super_source_scope(scope);
}
// The `super_xxx` methods comprise the default behavior and are
2016-02-09 11:52:39 -05:00
// not meant to be overridden.
2015-11-03 06:33:59 -05:00
fn super_body(
&mut self,
2020-04-12 10:31:00 -07:00
body: &$($mutability)? Body<'tcx>,
) {
super_body!(self, body, $($mutability, true)?);
2015-11-03 06:33:59 -05:00
}
fn super_basic_block_data(&mut self,
block: BasicBlock,
2019-02-09 16:29:31 +00:00
data: & $($mutability)? BasicBlockData<'tcx>) {
let BasicBlockData {
2019-02-09 16:29:31 +00:00
statements,
terminator,
is_cleanup: _
2019-02-09 16:29:31 +00:00
} = data;
let mut index = 0;
for statement in statements {
2020-12-29 22:02:47 +01:00
let location = Location { block, statement_index: index };
self.visit_statement(statement, location);
index += 1;
2015-11-03 06:33:59 -05:00
}
2019-02-09 16:29:31 +00:00
if let Some(terminator) = terminator {
2020-12-29 22:02:47 +01:00
let location = Location { block, statement_index: index };
self.visit_terminator(terminator, location);
}
2015-11-03 06:33:59 -05:00
}
fn super_source_scope_data(
&mut self,
scope_data: & $($mutability)? SourceScopeData<'tcx>,
) {
let SourceScopeData {
2019-02-09 16:29:31 +00:00
span,
parent_scope,
inlined,
inlined_parent_scope,
local_data: _,
2019-02-09 16:29:31 +00:00
} = scope_data;
self.visit_span($(& $mutability)? *span);
2019-02-09 16:29:31 +00:00
if let Some(parent_scope) = parent_scope {
self.visit_source_scope($(& $mutability)? *parent_scope);
}
if let Some((callee, callsite_span)) = inlined {
let location = Location::START;
self.visit_span($(& $mutability)? *callsite_span);
let ty::Instance { def: callee_def, args: callee_args } = callee;
match callee_def {
ty::InstanceDef::Item(_def_id) => {}
ty::InstanceDef::Intrinsic(_def_id) |
ty::InstanceDef::VTableShim(_def_id) |
ty::InstanceDef::ReifyShim(_def_id) |
ty::InstanceDef::Virtual(_def_id, _) |
ty::InstanceDef::ThreadLocalShim(_def_id) |
Support `#[track_caller]` on closures and generators This PR allows applying a `#[track_caller]` attribute to a closure/generator expression. The attribute as interpreted as applying to the compiler-generated implementation of the corresponding trait method (`FnOnce::call_once`, `FnMut::call_mut`, `Fn::call`, or `Generator::resume`). This feature does not have its own feature gate - however, it requires `#![feature(stmt_expr_attributes)]` in order to actually apply an attribute to a closure or generator. This is implemented in the same way as for functions - an extra location argument is appended to the end of the ABI. For closures, this argument is *not* part of the 'tupled' argument storing the parameters - the final closure argument for `#[track_caller]` closures is no longer a tuple. For direct (monomorphized) calls, the necessary support was already implemented - we just needeed to adjust some assertions around checking the ABI and argument count to take closures into account. For calls through a trait object, more work was needed. When creating a `ReifyShim`, we need to create a shim for the trait method (e.g. `FnOnce::call_mut`) - unlike normal functions, closures are never invoked directly, and always go through a trait method. Additional handling was needed for `InstanceDef::ClosureOnceShim`. In order to pass location information throgh a direct (monomorphized) call to `FnOnce::call_once` on an `FnMut` closure, we need to make `ClosureOnceShim` aware of `#[tracked_caller]`. A new field `track_caller` is added to `ClosureOnceShim` - this is used by `InstanceDef::requires_caller` location, allowing codegen to pass through the extra location argument. Since `ClosureOnceShim.track_caller` is only used by codegen, we end up generating two identical MIR shims - one for `track_caller == true`, and one for `track_caller == false`. However, these two shims are used by the entire crate (i.e. it's two shims total, not two shims per unique closure), so this shouldn't a big deal.
2021-06-27 14:01:11 -05:00
ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
ty::InstanceDef::DropGlue(_def_id, None) => {}
ty::InstanceDef::FnPtrShim(_def_id, ty) |
ty::InstanceDef::DropGlue(_def_id, Some(ty)) |
2022-07-20 14:32:58 +02:00
ty::InstanceDef::CloneShim(_def_id, ty) |
ty::InstanceDef::FnPtrAddrShim(_def_id, ty) => {
// FIXME(eddyb) use a better `TyContext` here.
2022-01-25 14:13:38 +11:00
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
}
self.visit_args(callee_args, location);
}
if let Some(inlined_parent_scope) = inlined_parent_scope {
self.visit_source_scope($(& $mutability)? *inlined_parent_scope);
}
}
fn super_statement(&mut self,
2019-02-09 16:29:31 +00:00
statement: & $($mutability)? Statement<'tcx>,
location: Location) {
let Statement {
2019-02-09 16:29:31 +00:00
source_info,
kind,
} = statement;
self.visit_source_info(source_info);
2019-02-09 16:29:31 +00:00
match kind {
StatementKind::Assign(
2022-07-04 09:40:58 +02:00
box (place, rvalue)
) => {
self.visit_assign(place, rvalue, location);
}
2021-03-29 22:48:44 -04:00
StatementKind::FakeRead(box (_, place)) => {
self.visit_place(
place,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
location
);
}
2019-02-09 16:29:31 +00:00
StatementKind::SetDiscriminant { place, .. } => {
self.visit_place(
place,
PlaceContext::MutatingUse(MutatingUseContext::SetDiscriminant),
location
);
}
2022-04-05 17:14:59 -04:00
StatementKind::Deinit(place) => {
self.visit_place(
place,
PlaceContext::MutatingUse(MutatingUseContext::Deinit),
2022-04-05 17:14:59 -04:00
location
)
}
2019-02-09 16:29:31 +00:00
StatementKind::StorageLive(local) => {
self.visit_local(
$(& $mutability)? *local,
PlaceContext::NonUse(NonUseContext::StorageLive),
location
);
}
2019-02-09 16:29:31 +00:00
StatementKind::StorageDead(local) => {
self.visit_local(
$(& $mutability)? *local,
PlaceContext::NonUse(NonUseContext::StorageDead),
location
);
}
2019-02-09 16:29:31 +00:00
StatementKind::Retag(kind, place) => {
2022-07-04 09:40:58 +02:00
self.visit_retag($(& $mutability)? *kind, place, location);
}
StatementKind::PlaceMention(place) => {
self.visit_place(
place,
2023-04-25 20:09:54 +00:00
PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention),
location
);
}
StatementKind::AscribeUserType(
2022-07-04 09:40:58 +02:00
box (place, user_ty),
variance
) => {
2022-07-04 09:40:58 +02:00
self.visit_ascribe_user_ty(place, $(& $mutability)? *variance, user_ty, location);
2018-02-23 20:52:05 +00:00
}
StatementKind::Coverage(coverage) => {
self.visit_coverage(
coverage,
location
)
}
StatementKind::Intrinsic(box ref $($mutability)? intrinsic) => {
match intrinsic {
NonDivergingIntrinsic::Assume(op) => self.visit_operand(op, location),
NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
self.visit_operand(src, location);
self.visit_operand(dst, location);
self.visit_operand(count, location);
}
}
}
StatementKind::ConstEvalCounter => {}
StatementKind::Nop => {}
}
2015-11-03 06:33:59 -05:00
}
fn super_assign(&mut self,
2019-02-09 16:29:31 +00:00
place: &$($mutability)? Place<'tcx>,
rvalue: &$($mutability)? Rvalue<'tcx>,
location: Location) {
self.visit_place(
place,
PlaceContext::MutatingUse(MutatingUseContext::Store),
location
);
self.visit_rvalue(rvalue, location);
}
fn super_terminator(&mut self,
2019-02-09 16:29:31 +00:00
terminator: &$($mutability)? Terminator<'tcx>,
location: Location) {
2019-02-09 16:29:31 +00:00
let Terminator { source_info, kind } = terminator;
self.visit_source_info(source_info);
2019-02-09 16:29:31 +00:00
match kind {
2019-04-26 21:36:36 +01:00
TerminatorKind::Goto { .. } |
TerminatorKind::UnwindResume |
TerminatorKind::UnwindTerminate(_) |
2019-04-26 21:36:36 +01:00
TerminatorKind::GeneratorDrop |
TerminatorKind::Unreachable |
2020-06-02 09:15:24 +02:00
TerminatorKind::FalseEdge { .. } |
2022-07-04 09:40:58 +02:00
TerminatorKind::FalseUnwind { .. } => {}
TerminatorKind::Return => {
// `return` logically moves from the return place `_0`. Note that the place
// cannot be changed by any visitor, though.
let $($mutability)? local = RETURN_PLACE;
self.visit_local(
$(& $mutability)? local,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
location,
);
assert_eq!(
local,
RETURN_PLACE,
"`MutVisitor` tried to mutate return place of `return` terminator"
);
}
2019-02-09 16:29:31 +00:00
TerminatorKind::SwitchInt {
discr,
2019-04-26 21:36:36 +01:00
targets: _
2019-02-09 16:29:31 +00:00
} => {
self.visit_operand(discr, location);
}
2019-02-09 16:29:31 +00:00
TerminatorKind::Drop {
place,
2019-04-26 21:36:36 +01:00
target: _,
unwind: _,
2023-05-25 17:30:23 +00:00
replace: _,
2019-02-09 16:29:31 +00:00
} => {
self.visit_place(
place,
PlaceContext::MutatingUse(MutatingUseContext::Drop),
location
);
}
2019-02-09 16:29:31 +00:00
TerminatorKind::Call {
func,
args,
destination,
target: _,
unwind: _,
call_source: _,
fn_span: _
2019-02-09 16:29:31 +00:00
} => {
self.visit_operand(func, location);
for arg in args {
self.visit_operand(arg, location);
}
self.visit_place(
destination,
PlaceContext::MutatingUse(MutatingUseContext::Call),
location
);
}
2019-02-09 16:29:31 +00:00
TerminatorKind::Assert {
cond,
expected: _,
msg,
2019-04-26 21:36:36 +01:00
target: _,
unwind: _,
2019-02-09 16:29:31 +00:00
} => {
self.visit_operand(cond, location);
self.visit_assert_message(msg, location);
}
2016-12-26 14:34:03 +01:00
2019-02-09 16:29:31 +00:00
TerminatorKind::Yield {
value,
2019-04-26 21:36:36 +01:00
resume: _,
resume_arg,
2019-04-26 21:36:36 +01:00
drop: _,
2019-02-09 16:29:31 +00:00
} => {
self.visit_operand(value, location);
self.visit_place(
resume_arg,
PlaceContext::MutatingUse(MutatingUseContext::Yield),
location,
);
2016-12-26 14:34:03 +01:00
}
2020-02-14 18:17:50 +00:00
TerminatorKind::InlineAsm {
template: _,
operands,
options: _,
2020-05-26 20:07:59 +01:00
line_spans: _,
2020-02-14 18:17:50 +00:00
destination: _,
unwind: _,
2020-02-14 18:17:50 +00:00
} => {
for op in operands {
match op {
2021-04-06 05:50:55 +01:00
InlineAsmOperand::In { value, .. } => {
self.visit_operand(value, location);
2020-02-14 18:17:50 +00:00
}
2021-08-16 17:30:23 +02:00
InlineAsmOperand::Out { place: Some(place), .. } => {
self.visit_place(
place,
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
2021-08-16 17:30:23 +02:00
location,
);
2020-02-14 18:17:50 +00:00
}
InlineAsmOperand::InOut { in_value, out_place, .. } => {
self.visit_operand(in_value, location);
2020-02-14 18:17:50 +00:00
if let Some(out_place) = out_place {
self.visit_place(
out_place,
PlaceContext::MutatingUse(MutatingUseContext::AsmOutput),
location,
2020-02-14 18:17:50 +00:00
);
}
}
2021-04-06 05:50:55 +01:00
InlineAsmOperand::Const { value }
| InlineAsmOperand::SymFn { value } => {
self.visit_constant(value, location);
2020-02-14 18:17:50 +00:00
}
2021-08-16 17:30:23 +02:00
InlineAsmOperand::Out { place: None, .. }
| InlineAsmOperand::SymStatic { def_id: _ } => {}
2020-02-14 18:17:50 +00:00
}
}
}
}
}
fn super_assert_message(&mut self,
2019-02-09 16:29:31 +00:00
msg: & $($mutability)? AssertMessage<'tcx>,
location: Location) {
2020-02-12 19:40:31 +01:00
use crate::mir::AssertKind::*;
match msg {
BoundsCheck { len, index } => {
self.visit_operand(len, location);
self.visit_operand(index, location);
}
Overflow(_, l, r) => {
self.visit_operand(l, location);
self.visit_operand(r, location);
}
OverflowNeg(op) | DivisionByZero(op) | RemainderByZero(op) => {
self.visit_operand(op, location);
}
ResumedAfterReturn(_) | ResumedAfterPanic(_) => {
// Nothing to visit
}
MisalignedPointerDereference { required, found } => {
self.visit_operand(required, location);
self.visit_operand(found, location);
}
}
}
fn super_rvalue(&mut self,
2019-02-09 16:29:31 +00:00
rvalue: & $($mutability)? Rvalue<'tcx>,
location: Location) {
2019-02-09 16:29:31 +00:00
match rvalue {
Rvalue::Use(operand) => {
self.visit_operand(operand, location);
}
2023-05-02 18:04:52 +01:00
Rvalue::Repeat(value, ct) => {
self.visit_operand(value, location);
2023-05-04 11:22:11 +01:00
self.visit_ty_const($(&$mutability)? *ct, location);
}
2020-05-02 21:44:25 +02:00
Rvalue::ThreadLocalRef(_) => {}
2019-02-09 16:29:31 +00:00
Rvalue::Ref(r, bk, path) => {
self.visit_region($(& $mutability)? *r, location);
let ctx = match bk {
BorrowKind::Shared => PlaceContext::NonMutatingUse(
NonMutatingUseContext::SharedBorrow
),
BorrowKind::Shallow => PlaceContext::NonMutatingUse(
NonMutatingUseContext::ShallowBorrow
),
BorrowKind::Mut { .. } =>
PlaceContext::MutatingUse(MutatingUseContext::Borrow),
};
self.visit_place(path, ctx, location);
}
2022-06-13 16:37:41 +03:00
Rvalue::CopyForDeref(place) => {
self.visit_place(
place,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
location
);
}
Rvalue::AddressOf(m, path) => {
let ctx = match m {
Mutability::Mut => PlaceContext::MutatingUse(
MutatingUseContext::AddressOf
),
Mutability::Not => PlaceContext::NonMutatingUse(
NonMutatingUseContext::AddressOf
),
};
self.visit_place(path, ctx, location);
}
2019-02-09 16:29:31 +00:00
Rvalue::Len(path) => {
self.visit_place(
path,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
location
);
}
2019-02-09 16:29:31 +00:00
Rvalue::Cast(_cast_kind, operand, ty) => {
self.visit_operand(operand, location);
2022-01-25 14:13:38 +11:00
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
2021-03-05 09:32:47 +00:00
Rvalue::BinaryOp(_bin_op, box(lhs, rhs))
| Rvalue::CheckedBinaryOp(_bin_op, box(lhs, rhs)) => {
self.visit_operand(lhs, location);
self.visit_operand(rhs, location);
}
2019-02-09 16:29:31 +00:00
Rvalue::UnaryOp(_un_op, op) => {
self.visit_operand(op, location);
}
2019-02-09 16:29:31 +00:00
Rvalue::Discriminant(place) => {
self.visit_place(
place,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect),
location
);
}
2019-02-09 16:29:31 +00:00
Rvalue::NullaryOp(_op, ty) => {
2022-01-25 14:13:38 +11:00
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
2019-02-09 16:29:31 +00:00
Rvalue::Aggregate(kind, operands) => {
let kind = &$($mutability)? **kind;
match kind {
AggregateKind::Array(ty) => {
2022-01-25 14:13:38 +11:00
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
AggregateKind::Tuple => {
}
2019-02-09 16:29:31 +00:00
AggregateKind::Adt(
_adt_def,
_variant_index,
args,
_user_args,
2019-02-09 16:29:31 +00:00
_active_field_index
) => {
self.visit_args(args, location);
}
2019-02-09 16:29:31 +00:00
AggregateKind::Closure(
2019-04-26 21:36:36 +01:00
_,
closure_args
2019-02-09 16:29:31 +00:00
) => {
self.visit_args(closure_args, location);
}
2019-02-09 16:29:31 +00:00
AggregateKind::Generator(
2019-04-26 21:36:36 +01:00
_,
generator_args,
2019-02-09 16:29:31 +00:00
_movability,
) => {
self.visit_args(generator_args, location);
2016-12-26 14:34:03 +01:00
}
}
for operand in operands {
self.visit_operand(operand, location);
}
}
2021-09-06 18:33:23 +01:00
Rvalue::ShallowInitBox(operand, ty) => {
self.visit_operand(operand, location);
2022-01-25 14:13:38 +11:00
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
2021-09-06 18:33:23 +01:00
}
}
}
fn super_operand(&mut self,
2019-02-09 16:29:31 +00:00
operand: & $($mutability)? Operand<'tcx>,
location: Location) {
2019-02-09 16:29:31 +00:00
match operand {
Operand::Copy(place) => {
self.visit_place(
place,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
location
);
}
2019-02-09 16:29:31 +00:00
Operand::Move(place) => {
self.visit_place(
place,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move),
location
);
}
2019-02-09 16:29:31 +00:00
Operand::Constant(constant) => {
self.visit_constant(constant, location);
}
}
}
fn super_ascribe_user_ty(&mut self,
2019-02-09 16:29:31 +00:00
place: & $($mutability)? Place<'tcx>,
variance: $(& $mutability)? ty::Variance,
user_ty: & $($mutability)? UserTypeProjection,
location: Location) {
self.visit_place(
place,
PlaceContext::NonUse(NonUseContext::AscribeUserTy($(* &$mutability *)? variance)),
location
);
self.visit_user_type_projection(user_ty);
2018-02-23 20:52:05 +00:00
}
fn super_coverage(&mut self,
Updates to experimental coverage counter injection This is a combination of 18 commits. Commit #2: Additional examples and some small improvements. Commit #3: fixed mir-opt non-mir extensions and spanview title elements Corrected a fairly recent assumption in runtest.rs that all MIR dump files end in .mir. (It was appending .mir to the graphviz .dot and spanview .html file names when generating blessed output files. That also left outdated files in the baseline alongside the files with the incorrect names, which I've now removed.) Updated spanview HTML title elements to match their content, replacing a hardcoded and incorrect name that was left in accidentally when originally submitted. Commit #4: added more test examples also improved Makefiles with support for non-zero exit status and to force validation of tests unless a specific test overrides it with a specific comment. Commit #5: Fixed rare issues after testing on real-world crate Commit #6: Addressed PR feedback, and removed temporary -Zexperimental-coverage -Zinstrument-coverage once again supports the latest capabilities of LLVM instrprof coverage instrumentation. Also fixed a bug in spanview. Commit #7: Fix closure handling, add tests for closures and inner items And cleaned up other tests for consistency, and to make it more clear where spans start/end by breaking up lines. Commit #8: renamed "typical" test results "expected" Now that the `llvm-cov show` tests are improved to normally expect matching actuals, and to allow individual tests to override that expectation. Commit #9: test coverage of inline generic struct function Commit #10: Addressed review feedback * Removed unnecessary Unreachable filter. * Replaced a match wildcard with remining variants. * Added more comments to help clarify the role of successors() in the CFG traversal Commit #11: refactoring based on feedback * refactored `fn coverage_spans()`. * changed the way I expand an empty coverage span to improve performance * fixed a typo that I had accidently left in, in visit.rs Commit #12: Optimized use of SourceMap and SourceFile Commit #13: Fixed a regression, and synched with upstream Some generated test file names changed due to some new change upstream. Commit #14: Stripping out crate disambiguators from demangled names These can vary depending on the test platform. Commit #15: Ignore llvm-cov show diff on test with generics, expand IO error message Tests with generics produce llvm-cov show results with demangled names that can include an unstable "crate disambiguator" (hex value). The value changes when run in the Rust CI Windows environment. I added a sed filter to strip them out (in a prior commit), but sed also appears to fail in the same environment. Until I can figure out a workaround, I'm just going to ignore this specific test result. I added a FIXME to follow up later, but it's not that critical. I also saw an error with Windows GNU, but the IO error did not specify a path for the directory or file that triggered the error. I updated the error messages to provide more info for next, time but also noticed some other tests with similar steps did not fail. Looks spurious. Commit #16: Modify rust-demangler to strip disambiguators by default Commit #17: Remove std::process::exit from coverage tests Due to Issue #77553, programs that call std::process::exit() do not generate coverage results on Windows MSVC. Commit #18: fix: test file paths exceeding Windows max path len
2020-09-01 16:15:17 -07:00
_coverage: & $($mutability)? Coverage,
_location: Location) {
}
fn super_retag(&mut self,
2022-07-04 09:40:58 +02:00
_kind: $(& $mutability)? RetagKind,
2019-02-09 16:29:31 +00:00
place: & $($mutability)? Place<'tcx>,
location: Location) {
self.visit_place(
place,
PlaceContext::MutatingUse(MutatingUseContext::Retag),
location,
);
}
fn super_local_decl(&mut self,
local: Local,
2019-02-09 16:29:31 +00:00
local_decl: & $($mutability)? LocalDecl<'tcx>) {
let LocalDecl {
mutability: _,
2019-02-09 16:29:31 +00:00
ty,
user_ty,
source_info,
internal: _,
2019-11-18 23:04:06 +00:00
local_info: _,
2019-02-09 16:29:31 +00:00
} = local_decl;
2022-01-25 14:13:38 +11:00
self.visit_ty($(& $mutability)? *ty, TyContext::LocalDecl {
local,
source_info: *source_info,
});
if let Some(user_ty) = user_ty {
for (user_ty, _) in & $($mutability)? user_ty.contents {
self.visit_user_type_projection(user_ty);
}
}
self.visit_source_info(source_info);
}
fn super_var_debug_info(
&mut self,
var_debug_info: & $($mutability)? VarDebugInfo<'tcx>
) {
let VarDebugInfo {
name: _,
source_info,
composite,
value,
argument_index: _,
} = var_debug_info;
self.visit_source_info(source_info);
let location = Location::START;
if let Some(box VarDebugInfoFragment { ref $($mutability)? ty, ref $($mutability)? projection }) = composite {
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
for elem in projection {
let ProjectionElem::Field(_, ty) = elem else { bug!() };
self.visit_ty($(& $mutability)? *ty, TyContext::Location(location));
}
}
match value {
VarDebugInfoContents::Const(c) => self.visit_constant(c, location),
VarDebugInfoContents::Place(place) =>
self.visit_place(
place,
PlaceContext::NonUse(NonUseContext::VarDebugInfo),
location
),
}
}
fn super_source_scope(
&mut self,
_scope: $(& $mutability)? SourceScope
) {}
fn super_constant(
&mut self,
constant: & $($mutability)? Constant<'tcx>,
location: Location
) {
2016-03-25 13:10:32 -04:00
let Constant {
2019-02-09 16:29:31 +00:00
span,
user_ty: _, // no visit method for this
2019-02-09 16:29:31 +00:00
literal,
} = constant;
2016-03-25 13:10:32 -04:00
self.visit_span($(& $mutability)? *span);
match literal {
2023-05-04 11:22:11 +01:00
ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location),
2022-01-25 14:13:38 +11:00
ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
}
}
2023-05-02 18:04:52 +01:00
fn super_ty_const(
&mut self,
2023-05-04 11:22:11 +01:00
_ct: $(& $mutability)? ty::Const<'tcx>,
2023-05-02 18:04:52 +01:00
_location: Location,
) {
}
fn super_span(&mut self, _span: $(& $mutability)? Span) {
}
2019-02-09 16:29:31 +00:00
fn super_source_info(&mut self, source_info: & $($mutability)? SourceInfo) {
let SourceInfo {
2019-02-09 16:29:31 +00:00
span,
scope,
} = source_info;
self.visit_span($(& $mutability)? *span);
self.visit_source_scope($(& $mutability)? *scope);
}
fn super_user_type_projection(
&mut self,
_ty: & $($mutability)? UserTypeProjection,
) {
}
2018-10-15 09:31:38 -04:00
fn super_user_type_annotation(
&mut self,
_index: UserTypeAnnotationIndex,
2019-02-09 16:29:31 +00:00
ty: & $($mutability)? CanonicalUserTypeAnnotation<'tcx>,
2018-10-15 09:31:38 -04:00
) {
self.visit_span($(& $mutability)? ty.span);
2022-01-25 14:13:38 +11:00
self.visit_ty($(& $mutability)? ty.inferred_ty, TyContext::UserTy(ty.span));
}
2019-04-25 22:54:19 +02:00
fn super_ty(&mut self, _ty: $(& $mutability)? Ty<'tcx>) {
}
fn super_region(&mut self, _region: $(& $mutability)? ty::Region<'tcx>) {
}
fn super_args(&mut self, _args: & $($mutability)? GenericArgsRef<'tcx>) {
}
// Convenience methods
fn visit_location(
&mut self,
2020-04-12 10:31:00 -07:00
body: &$($mutability)? Body<'tcx>,
location: Location
) {
let basic_block = & $($mutability)? basic_blocks!(body, $($mutability, true)?)[location.block];
if basic_block.statements.len() == location.statement_index {
if let Some(ref $($mutability)? terminator) = basic_block.terminator {
self.visit_terminator(terminator, location)
}
} else {
let statement = & $($mutability)?
basic_block.statements[location.statement_index];
self.visit_statement(statement, location)
}
}
}
}
}
macro_rules! basic_blocks {
($body:ident, mut, true) => {
$body.basic_blocks.as_mut()
};
($body:ident, mut, false) => {
$body.basic_blocks.as_mut_preserves_cfg()
};
($body:ident,) => {
$body.basic_blocks
};
}
macro_rules! basic_blocks_iter {
($body:ident, mut, $invalidate:tt) => {
basic_blocks!($body, mut, $invalidate).iter_enumerated_mut()
};
($body:ident,) => {
basic_blocks!($body,).iter_enumerated()
};
}
macro_rules! extra_body_methods {
(mut) => {
fn visit_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
self.super_body_preserves_cfg(body);
}
fn super_body_preserves_cfg(&mut self, body: &mut Body<'tcx>) {
super_body!(self, body, mut, false);
}
};
() => {};
}
macro_rules! super_body {
($self:ident, $body:ident, $($mutability:ident, $invalidate:tt)?) => {
let span = $body.span;
if let Some(gen) = &$($mutability)? $body.generator {
if let Some(yield_ty) = $(& $mutability)? gen.yield_ty {
$self.visit_ty(
yield_ty,
TyContext::YieldTy(SourceInfo::outermost(span))
);
}
}
for (bb, data) in basic_blocks_iter!($body, $($mutability, $invalidate)?) {
$self.visit_basic_block_data(bb, data);
}
for scope in &$($mutability)? $body.source_scopes {
$self.visit_source_scope_data(scope);
}
$self.visit_ty(
$(& $mutability)? $body.return_ty(),
TyContext::ReturnTy(SourceInfo::outermost($body.span))
);
for local in $body.local_decls.indices() {
$self.visit_local_decl(local, & $($mutability)? $body.local_decls[local]);
}
#[allow(unused_macro_rules)]
macro_rules! type_annotations {
(mut) => ($body.user_type_annotations.iter_enumerated_mut());
() => ($body.user_type_annotations.iter_enumerated());
}
for (index, annotation) in type_annotations!($($mutability)?) {
$self.visit_user_type_annotation(
index, annotation
);
}
for var_debug_info in &$($mutability)? $body.var_debug_info {
$self.visit_var_debug_info(var_debug_info);
}
$self.visit_span($(& $mutability)? $body.span);
for const_ in &$($mutability)? $body.required_consts {
let location = Location::START;
$self.visit_constant(const_, location);
}
}
}
macro_rules! visit_place_fns {
(mut) => {
2019-10-20 16:11:04 -04:00
fn tcx<'a>(&'a self) -> TyCtxt<'tcx>;
fn super_place(
&mut self,
place: &mut Place<'tcx>,
context: PlaceContext,
location: Location,
) {
2020-04-21 17:11:00 -03:00
self.visit_local(&mut place.local, context, location);
if let Some(new_projection) = self.process_projection(&place.projection, location) {
Rename many interner functions. (This is a large commit. The changes to `compiler/rustc_middle/src/ty/context.rs` are the most important ones.) The current naming scheme is a mess, with a mix of `_intern_`, `intern_` and `mk_` prefixes, with little consistency. In particular, in many cases it's easy to use an iterator interner when a (preferable) slice interner is available. The guiding principles of the new naming system: - No `_intern_` prefixes. - The `intern_` prefix is for internal operations. - The `mk_` prefix is for external operations. - For cases where there is a slice interner and an iterator interner, the former is `mk_foo` and the latter is `mk_foo_from_iter`. Also, `slice_interners!` and `direct_interners!` can now be `pub` or non-`pub`, which helps enforce the internal/external operations division. It's not perfect, but I think it's a clear improvement. The following lists show everything that was renamed. slice_interners - const_list - mk_const_list -> mk_const_list_from_iter - intern_const_list -> mk_const_list - substs - mk_substs -> mk_substs_from_iter - intern_substs -> mk_substs - check_substs -> check_and_mk_substs (this is a weird one) - canonical_var_infos - intern_canonical_var_infos -> mk_canonical_var_infos - poly_existential_predicates - mk_poly_existential_predicates -> mk_poly_existential_predicates_from_iter - intern_poly_existential_predicates -> mk_poly_existential_predicates - _intern_poly_existential_predicates -> intern_poly_existential_predicates - predicates - mk_predicates -> mk_predicates_from_iter - intern_predicates -> mk_predicates - _intern_predicates -> intern_predicates - projs - intern_projs -> mk_projs - place_elems - mk_place_elems -> mk_place_elems_from_iter - intern_place_elems -> mk_place_elems - bound_variable_kinds - mk_bound_variable_kinds -> mk_bound_variable_kinds_from_iter - intern_bound_variable_kinds -> mk_bound_variable_kinds direct_interners - region - intern_region (unchanged) - const - mk_const_internal -> intern_const - const_allocation - intern_const_alloc -> mk_const_alloc - layout - intern_layout -> mk_layout - adt_def - intern_adt_def -> mk_adt_def_from_data (unusual case, hard to avoid) - alloc_adt_def(!) -> mk_adt_def - external_constraints - intern_external_constraints -> mk_external_constraints Other - type_list - mk_type_list -> mk_type_list_from_iter - intern_type_list -> mk_type_list - tup - mk_tup -> mk_tup_from_iter - intern_tup -> mk_tup
2023-02-17 14:33:08 +11:00
place.projection = self.tcx().mk_place_elems(&new_projection);
}
}
fn process_projection<'a>(
&mut self,
projection: &'a [PlaceElem<'tcx>],
location: Location,
2019-10-20 16:11:04 -04:00
) -> Option<Vec<PlaceElem<'tcx>>> {
let mut projection = Cow::Borrowed(projection);
for i in 0..projection.len() {
2020-05-23 12:02:54 +02:00
if let Some(&elem) = projection.get(i) {
if let Some(elem) = self.process_projection_elem(elem, location) {
2019-10-20 16:11:04 -04:00
// This converts the borrowed projection into `Cow::Owned(_)` and returns a
// clone of the projection so we can mutate and reintern later.
let vec = projection.to_mut();
vec[i] = elem;
}
}
}
match projection {
Cow::Borrowed(_) => None,
2019-10-20 16:11:04 -04:00
Cow::Owned(vec) => Some(vec),
}
}
fn process_projection_elem(
&mut self,
2020-05-23 12:02:54 +02:00
elem: PlaceElem<'tcx>,
location: Location,
) -> Option<PlaceElem<'tcx>> {
match elem {
PlaceElem::Index(local) => {
2020-05-23 12:02:54 +02:00
let mut new_local = local;
self.visit_local(
&mut new_local,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
location,
);
2022-07-04 21:30:31 +02:00
if new_local == local { None } else { Some(PlaceElem::Index(new_local)) }
}
2021-10-16 14:03:30 +02:00
PlaceElem::Field(field, ty) => {
let mut new_ty = ty;
self.visit_ty(&mut new_ty, TyContext::Location(location));
2022-07-04 21:30:31 +02:00
if ty != new_ty { Some(PlaceElem::Field(field, new_ty)) } else { None }
2021-10-16 14:03:30 +02:00
}
PlaceElem::OpaqueCast(ty) => {
let mut new_ty = ty;
self.visit_ty(&mut new_ty, TyContext::Location(location));
if ty != new_ty { Some(PlaceElem::OpaqueCast(new_ty)) } else { None }
}
PlaceElem::Deref
| PlaceElem::ConstantIndex { .. }
| PlaceElem::Subslice { .. }
| PlaceElem::Downcast(..) => None,
}
}
};
() => {
fn visit_projection(
&mut self,
place_ref: PlaceRef<'tcx>,
context: PlaceContext,
location: Location,
) {
self.super_projection(place_ref, context, location);
}
fn visit_projection_elem(
&mut self,
place_ref: PlaceRef<'tcx>,
2020-05-23 12:02:54 +02:00
elem: PlaceElem<'tcx>,
context: PlaceContext,
location: Location,
) {
self.super_projection_elem(place_ref, elem, context, location);
}
fn super_place(&mut self, place: &Place<'tcx>, context: PlaceContext, location: Location) {
let mut context = context;
if !place.projection.is_empty() {
if context.is_use() {
// ^ Only change the context if it is a real use, not a "use" in debuginfo.
context = if context.is_mutating_use() {
PlaceContext::MutatingUse(MutatingUseContext::Projection)
} else {
PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection)
};
}
}
self.visit_local(place.local, context, location);
self.visit_projection(place.as_ref(), context, location);
}
fn super_projection(
&mut self,
place_ref: PlaceRef<'tcx>,
context: PlaceContext,
location: Location,
) {
for (base, elem) in place_ref.iter_projections().rev() {
self.visit_projection_elem(base, elem, context, location);
}
}
fn super_projection_elem(
&mut self,
_place_ref: PlaceRef<'tcx>,
2020-05-23 12:02:54 +02:00
elem: PlaceElem<'tcx>,
_context: PlaceContext,
location: Location,
) {
match elem {
ProjectionElem::OpaqueCast(ty) | ProjectionElem::Field(_, ty) => {
self.visit_ty(ty, TyContext::Location(location));
}
ProjectionElem::Index(local) => {
self.visit_local(
local,
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy),
location,
);
}
ProjectionElem::Deref
| ProjectionElem::Subslice { from: _, to: _, from_end: _ }
| ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ }
| ProjectionElem::Downcast(_, _) => {}
}
}
};
}
make_mir_visitor!(Visitor,);
make_mir_visitor!(MutVisitor, mut);
2017-12-12 11:59:09 -03:00
pub trait MirVisitable<'tcx> {
fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>);
}
impl<'tcx> MirVisitable<'tcx> for Statement<'tcx> {
fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
visitor.visit_statement(self, location)
2017-12-12 11:59:09 -03:00
}
}
impl<'tcx> MirVisitable<'tcx> for Terminator<'tcx> {
fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
visitor.visit_terminator(self, location)
2017-12-12 11:59:09 -03:00
}
}
impl<'tcx> MirVisitable<'tcx> for Option<Terminator<'tcx>> {
fn apply(&self, location: Location, visitor: &mut dyn Visitor<'tcx>) {
visitor.visit_terminator(self.as_ref().unwrap(), location)
2017-12-12 11:59:09 -03:00
}
}
/// Extra information passed to `visit_ty` and friends to give context
/// about where the type etc appears.
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq)]
pub enum TyContext {
LocalDecl {
/// The index of the local variable we are visiting.
local: Local,
/// The source location where this local variable was declared.
source_info: SourceInfo,
},
/// The inferred type of a user type annotation.
UserTy(Span),
2017-11-07 04:30:06 -05:00
/// The return type of the function.
ReturnTy(SourceInfo),
YieldTy(SourceInfo),
2017-11-07 04:30:06 -05:00
/// A type found at some location.
Location(Location),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum NonMutatingUseContext {
/// Being inspected in some way, like loading a len.
Inspect,
/// Consumed as part of an operand.
Copy,
/// Consumed as part of an operand.
Move,
/// Shared borrow.
SharedBorrow,
/// Shallow borrow.
ShallowBorrow,
/// AddressOf for *const pointer.
AddressOf,
2023-04-25 20:09:54 +00:00
/// PlaceMention statement.
///
/// This statement is executed as a check that the `Place` is live without reading from it,
/// so it must be considered as a non-mutating use.
2023-04-25 20:09:54 +00:00
PlaceMention,
/// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
/// For example, the projection `x.y` is not marked as a mutation in these cases:
2022-04-15 15:04:34 -07:00
/// ```ignore (illustrative)
/// z = x.y;
/// f(&x.y);
/// ```
Projection,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum MutatingUseContext {
/// Appears as LHS of an assignment.
Store,
/// Appears on `SetDiscriminant`
SetDiscriminant,
/// Appears on `Deinit`
Deinit,
/// Output operand of an inline assembly block.
AsmOutput,
/// Destination of a call.
Call,
/// Destination of a yield.
Yield,
/// Being dropped.
Drop,
/// Mutable borrow.
Borrow,
/// AddressOf for *mut pointer.
AddressOf,
/// Used as base for another place, e.g., `x` in `x.y`. Could potentially mutate the place.
/// For example, the projection `x.y` is marked as a mutation in these cases:
2022-04-15 15:04:34 -07:00
/// ```ignore (illustrative)
/// x.y = ...;
/// f(&mut x.y);
/// ```
Projection,
/// Retagging, a "Stacked Borrows" shadow state operation
Retag,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum NonUseContext {
/// Starting a storage live range.
StorageLive,
/// Ending a storage live range.
StorageDead,
/// User type annotation assertions for NLL.
AscribeUserTy(ty::Variance),
/// The data of a user variable, for debug info.
VarDebugInfo,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PlaceContext {
NonMutatingUse(NonMutatingUseContext),
MutatingUse(MutatingUseContext),
NonUse(NonUseContext),
}
2019-06-11 12:21:38 +03:00
impl PlaceContext {
/// Returns `true` if this place context represents a drop.
#[inline]
pub fn is_drop(&self) -> bool {
matches!(self, PlaceContext::MutatingUse(MutatingUseContext::Drop))
}
/// Returns `true` if this place context represents a borrow.
pub fn is_borrow(&self) -> bool {
matches!(
self,
PlaceContext::NonMutatingUse(
2023-05-29 17:15:48 +02:00
NonMutatingUseContext::SharedBorrow | NonMutatingUseContext::ShallowBorrow
) | PlaceContext::MutatingUse(MutatingUseContext::Borrow)
)
}
/// Returns `true` if this place context represents an address-of.
pub fn is_address_of(&self) -> bool {
matches!(
self,
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
| PlaceContext::MutatingUse(MutatingUseContext::AddressOf)
)
}
/// Returns `true` if this place context represents a storage live or storage dead marker.
#[inline]
pub fn is_storage_marker(&self) -> bool {
matches!(
self,
PlaceContext::NonUse(NonUseContext::StorageLive | NonUseContext::StorageDead)
)
}
/// Returns `true` if this place context represents a use that potentially changes the value.
#[inline]
pub fn is_mutating_use(&self) -> bool {
matches!(self, PlaceContext::MutatingUse(..))
}
/// Returns `true` if this place context represents a use.
#[inline]
pub fn is_use(&self) -> bool {
!matches!(self, PlaceContext::NonUse(..))
}
/// Returns `true` if this place context represents an assignment statement.
pub fn is_place_assignment(&self) -> bool {
matches!(
self,
PlaceContext::MutatingUse(
MutatingUseContext::Store
| MutatingUseContext::Call
| MutatingUseContext::AsmOutput,
)
)
}
}