1use std::borrow::Cow;
2use std::mem;
3use std::ops::Bound;
4
5use rustc_ast::AsmMacro;
6use rustc_data_structures::stack::ensure_sufficient_stack;
7use rustc_errors::DiagArgValue;
8use rustc_hir::def::DefKind;
9use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, find_attr};
10use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
11use rustc_middle::mir::BorrowKind;
12use rustc_middle::span_bug;
13use rustc_middle::thir::visit::Visitor;
14use rustc_middle::thir::*;
15use rustc_middle::ty::print::with_no_trimmed_paths;
16use rustc_middle::ty::{self, Ty, TyCtxt};
17use rustc_session::lint::Level;
18use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
19use rustc_span::def_id::{DefId, LocalDefId};
20use rustc_span::{Span, Symbol};
21
22use crate::builder::ExprCategory;
23use crate::errors::*;
24
25struct UnsafetyVisitor<'a, 'tcx> {
26 tcx: TyCtxt<'tcx>,
27 thir: &'a Thir<'tcx>,
28 hir_context: HirId,
31 safety_context: SafetyContext,
34 body_target_features: &'tcx [TargetFeature],
37 assignment_info: Option<Ty<'tcx>>,
40 in_union_destructure: bool,
41 typing_env: ty::TypingEnv<'tcx>,
42 inside_adt: bool,
43 warnings: &'a mut Vec<UnusedUnsafeWarning>,
44
45 suggest_unsafe_block: bool,
48}
49
50impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
51 fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&mut Self)) {
52 let prev_context = mem::replace(&mut self.safety_context, safety_context);
53
54 f(self);
55
56 let safety_context = mem::replace(&mut self.safety_context, prev_context);
57 if let SafetyContext::UnsafeBlock { used, span, hir_id, nested_used_blocks } =
58 safety_context
59 {
60 if !used {
61 self.warn_unused_unsafe(hir_id, span, None);
62
63 if let SafetyContext::UnsafeBlock {
64 nested_used_blocks: ref mut prev_nested_used_blocks,
65 ..
66 } = self.safety_context
67 {
68 prev_nested_used_blocks.extend(nested_used_blocks);
69 }
70 } else {
71 for block in nested_used_blocks {
72 self.warn_unused_unsafe(
73 block.hir_id,
74 block.span,
75 Some(UnusedUnsafeEnclosing::Block {
76 span: self.tcx.sess.source_map().guess_head_span(span),
77 }),
78 );
79 }
80
81 match self.safety_context {
82 SafetyContext::UnsafeBlock {
83 nested_used_blocks: ref mut prev_nested_used_blocks,
84 ..
85 } => {
86 prev_nested_used_blocks.push(NestedUsedBlock { hir_id, span });
87 }
88 _ => (),
89 }
90 }
91 }
92 }
93
94 fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool {
95 match kind {
96 &UnsafeOpKind::CallToUnsafeFunction(Some(id))
99 if !span.at_least_rust_2024()
100 && let Some(suggestion) = {
#[allow(deprecated)]
{
{
'done:
{
for i in self.tcx.get_all_attrs(id) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(RustcDeprecatedSafe2024 {
suggestion }) => {
break 'done Some(suggestion);
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}
}find_attr!(self.tcx, id, RustcDeprecatedSafe2024{suggestion} => suggestion) =>
101 {
102 let sm = self.tcx.sess.source_map();
103 let guarantee = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("that {0}", suggestion))
})format!("that {}", suggestion);
104 let suggestion = sm
105 .indentation_before(span)
106 .map(|indent| {
107 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}// TODO: Audit that {1}.\n",
indent, suggestion))
})format!("{}// TODO: Audit that {}.\n", indent, suggestion) })
109 .unwrap_or_default();
110
111 self.tcx.emit_node_span_lint(
112 DEPRECATED_SAFE_2024,
113 self.hir_context,
114 span,
115 CallToDeprecatedSafeFnRequiresUnsafe {
116 span,
117 function: { let _guard = NoTrimmedGuard::new(); self.tcx.def_path_str(id) }with_no_trimmed_paths!(self.tcx.def_path_str(id)),
118 guarantee,
119 sub: CallToDeprecatedSafeFnRequiresUnsafeSub {
120 start_of_line_suggestion: suggestion,
121 start_of_line: sm.span_extend_to_line(span).shrink_to_lo(),
122 left: span.shrink_to_lo(),
123 right: span.shrink_to_hi(),
124 },
125 },
126 );
127 true
128 }
129 _ => false,
130 }
131 }
132
133 fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
134 let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed();
135 match self.safety_context {
136 SafetyContext::BuiltinUnsafeBlock => {}
137 SafetyContext::UnsafeBlock { ref mut used, .. } => {
138 *used = true;
143 }
144 SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
145 SafetyContext::UnsafeFn => {
146 let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind);
147 if !deprecated_safe_fn {
148 kind.emit_unsafe_op_in_unsafe_fn_lint(
150 self.tcx,
151 self.hir_context,
152 span,
153 self.suggest_unsafe_block,
154 );
155 self.suggest_unsafe_block = false;
156 }
157 }
158 SafetyContext::Safe => {
159 let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind);
160 if !deprecated_safe_fn {
161 kind.emit_requires_unsafe_err(
162 self.tcx,
163 span,
164 self.hir_context,
165 unsafe_op_in_unsafe_fn_allowed,
166 );
167 }
168 }
169 }
170 }
171
172 fn warn_unused_unsafe(
173 &mut self,
174 hir_id: HirId,
175 block_span: Span,
176 enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
177 ) {
178 self.warnings.push(UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe });
179 }
180
181 fn unsafe_op_in_unsafe_fn_allowed(&self) -> bool {
183 self.tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, self.hir_context).level == Level::Allow
184 }
185
186 fn visit_inner_body(&mut self, def: LocalDefId) {
188 if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
189 self.tcx.ensure_done().mir_built(def);
191 let inner_thir = if self.tcx.sess.opts.unstable_opts.no_steal_thir {
192 &inner_thir.borrow()
193 } else {
194 &inner_thir.steal()
196 };
197 let hir_context = self.tcx.local_def_id_to_hir_id(def);
198 let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe);
199 let mut inner_visitor = UnsafetyVisitor {
200 tcx: self.tcx,
201 thir: inner_thir,
202 hir_context,
203 safety_context,
204 body_target_features: self.body_target_features,
205 assignment_info: self.assignment_info,
206 in_union_destructure: false,
207 typing_env: self.typing_env,
208 inside_adt: false,
209 warnings: self.warnings,
210 suggest_unsafe_block: self.suggest_unsafe_block,
211 };
212 for param in &inner_thir.params {
214 if let Some(param_pat) = param.pat.as_deref() {
215 inner_visitor.visit_pat(param_pat);
216 }
217 }
218 inner_visitor.visit_expr(&inner_thir[expr]);
220 self.safety_context = inner_visitor.safety_context;
222 }
223 }
224}
225
226struct LayoutConstrainedPlaceVisitor<'a, 'tcx> {
228 found: bool,
229 thir: &'a Thir<'tcx>,
230 tcx: TyCtxt<'tcx>,
231}
232
233impl<'a, 'tcx> LayoutConstrainedPlaceVisitor<'a, 'tcx> {
234 fn new(thir: &'a Thir<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
235 Self { found: false, thir, tcx }
236 }
237}
238
239impl<'a, 'tcx> Visitor<'a, 'tcx> for LayoutConstrainedPlaceVisitor<'a, 'tcx> {
240 fn thir(&self) -> &'a Thir<'tcx> {
241 self.thir
242 }
243
244 fn visit_expr(&mut self, expr: &'a Expr<'tcx>) {
245 match expr.kind {
246 ExprKind::Field { lhs, .. } => {
247 if let ty::Adt(adt_def, _) = self.thir[lhs].ty.kind() {
248 if (Bound::Unbounded, Bound::Unbounded)
249 != self.tcx.layout_scalar_valid_range(adt_def.did())
250 {
251 self.found = true;
252 }
253 }
254 visit::walk_expr(self, expr);
255 }
256
257 ExprKind::Deref { .. } => {}
261 ref kind if ExprCategory::of(kind).is_none_or(|cat| cat == ExprCategory::Place) => {
262 visit::walk_expr(self, expr);
263 }
264
265 _ => {}
266 }
267 }
268}
269
270impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
271 fn thir(&self) -> &'a Thir<'tcx> {
272 self.thir
273 }
274
275 fn visit_block(&mut self, block: &'a Block) {
276 match block.safety_mode {
277 BlockSafety::BuiltinUnsafe => {
280 self.in_safety_context(SafetyContext::BuiltinUnsafeBlock, |this| {
281 visit::walk_block(this, block)
282 });
283 }
284 BlockSafety::ExplicitUnsafe(hir_id) => {
285 let used = #[allow(non_exhaustive_omitted_patterns)] match self.tcx.lint_level_at_node(UNUSED_UNSAFE,
hir_id).level {
Level::Allow => true,
_ => false,
}matches!(
286 self.tcx.lint_level_at_node(UNUSED_UNSAFE, hir_id).level,
287 Level::Allow
288 );
289 self.in_safety_context(
290 SafetyContext::UnsafeBlock {
291 span: block.span,
292 hir_id,
293 used,
294 nested_used_blocks: Vec::new(),
295 },
296 |this| visit::walk_block(this, block),
297 );
298 }
299 BlockSafety::Safe => {
300 visit::walk_block(self, block);
301 }
302 }
303 }
304
305 fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
306 if self.in_union_destructure {
307 match pat.kind {
308 PatKind::Missing => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
309 PatKind::Binding { .. }
311 | PatKind::Constant { .. }
313 | PatKind::Variant { .. }
314 | PatKind::Leaf { .. }
315 | PatKind::Deref { .. }
316 | PatKind::DerefPattern { .. }
317 | PatKind::Range { .. }
318 | PatKind::Slice { .. }
319 | PatKind::Array { .. }
320 | PatKind::Never => {
322 self.requires_unsafe(pat.span, AccessToUnionField);
323 return; }
325 PatKind::Wild |
327 PatKind::Or { .. } |
329 PatKind::Error(_) => {}
330 }
331 };
332
333 match &pat.kind {
334 PatKind::Leaf { subpatterns, .. } => {
335 if let ty::Adt(adt_def, ..) = pat.ty.kind() {
336 for pat in subpatterns {
337 if adt_def.non_enum_variant().fields[pat.field].safety.is_unsafe() {
338 self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
339 }
340 }
341 if adt_def.is_union() {
342 let old_in_union_destructure =
343 std::mem::replace(&mut self.in_union_destructure, true);
344 visit::walk_pat(self, pat);
345 self.in_union_destructure = old_in_union_destructure;
346 } else if (Bound::Unbounded, Bound::Unbounded)
347 != self.tcx.layout_scalar_valid_range(adt_def.did())
348 {
349 let old_inside_adt = std::mem::replace(&mut self.inside_adt, true);
350 visit::walk_pat(self, pat);
351 self.inside_adt = old_inside_adt;
352 } else {
353 visit::walk_pat(self, pat);
354 }
355 } else {
356 visit::walk_pat(self, pat);
357 }
358 }
359 PatKind::Variant { adt_def, args: _, variant_index, subpatterns } => {
360 for pat in subpatterns {
361 let field = &pat.field;
362 if adt_def.variant(*variant_index).fields[*field].safety.is_unsafe() {
363 self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
364 }
365 }
366 visit::walk_pat(self, pat);
367 }
368 PatKind::Binding { mode: BindingMode(ByRef::Yes(_, rm), _), ty, .. } => {
369 if self.inside_adt {
370 let ty::Ref(_, ty, _) = ty.kind() else {
371 ::rustc_middle::util::bug::span_bug_fmt(pat.span,
format_args!("ByRef::Yes in pattern, but found non-reference type {0}",
ty));span_bug!(
372 pat.span,
373 "ByRef::Yes in pattern, but found non-reference type {}",
374 ty
375 );
376 };
377 match rm {
378 Mutability::Not => {
379 if !ty.is_freeze(self.tcx, self.typing_env) {
380 self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
381 }
382 }
383 Mutability::Mut { .. } => {
384 self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
385 }
386 }
387 }
388 visit::walk_pat(self, pat);
389 }
390 PatKind::Deref { .. } | PatKind::DerefPattern { .. } => {
391 let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
392 visit::walk_pat(self, pat);
393 self.inside_adt = old_inside_adt;
394 }
395 _ => {
396 visit::walk_pat(self, pat);
397 }
398 }
399 }
400
401 fn visit_expr(&mut self, expr: &'a Expr<'tcx>) {
402 match expr.kind {
404 ExprKind::Field { .. }
405 | ExprKind::VarRef { .. }
406 | ExprKind::UpvarRef { .. }
407 | ExprKind::Scope { .. }
408 | ExprKind::Cast { .. } => {}
409
410 ExprKind::RawBorrow { .. }
411 | ExprKind::Adt { .. }
412 | ExprKind::Array { .. }
413 | ExprKind::Binary { .. }
414 | ExprKind::Block { .. }
415 | ExprKind::Borrow { .. }
416 | ExprKind::Literal { .. }
417 | ExprKind::NamedConst { .. }
418 | ExprKind::NonHirLiteral { .. }
419 | ExprKind::ZstLiteral { .. }
420 | ExprKind::ConstParam { .. }
421 | ExprKind::ConstBlock { .. }
422 | ExprKind::Deref { .. }
423 | ExprKind::Index { .. }
424 | ExprKind::NeverToAny { .. }
425 | ExprKind::PlaceTypeAscription { .. }
426 | ExprKind::ValueTypeAscription { .. }
427 | ExprKind::PlaceUnwrapUnsafeBinder { .. }
428 | ExprKind::ValueUnwrapUnsafeBinder { .. }
429 | ExprKind::WrapUnsafeBinder { .. }
430 | ExprKind::PointerCoercion { .. }
431 | ExprKind::Repeat { .. }
432 | ExprKind::StaticRef { .. }
433 | ExprKind::ThreadLocalRef { .. }
434 | ExprKind::Tuple { .. }
435 | ExprKind::Unary { .. }
436 | ExprKind::Call { .. }
437 | ExprKind::ByUse { .. }
438 | ExprKind::Assign { .. }
439 | ExprKind::AssignOp { .. }
440 | ExprKind::Break { .. }
441 | ExprKind::Closure { .. }
442 | ExprKind::Continue { .. }
443 | ExprKind::ConstContinue { .. }
444 | ExprKind::Return { .. }
445 | ExprKind::Become { .. }
446 | ExprKind::Yield { .. }
447 | ExprKind::Loop { .. }
448 | ExprKind::LoopMatch { .. }
449 | ExprKind::Let { .. }
450 | ExprKind::Match { .. }
451 | ExprKind::If { .. }
452 | ExprKind::InlineAsm { .. }
453 | ExprKind::LogicalOp { .. }
454 | ExprKind::Use { .. } => {
455 self.assignment_info = None;
459 }
460 };
461 match expr.kind {
462 ExprKind::Scope { value, hir_id, region_scope: _ } => {
463 let prev_id = self.hir_context;
464 self.hir_context = hir_id;
465 ensure_sufficient_stack(|| {
466 self.visit_expr(&self.thir[value]);
467 });
468 self.hir_context = prev_id;
469 return; }
471 ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
472 let fn_ty = self.thir[fun].ty;
473 let sig = fn_ty.fn_sig(self.tcx);
474 let (callee_features, safe_target_features): (&[_], _) = match *fn_ty.kind() {
475 ty::FnDef(func_id, ..) => {
476 let cg_attrs = self.tcx.codegen_fn_attrs(func_id);
477 (&cg_attrs.target_features, cg_attrs.safe_target_features)
478 }
479 _ => (&[], false),
480 };
481 if sig.safety().is_unsafe() && !safe_target_features {
482 let func_id = if let ty::FnDef(func_id, _) = fn_ty.kind() {
483 Some(*func_id)
484 } else {
485 None
486 };
487 self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
488 } else if let &ty::FnDef(func_did, _) = fn_ty.kind() {
489 if !self
490 .tcx
491 .is_target_feature_call_safe(callee_features, self.body_target_features)
492 {
493 let missing: Vec<_> = callee_features
494 .iter()
495 .copied()
496 .filter(|feature| {
497 feature.kind == TargetFeatureKind::Enabled
498 && !self
499 .body_target_features
500 .iter()
501 .any(|body_feature| body_feature.name == feature.name)
502 })
503 .map(|feature| feature.name)
504 .collect();
505 let build_enabled = self
506 .tcx
507 .sess
508 .target_features
509 .iter()
510 .copied()
511 .filter(|feature| missing.contains(feature))
512 .collect();
513 self.requires_unsafe(
514 expr.span,
515 CallToFunctionWith { function: func_did, missing, build_enabled },
516 );
517 }
518 }
519 }
520 ExprKind::RawBorrow { arg, .. } => {
521 if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind
522 && let ExprKind::Deref { arg } = self.thir[arg].kind
523 {
524 visit::walk_expr(self, &self.thir[arg]);
527 return;
528 }
529
530 let mut peeled = arg;
534 while let ExprKind::Scope { value: arg, .. } = self.thir[peeled].kind
535 && let ExprKind::Field { lhs, name: _, variant_index: _ } = self.thir[arg].kind
536 && let ty::Adt(def, _) = &self.thir[lhs].ty.kind()
537 && def.is_union()
538 {
539 peeled = lhs;
540 }
541 visit::walk_expr(self, &self.thir[peeled]);
542 return;
544 }
545 ExprKind::Deref { arg } => {
546 if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
547 self.thir[arg].kind
548 {
549 if self.tcx.is_mutable_static(def_id) {
550 self.requires_unsafe(expr.span, UseOfMutableStatic);
551 } else if self.tcx.is_foreign_item(def_id) {
552 match self.tcx.def_kind(def_id) {
553 DefKind::Static { safety: hir::Safety::Safe, .. } => {}
554 _ => self.requires_unsafe(expr.span, UseOfExternStatic),
555 }
556 }
557 } else if self.thir[arg].ty.is_raw_ptr() {
558 self.requires_unsafe(expr.span, DerefOfRawPointer);
559 }
560 }
561 ExprKind::InlineAsm(box InlineAsmExpr {
562 asm_macro: asm_macro @ (AsmMacro::Asm | AsmMacro::NakedAsm),
563 ref operands,
564 template: _,
565 options: _,
566 line_spans: _,
567 }) => {
568 if let AsmMacro::Asm = asm_macro {
571 self.requires_unsafe(expr.span, UseOfInlineAssembly);
572 }
573
574 for op in &**operands {
577 use rustc_middle::thir::InlineAsmOperand::*;
578 match op {
579 In { expr, reg: _ }
580 | Out { expr: Some(expr), reg: _, late: _ }
581 | InOut { expr, reg: _, late: _ } => self.visit_expr(&self.thir()[*expr]),
582 SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
583 self.visit_expr(&self.thir()[*in_expr]);
584 if let Some(out_expr) = out_expr {
585 self.visit_expr(&self.thir()[*out_expr]);
586 }
587 }
588 Out { expr: None, reg: _, late: _ }
589 | Const { value: _, span: _ }
590 | SymFn { value: _ }
591 | SymStatic { def_id: _ } => {}
592 Label { block } => {
593 self.in_safety_context(SafetyContext::Safe, |this| {
598 visit::walk_block(this, &this.thir()[*block])
599 });
600 }
601 }
602 }
603 return;
604 }
605 ExprKind::Adt(box AdtExpr {
606 adt_def,
607 variant_index,
608 args: _,
609 user_ty: _,
610 fields: _,
611 base: _,
612 }) => {
613 if adt_def.variant(variant_index).has_unsafe_fields() {
614 self.requires_unsafe(expr.span, InitializingTypeWithUnsafeField)
615 }
616 match self.tcx.layout_scalar_valid_range(adt_def.did()) {
617 (Bound::Unbounded, Bound::Unbounded) => {}
618 _ => self.requires_unsafe(expr.span, InitializingTypeWith),
619 }
620 }
621 ExprKind::Closure(box ClosureExpr {
622 closure_id,
623 args: _,
624 upvars: _,
625 movability: _,
626 fake_reads: _,
627 }) => {
628 self.visit_inner_body(closure_id);
629 }
630 ExprKind::ConstBlock { did, args: _ } => {
631 let def_id = did.expect_local();
632 self.visit_inner_body(def_id);
633 }
634 ExprKind::Field { lhs, variant_index, name } => {
635 let lhs = &self.thir[lhs];
636 if let ty::Adt(adt_def, _) = lhs.ty.kind() {
637 if adt_def.variant(variant_index).fields[name].safety.is_unsafe() {
638 self.requires_unsafe(expr.span, UseOfUnsafeField);
639 } else if adt_def.is_union() {
640 if let Some(assigned_ty) = self.assignment_info {
641 if assigned_ty.needs_drop(self.tcx, self.typing_env) {
642 if !self.tcx.dcx().has_errors().is_some() {
{
::core::panicking::panic_fmt(format_args!("union fields that need dropping should be impossible: {0}",
assigned_ty));
}
};assert!(
645 self.tcx.dcx().has_errors().is_some(),
646 "union fields that need dropping should be impossible: {assigned_ty}"
647 );
648 }
649 } else {
650 self.requires_unsafe(expr.span, AccessToUnionField);
651 }
652 }
653 }
654 }
655 ExprKind::Assign { lhs, rhs } | ExprKind::AssignOp { lhs, rhs, .. } => {
656 let lhs = &self.thir[lhs];
657 let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
659 visit::walk_expr(&mut visitor, lhs);
660 if visitor.found {
661 self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField);
662 }
663
664 if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
ExprKind::Assign { .. } => true,
_ => false,
}matches!(expr.kind, ExprKind::Assign { .. }) {
668 self.assignment_info = Some(lhs.ty);
669 visit::walk_expr(self, lhs);
670 self.assignment_info = None;
671 visit::walk_expr(self, &self.thir()[rhs]);
672 return; }
674 }
675 ExprKind::Borrow { borrow_kind, arg } => {
676 let mut visitor = LayoutConstrainedPlaceVisitor::new(self.thir, self.tcx);
677 visit::walk_expr(&mut visitor, expr);
678 if visitor.found {
679 match borrow_kind {
680 BorrowKind::Fake(_) | BorrowKind::Shared
681 if !self.thir[arg].ty.is_freeze(self.tcx, self.typing_env) =>
682 {
683 self.requires_unsafe(expr.span, BorrowOfLayoutConstrainedField)
684 }
685 BorrowKind::Mut { .. } => {
686 self.requires_unsafe(expr.span, MutationOfLayoutConstrainedField)
687 }
688 BorrowKind::Fake(_) | BorrowKind::Shared => {}
689 }
690 }
691 }
692 ExprKind::PlaceUnwrapUnsafeBinder { .. }
693 | ExprKind::ValueUnwrapUnsafeBinder { .. }
694 | ExprKind::WrapUnsafeBinder { .. } => {
695 self.requires_unsafe(expr.span, UnsafeBinderCast);
696 }
697 _ => {}
698 }
699 visit::walk_expr(self, expr);
700 }
701}
702
703#[derive(#[automatically_derived]
impl ::core::clone::Clone for SafetyContext {
#[inline]
fn clone(&self) -> SafetyContext {
match self {
SafetyContext::Safe => SafetyContext::Safe,
SafetyContext::BuiltinUnsafeBlock =>
SafetyContext::BuiltinUnsafeBlock,
SafetyContext::UnsafeFn => SafetyContext::UnsafeFn,
SafetyContext::UnsafeBlock {
span: __self_0,
hir_id: __self_1,
used: __self_2,
nested_used_blocks: __self_3 } =>
SafetyContext::UnsafeBlock {
span: ::core::clone::Clone::clone(__self_0),
hir_id: ::core::clone::Clone::clone(__self_1),
used: ::core::clone::Clone::clone(__self_2),
nested_used_blocks: ::core::clone::Clone::clone(__self_3),
},
}
}
}Clone)]
704enum SafetyContext {
705 Safe,
706 BuiltinUnsafeBlock,
707 UnsafeFn,
708 UnsafeBlock { span: Span, hir_id: HirId, used: bool, nested_used_blocks: Vec<NestedUsedBlock> },
709}
710
711#[derive(#[automatically_derived]
impl ::core::clone::Clone for NestedUsedBlock {
#[inline]
fn clone(&self) -> NestedUsedBlock {
let _: ::core::clone::AssertParamIsClone<HirId>;
let _: ::core::clone::AssertParamIsClone<Span>;
*self
}
}Clone, #[automatically_derived]
impl ::core::marker::Copy for NestedUsedBlock { }Copy)]
712struct NestedUsedBlock {
713 hir_id: HirId,
714 span: Span,
715}
716
717struct UnusedUnsafeWarning {
718 hir_id: HirId,
719 block_span: Span,
720 enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
721}
722
723#[derive(#[automatically_derived]
impl ::core::clone::Clone for UnsafeOpKind {
#[inline]
fn clone(&self) -> UnsafeOpKind {
match self {
UnsafeOpKind::CallToUnsafeFunction(__self_0) =>
UnsafeOpKind::CallToUnsafeFunction(::core::clone::Clone::clone(__self_0)),
UnsafeOpKind::UseOfInlineAssembly =>
UnsafeOpKind::UseOfInlineAssembly,
UnsafeOpKind::InitializingTypeWith =>
UnsafeOpKind::InitializingTypeWith,
UnsafeOpKind::InitializingTypeWithUnsafeField =>
UnsafeOpKind::InitializingTypeWithUnsafeField,
UnsafeOpKind::UseOfMutableStatic =>
UnsafeOpKind::UseOfMutableStatic,
UnsafeOpKind::UseOfExternStatic =>
UnsafeOpKind::UseOfExternStatic,
UnsafeOpKind::UseOfUnsafeField => UnsafeOpKind::UseOfUnsafeField,
UnsafeOpKind::DerefOfRawPointer =>
UnsafeOpKind::DerefOfRawPointer,
UnsafeOpKind::AccessToUnionField =>
UnsafeOpKind::AccessToUnionField,
UnsafeOpKind::MutationOfLayoutConstrainedField =>
UnsafeOpKind::MutationOfLayoutConstrainedField,
UnsafeOpKind::BorrowOfLayoutConstrainedField =>
UnsafeOpKind::BorrowOfLayoutConstrainedField,
UnsafeOpKind::CallToFunctionWith {
function: __self_0, missing: __self_1, build_enabled: __self_2
} =>
UnsafeOpKind::CallToFunctionWith {
function: ::core::clone::Clone::clone(__self_0),
missing: ::core::clone::Clone::clone(__self_1),
build_enabled: ::core::clone::Clone::clone(__self_2),
},
UnsafeOpKind::UnsafeBinderCast => UnsafeOpKind::UnsafeBinderCast,
}
}
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for UnsafeOpKind {
#[inline]
fn eq(&self, other: &UnsafeOpKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(UnsafeOpKind::CallToUnsafeFunction(__self_0),
UnsafeOpKind::CallToUnsafeFunction(__arg1_0)) =>
__self_0 == __arg1_0,
(UnsafeOpKind::CallToFunctionWith {
function: __self_0,
missing: __self_1,
build_enabled: __self_2 },
UnsafeOpKind::CallToFunctionWith {
function: __arg1_0,
missing: __arg1_1,
build_enabled: __arg1_2 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1 &&
__self_2 == __arg1_2,
_ => true,
}
}
}PartialEq)]
724enum UnsafeOpKind {
725 CallToUnsafeFunction(Option<DefId>),
726 UseOfInlineAssembly,
727 InitializingTypeWith,
728 InitializingTypeWithUnsafeField,
729 UseOfMutableStatic,
730 UseOfExternStatic,
731 UseOfUnsafeField,
732 DerefOfRawPointer,
733 AccessToUnionField,
734 MutationOfLayoutConstrainedField,
735 BorrowOfLayoutConstrainedField,
736 CallToFunctionWith {
737 function: DefId,
738 missing: Vec<Symbol>,
741 build_enabled: Vec<Symbol>,
744 },
745 UnsafeBinderCast,
746}
747
748use UnsafeOpKind::*;
749
750impl UnsafeOpKind {
751 fn emit_unsafe_op_in_unsafe_fn_lint(
752 &self,
753 tcx: TyCtxt<'_>,
754 hir_id: HirId,
755 span: Span,
756 suggest_unsafe_block: bool,
757 ) {
758 if tcx.hir_opt_delegation_sig_id(hir_id.owner.def_id).is_some() {
759 return;
762 }
763 let parent_id = tcx.hir_get_parent_item(hir_id);
764 let parent_owner = tcx.hir_owner_node(parent_id);
765 let should_suggest = parent_owner.fn_sig().is_some_and(|sig| {
766 #[allow(non_exhaustive_omitted_patterns)] match sig.header.safety {
hir::HeaderSafety::Normal(hir::Safety::Unsafe) => true,
_ => false,
}matches!(sig.header.safety, hir::HeaderSafety::Normal(hir::Safety::Unsafe))
768 });
769 let unsafe_not_inherited_note = if should_suggest {
770 suggest_unsafe_block.then(|| {
771 let body_span = tcx.hir_body(parent_owner.body_id().unwrap()).value.span;
772 UnsafeNotInheritedLintNote {
773 signature_span: tcx.def_span(parent_id.def_id),
774 body_span,
775 }
776 })
777 } else {
778 None
779 };
780 match self {
783 CallToUnsafeFunction(Some(did)) => tcx.emit_node_span_lint(
784 UNSAFE_OP_IN_UNSAFE_FN,
785 hir_id,
786 span,
787 UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
788 span,
789 function: { let _guard = NoTrimmedGuard::new(); tcx.def_path_str(*did) }with_no_trimmed_paths!(tcx.def_path_str(*did)),
790 unsafe_not_inherited_note,
791 },
792 ),
793 CallToUnsafeFunction(None) => tcx.emit_node_span_lint(
794 UNSAFE_OP_IN_UNSAFE_FN,
795 hir_id,
796 span,
797 UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
798 span,
799 unsafe_not_inherited_note,
800 },
801 ),
802 UseOfInlineAssembly => tcx.emit_node_span_lint(
803 UNSAFE_OP_IN_UNSAFE_FN,
804 hir_id,
805 span,
806 UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
807 span,
808 unsafe_not_inherited_note,
809 },
810 ),
811 InitializingTypeWith => tcx.emit_node_span_lint(
812 UNSAFE_OP_IN_UNSAFE_FN,
813 hir_id,
814 span,
815 UnsafeOpInUnsafeFnInitializingTypeWithRequiresUnsafe {
816 span,
817 unsafe_not_inherited_note,
818 },
819 ),
820 InitializingTypeWithUnsafeField => tcx.emit_node_span_lint(
821 UNSAFE_OP_IN_UNSAFE_FN,
822 hir_id,
823 span,
824 UnsafeOpInUnsafeFnInitializingTypeWithUnsafeFieldRequiresUnsafe {
825 span,
826 unsafe_not_inherited_note,
827 },
828 ),
829 UseOfMutableStatic => tcx.emit_node_span_lint(
830 UNSAFE_OP_IN_UNSAFE_FN,
831 hir_id,
832 span,
833 UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
834 span,
835 unsafe_not_inherited_note,
836 },
837 ),
838 UseOfExternStatic => tcx.emit_node_span_lint(
839 UNSAFE_OP_IN_UNSAFE_FN,
840 hir_id,
841 span,
842 UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
843 span,
844 unsafe_not_inherited_note,
845 },
846 ),
847 UseOfUnsafeField => tcx.emit_node_span_lint(
848 UNSAFE_OP_IN_UNSAFE_FN,
849 hir_id,
850 span,
851 UnsafeOpInUnsafeFnUseOfUnsafeFieldRequiresUnsafe {
852 span,
853 unsafe_not_inherited_note,
854 },
855 ),
856 DerefOfRawPointer => tcx.emit_node_span_lint(
857 UNSAFE_OP_IN_UNSAFE_FN,
858 hir_id,
859 span,
860 UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
861 span,
862 unsafe_not_inherited_note,
863 },
864 ),
865 AccessToUnionField => tcx.emit_node_span_lint(
866 UNSAFE_OP_IN_UNSAFE_FN,
867 hir_id,
868 span,
869 UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
870 span,
871 unsafe_not_inherited_note,
872 },
873 ),
874 MutationOfLayoutConstrainedField => tcx.emit_node_span_lint(
875 UNSAFE_OP_IN_UNSAFE_FN,
876 hir_id,
877 span,
878 UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
879 span,
880 unsafe_not_inherited_note,
881 },
882 ),
883 BorrowOfLayoutConstrainedField => tcx.emit_node_span_lint(
884 UNSAFE_OP_IN_UNSAFE_FN,
885 hir_id,
886 span,
887 UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
888 span,
889 unsafe_not_inherited_note,
890 },
891 ),
892 CallToFunctionWith { function, missing, build_enabled } => tcx.emit_node_span_lint(
893 UNSAFE_OP_IN_UNSAFE_FN,
894 hir_id,
895 span,
896 UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
897 span,
898 function: { let _guard = NoTrimmedGuard::new(); tcx.def_path_str(*function) }with_no_trimmed_paths!(tcx.def_path_str(*function)),
899 missing_target_features: DiagArgValue::StrListSepByAnd(
900 missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
901 ),
902 missing_target_features_count: missing.len(),
903 note: !build_enabled.is_empty(),
904 build_target_features: DiagArgValue::StrListSepByAnd(
905 build_enabled
906 .iter()
907 .map(|feature| Cow::from(feature.to_string()))
908 .collect(),
909 ),
910 build_target_features_count: build_enabled.len(),
911 unsafe_not_inherited_note,
912 },
913 ),
914 UnsafeBinderCast => tcx.emit_node_span_lint(
915 UNSAFE_OP_IN_UNSAFE_FN,
916 hir_id,
917 span,
918 UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe {
919 span,
920 unsafe_not_inherited_note,
921 },
922 ),
923 }
924 }
925
926 fn emit_requires_unsafe_err(
927 &self,
928 tcx: TyCtxt<'_>,
929 span: Span,
930 hir_context: HirId,
931 unsafe_op_in_unsafe_fn_allowed: bool,
932 ) {
933 let note_non_inherited = tcx.hir_parent_iter(hir_context).find(|(id, node)| {
934 if let hir::Node::Expr(block) = node
935 && let hir::ExprKind::Block(block, _) = block.kind
936 && let hir::BlockCheckMode::UnsafeBlock(_) = block.rules
937 {
938 true
939 } else if let Some(sig) = tcx.hir_fn_sig_by_hir_id(*id)
940 && #[allow(non_exhaustive_omitted_patterns)] match sig.header.safety {
hir::HeaderSafety::Normal(hir::Safety::Unsafe) => true,
_ => false,
}matches!(sig.header.safety, hir::HeaderSafety::Normal(hir::Safety::Unsafe))
941 {
942 true
943 } else {
944 false
945 }
946 });
947 let unsafe_not_inherited_note = if let Some((id, _)) = note_non_inherited {
948 let span = tcx.hir_span(id);
949 let span = tcx.sess.source_map().guess_head_span(span);
950 Some(UnsafeNotInheritedNote { span })
951 } else {
952 None
953 };
954
955 let dcx = tcx.dcx();
956 match self {
957 CallToUnsafeFunction(Some(did)) if unsafe_op_in_unsafe_fn_allowed => {
958 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
959 span,
960 unsafe_not_inherited_note,
961 function: tcx.def_path_str(*did),
962 });
963 }
964 CallToUnsafeFunction(Some(did)) => {
965 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafe {
966 span,
967 unsafe_not_inherited_note,
968 function: tcx.def_path_str(*did),
969 });
970 }
971 CallToUnsafeFunction(None) if unsafe_op_in_unsafe_fn_allowed => {
972 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
973 span,
974 unsafe_not_inherited_note,
975 });
976 }
977 CallToUnsafeFunction(None) => {
978 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless {
979 span,
980 unsafe_not_inherited_note,
981 });
982 }
983 UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
984 dcx.emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
985 span,
986 unsafe_not_inherited_note,
987 });
988 }
989 UseOfInlineAssembly => {
990 dcx.emit_err(UseOfInlineAssemblyRequiresUnsafe { span, unsafe_not_inherited_note });
991 }
992 InitializingTypeWith if unsafe_op_in_unsafe_fn_allowed => {
993 dcx.emit_err(InitializingTypeWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
994 span,
995 unsafe_not_inherited_note,
996 });
997 }
998 InitializingTypeWith => {
999 dcx.emit_err(InitializingTypeWithRequiresUnsafe {
1000 span,
1001 unsafe_not_inherited_note,
1002 });
1003 }
1004 InitializingTypeWithUnsafeField if unsafe_op_in_unsafe_fn_allowed => {
1005 dcx.emit_err(
1006 InitializingTypeWithUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1007 span,
1008 unsafe_not_inherited_note,
1009 },
1010 );
1011 }
1012 InitializingTypeWithUnsafeField => {
1013 dcx.emit_err(InitializingTypeWithUnsafeFieldRequiresUnsafe {
1014 span,
1015 unsafe_not_inherited_note,
1016 });
1017 }
1018 UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
1019 dcx.emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1020 span,
1021 unsafe_not_inherited_note,
1022 });
1023 }
1024 UseOfMutableStatic => {
1025 dcx.emit_err(UseOfMutableStaticRequiresUnsafe { span, unsafe_not_inherited_note });
1026 }
1027 UseOfExternStatic if unsafe_op_in_unsafe_fn_allowed => {
1028 dcx.emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1029 span,
1030 unsafe_not_inherited_note,
1031 });
1032 }
1033 UseOfExternStatic => {
1034 dcx.emit_err(UseOfExternStaticRequiresUnsafe { span, unsafe_not_inherited_note });
1035 }
1036 UseOfUnsafeField if unsafe_op_in_unsafe_fn_allowed => {
1037 dcx.emit_err(UseOfUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1038 span,
1039 unsafe_not_inherited_note,
1040 });
1041 }
1042 UseOfUnsafeField => {
1043 dcx.emit_err(UseOfUnsafeFieldRequiresUnsafe { span, unsafe_not_inherited_note });
1044 }
1045 DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => {
1046 dcx.emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1047 span,
1048 unsafe_not_inherited_note,
1049 });
1050 }
1051 DerefOfRawPointer => {
1052 dcx.emit_err(DerefOfRawPointerRequiresUnsafe { span, unsafe_not_inherited_note });
1053 }
1054 AccessToUnionField if unsafe_op_in_unsafe_fn_allowed => {
1055 dcx.emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1056 span,
1057 unsafe_not_inherited_note,
1058 });
1059 }
1060 AccessToUnionField => {
1061 dcx.emit_err(AccessToUnionFieldRequiresUnsafe { span, unsafe_not_inherited_note });
1062 }
1063 MutationOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
1064 dcx.emit_err(
1065 MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1066 span,
1067 unsafe_not_inherited_note,
1068 },
1069 );
1070 }
1071 MutationOfLayoutConstrainedField => {
1072 dcx.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe {
1073 span,
1074 unsafe_not_inherited_note,
1075 });
1076 }
1077 BorrowOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
1078 dcx.emit_err(
1079 BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1080 span,
1081 unsafe_not_inherited_note,
1082 },
1083 );
1084 }
1085 BorrowOfLayoutConstrainedField => {
1086 dcx.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe {
1087 span,
1088 unsafe_not_inherited_note,
1089 });
1090 }
1091 CallToFunctionWith { function, missing, build_enabled }
1092 if unsafe_op_in_unsafe_fn_allowed =>
1093 {
1094 dcx.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1095 span,
1096 missing_target_features: DiagArgValue::StrListSepByAnd(
1097 missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
1098 ),
1099 missing_target_features_count: missing.len(),
1100 note: !build_enabled.is_empty(),
1101 build_target_features: DiagArgValue::StrListSepByAnd(
1102 build_enabled
1103 .iter()
1104 .map(|feature| Cow::from(feature.to_string()))
1105 .collect(),
1106 ),
1107 build_target_features_count: build_enabled.len(),
1108 unsafe_not_inherited_note,
1109 function: tcx.def_path_str(*function),
1110 });
1111 }
1112 CallToFunctionWith { function, missing, build_enabled } => {
1113 dcx.emit_err(CallToFunctionWithRequiresUnsafe {
1114 span,
1115 missing_target_features: DiagArgValue::StrListSepByAnd(
1116 missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
1117 ),
1118 missing_target_features_count: missing.len(),
1119 note: !build_enabled.is_empty(),
1120 build_target_features: DiagArgValue::StrListSepByAnd(
1121 build_enabled
1122 .iter()
1123 .map(|feature| Cow::from(feature.to_string()))
1124 .collect(),
1125 ),
1126 build_target_features_count: build_enabled.len(),
1127 unsafe_not_inherited_note,
1128 function: tcx.def_path_str(*function),
1129 });
1130 }
1131 UnsafeBinderCast if unsafe_op_in_unsafe_fn_allowed => {
1132 dcx.emit_err(UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1133 span,
1134 unsafe_not_inherited_note,
1135 });
1136 }
1137 UnsafeBinderCast => {
1138 dcx.emit_err(UnsafeBinderCastRequiresUnsafe { span, unsafe_not_inherited_note });
1139 }
1140 }
1141 }
1142}
1143
1144pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
1145 if !!tcx.is_typeck_child(def.to_def_id()) {
::core::panicking::panic("assertion failed: !tcx.is_typeck_child(def.to_def_id())")
};assert!(!tcx.is_typeck_child(def.to_def_id()));
1147 if {
#[allow(deprecated)]
{
{
'done:
{
for i in tcx.get_all_attrs(def) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(CustomMir(..)) => {
break 'done Some(());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}
}find_attr!(tcx, def, CustomMir(..) => ()).is_some() {
1149 return;
1150 }
1151
1152 let Ok((thir, expr)) = tcx.thir_body(def) else { return };
1153 tcx.ensure_done().mir_built(def);
1155 let thir = if tcx.sess.opts.unstable_opts.no_steal_thir {
1156 &thir.borrow()
1157 } else {
1158 &thir.steal()
1160 };
1161
1162 let hir_id = tcx.local_def_id_to_hir_id(def);
1163 let safety_context = tcx.hir_fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
1164 match fn_sig.header.safety {
1165 hir::HeaderSafety::SafeTargetFeatures => SafetyContext::Safe,
1169 hir::HeaderSafety::Normal(safety) => match safety {
1170 hir::Safety::Unsafe => SafetyContext::UnsafeFn,
1171 hir::Safety::Safe => SafetyContext::Safe,
1172 },
1173 }
1174 });
1175 let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
1176 let mut warnings = Vec::new();
1177 let mut visitor = UnsafetyVisitor {
1178 tcx,
1179 thir,
1180 safety_context,
1181 hir_context: hir_id,
1182 body_target_features,
1183 assignment_info: None,
1184 in_union_destructure: false,
1185 typing_env: ty::TypingEnv::non_body_analysis(tcx, def),
1187 inside_adt: false,
1188 warnings: &mut warnings,
1189 suggest_unsafe_block: true,
1190 };
1191 for param in &thir.params {
1193 if let Some(param_pat) = param.pat.as_deref() {
1194 visitor.visit_pat(param_pat);
1195 }
1196 }
1197 visitor.visit_expr(&thir[expr]);
1199
1200 warnings.sort_by_key(|w| w.block_span);
1201 for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings {
1202 let block_span = tcx.sess.source_map().guess_head_span(block_span);
1203 tcx.emit_node_span_lint(
1204 UNUSED_UNSAFE,
1205 hir_id,
1206 block_span,
1207 UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
1208 );
1209 }
1210}