1
Fork 0

Adapt the THIR visitor to the vec-stored THIR

This commit is contained in:
LeSeulArtichaut 2021-05-13 22:01:25 +02:00
parent dc3eabd487
commit 7093a21e27
2 changed files with 95 additions and 94 deletions

View file

@ -9,8 +9,9 @@ use rustc_session::lint::Level;
use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::Span; use rustc_span::Span;
struct UnsafetyVisitor<'tcx> { struct UnsafetyVisitor<'a, 'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
thir: &'a Thir<'tcx>,
/// The `HirId` of the current scope, which would be the `HirId` /// The `HirId` of the current scope, which would be the `HirId`
/// of the current HIR node, modulo adjustments. Used for lint levels. /// of the current HIR node, modulo adjustments. Used for lint levels.
hir_context: hir::HirId, hir_context: hir::HirId,
@ -20,7 +21,7 @@ struct UnsafetyVisitor<'tcx> {
body_unsafety: BodyUnsafety, body_unsafety: BodyUnsafety,
} }
impl<'tcx> UnsafetyVisitor<'tcx> { impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
fn in_safety_context<R>( fn in_safety_context<R>(
&mut self, &mut self,
safety_context: SafetyContext, safety_context: SafetyContext,
@ -127,8 +128,12 @@ impl<'tcx> UnsafetyVisitor<'tcx> {
} }
} }
impl<'thir, 'tcx> Visitor<'thir, 'tcx> for UnsafetyVisitor<'tcx> { impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
fn visit_block(&mut self, block: &Block<'thir, 'tcx>) { fn thir(&self) -> &'a Thir<'tcx> {
&self.thir
}
fn visit_block(&mut self, block: &Block) {
if let BlockSafety::ExplicitUnsafe(hir_id) = block.safety_mode { if let BlockSafety::ExplicitUnsafe(hir_id) = block.safety_mode {
self.in_safety_context( self.in_safety_context(
SafetyContext::UnsafeBlock { span: block.span, hir_id, used: false }, SafetyContext::UnsafeBlock { span: block.span, hir_id, used: false },
@ -139,17 +144,17 @@ impl<'thir, 'tcx> Visitor<'thir, 'tcx> for UnsafetyVisitor<'tcx> {
} }
} }
fn visit_expr(&mut self, expr: &'thir Expr<'thir, 'tcx>) { fn visit_expr(&mut self, expr: &Expr<'tcx>) {
match expr.kind { match expr.kind {
ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => { ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => {
let prev_id = self.hir_context; let prev_id = self.hir_context;
self.hir_context = hir_id; self.hir_context = hir_id;
self.visit_expr(value); self.visit_expr(&self.thir[value]);
self.hir_context = prev_id; self.hir_context = prev_id;
return; return;
} }
ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => { ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
if fun.ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe { if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
self.requires_unsafe(expr.span, CallToUnsafeFunction); self.requires_unsafe(expr.span, CallToUnsafeFunction);
} }
} }
@ -293,7 +298,12 @@ impl UnsafeOpKind {
// FIXME: checking unsafety for closures should be handled by their parent body, // FIXME: checking unsafety for closures should be handled by their parent body,
// as they inherit their "safety context" from their declaration site. // as they inherit their "safety context" from their declaration site.
pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, thir: &Expr<'_, 'tcx>, hir_id: hir::HirId) { pub fn check_unsafety<'tcx>(
tcx: TyCtxt<'tcx>,
thir: &Thir<'tcx>,
expr: ExprId,
hir_id: hir::HirId,
) {
let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| { let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
if fn_sig.header.unsafety == hir::Unsafety::Unsafe { if fn_sig.header.unsafety == hir::Unsafety::Unsafe {
BodyUnsafety::Unsafe(fn_sig.span) BodyUnsafety::Unsafe(fn_sig.span)
@ -303,8 +313,9 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, thir: &Expr<'_, 'tcx>, hir_id: hi
}); });
let safety_context = let safety_context =
if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe }; if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
let mut visitor = UnsafetyVisitor { tcx, safety_context, hir_context: hir_id, body_unsafety }; let mut visitor =
visitor.visit_expr(thir); UnsafetyVisitor { tcx, thir, safety_context, hir_context: hir_id, body_unsafety };
visitor.visit_expr(&thir[expr]);
} }
crate fn thir_check_unsafety_inner<'tcx>( crate fn thir_check_unsafety_inner<'tcx>(
@ -314,10 +325,8 @@ crate fn thir_check_unsafety_inner<'tcx>(
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
let body_id = tcx.hir().body_owned_by(hir_id); let body_id = tcx.hir().body_owned_by(hir_id);
let body = tcx.hir().body(body_id); let body = tcx.hir().body(body_id);
let (thir, expr) = cx::build_thir(tcx, def, &body.value);
let arena = Arena::default(); check_unsafety(tcx, &thir, expr, hir_id);
let thir = cx::build_thir(tcx, def, &arena, &body.value);
check_unsafety(tcx, thir, hir_id);
} }
crate fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { crate fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) {

View file

@ -1,123 +1,124 @@
use crate::thir::*; use crate::thir::*;
pub trait Visitor<'thir, 'tcx>: Sized { pub trait Visitor<'a, 'tcx: 'a>: Sized {
fn visit_expr(&mut self, expr: &'thir Expr<'thir, 'tcx>) { fn thir(&self) -> &'a Thir<'tcx>;
fn visit_expr(&mut self, expr: &Expr<'tcx>) {
walk_expr(self, expr); walk_expr(self, expr);
} }
fn visit_stmt(&mut self, stmt: &'thir Stmt<'thir, 'tcx>) { fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) {
walk_stmt(self, stmt); walk_stmt(self, stmt);
} }
fn visit_block(&mut self, block: &Block<'thir, 'tcx>) { fn visit_block(&mut self, block: &Block) {
walk_block(self, block); walk_block(self, block);
} }
fn visit_arm(&mut self, arm: &'thir Arm<'thir, 'tcx>) { fn visit_arm(&mut self, arm: &Arm<'tcx>) {
walk_arm(self, arm); walk_arm(self, arm);
} }
fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {}
} }
pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>( pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {
visitor: &mut V,
expr: &'thir Expr<'thir, 'tcx>,
) {
use ExprKind::*; use ExprKind::*;
match expr.kind { match expr.kind {
Scope { value, region_scope: _, lint_level: _ } => visitor.visit_expr(value), Scope { value, region_scope: _, lint_level: _ } => {
Box { value } => visitor.visit_expr(value), visitor.visit_expr(&visitor.thir()[value])
}
Box { value } => visitor.visit_expr(&visitor.thir()[value]),
If { cond, then, else_opt } => { If { cond, then, else_opt } => {
visitor.visit_expr(cond); visitor.visit_expr(&visitor.thir()[cond]);
visitor.visit_expr(then); visitor.visit_expr(&visitor.thir()[then]);
if let Some(else_expr) = else_opt { if let Some(else_expr) = else_opt {
visitor.visit_expr(else_expr); visitor.visit_expr(&visitor.thir()[else_expr]);
} }
} }
Call { fun, args, ty: _, from_hir_call: _, fn_span: _ } => { Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => {
visitor.visit_expr(fun); visitor.visit_expr(&visitor.thir()[fun]);
for arg in args { for &arg in &**args {
visitor.visit_expr(arg); visitor.visit_expr(&visitor.thir()[arg]);
} }
} }
Deref { arg } => visitor.visit_expr(arg), Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]),
Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
visitor.visit_expr(lhs); visitor.visit_expr(&visitor.thir()[lhs]);
visitor.visit_expr(rhs); visitor.visit_expr(&visitor.thir()[rhs]);
} }
Unary { arg, op: _ } => visitor.visit_expr(arg), Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]),
Cast { source } => visitor.visit_expr(source), Cast { source } => visitor.visit_expr(&visitor.thir()[source]),
Use { source } => visitor.visit_expr(source), Use { source } => visitor.visit_expr(&visitor.thir()[source]),
NeverToAny { source } => visitor.visit_expr(source), NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]),
Pointer { source, cast: _ } => visitor.visit_expr(source), Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]),
Loop { body } => visitor.visit_expr(body), Loop { body } => visitor.visit_expr(&visitor.thir()[body]),
Match { scrutinee, arms } => { Match { scrutinee, ref arms } => {
visitor.visit_expr(scrutinee); visitor.visit_expr(&visitor.thir()[scrutinee]);
for arm in arms { for &arm in &**arms {
visitor.visit_arm(arm); visitor.visit_arm(&visitor.thir()[arm]);
} }
} }
Block { ref body } => visitor.visit_block(body), Block { ref body } => visitor.visit_block(body),
Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
visitor.visit_expr(lhs); visitor.visit_expr(&visitor.thir()[lhs]);
visitor.visit_expr(rhs); visitor.visit_expr(&visitor.thir()[rhs]);
} }
Field { lhs, name: _ } => visitor.visit_expr(lhs), Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]),
Index { lhs, index } => { Index { lhs, index } => {
visitor.visit_expr(lhs); visitor.visit_expr(&visitor.thir()[lhs]);
visitor.visit_expr(index); visitor.visit_expr(&visitor.thir()[index]);
} }
VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
Borrow { arg, borrow_kind: _ } => visitor.visit_expr(arg), Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]),
AddressOf { arg, mutability: _ } => visitor.visit_expr(arg), AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]),
Break { value, label: _ } => { Break { value, label: _ } => {
if let Some(value) = value { if let Some(value) = value {
visitor.visit_expr(value) visitor.visit_expr(&visitor.thir()[value])
} }
} }
Continue { label: _ } => {} Continue { label: _ } => {}
Return { value } => { Return { value } => {
if let Some(value) = value { if let Some(value) = value {
visitor.visit_expr(value) visitor.visit_expr(&visitor.thir()[value])
} }
} }
ConstBlock { value } => visitor.visit_const(value), ConstBlock { value } => visitor.visit_const(value),
Repeat { value, count } => { Repeat { value, count } => {
visitor.visit_expr(value); visitor.visit_expr(&visitor.thir()[value]);
visitor.visit_const(count); visitor.visit_const(count);
} }
Array { fields } | Tuple { fields } => { Array { ref fields } | Tuple { ref fields } => {
for field in fields { for &field in &**fields {
visitor.visit_expr(field); visitor.visit_expr(&visitor.thir()[field]);
} }
} }
Adt { fields, ref base, adt_def: _, variant_index: _, substs: _, user_ty: _ } => { Adt { ref fields, ref base, adt_def: _, variant_index: _, substs: _, user_ty: _ } => {
for field in fields { for field in &**fields {
visitor.visit_expr(field.expr); visitor.visit_expr(&visitor.thir()[field.expr]);
} }
if let Some(base) = base { if let Some(base) = base {
visitor.visit_expr(base.base); visitor.visit_expr(&visitor.thir()[base.base]);
} }
} }
PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => {
visitor.visit_expr(source) visitor.visit_expr(&visitor.thir()[source])
} }
Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
StaticRef { literal, def_id: _ } => visitor.visit_const(literal), StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
InlineAsm { operands, template: _, options: _, line_spans: _ } => { InlineAsm { ref operands, template: _, options: _, line_spans: _ } => {
for op in operands { for op in &**operands {
use InlineAsmOperand::*; use InlineAsmOperand::*;
match op { match op {
In { expr, reg: _ } In { expr, reg: _ }
| Out { expr: Some(expr), reg: _, late: _ } | Out { expr: Some(expr), reg: _, late: _ }
| InOut { expr, reg: _, late: _ } | InOut { expr, reg: _, late: _ }
| SymFn { expr } => visitor.visit_expr(expr), | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]),
SplitInOut { in_expr, out_expr, reg: _, late: _ } => { SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
visitor.visit_expr(in_expr); visitor.visit_expr(&visitor.thir()[*in_expr]);
if let Some(out_expr) = out_expr { if let Some(out_expr) = out_expr {
visitor.visit_expr(out_expr); visitor.visit_expr(&visitor.thir()[*out_expr]);
} }
} }
Out { expr: None, reg: _, late: _ } Out { expr: None, reg: _, late: _ }
@ -127,24 +128,21 @@ pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
} }
} }
ThreadLocalRef(_) => {} ThreadLocalRef(_) => {}
LlvmInlineAsm { outputs, inputs, asm: _ } => { LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
for out_expr in outputs { for &out_expr in &**outputs {
visitor.visit_expr(out_expr); visitor.visit_expr(&visitor.thir()[out_expr]);
} }
for in_expr in inputs { for &in_expr in &**inputs {
visitor.visit_expr(in_expr); visitor.visit_expr(&visitor.thir()[in_expr]);
} }
} }
Yield { value } => visitor.visit_expr(value), Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
} }
} }
pub fn walk_stmt<'thir, 'tcx, V: Visitor<'thir, 'tcx>>( pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) {
visitor: &mut V,
stmt: &'thir Stmt<'thir, 'tcx>,
) {
match stmt.kind { match stmt.kind {
StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(expr), StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[expr]),
StmtKind::Let { StmtKind::Let {
initializer, initializer,
remainder_scope: _, remainder_scope: _,
@ -153,34 +151,28 @@ pub fn walk_stmt<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
lint_level: _, lint_level: _,
} => { } => {
if let Some(init) = initializer { if let Some(init) = initializer {
visitor.visit_expr(init); visitor.visit_expr(&visitor.thir()[init]);
} }
} }
} }
} }
pub fn walk_block<'thir, 'tcx, V: Visitor<'thir, 'tcx>>( pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) {
visitor: &mut V, for &stmt in &*block.stmts {
block: &Block<'thir, 'tcx>, visitor.visit_stmt(&visitor.thir()[stmt]);
) {
for stmt in block.stmts {
visitor.visit_stmt(stmt);
} }
if let Some(expr) = block.expr { if let Some(expr) = block.expr {
visitor.visit_expr(expr); visitor.visit_expr(&visitor.thir()[expr]);
} }
} }
pub fn walk_arm<'thir, 'tcx, V: Visitor<'thir, 'tcx>>( pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) {
visitor: &mut V,
arm: &'thir Arm<'thir, 'tcx>,
) {
match arm.guard { match arm.guard {
Some(Guard::If(expr)) => visitor.visit_expr(expr), Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]),
Some(Guard::IfLet(ref _pat, expr)) => { Some(Guard::IfLet(ref _pat, expr)) => {
visitor.visit_expr(expr); visitor.visit_expr(&visitor.thir()[expr]);
} }
None => {} None => {}
} }
visitor.visit_expr(arm.body); visitor.visit_expr(&visitor.thir()[arm.body]);
} }