Skip to content

Commit 327b8c9

Browse files
Extend reported unsafe operations
We add union fields access (in both expressions and patterns) and inline assembly. That completes the unsafe check (there are some other unsafe things but they are unstable), and so also opens the door to reporting unused unsafe without annoying people about their not-unused unsafe blocks.
1 parent e6276c8 commit 327b8c9

File tree

7 files changed

+499
-113
lines changed

7 files changed

+499
-113
lines changed

crates/hir-def/src/body.rs

Lines changed: 131 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,8 @@ impl Body {
408408
f(else_branch);
409409
}
410410
}
411-
Expr::Let { expr, .. } => {
411+
Expr::Let { expr, pat } => {
412+
self.walk_exprs_in_pat(*pat, &mut f);
412413
f(*expr);
413414
}
414415
Expr::Block { statements, tail, .. }
@@ -444,7 +445,10 @@ impl Body {
444445
}
445446
Expr::Match { expr, arms } => {
446447
f(*expr);
447-
arms.iter().map(|arm| arm.expr).for_each(f);
448+
arms.iter().for_each(|arm| {
449+
f(arm.expr);
450+
self.walk_exprs_in_pat(arm.pat, &mut f);
451+
});
448452
}
449453
Expr::Break { expr, .. }
450454
| Expr::Return { expr }
@@ -505,6 +509,131 @@ impl Body {
505509
}
506510
}
507511

512+
pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
513+
let expr = &self[expr_id];
514+
match expr {
515+
Expr::Continue { .. }
516+
| Expr::Const(_)
517+
| Expr::Missing
518+
| Expr::Path(_)
519+
| Expr::OffsetOf(_)
520+
| Expr::Literal(_)
521+
| Expr::Underscore => {}
522+
Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
523+
AsmOperand::In { expr, .. }
524+
| AsmOperand::Out { expr: Some(expr), .. }
525+
| AsmOperand::InOut { expr, .. } => f(*expr),
526+
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
527+
f(*in_expr);
528+
if let Some(out_expr) = out_expr {
529+
f(*out_expr);
530+
}
531+
}
532+
AsmOperand::Out { expr: None, .. }
533+
| AsmOperand::Const(_)
534+
| AsmOperand::Label(_)
535+
| AsmOperand::Sym(_) => (),
536+
}),
537+
Expr::If { condition, then_branch, else_branch } => {
538+
f(*condition);
539+
f(*then_branch);
540+
if let &Some(else_branch) = else_branch {
541+
f(else_branch);
542+
}
543+
}
544+
Expr::Let { expr, .. } => {
545+
f(*expr);
546+
}
547+
Expr::Block { statements, tail, .. }
548+
| Expr::Unsafe { statements, tail, .. }
549+
| Expr::Async { statements, tail, .. } => {
550+
for stmt in statements.iter() {
551+
match stmt {
552+
Statement::Let { initializer, else_branch, .. } => {
553+
if let &Some(expr) = initializer {
554+
f(expr);
555+
}
556+
if let &Some(expr) = else_branch {
557+
f(expr);
558+
}
559+
}
560+
Statement::Expr { expr: expression, .. } => f(*expression),
561+
Statement::Item(_) => (),
562+
}
563+
}
564+
if let &Some(expr) = tail {
565+
f(expr);
566+
}
567+
}
568+
Expr::Loop { body, .. } => f(*body),
569+
Expr::Call { callee, args, .. } => {
570+
f(*callee);
571+
args.iter().copied().for_each(f);
572+
}
573+
Expr::MethodCall { receiver, args, .. } => {
574+
f(*receiver);
575+
args.iter().copied().for_each(f);
576+
}
577+
Expr::Match { expr, arms } => {
578+
f(*expr);
579+
arms.iter().map(|arm| arm.expr).for_each(f);
580+
}
581+
Expr::Break { expr, .. }
582+
| Expr::Return { expr }
583+
| Expr::Yield { expr }
584+
| Expr::Yeet { expr } => {
585+
if let &Some(expr) = expr {
586+
f(expr);
587+
}
588+
}
589+
Expr::Become { expr } => f(*expr),
590+
Expr::RecordLit { fields, spread, .. } => {
591+
for field in fields.iter() {
592+
f(field.expr);
593+
}
594+
if let &Some(expr) = spread {
595+
f(expr);
596+
}
597+
}
598+
Expr::Closure { body, .. } => {
599+
f(*body);
600+
}
601+
Expr::BinaryOp { lhs, rhs, .. } => {
602+
f(*lhs);
603+
f(*rhs);
604+
}
605+
Expr::Range { lhs, rhs, .. } => {
606+
if let &Some(lhs) = rhs {
607+
f(lhs);
608+
}
609+
if let &Some(rhs) = lhs {
610+
f(rhs);
611+
}
612+
}
613+
Expr::Index { base, index, .. } => {
614+
f(*base);
615+
f(*index);
616+
}
617+
Expr::Field { expr, .. }
618+
| Expr::Await { expr }
619+
| Expr::Cast { expr, .. }
620+
| Expr::Ref { expr, .. }
621+
| Expr::UnaryOp { expr, .. }
622+
| Expr::Box { expr } => {
623+
f(*expr);
624+
}
625+
Expr::Tuple { exprs, .. } => exprs.iter().copied().for_each(f),
626+
Expr::Array(a) => match a {
627+
Array::ElementList { elements, .. } => elements.iter().copied().for_each(f),
628+
Array::Repeat { initializer, repeat } => {
629+
f(*initializer);
630+
f(*repeat)
631+
}
632+
},
633+
&Expr::Assignment { target: _, value } => f(value),
634+
}
635+
}
636+
508637
pub fn walk_exprs_in_pat(&self, pat_id: PatId, f: &mut impl FnMut(ExprId)) {
509638
self.walk_pats(pat_id, &mut |pat| {
510639
if let Pat::Expr(expr) | Pat::ConstBlock(expr) = self[pat] {

crates/hir-ty/src/diagnostics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,5 @@ pub use crate::diagnostics::{
99
expr::{
1010
record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic,
1111
},
12-
unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr},
12+
unsafe_check::{missing_unsafe, unsafe_expressions, InsideUnsafeBlock, UnsafetyReason},
1313
};

0 commit comments

Comments
 (0)