Auto merge of #138830 - matthiaskrgr:rollup-gaxgfwl, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #138410 (Couple mir building cleanups) - #138490 (Forward `stream_position` in `Arc<File>` as well) - #138535 (Cleanup `LangString::parse`) - #138536 (stable_mir: Add `MutMirVisitor`) - #138673 (Fix build failure on Trusty) - #138750 (Make `crate_hash` not iterate over `hir_crate` owners anymore) - #138763 (jsondocck: Replace `jsonpath_lib` with `jsonpath-rust`) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
d93f678fa5
165 changed files with 1878 additions and 1645 deletions
|
@ -1176,15 +1176,14 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
|
|||
debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher);
|
||||
if tcx.sess.opts.incremental.is_some() {
|
||||
let definitions = tcx.untracked().definitions.freeze();
|
||||
let mut owner_spans: Vec<_> = krate
|
||||
.owners
|
||||
.iter_enumerated()
|
||||
.filter_map(|(def_id, info)| {
|
||||
let _ = info.as_owner()?;
|
||||
let mut owner_spans: Vec<_> = tcx
|
||||
.hir_crate_items(())
|
||||
.definitions()
|
||||
.map(|def_id| {
|
||||
let def_path_hash = definitions.def_path_hash(def_id);
|
||||
let span = tcx.source_span(def_id);
|
||||
debug_assert_eq!(span.parent(), None);
|
||||
Some((def_path_hash, span))
|
||||
(def_path_hash, span)
|
||||
})
|
||||
.collect();
|
||||
owner_spans.sort_unstable_by_key(|bn| bn.0);
|
||||
|
|
|
@ -105,23 +105,19 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>
|
|||
return Const::Ty(Ty::new_error(tcx, guar), ty::Const::new_error(tcx, guar));
|
||||
}
|
||||
|
||||
let trunc = |n, width: ty::UintTy| {
|
||||
let width = width
|
||||
.normalize(tcx.data_layout.pointer_size.bits().try_into().unwrap())
|
||||
.bit_width()
|
||||
.unwrap();
|
||||
let width = Size::from_bits(width);
|
||||
let lit_ty = match *ty.kind() {
|
||||
ty::Pat(base, _) => base,
|
||||
_ => ty,
|
||||
};
|
||||
|
||||
let trunc = |n| {
|
||||
let width = lit_ty.primitive_size(tcx);
|
||||
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
|
||||
let result = width.truncate(n);
|
||||
trace!("trunc result: {}", result);
|
||||
ConstValue::Scalar(Scalar::from_uint(result, width))
|
||||
};
|
||||
|
||||
let lit_ty = match *ty.kind() {
|
||||
ty::Pat(base, _) => base,
|
||||
_ => ty,
|
||||
};
|
||||
|
||||
let value = match (lit, lit_ty.kind()) {
|
||||
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
|
||||
let s = s.as_str();
|
||||
|
@ -149,11 +145,10 @@ fn lit_to_mir_constant<'tcx>(tcx: TyCtxt<'tcx>, lit_input: LitToConstInput<'tcx>
|
|||
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
|
||||
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
|
||||
}
|
||||
(ast::LitKind::Int(n, _), ty::Uint(ui)) if !neg => trunc(n.get(), *ui),
|
||||
(ast::LitKind::Int(n, _), ty::Int(i)) => trunc(
|
||||
if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() },
|
||||
i.to_unsigned(),
|
||||
),
|
||||
(ast::LitKind::Int(n, _), ty::Uint(_)) if !neg => trunc(n.get()),
|
||||
(ast::LitKind::Int(n, _), ty::Int(_)) => {
|
||||
trunc(if neg { (n.get() as i128).overflowing_neg().0 as u128 } else { n.get() })
|
||||
}
|
||||
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
|
||||
parse_float_into_constval(*n, *fty, neg).unwrap()
|
||||
}
|
||||
|
|
|
@ -305,27 +305,25 @@ impl DropTree {
|
|||
}
|
||||
|
||||
/// Builds the MIR for a given drop tree.
|
||||
///
|
||||
/// `blocks` should have the same length as `self.drops`, and may have its
|
||||
/// first value set to some already existing block.
|
||||
fn build_mir<'tcx, T: DropTreeBuilder<'tcx>>(
|
||||
&mut self,
|
||||
cfg: &mut CFG<'tcx>,
|
||||
blocks: &mut IndexVec<DropIdx, Option<BasicBlock>>,
|
||||
) {
|
||||
root_node: Option<BasicBlock>,
|
||||
) -> IndexVec<DropIdx, Option<BasicBlock>> {
|
||||
debug!("DropTree::build_mir(drops = {:#?})", self);
|
||||
assert_eq!(blocks.len(), self.drops.len());
|
||||
|
||||
self.assign_blocks::<T>(cfg, blocks);
|
||||
self.link_blocks(cfg, blocks)
|
||||
let mut blocks = self.assign_blocks::<T>(cfg, root_node);
|
||||
self.link_blocks(cfg, &mut blocks);
|
||||
|
||||
blocks
|
||||
}
|
||||
|
||||
/// Assign blocks for all of the drops in the drop tree that need them.
|
||||
fn assign_blocks<'tcx, T: DropTreeBuilder<'tcx>>(
|
||||
&mut self,
|
||||
cfg: &mut CFG<'tcx>,
|
||||
blocks: &mut IndexVec<DropIdx, Option<BasicBlock>>,
|
||||
) {
|
||||
root_node: Option<BasicBlock>,
|
||||
) -> IndexVec<DropIdx, Option<BasicBlock>> {
|
||||
// StorageDead statements can share blocks with each other and also with
|
||||
// a Drop terminator. We iterate through the drops to find which drops
|
||||
// need their own block.
|
||||
|
@ -342,8 +340,11 @@ impl DropTree {
|
|||
Own,
|
||||
}
|
||||
|
||||
let mut blocks = IndexVec::from_elem(None, &self.drops);
|
||||
blocks[ROOT_NODE] = root_node;
|
||||
|
||||
let mut needs_block = IndexVec::from_elem(Block::None, &self.drops);
|
||||
if blocks[ROOT_NODE].is_some() {
|
||||
if root_node.is_some() {
|
||||
// In some cases (such as drops for `continue`) the root node
|
||||
// already has a block. In this case, make sure that we don't
|
||||
// override it.
|
||||
|
@ -385,6 +386,8 @@ impl DropTree {
|
|||
|
||||
debug!("assign_blocks: blocks = {:#?}", blocks);
|
||||
assert!(entry_points.is_empty());
|
||||
|
||||
blocks
|
||||
}
|
||||
|
||||
fn link_blocks<'tcx>(
|
||||
|
@ -1574,10 +1577,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
|
|||
span: Span,
|
||||
continue_block: Option<BasicBlock>,
|
||||
) -> Option<BlockAnd<()>> {
|
||||
let mut blocks = IndexVec::from_elem(None, &drops.drops);
|
||||
blocks[ROOT_NODE] = continue_block;
|
||||
|
||||
drops.build_mir::<ExitScopes>(&mut self.cfg, &mut blocks);
|
||||
let blocks = drops.build_mir::<ExitScopes>(&mut self.cfg, continue_block);
|
||||
let is_coroutine = self.coroutine.is_some();
|
||||
|
||||
// Link the exit drop tree to unwind drop tree.
|
||||
|
@ -1633,8 +1633,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
|
|||
let drops = &mut self.scopes.coroutine_drops;
|
||||
let cfg = &mut self.cfg;
|
||||
let fn_span = self.fn_span;
|
||||
let mut blocks = IndexVec::from_elem(None, &drops.drops);
|
||||
drops.build_mir::<CoroutineDrop>(cfg, &mut blocks);
|
||||
let blocks = drops.build_mir::<CoroutineDrop>(cfg, None);
|
||||
if let Some(root_block) = blocks[ROOT_NODE] {
|
||||
cfg.terminate(
|
||||
root_block,
|
||||
|
@ -1670,9 +1669,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
|
|||
fn_span: Span,
|
||||
resume_block: &mut Option<BasicBlock>,
|
||||
) {
|
||||
let mut blocks = IndexVec::from_elem(None, &drops.drops);
|
||||
blocks[ROOT_NODE] = *resume_block;
|
||||
drops.build_mir::<Unwind>(cfg, &mut blocks);
|
||||
let blocks = drops.build_mir::<Unwind>(cfg, *resume_block);
|
||||
if let (None, Some(resume)) = (*resume_block, blocks[ROOT_NODE]) {
|
||||
cfg.terminate(resume, SourceInfo::outermost(fn_span), TerminatorKind::UnwindResume);
|
||||
|
||||
|
|
|
@ -5,4 +5,4 @@ pub mod pretty;
|
|||
pub mod visit;
|
||||
|
||||
pub use body::*;
|
||||
pub use visit::MirVisitor;
|
||||
pub use visit::{MirVisitor, MutMirVisitor};
|
||||
|
|
|
@ -77,6 +77,22 @@ impl Body {
|
|||
&self.locals[self.arg_count + 1..]
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the local that holds this function's return value.
|
||||
pub(crate) fn ret_local_mut(&mut self) -> &mut LocalDecl {
|
||||
&mut self.locals[RETURN_LOCAL]
|
||||
}
|
||||
|
||||
/// Returns a mutable slice of locals corresponding to this function's arguments.
|
||||
pub(crate) fn arg_locals_mut(&mut self) -> &mut [LocalDecl] {
|
||||
&mut self.locals[1..][..self.arg_count]
|
||||
}
|
||||
|
||||
/// Returns a mutable slice of inner locals for this function.
|
||||
/// Inner locals are those that are neither the return local nor the argument locals.
|
||||
pub(crate) fn inner_locals_mut(&mut self) -> &mut [LocalDecl] {
|
||||
&mut self.locals[self.arg_count + 1..]
|
||||
}
|
||||
|
||||
/// Convenience function to get all the locals in this function.
|
||||
///
|
||||
/// Locals are typically accessed via the more specific methods `ret_local`,
|
||||
|
|
|
@ -39,406 +39,486 @@ use crate::mir::*;
|
|||
use crate::ty::{GenericArgs, MirConst, Region, Ty, TyConst};
|
||||
use crate::{Error, Opaque, Span};
|
||||
|
||||
pub trait MirVisitor {
|
||||
fn visit_body(&mut self, body: &Body) {
|
||||
self.super_body(body)
|
||||
}
|
||||
macro_rules! make_mir_visitor {
|
||||
($visitor_trait_name:ident, $($mutability:ident)?) => {
|
||||
pub trait $visitor_trait_name {
|
||||
fn visit_body(&mut self, body: &$($mutability)? Body) {
|
||||
self.super_body(body)
|
||||
}
|
||||
|
||||
fn visit_basic_block(&mut self, bb: &BasicBlock) {
|
||||
self.super_basic_block(bb)
|
||||
}
|
||||
fn visit_basic_block(&mut self, bb: &$($mutability)? BasicBlock) {
|
||||
self.super_basic_block(bb)
|
||||
}
|
||||
|
||||
fn visit_ret_decl(&mut self, local: Local, decl: &LocalDecl) {
|
||||
self.super_ret_decl(local, decl)
|
||||
}
|
||||
fn visit_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
|
||||
self.super_ret_decl(local, decl)
|
||||
}
|
||||
|
||||
fn visit_arg_decl(&mut self, local: Local, decl: &LocalDecl) {
|
||||
self.super_arg_decl(local, decl)
|
||||
}
|
||||
fn visit_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
|
||||
self.super_arg_decl(local, decl)
|
||||
}
|
||||
|
||||
fn visit_local_decl(&mut self, local: Local, decl: &LocalDecl) {
|
||||
self.super_local_decl(local, decl)
|
||||
}
|
||||
fn visit_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
|
||||
self.super_local_decl(local, decl)
|
||||
}
|
||||
|
||||
fn visit_statement(&mut self, stmt: &Statement, location: Location) {
|
||||
self.super_statement(stmt, location)
|
||||
}
|
||||
fn visit_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) {
|
||||
self.super_statement(stmt, location)
|
||||
}
|
||||
|
||||
fn visit_terminator(&mut self, term: &Terminator, location: Location) {
|
||||
self.super_terminator(term, location)
|
||||
}
|
||||
fn visit_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) {
|
||||
self.super_terminator(term, location)
|
||||
}
|
||||
|
||||
fn visit_span(&mut self, span: &Span) {
|
||||
self.super_span(span)
|
||||
}
|
||||
fn visit_span(&mut self, span: &$($mutability)? Span) {
|
||||
self.super_span(span)
|
||||
}
|
||||
|
||||
fn visit_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
|
||||
self.super_place(place, ptx, location)
|
||||
}
|
||||
fn visit_place(&mut self, place: &$($mutability)? Place, ptx: PlaceContext, location: Location) {
|
||||
self.super_place(place, ptx, location)
|
||||
}
|
||||
|
||||
fn visit_projection_elem(
|
||||
&mut self,
|
||||
place_ref: PlaceRef<'_>,
|
||||
elem: &ProjectionElem,
|
||||
ptx: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
let _ = place_ref;
|
||||
self.super_projection_elem(elem, ptx, location);
|
||||
}
|
||||
visit_place_fns!($($mutability)?);
|
||||
|
||||
fn visit_local(&mut self, local: &Local, ptx: PlaceContext, location: Location) {
|
||||
let _ = (local, ptx, location);
|
||||
}
|
||||
fn visit_local(&mut self, local: &$($mutability)? Local, ptx: PlaceContext, location: Location) {
|
||||
let _ = (local, ptx, location);
|
||||
}
|
||||
|
||||
fn visit_rvalue(&mut self, rvalue: &Rvalue, location: Location) {
|
||||
self.super_rvalue(rvalue, location)
|
||||
}
|
||||
fn visit_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) {
|
||||
self.super_rvalue(rvalue, location)
|
||||
}
|
||||
|
||||
fn visit_operand(&mut self, operand: &Operand, location: Location) {
|
||||
self.super_operand(operand, location)
|
||||
}
|
||||
fn visit_operand(&mut self, operand: &$($mutability)? Operand, location: Location) {
|
||||
self.super_operand(operand, location)
|
||||
}
|
||||
|
||||
fn visit_user_type_projection(&mut self, projection: &UserTypeProjection) {
|
||||
self.super_user_type_projection(projection)
|
||||
}
|
||||
fn visit_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) {
|
||||
self.super_user_type_projection(projection)
|
||||
}
|
||||
|
||||
fn visit_ty(&mut self, ty: &Ty, location: Location) {
|
||||
let _ = location;
|
||||
self.super_ty(ty)
|
||||
}
|
||||
fn visit_ty(&mut self, ty: &$($mutability)? Ty, location: Location) {
|
||||
let _ = location;
|
||||
self.super_ty(ty)
|
||||
}
|
||||
|
||||
fn visit_const_operand(&mut self, constant: &ConstOperand, location: Location) {
|
||||
self.super_const_operand(constant, location)
|
||||
}
|
||||
fn visit_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) {
|
||||
self.super_const_operand(constant, location)
|
||||
}
|
||||
|
||||
fn visit_mir_const(&mut self, constant: &MirConst, location: Location) {
|
||||
self.super_mir_const(constant, location)
|
||||
}
|
||||
fn visit_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) {
|
||||
self.super_mir_const(constant, location)
|
||||
}
|
||||
|
||||
fn visit_ty_const(&mut self, constant: &TyConst, location: Location) {
|
||||
let _ = location;
|
||||
self.super_ty_const(constant)
|
||||
}
|
||||
fn visit_ty_const(&mut self, constant: &$($mutability)? TyConst, location: Location) {
|
||||
let _ = location;
|
||||
self.super_ty_const(constant)
|
||||
}
|
||||
|
||||
fn visit_region(&mut self, region: &Region, location: Location) {
|
||||
let _ = location;
|
||||
self.super_region(region)
|
||||
}
|
||||
fn visit_region(&mut self, region: &$($mutability)? Region, location: Location) {
|
||||
let _ = location;
|
||||
self.super_region(region)
|
||||
}
|
||||
|
||||
fn visit_args(&mut self, args: &GenericArgs, location: Location) {
|
||||
let _ = location;
|
||||
self.super_args(args)
|
||||
}
|
||||
fn visit_args(&mut self, args: &$($mutability)? GenericArgs, location: Location) {
|
||||
let _ = location;
|
||||
self.super_args(args)
|
||||
}
|
||||
|
||||
fn visit_assert_msg(&mut self, msg: &AssertMessage, location: Location) {
|
||||
self.super_assert_msg(msg, location)
|
||||
}
|
||||
fn visit_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) {
|
||||
self.super_assert_msg(msg, location)
|
||||
}
|
||||
|
||||
fn visit_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) {
|
||||
self.super_var_debug_info(var_debug_info);
|
||||
}
|
||||
fn visit_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) {
|
||||
self.super_var_debug_info(var_debug_info);
|
||||
}
|
||||
|
||||
fn super_body(&mut self, body: &Body) {
|
||||
let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = body;
|
||||
fn super_body(&mut self, body: &$($mutability)? Body) {
|
||||
super_body!(self, body, $($mutability)?);
|
||||
}
|
||||
|
||||
for bb in blocks {
|
||||
self.visit_basic_block(bb);
|
||||
fn super_basic_block(&mut self, bb: &$($mutability)? BasicBlock) {
|
||||
let BasicBlock { statements, terminator } = bb;
|
||||
for stmt in statements {
|
||||
self.visit_statement(stmt, Location(stmt.span));
|
||||
}
|
||||
self.visit_terminator(terminator, Location(terminator.span));
|
||||
}
|
||||
|
||||
fn super_local_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
|
||||
let _ = local;
|
||||
let LocalDecl { ty, span, .. } = decl;
|
||||
self.visit_ty(ty, Location(*span));
|
||||
}
|
||||
|
||||
fn super_ret_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
|
||||
self.super_local_decl(local, decl)
|
||||
}
|
||||
|
||||
fn super_arg_decl(&mut self, local: Local, decl: &$($mutability)? LocalDecl) {
|
||||
self.super_local_decl(local, decl)
|
||||
}
|
||||
|
||||
fn super_statement(&mut self, stmt: &$($mutability)? Statement, location: Location) {
|
||||
let Statement { kind, span } = stmt;
|
||||
self.visit_span(span);
|
||||
match kind {
|
||||
StatementKind::Assign(place, rvalue) => {
|
||||
self.visit_place(place, PlaceContext::MUTATING, location);
|
||||
self.visit_rvalue(rvalue, location);
|
||||
}
|
||||
StatementKind::FakeRead(_, place) | StatementKind::PlaceMention(place) => {
|
||||
self.visit_place(place, PlaceContext::NON_MUTATING, location);
|
||||
}
|
||||
StatementKind::SetDiscriminant { place, .. }
|
||||
| StatementKind::Deinit(place)
|
||||
| StatementKind::Retag(_, place) => {
|
||||
self.visit_place(place, PlaceContext::MUTATING, location);
|
||||
}
|
||||
StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
|
||||
self.visit_local(local, PlaceContext::NON_USE, location);
|
||||
}
|
||||
StatementKind::AscribeUserType { place, projections, variance: _ } => {
|
||||
self.visit_place(place, PlaceContext::NON_USE, location);
|
||||
self.visit_user_type_projection(projections);
|
||||
}
|
||||
StatementKind::Coverage(coverage) => visit_opaque(coverage),
|
||||
StatementKind::Intrinsic(intrisic) => match intrisic {
|
||||
NonDivergingIntrinsic::Assume(operand) => {
|
||||
self.visit_operand(operand, 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 => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_terminator(&mut self, term: &$($mutability)? Terminator, location: Location) {
|
||||
let Terminator { kind, span } = term;
|
||||
self.visit_span(span);
|
||||
match kind {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Unreachable => {}
|
||||
TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
|
||||
self.visit_operand(cond, location);
|
||||
self.visit_assert_msg(msg, location);
|
||||
}
|
||||
TerminatorKind::Drop { place, target: _, unwind: _ } => {
|
||||
self.visit_place(place, PlaceContext::MUTATING, location);
|
||||
}
|
||||
TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => {
|
||||
self.visit_operand(func, location);
|
||||
for arg in args {
|
||||
self.visit_operand(arg, location);
|
||||
}
|
||||
self.visit_place(destination, PlaceContext::MUTATING, location);
|
||||
}
|
||||
TerminatorKind::InlineAsm { operands, .. } => {
|
||||
for op in operands {
|
||||
let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op;
|
||||
if let Some(input) = in_value {
|
||||
self.visit_operand(input, location);
|
||||
}
|
||||
if let Some(output) = out_place {
|
||||
self.visit_place(output, PlaceContext::MUTATING, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
TerminatorKind::Return => {
|
||||
let $($mutability)? local = RETURN_LOCAL;
|
||||
self.visit_local(&$($mutability)? local, PlaceContext::NON_MUTATING, location);
|
||||
}
|
||||
TerminatorKind::SwitchInt { discr, targets: _ } => {
|
||||
self.visit_operand(discr, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_span(&mut self, span: &$($mutability)? Span) {
|
||||
let _ = span;
|
||||
}
|
||||
|
||||
fn super_rvalue(&mut self, rvalue: &$($mutability)? Rvalue, location: Location) {
|
||||
match rvalue {
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut };
|
||||
self.visit_place(place, pcx, location);
|
||||
}
|
||||
Rvalue::Aggregate(_, operands) => {
|
||||
for op in operands {
|
||||
self.visit_operand(op, location);
|
||||
}
|
||||
}
|
||||
Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
|
||||
self.visit_operand(lhs, location);
|
||||
self.visit_operand(rhs, location);
|
||||
}
|
||||
Rvalue::Cast(_, op, ty) => {
|
||||
self.visit_operand(op, location);
|
||||
self.visit_ty(ty, location);
|
||||
}
|
||||
Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => {
|
||||
self.visit_place(place, PlaceContext::NON_MUTATING, location);
|
||||
}
|
||||
Rvalue::Ref(region, kind, place) => {
|
||||
self.visit_region(region, location);
|
||||
let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) };
|
||||
self.visit_place(place, pcx, location);
|
||||
}
|
||||
Rvalue::Repeat(op, constant) => {
|
||||
self.visit_operand(op, location);
|
||||
self.visit_ty_const(constant, location);
|
||||
}
|
||||
Rvalue::ShallowInitBox(op, ty) => {
|
||||
self.visit_ty(ty, location);
|
||||
self.visit_operand(op, location)
|
||||
}
|
||||
Rvalue::ThreadLocalRef(_) => {}
|
||||
Rvalue::NullaryOp(_, ty) => {
|
||||
self.visit_ty(ty, location);
|
||||
}
|
||||
Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
|
||||
self.visit_operand(op, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_operand(&mut self, operand: &$($mutability)? Operand, location: Location) {
|
||||
match operand {
|
||||
Operand::Copy(place) | Operand::Move(place) => {
|
||||
self.visit_place(place, PlaceContext::NON_MUTATING, location)
|
||||
}
|
||||
Operand::Constant(constant) => {
|
||||
self.visit_const_operand(constant, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_user_type_projection(&mut self, projection: &$($mutability)? UserTypeProjection) {
|
||||
// This is a no-op on mir::Visitor.
|
||||
let _ = projection;
|
||||
}
|
||||
|
||||
fn super_ty(&mut self, ty: &$($mutability)? Ty) {
|
||||
let _ = ty;
|
||||
}
|
||||
|
||||
fn super_const_operand(&mut self, constant: &$($mutability)? ConstOperand, location: Location) {
|
||||
let ConstOperand { span, user_ty: _, const_ } = constant;
|
||||
self.visit_span(span);
|
||||
self.visit_mir_const(const_, location);
|
||||
}
|
||||
|
||||
fn super_mir_const(&mut self, constant: &$($mutability)? MirConst, location: Location) {
|
||||
let MirConst { kind: _, ty, id: _ } = constant;
|
||||
self.visit_ty(ty, location);
|
||||
}
|
||||
|
||||
fn super_ty_const(&mut self, constant: &$($mutability)? TyConst) {
|
||||
let _ = constant;
|
||||
}
|
||||
|
||||
fn super_region(&mut self, region: &$($mutability)? Region) {
|
||||
let _ = region;
|
||||
}
|
||||
|
||||
fn super_args(&mut self, args: &$($mutability)? GenericArgs) {
|
||||
let _ = args;
|
||||
}
|
||||
|
||||
fn super_var_debug_info(&mut self, var_debug_info: &$($mutability)? VarDebugInfo) {
|
||||
let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } =
|
||||
var_debug_info;
|
||||
self.visit_span(&$($mutability)? source_info.span);
|
||||
let location = Location(source_info.span);
|
||||
if let Some(composite) = composite {
|
||||
self.visit_ty(&$($mutability)? composite.ty, location);
|
||||
}
|
||||
match value {
|
||||
VarDebugInfoContents::Place(place) => {
|
||||
self.visit_place(place, PlaceContext::NON_USE, location);
|
||||
}
|
||||
VarDebugInfoContents::Const(constant) => {
|
||||
self.visit_mir_const(&$($mutability)? constant.const_, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_assert_msg(&mut self, msg: &$($mutability)? AssertMessage, location: Location) {
|
||||
match msg {
|
||||
AssertMessage::BoundsCheck { len, index } => {
|
||||
self.visit_operand(len, location);
|
||||
self.visit_operand(index, location);
|
||||
}
|
||||
AssertMessage::Overflow(_, left, right) => {
|
||||
self.visit_operand(left, location);
|
||||
self.visit_operand(right, location);
|
||||
}
|
||||
AssertMessage::OverflowNeg(op)
|
||||
| AssertMessage::DivisionByZero(op)
|
||||
| AssertMessage::RemainderByZero(op) => {
|
||||
self.visit_operand(op, location);
|
||||
}
|
||||
AssertMessage::ResumedAfterReturn(_)
|
||||
| AssertMessage::ResumedAfterPanic(_)
|
||||
| AssertMessage::NullPointerDereference => {
|
||||
//nothing to visit
|
||||
}
|
||||
AssertMessage::MisalignedPointerDereference { required, found } => {
|
||||
self.visit_operand(required, location);
|
||||
self.visit_operand(found, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! super_body {
|
||||
($self:ident, $body:ident, mut) => {
|
||||
for bb in $body.blocks.iter_mut() {
|
||||
$self.visit_basic_block(bb);
|
||||
}
|
||||
|
||||
self.visit_ret_decl(RETURN_LOCAL, body.ret_local());
|
||||
$self.visit_ret_decl(RETURN_LOCAL, $body.ret_local_mut());
|
||||
|
||||
for (idx, arg) in body.arg_locals().iter().enumerate() {
|
||||
self.visit_arg_decl(idx + 1, arg)
|
||||
for (idx, arg) in $body.arg_locals_mut().iter_mut().enumerate() {
|
||||
$self.visit_arg_decl(idx + 1, arg)
|
||||
}
|
||||
|
||||
let local_start = $body.arg_count + 1;
|
||||
for (idx, arg) in $body.inner_locals_mut().iter_mut().enumerate() {
|
||||
$self.visit_local_decl(idx + local_start, arg)
|
||||
}
|
||||
|
||||
for info in $body.var_debug_info.iter_mut() {
|
||||
$self.visit_var_debug_info(info);
|
||||
}
|
||||
|
||||
$self.visit_span(&mut $body.span)
|
||||
};
|
||||
|
||||
($self:ident, $body:ident, ) => {
|
||||
let Body { blocks, locals: _, arg_count, var_debug_info, spread_arg: _, span } = $body;
|
||||
|
||||
for bb in blocks {
|
||||
$self.visit_basic_block(bb);
|
||||
}
|
||||
|
||||
$self.visit_ret_decl(RETURN_LOCAL, $body.ret_local());
|
||||
|
||||
for (idx, arg) in $body.arg_locals().iter().enumerate() {
|
||||
$self.visit_arg_decl(idx + 1, arg)
|
||||
}
|
||||
|
||||
let local_start = arg_count + 1;
|
||||
for (idx, arg) in body.inner_locals().iter().enumerate() {
|
||||
self.visit_local_decl(idx + local_start, arg)
|
||||
for (idx, arg) in $body.inner_locals().iter().enumerate() {
|
||||
$self.visit_local_decl(idx + local_start, arg)
|
||||
}
|
||||
|
||||
for info in var_debug_info.iter() {
|
||||
self.visit_var_debug_info(info);
|
||||
$self.visit_var_debug_info(info);
|
||||
}
|
||||
|
||||
self.visit_span(span)
|
||||
}
|
||||
|
||||
fn super_basic_block(&mut self, bb: &BasicBlock) {
|
||||
let BasicBlock { statements, terminator } = bb;
|
||||
for stmt in statements {
|
||||
self.visit_statement(stmt, Location(stmt.span));
|
||||
}
|
||||
self.visit_terminator(terminator, Location(terminator.span));
|
||||
}
|
||||
|
||||
fn super_local_decl(&mut self, local: Local, decl: &LocalDecl) {
|
||||
let _ = local;
|
||||
let LocalDecl { ty, span, .. } = decl;
|
||||
self.visit_ty(ty, Location(*span));
|
||||
}
|
||||
|
||||
fn super_ret_decl(&mut self, local: Local, decl: &LocalDecl) {
|
||||
self.super_local_decl(local, decl)
|
||||
}
|
||||
|
||||
fn super_arg_decl(&mut self, local: Local, decl: &LocalDecl) {
|
||||
self.super_local_decl(local, decl)
|
||||
}
|
||||
|
||||
fn super_statement(&mut self, stmt: &Statement, location: Location) {
|
||||
let Statement { kind, span } = stmt;
|
||||
self.visit_span(span);
|
||||
match kind {
|
||||
StatementKind::Assign(place, rvalue) => {
|
||||
self.visit_place(place, PlaceContext::MUTATING, location);
|
||||
self.visit_rvalue(rvalue, location);
|
||||
}
|
||||
StatementKind::FakeRead(_, place) | StatementKind::PlaceMention(place) => {
|
||||
self.visit_place(place, PlaceContext::NON_MUTATING, location);
|
||||
}
|
||||
StatementKind::SetDiscriminant { place, .. }
|
||||
| StatementKind::Deinit(place)
|
||||
| StatementKind::Retag(_, place) => {
|
||||
self.visit_place(place, PlaceContext::MUTATING, location);
|
||||
}
|
||||
StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
|
||||
self.visit_local(local, PlaceContext::NON_USE, location);
|
||||
}
|
||||
StatementKind::AscribeUserType { place, projections, variance: _ } => {
|
||||
self.visit_place(place, PlaceContext::NON_USE, location);
|
||||
self.visit_user_type_projection(projections);
|
||||
}
|
||||
StatementKind::Coverage(coverage) => visit_opaque(coverage),
|
||||
StatementKind::Intrinsic(intrisic) => match intrisic {
|
||||
NonDivergingIntrinsic::Assume(operand) => {
|
||||
self.visit_operand(operand, 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 => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_terminator(&mut self, term: &Terminator, location: Location) {
|
||||
let Terminator { kind, span } = term;
|
||||
self.visit_span(span);
|
||||
match kind {
|
||||
TerminatorKind::Goto { .. }
|
||||
| TerminatorKind::Resume
|
||||
| TerminatorKind::Abort
|
||||
| TerminatorKind::Unreachable => {}
|
||||
TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
|
||||
self.visit_operand(cond, location);
|
||||
self.visit_assert_msg(msg, location);
|
||||
}
|
||||
TerminatorKind::Drop { place, target: _, unwind: _ } => {
|
||||
self.visit_place(place, PlaceContext::MUTATING, location);
|
||||
}
|
||||
TerminatorKind::Call { func, args, destination, target: _, unwind: _ } => {
|
||||
self.visit_operand(func, location);
|
||||
for arg in args {
|
||||
self.visit_operand(arg, location);
|
||||
}
|
||||
self.visit_place(destination, PlaceContext::MUTATING, location);
|
||||
}
|
||||
TerminatorKind::InlineAsm { operands, .. } => {
|
||||
for op in operands {
|
||||
let InlineAsmOperand { in_value, out_place, raw_rpr: _ } = op;
|
||||
if let Some(input) = in_value {
|
||||
self.visit_operand(input, location);
|
||||
}
|
||||
if let Some(output) = out_place {
|
||||
self.visit_place(output, PlaceContext::MUTATING, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
TerminatorKind::Return => {
|
||||
let local = RETURN_LOCAL;
|
||||
self.visit_local(&local, PlaceContext::NON_MUTATING, location);
|
||||
}
|
||||
TerminatorKind::SwitchInt { discr, targets: _ } => {
|
||||
self.visit_operand(discr, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_span(&mut self, span: &Span) {
|
||||
let _ = span;
|
||||
}
|
||||
|
||||
fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
|
||||
let _ = location;
|
||||
let _ = ptx;
|
||||
self.visit_local(&place.local, ptx, location);
|
||||
|
||||
for (idx, elem) in place.projection.iter().enumerate() {
|
||||
let place_ref = PlaceRef { local: place.local, projection: &place.projection[..idx] };
|
||||
self.visit_projection_elem(place_ref, elem, ptx, location);
|
||||
}
|
||||
}
|
||||
|
||||
fn super_projection_elem(
|
||||
&mut self,
|
||||
elem: &ProjectionElem,
|
||||
ptx: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
match elem {
|
||||
ProjectionElem::Downcast(_idx) => {}
|
||||
ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ }
|
||||
| ProjectionElem::Deref
|
||||
| ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
|
||||
ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
|
||||
ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
|
||||
ProjectionElem::OpaqueCast(ty) | ProjectionElem::Subtype(ty) => {
|
||||
self.visit_ty(ty, location)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_rvalue(&mut self, rvalue: &Rvalue, location: Location) {
|
||||
match rvalue {
|
||||
Rvalue::AddressOf(mutability, place) => {
|
||||
let pcx = PlaceContext { is_mut: *mutability == RawPtrKind::Mut };
|
||||
self.visit_place(place, pcx, location);
|
||||
}
|
||||
Rvalue::Aggregate(_, operands) => {
|
||||
for op in operands {
|
||||
self.visit_operand(op, location);
|
||||
}
|
||||
}
|
||||
Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => {
|
||||
self.visit_operand(lhs, location);
|
||||
self.visit_operand(rhs, location);
|
||||
}
|
||||
Rvalue::Cast(_, op, ty) => {
|
||||
self.visit_operand(op, location);
|
||||
self.visit_ty(ty, location);
|
||||
}
|
||||
Rvalue::CopyForDeref(place) | Rvalue::Discriminant(place) | Rvalue::Len(place) => {
|
||||
self.visit_place(place, PlaceContext::NON_MUTATING, location);
|
||||
}
|
||||
Rvalue::Ref(region, kind, place) => {
|
||||
self.visit_region(region, location);
|
||||
let pcx = PlaceContext { is_mut: matches!(kind, BorrowKind::Mut { .. }) };
|
||||
self.visit_place(place, pcx, location);
|
||||
}
|
||||
Rvalue::Repeat(op, constant) => {
|
||||
self.visit_operand(op, location);
|
||||
self.visit_ty_const(constant, location);
|
||||
}
|
||||
Rvalue::ShallowInitBox(op, ty) => {
|
||||
self.visit_ty(ty, location);
|
||||
self.visit_operand(op, location)
|
||||
}
|
||||
Rvalue::ThreadLocalRef(_) => {}
|
||||
Rvalue::NullaryOp(_, ty) => {
|
||||
self.visit_ty(ty, location);
|
||||
}
|
||||
Rvalue::UnaryOp(_, op) | Rvalue::Use(op) => {
|
||||
self.visit_operand(op, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_operand(&mut self, operand: &Operand, location: Location) {
|
||||
match operand {
|
||||
Operand::Copy(place) | Operand::Move(place) => {
|
||||
self.visit_place(place, PlaceContext::NON_MUTATING, location)
|
||||
}
|
||||
Operand::Constant(constant) => {
|
||||
self.visit_const_operand(constant, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_user_type_projection(&mut self, projection: &UserTypeProjection) {
|
||||
// This is a no-op on mir::Visitor.
|
||||
let _ = projection;
|
||||
}
|
||||
|
||||
fn super_ty(&mut self, ty: &Ty) {
|
||||
let _ = ty;
|
||||
}
|
||||
|
||||
fn super_const_operand(&mut self, constant: &ConstOperand, location: Location) {
|
||||
let ConstOperand { span, user_ty: _, const_ } = constant;
|
||||
self.visit_span(span);
|
||||
self.visit_mir_const(const_, location);
|
||||
}
|
||||
|
||||
fn super_mir_const(&mut self, constant: &MirConst, location: Location) {
|
||||
let MirConst { kind: _, ty, id: _ } = constant;
|
||||
self.visit_ty(ty, location);
|
||||
}
|
||||
|
||||
fn super_ty_const(&mut self, constant: &TyConst) {
|
||||
let _ = constant;
|
||||
}
|
||||
|
||||
fn super_region(&mut self, region: &Region) {
|
||||
let _ = region;
|
||||
}
|
||||
|
||||
fn super_args(&mut self, args: &GenericArgs) {
|
||||
let _ = args;
|
||||
}
|
||||
|
||||
fn super_var_debug_info(&mut self, var_debug_info: &VarDebugInfo) {
|
||||
let VarDebugInfo { source_info, composite, value, name: _, argument_index: _ } =
|
||||
var_debug_info;
|
||||
self.visit_span(&source_info.span);
|
||||
let location = Location(source_info.span);
|
||||
if let Some(composite) = composite {
|
||||
self.visit_ty(&composite.ty, location);
|
||||
}
|
||||
match value {
|
||||
VarDebugInfoContents::Place(place) => {
|
||||
self.visit_place(place, PlaceContext::NON_USE, location);
|
||||
}
|
||||
VarDebugInfoContents::Const(constant) => {
|
||||
self.visit_mir_const(&constant.const_, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn super_assert_msg(&mut self, msg: &AssertMessage, location: Location) {
|
||||
match msg {
|
||||
AssertMessage::BoundsCheck { len, index } => {
|
||||
self.visit_operand(len, location);
|
||||
self.visit_operand(index, location);
|
||||
}
|
||||
AssertMessage::Overflow(_, left, right) => {
|
||||
self.visit_operand(left, location);
|
||||
self.visit_operand(right, location);
|
||||
}
|
||||
AssertMessage::OverflowNeg(op)
|
||||
| AssertMessage::DivisionByZero(op)
|
||||
| AssertMessage::RemainderByZero(op) => {
|
||||
self.visit_operand(op, location);
|
||||
}
|
||||
AssertMessage::ResumedAfterReturn(_)
|
||||
| AssertMessage::ResumedAfterPanic(_)
|
||||
| AssertMessage::NullPointerDereference => {
|
||||
//nothing to visit
|
||||
}
|
||||
AssertMessage::MisalignedPointerDereference { required, found } => {
|
||||
self.visit_operand(required, location);
|
||||
self.visit_operand(found, location);
|
||||
}
|
||||
}
|
||||
}
|
||||
$self.visit_span(span)
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! visit_place_fns {
|
||||
(mut) => {
|
||||
fn super_place(&mut self, place: &mut Place, ptx: PlaceContext, location: Location) {
|
||||
self.visit_local(&mut place.local, ptx, location);
|
||||
|
||||
for elem in place.projection.iter_mut() {
|
||||
self.visit_projection_elem(elem, ptx, location);
|
||||
}
|
||||
}
|
||||
|
||||
// We don't have to replicate the `process_projection()` like we did in
|
||||
// `rustc_middle::mir::visit.rs` here because the `projection` field in `Place`
|
||||
// of Stable-MIR is not an immutable borrow, unlike in `Place` of MIR.
|
||||
fn visit_projection_elem(
|
||||
&mut self,
|
||||
elem: &mut ProjectionElem,
|
||||
ptx: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
self.super_projection_elem(elem, ptx, location)
|
||||
}
|
||||
|
||||
fn super_projection_elem(
|
||||
&mut self,
|
||||
elem: &mut ProjectionElem,
|
||||
ptx: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
match elem {
|
||||
ProjectionElem::Deref => {}
|
||||
ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
|
||||
ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
|
||||
ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {}
|
||||
ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
|
||||
ProjectionElem::Downcast(_idx) => {}
|
||||
ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
|
||||
ProjectionElem::Subtype(ty) => self.visit_ty(ty, location),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
() => {
|
||||
fn super_place(&mut self, place: &Place, ptx: PlaceContext, location: Location) {
|
||||
self.visit_local(&place.local, ptx, location);
|
||||
|
||||
for (idx, elem) in place.projection.iter().enumerate() {
|
||||
let place_ref =
|
||||
PlaceRef { local: place.local, projection: &place.projection[..idx] };
|
||||
self.visit_projection_elem(place_ref, elem, ptx, location);
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_projection_elem<'a>(
|
||||
&mut self,
|
||||
place_ref: PlaceRef<'a>,
|
||||
elem: &ProjectionElem,
|
||||
ptx: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
let _ = place_ref;
|
||||
self.super_projection_elem(elem, ptx, location);
|
||||
}
|
||||
|
||||
fn super_projection_elem(
|
||||
&mut self,
|
||||
elem: &ProjectionElem,
|
||||
ptx: PlaceContext,
|
||||
location: Location,
|
||||
) {
|
||||
match elem {
|
||||
ProjectionElem::Deref => {}
|
||||
ProjectionElem::Field(_idx, ty) => self.visit_ty(ty, location),
|
||||
ProjectionElem::Index(local) => self.visit_local(local, ptx, location),
|
||||
ProjectionElem::ConstantIndex { offset: _, min_length: _, from_end: _ } => {}
|
||||
ProjectionElem::Subslice { from: _, to: _, from_end: _ } => {}
|
||||
ProjectionElem::Downcast(_idx) => {}
|
||||
ProjectionElem::OpaqueCast(ty) => self.visit_ty(ty, location),
|
||||
ProjectionElem::Subtype(ty) => self.visit_ty(ty, location),
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
make_mir_visitor!(MirVisitor,);
|
||||
make_mir_visitor!(MutMirVisitor, mut);
|
||||
|
||||
/// This function is a no-op that gets used to ensure this visitor is kept up-to-date.
|
||||
///
|
||||
/// The idea is that whenever we replace an Opaque type by a real type, the compiler will fail
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue