Add helper for switching safety contexts

This commit is contained in:
LeSeulArtichaut 2021-04-03 22:45:33 +02:00
parent d5ea294114
commit 985fb4caa0
3 changed files with 74 additions and 51 deletions

View File

@ -21,6 +21,36 @@ struct UnsafetyVisitor<'tcx> {
}
impl<'tcx> UnsafetyVisitor<'tcx> {
fn in_safety_context<R>(
&mut self,
safety_context: SafetyContext,
f: impl FnOnce(&mut Self) -> R,
) {
if let (
SafetyContext::UnsafeBlock { span: enclosing_span, .. },
SafetyContext::UnsafeBlock { span: block_span, hir_id, .. },
) = (self.safety_context, safety_context)
{
self.warn_unused_unsafe(
hir_id,
block_span,
Some(self.tcx.sess.source_map().guess_head_span(enclosing_span)),
);
f(self);
} else {
let prev_context = self.safety_context;
self.safety_context = safety_context;
f(self);
if let SafetyContext::UnsafeBlock { used: false, span, hir_id } = self.safety_context {
self.warn_unused_unsafe(hir_id, span, self.body_unsafety.unsafe_fn_sig_span());
}
self.safety_context = prev_context;
return;
}
}
fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
let (description, note) = kind.description_and_note();
let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed();
@ -100,40 +130,25 @@ impl<'tcx> UnsafetyVisitor<'tcx> {
impl<'thir, 'tcx> Visitor<'thir, 'tcx> for UnsafetyVisitor<'tcx> {
fn visit_block(&mut self, block: &Block<'thir, 'tcx>) {
if let BlockSafety::ExplicitUnsafe(hir_id) = block.safety_mode {
if let SafetyContext::UnsafeBlock { span: enclosing_span, .. } = self.safety_context {
self.warn_unused_unsafe(
hir_id,
block.span,
Some(self.tcx.sess.source_map().guess_head_span(enclosing_span)),
);
} else {
let prev_context = self.safety_context;
self.safety_context =
SafetyContext::UnsafeBlock { span: block.span, hir_id, used: false };
visit::walk_block(self, block);
if let SafetyContext::UnsafeBlock { used: false, span, hir_id } =
self.safety_context
{
self.warn_unused_unsafe(hir_id, span, self.body_unsafety.unsafe_fn_sig_span());
}
self.safety_context = prev_context;
return;
}
self.in_safety_context(
SafetyContext::UnsafeBlock { span: block.span, hir_id, used: false },
|this| visit::walk_block(this, block),
);
} else {
visit::walk_block(self, block);
}
visit::walk_block(self, block);
}
fn visit_expr(&mut self, expr: &'thir Expr<'thir, 'tcx>) {
match expr.kind {
ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), .. } => {
ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => {
let prev_id = self.hir_context;
self.hir_context = hir_id;
self.visit_expr(value);
self.hir_context = prev_id;
return;
}
ExprKind::Call { fun, .. } => {
ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
if fun.ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe {
self.requires_unsafe(expr.span, CallToUnsafeFunction);
}

View File

@ -26,7 +26,7 @@ pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
) {
use ExprKind::*;
match expr.kind {
Scope { value, .. } => visitor.visit_expr(value),
Scope { value, region_scope: _, lint_level: _ } => visitor.visit_expr(value),
Box { value } => visitor.visit_expr(value),
If { cond, then, else_opt } => {
visitor.visit_expr(cond);
@ -35,22 +35,22 @@ pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
visitor.visit_expr(else_expr);
}
}
Call { fun, args, .. } => {
Call { fun, args, ty: _, from_hir_call: _, fn_span: _ } => {
visitor.visit_expr(fun);
for arg in args {
visitor.visit_expr(arg);
}
}
Deref { arg } => visitor.visit_expr(arg),
Binary { lhs, rhs, .. } | LogicalOp { lhs, rhs, .. } => {
Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => {
visitor.visit_expr(lhs);
visitor.visit_expr(rhs);
}
Unary { arg, .. } => visitor.visit_expr(arg),
Unary { arg, op: _ } => visitor.visit_expr(arg),
Cast { source } => visitor.visit_expr(source),
Use { source } => visitor.visit_expr(source),
NeverToAny { source } => visitor.visit_expr(source),
Pointer { source, .. } => visitor.visit_expr(source),
Pointer { source, cast: _ } => visitor.visit_expr(source),
Loop { body } => visitor.visit_expr(body),
Match { scrutinee, arms } => {
visitor.visit_expr(scrutinee);
@ -59,24 +59,24 @@ pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
}
}
Block { ref body } => visitor.visit_block(body),
Assign { lhs, rhs } | AssignOp { lhs, rhs, .. } => {
Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => {
visitor.visit_expr(lhs);
visitor.visit_expr(rhs);
}
Field { lhs, .. } => visitor.visit_expr(lhs),
Field { lhs, name: _ } => visitor.visit_expr(lhs),
Index { lhs, index } => {
visitor.visit_expr(lhs);
visitor.visit_expr(index);
}
VarRef { .. } | UpvarRef { .. } => {}
Borrow { arg, .. } => visitor.visit_expr(arg),
AddressOf { arg, .. } => visitor.visit_expr(arg),
Break { value, .. } => {
VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {}
Borrow { arg, borrow_kind: _ } => visitor.visit_expr(arg),
AddressOf { arg, mutability: _ } => visitor.visit_expr(arg),
Break { value, label: _ } => {
if let Some(value) = value {
visitor.visit_expr(value)
}
}
Continue { .. } => {}
Continue { label: _ } => {}
Return { value } => {
if let Some(value) = value {
visitor.visit_expr(value)
@ -92,7 +92,7 @@ pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
visitor.visit_expr(field);
}
}
Adt { fields, ref base, .. } => {
Adt { fields, ref base, adt_def: _, variant_index: _, substs: _, user_ty: _ } => {
for field in fields {
visitor.visit_expr(field.expr);
}
@ -100,32 +100,34 @@ pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
visitor.visit_expr(base.base);
}
}
PlaceTypeAscription { source, .. } | ValueTypeAscription { source, .. } => {
PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => {
visitor.visit_expr(source)
}
Closure { .. } => {}
Literal { literal, .. } => visitor.visit_const(literal),
StaticRef { literal, .. } => visitor.visit_const(literal),
InlineAsm { operands, .. } => {
Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {}
Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal),
StaticRef { literal, def_id: _ } => visitor.visit_const(literal),
InlineAsm { operands, template: _, options: _, line_spans: _ } => {
for op in operands {
use InlineAsmOperand::*;
match op {
In { expr, .. }
| Out { expr: Some(expr), .. }
| InOut { expr, .. }
In { expr, reg: _ }
| Out { expr: Some(expr), reg: _, late: _ }
| InOut { expr, reg: _, late: _ }
| SymFn { expr } => visitor.visit_expr(expr),
SplitInOut { in_expr, out_expr, .. } => {
SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
visitor.visit_expr(in_expr);
if let Some(out_expr) = out_expr {
visitor.visit_expr(out_expr);
}
}
Out { .. } | Const { .. } | SymStatic { .. } => {}
Out { expr: None, reg: _, late: _ }
| Const { value: _, span: _ }
| SymStatic { def_id: _ } => {}
}
}
}
ThreadLocalRef(_) => {}
LlvmInlineAsm { outputs, inputs, .. } => {
LlvmInlineAsm { outputs, inputs, asm: _ } => {
for out_expr in outputs {
visitor.visit_expr(out_expr);
}
@ -142,8 +144,14 @@ pub fn walk_stmt<'thir, 'tcx, V: Visitor<'thir, 'tcx>>(
stmt: &'thir Stmt<'thir, 'tcx>,
) {
match stmt.kind {
StmtKind::Expr { expr, .. } => visitor.visit_expr(expr),
StmtKind::Let { pattern: _, initializer, .. } => {
StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(expr),
StmtKind::Let {
initializer,
remainder_scope: _,
init_scope: _,
pattern: _,
lint_level: _,
} => {
if let Some(init) = initializer {
visitor.visit_expr(init);
}

View File

@ -7,8 +7,8 @@ use std::path::Path;
const ENTRY_LIMIT: usize = 1000;
// FIXME: The following limits should be reduced eventually.
const ROOT_ENTRY_LIMIT: usize = 1369;
const ISSUES_ENTRY_LIMIT: usize = 2551;
const ROOT_ENTRY_LIMIT: usize = 1370;
const ISSUES_ENTRY_LIMIT: usize = 2555;
fn check_entries(path: &Path, bad: &mut bool) {
let dirs = walkdir::WalkDir::new(&path.join("test/ui"))