Skip to content

Instantly share code, notes, and snippets.

@momvart
Last active January 5, 2023 04:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save momvart/1a0f22e7d4a0712c0c988ca73de945f1 to your computer and use it in GitHub Desktop.
Save momvart/1a0f22e7d4a0712c0c988ca73de945f1 to your computer and use it in GitHub Desktop.
Inspired by the default generic rustc visitors, here are a set of visitors written for StatementKind, TerminatorKind, and Rvalue
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece, Mutability};
use rustc_middle::{
mir::{
AggregateKind, AssertMessage, BasicBlock, BinOp, BorrowKind, CastKind, Coverage,
FakeReadCause, InlineAsmOperand, Local, NonDivergingIntrinsic, NullOp, Operand, Place,
RetagKind, Rvalue, StatementKind, SwitchTargets, TerminatorKind, UnOp, UserTypeProjection,
},
ty::{Const, Region, Ty, Variance},
};
use rustc_span::Span;
use rustc_target::abi::VariantIdx;
macro_rules! make_statement_kind_visitor {
($visitor_trait_name:ident, $($mutability:ident)?) => {
pub trait $visitor_trait_name<'tcx, T: Default> {
fn visit_statement_kind(&mut self, kind: & $($mutability)? StatementKind<'tcx>) -> T {
self.super_statement_kind(kind)
}
fn visit_assign(&mut self, place: & $($mutability)? Place<'tcx>, rvalue: & $($mutability)? Rvalue<'tcx>) -> T {
Default::default()
}
fn visit_fake_read(&mut self, cause: & $($mutability)? FakeReadCause, place: & $($mutability)? Place<'tcx>) -> T {
Default::default()
}
fn visit_set_discriminant(
&mut self,
place: &Place<'tcx>,
variant_index: & $($mutability)? VariantIdx,
) -> T {
Default::default()
}
fn visit_deinit(&mut self, place: & $($mutability)? Place<'tcx>) -> T {
Default::default()
}
fn visit_storage_live(&mut self, local: & $($mutability)? Local) -> T {
Default::default()
}
fn visit_storage_dead(&mut self, local: & $($mutability)? Local) -> T {
Default::default()
}
fn visit_retag(&mut self, kind: & $($mutability)? RetagKind, place: & $($mutability)? Place<'tcx>) -> T {
Default::default()
}
fn visit_ascribe_user_type(
&mut self,
place: & $($mutability)? Place<'tcx>,
user_type_proj: & $($mutability)? UserTypeProjection,
variance: & $($mutability)? Variance,
) -> T {
Default::default()
}
fn visit_coverage(&mut self, coverage: & $($mutability)? Coverage) -> T {
Default::default()
}
fn visit_intrinsic(&mut self, intrinsic: & $($mutability)? NonDivergingIntrinsic<'tcx>) -> T {
Default::default()
}
fn visit_nop(&mut self) -> T {
Default::default()
}
fn super_statement_kind(&mut self, kind: & $($mutability)? StatementKind<'tcx>) -> T {
match kind {
StatementKind::Assign(box (place, rvalue)) => self.visit_assign(place, rvalue),
StatementKind::FakeRead(box (cause, place)) => {
self.visit_fake_read(cause, place)
}
StatementKind::SetDiscriminant {
place,
variant_index,
} => self.visit_set_discriminant(place, variant_index),
StatementKind::Deinit(place) => self.visit_deinit(place),
StatementKind::StorageLive(local) => self.visit_storage_live(local),
StatementKind::StorageDead(local) => self.visit_storage_dead(local),
StatementKind::Retag(kind, place) => self.visit_retag(kind, place),
StatementKind::AscribeUserType(box (place, user_type_proj), variance) => {
self.visit_ascribe_user_type(place, user_type_proj, variance)
}
StatementKind::Coverage(coverage) => self.visit_coverage(coverage),
StatementKind::Intrinsic(intrinsic) => self.visit_intrinsic(intrinsic),
StatementKind::Nop => self.visit_nop(),
}
}
}
};
}
make_statement_kind_visitor!(StatementKindVisitor,);
make_statement_kind_visitor!(StatementKindMutVisitor, mut);
macro_rules! make_terminator_kind_visitor {
($visitor_trait_name:ident, $($mutability:ident)?) => {
pub trait $visitor_trait_name<'tcx, T: Default> {
fn visit_terminator_kind(&mut self, kind: & $($mutability)? TerminatorKind<'tcx>) -> T {
self.super_terminator_kind(kind)
}
fn visit_goto(&mut self, target: & $($mutability)? BasicBlock) -> T {
Default::default()
}
fn visit_switch_int(&mut self, discr: & $($mutability)? Operand<'tcx>, targets: & $($mutability)? SwitchTargets) -> T {
Default::default()
}
fn visit_resume(&mut self) -> T {
Default::default()
}
fn visit_abort(&mut self) -> T {
Default::default()
}
fn visit_return(&mut self) -> T {
Default::default()
}
fn visit_unreachable(&mut self) -> T {
Default::default()
}
fn visit_drop(
&mut self,
place: & $($mutability)? Place<'tcx>,
target: & $($mutability)? BasicBlock,
unwind: & $($mutability)? Option<BasicBlock>,
) -> T {
Default::default()
}
fn visit_drop_and_replace(
&mut self,
place: & $($mutability)? Place<'tcx>,
value: & $($mutability)? Operand<'tcx>,
target: & $($mutability)? BasicBlock,
unwind: & $($mutability)? Option<BasicBlock>,
) -> T {
Default::default()
}
fn visit_call(
&mut self,
func: & $($mutability)? Operand<'tcx>,
args: & $($mutability)? Vec<Operand<'tcx>>,
destination: & $($mutability)? Place<'tcx>,
target: & $($mutability)? Option<BasicBlock>,
cleanup: & $($mutability)? Option<BasicBlock>,
from_hir_call: bool,
fn_span: Span,
) -> T {
Default::default()
}
fn visit_assert(
&mut self,
cond: & $($mutability)? Operand<'tcx>,
expected: & $($mutability)? bool,
msg: & $($mutability)? AssertMessage<'tcx>,
target: & $($mutability)? BasicBlock,
cleanup: & $($mutability)? Option<BasicBlock>,
) -> T {
Default::default()
}
fn visit_yield(
&mut self,
value: & $($mutability)? Operand<'tcx>,
resume: & $($mutability)? BasicBlock,
resume_arg: & $($mutability)? Place<'tcx>,
drop: & $($mutability)? Option<BasicBlock>,
) -> T {
Default::default()
}
fn visit_generator_drop(&mut self) -> T {
Default::default()
}
fn visit_false_edge(
&mut self,
real_target: & $($mutability)? BasicBlock,
imaginary_target: & $($mutability)? BasicBlock,
) -> T {
Default::default()
}
fn visit_false_unwind(
&mut self,
real_target: & $($mutability)? BasicBlock,
unwind: & $($mutability)? Option<BasicBlock>,
) -> T {
Default::default()
}
fn visit_inline_asm(
&mut self,
template: & $($mutability)? &[InlineAsmTemplatePiece],
operands: & $($mutability)? Vec<InlineAsmOperand<'tcx>>,
options: & $($mutability)? InlineAsmOptions,
line_spans: &'tcx [Span],
destination: & $($mutability)? Option<BasicBlock>,
cleanup: & $($mutability)? Option<BasicBlock>,
) -> T {
Default::default()
}
fn super_terminator_kind(&mut self, kind: & $($mutability)? TerminatorKind<'tcx>) -> T {
match kind {
TerminatorKind::Goto { ref $($mutability)? target } => self.visit_goto(target),
TerminatorKind::SwitchInt {
discr,
ref $($mutability)? targets,
} => self.visit_switch_int(discr, targets),
TerminatorKind::Resume => self.visit_resume(),
TerminatorKind::Abort => self.visit_abort(),
TerminatorKind::Return => self.visit_return(),
TerminatorKind::Unreachable => self.visit_unreachable(),
TerminatorKind::Drop {
ref $($mutability)? place,
ref $($mutability)? target,
ref $($mutability)? unwind,
} => self.visit_drop(place, target, unwind),
TerminatorKind::DropAndReplace {
ref $($mutability)? place,
ref $($mutability)? value,
ref $($mutability)? target,
ref $($mutability)? unwind,
} => self.visit_drop_and_replace(place, value, target, unwind),
TerminatorKind::Call {
func,
args,
ref $($mutability)? destination,
ref $($mutability)? target,
ref $($mutability)? cleanup,
from_hir_call,
fn_span,
} => self.visit_call(
func,
args,
destination,
target,
cleanup,
*from_hir_call,
*fn_span,
),
TerminatorKind::Assert {
ref $($mutability)? cond,
ref $($mutability)? expected,
ref $($mutability)? msg,
ref $($mutability)? target,
ref $($mutability)? cleanup,
} => self.visit_assert(cond, expected, msg, target, cleanup),
TerminatorKind::Yield {
ref $($mutability)? value,
ref $($mutability)? resume,
ref $($mutability)? resume_arg,
ref $($mutability)? drop,
} => self.visit_yield(value, resume, resume_arg, drop),
TerminatorKind::GeneratorDrop => self.visit_generator_drop(),
TerminatorKind::FalseEdge {
ref $($mutability)? real_target,
ref $($mutability)? imaginary_target,
} => self.visit_false_edge(real_target, imaginary_target),
TerminatorKind::FalseUnwind {
ref $($mutability)? real_target,
ref $($mutability)? unwind,
} => self.visit_false_unwind(real_target, unwind),
TerminatorKind::InlineAsm {
ref $($mutability)? template,
ref $($mutability)? operands,
ref $($mutability)? options,
line_spans,
ref $($mutability)? destination,
ref $($mutability)? cleanup,
} => self.visit_inline_asm(
template,
operands,
options,
line_spans,
destination,
cleanup,
),
}
}
}
}
}
make_terminator_kind_visitor!(TerminatorKindVisitor,);
make_terminator_kind_visitor!(TerminatorKindMutVisitor, mut);
macro_rules! make_rvalue_visitor {
($visitor_trait_name:ident, $($mutability:ident)?) => {
pub trait $visitor_trait_name<'tcx, T: Default> {
fn visit_rvalue(&mut self, rvalue: & $($mutability)? Rvalue<'tcx>) -> T {
self.super_rvalue(rvalue)
}
fn visit_use(&mut self, operand: & $($mutability)? Operand<'tcx>) -> T {
Default::default()
}
fn visit_repeat(&mut self, operand: & $($mutability)? Operand<'tcx>, count: & $($mutability)? Const<'tcx>) -> T {
Default::default()
}
fn visit_ref(
&mut self,
region: & $($mutability)? Region,
borrow_kind: & $($mutability)? BorrowKind,
place: & $($mutability)? Place<'tcx>,
) -> T {
Default::default()
}
fn visit_thread_local_ref(
&mut self,
/* DefId is weirdly private at the current time of development.
def_id: & $($mutability)? DefId,
*/
) -> T {
Default::default()
}
fn visit_address_of(
&mut self,
mutability: & $($mutability)? Mutability,
place: & $($mutability)? Place<'tcx>,
) -> T {
Default::default()
}
fn visit_len(&mut self, place: & $($mutability)? Place<'tcx>) -> T {
Default::default()
}
fn visit_cast(
&mut self,
kind: & $($mutability)? CastKind,
operand: & $($mutability)? Operand<'tcx>,
ty: & $($mutability)? Ty<'tcx>,
) -> T {
Default::default()
}
fn visit_binary_op(
&mut self,
op: & $($mutability)? BinOp,
operands: & $($mutability)? Box<(Operand<'tcx>, Operand<'tcx>)>,
) -> T {
Default::default()
}
fn visit_checked_binary_op(
&mut self,
op: & $($mutability)? BinOp,
operands: & $($mutability)? Box<(Operand<'tcx>, Operand<'tcx>)>,
) -> T {
Default::default()
}
fn visit_nullary_op(&mut self, op: & $($mutability)? NullOp, ty: & $($mutability)? Ty<'tcx>) -> T {
Default::default()
}
fn visit_unary_op(&mut self, op: & $($mutability)? UnOp, operand: & $($mutability)? Operand<'tcx>) -> T {
Default::default()
}
fn visit_discriminant(&mut self, place: & $($mutability)? Place<'tcx>) -> T {
Default::default()
}
fn visit_aggregate(
&mut self,
kind: & $($mutability)? Box<AggregateKind>,
operands: & $($mutability)? Vec<Operand<'tcx>>,
) -> T {
Default::default()
}
fn visit_shallow_init_box(
&mut self,
operand: & $($mutability)? Operand<'tcx>,
ty: & $($mutability)? Ty<'tcx>,
) -> T {
Default::default()
}
fn visit_copy_for_deref(&mut self, place: & $($mutability)? Place<'tcx>) -> T {
Default::default()
}
fn super_rvalue(&mut self, rvalue: & $($mutability)? Rvalue<'tcx>) -> T {
match rvalue {
Rvalue::Use(operand) => self.visit_use(operand),
Rvalue::Repeat(operand, count) => self.visit_repeat(operand, count),
Rvalue::Ref(region, borrow_kind, place) => {
self.visit_ref(region, borrow_kind, place)
}
Rvalue::ThreadLocalRef(_) => self.visit_thread_local_ref(),
Rvalue::AddressOf(mutability, place) => {
self.visit_address_of(mutability, place)
}
Rvalue::Len(place) => self.visit_len(place),
Rvalue::Cast(kind, operand, ty) => self.visit_cast(kind, operand, ty),
Rvalue::BinaryOp(op, operands) => self.visit_binary_op(op, operands),
Rvalue::CheckedBinaryOp(op, operands) => {
self.visit_checked_binary_op(op, operands)
}
Rvalue::NullaryOp(op, ty) => self.visit_nullary_op(op, ty),
Rvalue::UnaryOp(op, operand) => self.visit_unary_op(op, operand),
Rvalue::Discriminant(place) => self.visit_discriminant(place),
Rvalue::Aggregate(kind, operands) => self.visit_aggregate(kind, operands),
Rvalue::ShallowInitBox(operand, ty) => self.visit_shallow_init_box(operand, ty),
Rvalue::CopyForDeref(place) => self.visit_copy_for_deref(place),
}
}
}
};
}
make_rvalue_visitor!(RvalueVisitor,);
make_rvalue_visitor!(RvalueMutVisitor, mut);
@momvart
Copy link
Author

momvart commented Jan 5, 2023

Following the implementation style of rustc_middle::mir::visit::Visitor at the time of writing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment