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