Skip to main content

rustc_mir_build/
check_unsafety.rs

1use std::borrow::Cow;
2use std::mem;
3
4use rustc_ast::AsmMacro;
5use rustc_errors::DiagArgValue;
6use rustc_hir::attrs::lang_items::LangItem;
7use rustc_hir::def::DefKind;
8use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, find_attr};
9use rustc_lint_defs::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
10use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
11use rustc_middle::thir::visit::Visitor;
12use rustc_middle::thir::*;
13use rustc_middle::ty::print::with_no_trimmed_paths;
14use rustc_middle::ty::{self, Ty, TyCtxt};
15use rustc_span::def_id::{DefId, LocalDefId};
16use rustc_span::{Span, Symbol, span_bug};
17
18use crate::diagnostics::*;
19
20struct UnsafetyVisitor<'a, 'tcx> {
21    tcx: TyCtxt<'tcx>,
22    thir: &'a Thir<'tcx>,
23    /// The `HirId` of the current scope, which would be the `HirId`
24    /// of the current HIR node, modulo adjustments. Used for lint levels.
25    hir_context: HirId,
26    /// The current "safety context". This notably tracks whether we are in an
27    /// `unsafe` block, and whether it has been used.
28    safety_context: SafetyContext,
29    /// The `#[target_feature]` attributes of the body. Used for checking
30    /// calls to functions with `#[target_feature]` (RFC 2396).
31    body_target_features: &'tcx [TargetFeature],
32    /// When inside the LHS of an assignment to a field, this is the type
33    /// of the LHS and the span of the assignment expression.
34    assignment_info: Option<Ty<'tcx>>,
35    in_union_destructure: bool,
36    typing_env: ty::TypingEnv<'tcx>,
37    inside_adt: bool,
38    warnings: &'a mut Vec<UnusedUnsafeWarning>,
39
40    /// Flag to ensure that we only suggest wrapping the entire function body in
41    /// an unsafe block once.
42    suggest_unsafe_block: bool,
43}
44
45impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
46    fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&mut Self)) {
47        let prev_context = mem::replace(&mut self.safety_context, safety_context);
48
49        f(self);
50
51        let safety_context = mem::replace(&mut self.safety_context, prev_context);
52        if let SafetyContext::UnsafeBlock { used, span, hir_id, nested_used_blocks } =
53            safety_context
54        {
55            if !used {
56                self.warn_unused_unsafe(hir_id, span, None);
57
58                if let SafetyContext::UnsafeBlock {
59                    nested_used_blocks: ref mut prev_nested_used_blocks,
60                    ..
61                } = self.safety_context
62                {
63                    prev_nested_used_blocks.extend(nested_used_blocks);
64                }
65            } else {
66                for block in nested_used_blocks {
67                    self.warn_unused_unsafe(
68                        block.hir_id,
69                        block.span,
70                        Some(UnusedUnsafeEnclosing::Block {
71                            span: self.tcx.sess.source_map().guess_head_span(span),
72                        }),
73                    );
74                }
75
76                match self.safety_context {
77                    SafetyContext::UnsafeBlock {
78                        nested_used_blocks: ref mut prev_nested_used_blocks,
79                        ..
80                    } => {
81                        prev_nested_used_blocks.push(NestedUsedBlock { hir_id, span });
82                    }
83                    _ => (),
84                }
85            }
86        }
87    }
88
89    fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool {
90        match kind {
91            // Allow calls to deprecated-safe unsafe functions if the caller is
92            // from an edition before 2024.
93            &UnsafeOpKind::CallToUnsafeFunction(Some(id))
94                if !span.at_least_rust_2024()
95                    && let Some(suggestion) = {
    {
        'done:
            {
            for i in ::rustc_attr_ir::HasAttrs::get_attrs(id, &self.tcx) {
                #[allow(unused_imports)]
                use ::rustc_attr_ir::AttributeKind::*;
                let i: &::rustc_attr_ir::Attribute = i;
                match i {
                    ::rustc_attr_ir::Attribute::Parsed(RustcDeprecatedSafe2024 {
                        suggestion }) => {
                        break 'done Some(suggestion);
                    }
                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(self.tcx, id, RustcDeprecatedSafe2024{suggestion} => suggestion) =>
96            {
97                let sm = self.tcx.sess.source_map();
98                let guarantee = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("that {0}", suggestion))
    })format!("that {}", suggestion);
99                let suggestion = sm
100                    .indentation_before(span)
101                    .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))
102                    .unwrap_or_default();
103
104                self.tcx.emit_node_span_lint(
105                    DEPRECATED_SAFE_2024,
106                    self.hir_context,
107                    span,
108                    CallToDeprecatedSafeFnRequiresUnsafe {
109                        span,
110                        function: { let _guard = NoTrimmedGuard::new(); self.tcx.def_path_str(id) }with_no_trimmed_paths!(self.tcx.def_path_str(id)),
111                        sub: CallToDeprecatedSafeFnRequiresUnsafeSub {
112                            start_of_line_suggestion: suggestion,
113                            start_of_line: sm.span_extend_to_line(span).shrink_to_lo(),
114                            left: span.shrink_to_lo(),
115                            right: span.shrink_to_hi(),
116                            guarantee,
117                        },
118                    },
119                );
120                true
121            }
122            _ => false,
123        }
124    }
125
126    fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
127        let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed();
128        match self.safety_context {
129            SafetyContext::BuiltinUnsafeBlock => {}
130            SafetyContext::UnsafeBlock { ref mut used, .. } => {
131                // Mark this block as useful (even inside `unsafe fn`, where it is technically
132                // redundant -- but we want to eventually enable `unsafe_op_in_unsafe_fn` by
133                // default which will require those blocks:
134                // https://github.com/rust-lang/rust/issues/71668#issuecomment-1203075594).
135                *used = true;
136            }
137            SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
138            SafetyContext::UnsafeFn => {
139                let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind);
140                if !deprecated_safe_fn {
141                    // unsafe_op_in_unsafe_fn is disallowed
142                    kind.emit_unsafe_op_in_unsafe_fn_lint(
143                        self.tcx,
144                        self.hir_context,
145                        span,
146                        self.suggest_unsafe_block,
147                    );
148                    self.suggest_unsafe_block = false;
149                }
150            }
151            SafetyContext::Safe => {
152                let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind);
153                if !deprecated_safe_fn {
154                    kind.emit_requires_unsafe_err(
155                        self.tcx,
156                        span,
157                        self.hir_context,
158                        unsafe_op_in_unsafe_fn_allowed,
159                    );
160                }
161            }
162        }
163    }
164
165    fn warn_unused_unsafe(
166        &mut self,
167        hir_id: HirId,
168        block_span: Span,
169        enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
170    ) {
171        self.warnings.push(UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe });
172    }
173
174    /// Whether the `unsafe_op_in_unsafe_fn` lint is `allow`ed at the current HIR node.
175    fn unsafe_op_in_unsafe_fn_allowed(&self) -> bool {
176        self.tcx.lint_level_spec_at_node(UNSAFE_OP_IN_UNSAFE_FN, self.hir_context).is_allow()
177    }
178
179    /// Handle closures/coroutines/inline-consts, which is unsafecked with their parent body.
180    fn visit_inner_body(&mut self, def: LocalDefId) {
181        if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
182            // Run all other queries that depend on THIR.
183            self.tcx.ensure_done().mir_built(def);
184            let inner_thir = if self.tcx.sess.opts.unstable_opts.no_steal_thir {
185                &inner_thir.borrow()
186            } else {
187                // We don't have other use for the THIR. Steal it to reduce memory usage.
188                &inner_thir.steal()
189            };
190            let hir_context = self.tcx.local_def_id_to_hir_id(def);
191            let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe);
192            let mut inner_visitor = UnsafetyVisitor {
193                tcx: self.tcx,
194                thir: inner_thir,
195                hir_context,
196                safety_context,
197                body_target_features: self.body_target_features,
198                assignment_info: self.assignment_info,
199                in_union_destructure: false,
200                typing_env: self.typing_env,
201                inside_adt: false,
202                warnings: self.warnings,
203                suggest_unsafe_block: self.suggest_unsafe_block,
204            };
205            // params in THIR may be unsafe, e.g. a union pattern.
206            for param in &inner_thir.params {
207                if let Some(param_pat) = param.pat.as_deref() {
208                    inner_visitor.visit_pat(param_pat);
209                }
210            }
211            // Visit the body.
212            inner_visitor.visit_expr(&inner_thir[expr]);
213            // Unsafe blocks can be used in the inner body, make sure to take it into account
214            self.safety_context = inner_visitor.safety_context;
215        }
216    }
217}
218
219impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
220    fn thir(&self) -> &'a Thir<'tcx> {
221        self.thir
222    }
223
224    fn visit_block(&mut self, block: &'a Block) {
225        match block.safety_mode {
226            // compiler-generated unsafe code should not count towards the usefulness of
227            // an outer unsafe block
228            BlockSafety::BuiltinUnsafe => {
229                self.in_safety_context(SafetyContext::BuiltinUnsafeBlock, |this| {
230                    visit::walk_block(this, block)
231                });
232            }
233            BlockSafety::ExplicitUnsafe(hir_id) => {
234                let used = self.tcx.lint_level_spec_at_node(UNUSED_UNSAFE, hir_id).is_allow();
235                self.in_safety_context(
236                    SafetyContext::UnsafeBlock {
237                        span: block.span,
238                        hir_id,
239                        used,
240                        nested_used_blocks: Vec::new(),
241                    },
242                    |this| visit::walk_block(this, block),
243                );
244            }
245            BlockSafety::Safe => {
246                visit::walk_block(self, block);
247            }
248        }
249    }
250
251    fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
252        if self.in_union_destructure {
253            match pat.kind {
254                PatKind::Missing => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
255                // binding to a variable allows getting stuff out of variable
256                PatKind::Binding { .. }
257                // match is conditional on having this value
258                | PatKind::Constant { .. }
259                | PatKind::Variant { .. }
260                | PatKind::Leaf { .. }
261                | PatKind::Deref { .. }
262                | PatKind::DerefPattern { .. }
263                | PatKind::Range { .. }
264                | PatKind::Slice { .. }
265                | PatKind::Array { .. }
266                | PatKind::Guard { .. }
267                // Never constitutes a witness of uninhabitedness.
268                | PatKind::Never => {
269                    self.requires_unsafe(pat.span, AccessToUnionField);
270                    return; // we can return here since this already requires unsafe
271                }
272                // wildcard doesn't read anything.
273                PatKind::Wild |
274                // these just wrap other patterns, which we recurse on below.
275                PatKind::Or { .. } |
276                PatKind::Error(_) => {}
277            }
278        };
279
280        match &pat.kind {
281            PatKind::Leaf { subpatterns, .. } => {
282                if let ty::Adt(adt_def, ..) = pat.ty.kind() {
283                    for pat in subpatterns {
284                        if adt_def.non_enum_variant().fields[pat.field].safety.is_unsafe() {
285                            self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
286                        }
287                    }
288                    if adt_def.is_union() {
289                        let old_in_union_destructure =
290                            std::mem::replace(&mut self.in_union_destructure, true);
291                        visit::walk_pat(self, pat);
292                        self.in_union_destructure = old_in_union_destructure;
293                    } else {
294                        visit::walk_pat(self, pat);
295                    }
296                } else {
297                    visit::walk_pat(self, pat);
298                }
299            }
300            PatKind::Variant { adt_def, args: _, variant_index, subpatterns } => {
301                for pat in subpatterns {
302                    let field = &pat.field;
303                    if adt_def.variant(*variant_index).fields[*field].safety.is_unsafe() {
304                        self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
305                    }
306                }
307                visit::walk_pat(self, pat);
308            }
309            PatKind::Binding { mode: BindingMode(ByRef::Yes(_, rm), _), ty, .. } => {
310                if self.inside_adt {
311                    let ty::Ref(_, ty, _) = ty.kind() else {
312                        bug_impl(Some(pat.span),
    format_args!("ByRef::Yes in pattern, but found non-reference type {0}",
        ty), Location::caller());span_bug!(
313                            pat.span,
314                            "ByRef::Yes in pattern, but found non-reference type {}",
315                            ty
316                        );
317                    };
318                    match rm {
319                        Mutability::Not => {
320                            if !ty.is_freeze(self.tcx, self.typing_env) {
321                                self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
322                            }
323                        }
324                        Mutability::Mut { .. } => {
325                            self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
326                        }
327                    }
328                }
329                visit::walk_pat(self, pat);
330            }
331            PatKind::Deref { .. } | PatKind::DerefPattern { .. } => {
332                let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
333                visit::walk_pat(self, pat);
334                self.inside_adt = old_inside_adt;
335            }
336            _ => {
337                visit::walk_pat(self, pat);
338            }
339        }
340    }
341
342    fn visit_expr(&mut self, expr: &'a Expr<'tcx>) {
343        // could we be in the LHS of an assignment to a field?
344        match expr.kind {
345            ExprKind::Field { .. }
346            | ExprKind::VarRef { .. }
347            | ExprKind::UpvarRef { .. }
348            | ExprKind::Scope { .. }
349            | ExprKind::Cast { .. } => {}
350
351            ExprKind::RawBorrow { .. }
352            | ExprKind::Adt { .. }
353            | ExprKind::Array { .. }
354            | ExprKind::Binary { .. }
355            | ExprKind::Block { .. }
356            | ExprKind::Borrow { .. }
357            | ExprKind::Literal { .. }
358            | ExprKind::NamedConst { .. }
359            | ExprKind::NonHirLiteral { .. }
360            | ExprKind::ZstLiteral { .. }
361            | ExprKind::ConstParam { .. }
362            | ExprKind::ConstBlock { .. }
363            | ExprKind::Deref { .. }
364            | ExprKind::Index { .. }
365            | ExprKind::NeverToAny { .. }
366            | ExprKind::PlaceTypeAscription { .. }
367            | ExprKind::ValueTypeAscription { .. }
368            | ExprKind::PlaceUnwrapUnsafeBinder { .. }
369            | ExprKind::ValueUnwrapUnsafeBinder { .. }
370            | ExprKind::WrapUnsafeBinder { .. }
371            | ExprKind::PointerCoercion { .. }
372            | ExprKind::Repeat { .. }
373            | ExprKind::StaticRef { .. }
374            | ExprKind::ThreadLocalRef { .. }
375            | ExprKind::Tuple { .. }
376            | ExprKind::Unary { .. }
377            | ExprKind::Call { .. }
378            | ExprKind::ByUse { .. }
379            | ExprKind::Assign { .. }
380            | ExprKind::AssignOp { .. }
381            | ExprKind::Break { .. }
382            | ExprKind::Closure { .. }
383            | ExprKind::Continue { .. }
384            | ExprKind::ConstContinue { .. }
385            | ExprKind::Return { .. }
386            | ExprKind::Become { .. }
387            | ExprKind::Yield { .. }
388            | ExprKind::Loop { .. }
389            | ExprKind::LoopMatch { .. }
390            | ExprKind::Let { .. }
391            | ExprKind::Match { .. }
392            | ExprKind::If { .. }
393            | ExprKind::InlineAsm { .. }
394            | ExprKind::LogicalOp { .. }
395            | ExprKind::ValueExpr { .. }
396            | ExprKind::Reborrow { .. } => {
397                // We don't need to save the old value and restore it
398                // because all the place expressions can't have more
399                // than one child.
400                self.assignment_info = None;
401            }
402        };
403        match expr.kind {
404            ExprKind::Scope { value, hir_id, region_scope: _ } => {
405                let prev_id = self.hir_context;
406                self.hir_context = hir_id;
407                self.visit_expr(&self.thir[value]);
408                self.hir_context = prev_id;
409                return; // don't visit the whole expression
410            }
411            ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
412                let fn_ty = self.thir[fun].ty;
413                let sig = fn_ty.fn_sig(self.tcx);
414                let (callee_features, safe_target_features): (&[_], _) = match *fn_ty.kind() {
415                    ty::FnDef(func_id, ..) => {
416                        let cg_attrs = self.tcx.codegen_fn_attrs(func_id);
417                        (&cg_attrs.target_features, cg_attrs.safe_target_features)
418                    }
419                    _ => (&[], false),
420                };
421                if sig.safety().is_unsafe() && !safe_target_features {
422                    let func_id = if let ty::FnDef(func_id, _) = fn_ty.kind() {
423                        Some(*func_id)
424                    } else {
425                        None
426                    };
427                    self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
428                } else if let &ty::FnDef(func_did, _) = fn_ty.kind() {
429                    if !self
430                        .tcx
431                        .is_target_feature_call_safe(callee_features, self.body_target_features)
432                    {
433                        let missing: Vec<_> = callee_features
434                            .iter()
435                            .copied()
436                            .filter(|feature| {
437                                feature.kind == TargetFeatureKind::Enabled
438                                    && !self
439                                        .body_target_features
440                                        .iter()
441                                        .any(|body_feature| body_feature.name == feature.name)
442                            })
443                            .map(|feature| feature.name)
444                            .collect();
445                        let build_enabled = self
446                            .tcx
447                            .sess
448                            .internal_target_features
449                            .iter()
450                            .copied()
451                            .filter(|feature| missing.contains(feature))
452                            .collect();
453                        self.requires_unsafe(
454                            expr.span,
455                            CallToFunctionWith { function: func_did, missing, build_enabled },
456                        );
457                    }
458                    if let Some(trait_did) = self.tcx.trait_of_assoc(func_did)
459                        && self.tcx.is_lang_item(trait_did, LangItem::Drop)
460                    {
461                        self.requires_unsafe(expr.span, CallDropExplicitly(func_did));
462                    }
463                }
464            }
465            ExprKind::RawBorrow { arg, .. } => {
466                if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind
467                    && let ExprKind::Deref { arg } = self.thir[arg].kind
468                {
469                    // Taking a raw ref to a deref place expr is always safe.
470                    // Make sure the expression we're deref'ing is safe, though.
471                    visit::walk_expr(self, &self.thir[arg]);
472                    return;
473                }
474
475                // Secondly, we allow raw borrows of union field accesses. Peel
476                // any of those off, and recurse normally on the LHS, which should
477                // reject any unsafe operations within.
478                let mut peeled = arg;
479                while let ExprKind::Scope { value: arg, .. } = self.thir[peeled].kind
480                    && let ExprKind::Field { lhs, name: _, variant_index: _ } = self.thir[arg].kind
481                    && let ty::Adt(def, _) = &self.thir[lhs].ty.kind()
482                    && def.is_union()
483                {
484                    peeled = lhs;
485                }
486                visit::walk_expr(self, &self.thir[peeled]);
487                // And return so we don't recurse directly onto the union field access(es).
488                return;
489            }
490            ExprKind::Deref { arg } => {
491                if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
492                    self.thir[arg].kind
493                {
494                    if self.tcx.is_mutable_static(def_id) {
495                        self.requires_unsafe(expr.span, UseOfMutableStatic);
496                    } else if self.tcx.is_foreign_item(def_id) {
497                        match self.tcx.def_kind(def_id) {
498                            DefKind::Static { safety: hir::Safety::Safe, .. } => {}
499                            _ => self.requires_unsafe(expr.span, UseOfExternStatic),
500                        }
501                    }
502                } else if self.thir[arg].ty.is_raw_ptr() {
503                    self.requires_unsafe(expr.span, DerefOfRawPointer);
504                }
505            }
506            ExprKind::InlineAsm(InlineAsmExpr {
507                asm_macro: asm_macro @ (AsmMacro::Asm | AsmMacro::NakedAsm),
508                ref operands,
509                template: _,
510                options: _,
511                line_spans: _,
512            }) => {
513                // The `naked` attribute and the `naked_asm!` block form one atomic unit of
514                // unsafety, and `naked_asm!` does not itself need to be wrapped in an unsafe block.
515                if let AsmMacro::Asm = asm_macro {
516                    self.requires_unsafe(expr.span, UseOfInlineAssembly);
517                }
518
519                // For inline asm, do not use `walk_expr`, since we want to handle the label block
520                // specially.
521                for op in &**operands {
522                    use rustc_middle::thir::InlineAsmOperand::*;
523                    match op {
524                        In { expr, reg: _ }
525                        | Out { expr: Some(expr), reg: _, late: _ }
526                        | InOut { expr, reg: _, late: _ } => self.visit_expr(&self.thir()[*expr]),
527                        SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
528                            self.visit_expr(&self.thir()[*in_expr]);
529                            if let Some(out_expr) = out_expr {
530                                self.visit_expr(&self.thir()[*out_expr]);
531                            }
532                        }
533                        Out { expr: None, reg: _, late: _ }
534                        | Const { value: _, span: _ }
535                        | SymFn { value: _ }
536                        | SymStatic { def_id: _ } => {}
537                        Label { block } => {
538                            // Label blocks are safe context.
539                            // `asm!()` is forced to be wrapped inside unsafe. If there's no special
540                            // treatment, the label blocks would also always be unsafe with no way
541                            // of opting out.
542                            self.in_safety_context(SafetyContext::Safe, |this| {
543                                visit::walk_block(this, &this.thir()[*block])
544                            });
545                        }
546                    }
547                }
548                return;
549            }
550            ExprKind::Adt(AdtExpr {
551                adt_def,
552                variant_index,
553                args: _,
554                user_ty: _,
555                fields: _,
556                base: _,
557            }) => {
558                if adt_def.variant(variant_index).has_unsafe_fields() {
559                    self.requires_unsafe(expr.span, InitializingTypeWithUnsafeField)
560                }
561            }
562            ExprKind::Closure(ClosureExpr {
563                closure_id,
564                args: _,
565                upvars: _,
566                movability: _,
567                fake_reads: _,
568            }) => {
569                self.visit_inner_body(closure_id);
570            }
571            ExprKind::ConstBlock { did, args: _ } => {
572                let def_id = did.expect_local();
573                self.visit_inner_body(def_id);
574            }
575            ExprKind::Field { lhs, variant_index, name } => {
576                let lhs = &self.thir[lhs];
577                if let ty::Adt(adt_def, _) = lhs.ty.kind() {
578                    if adt_def.variant(variant_index).fields[name].safety.is_unsafe() {
579                        self.requires_unsafe(expr.span, UseOfUnsafeField);
580                    } else if adt_def.is_union() {
581                        if let Some(assigned_ty) = self.assignment_info {
582                            if assigned_ty.needs_drop(self.tcx, self.typing_env) {
583                                // This would be unsafe, but should be outright impossible since we
584                                // reject such unions.
585                                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!(
586                                    self.tcx.dcx().has_errors().is_some(),
587                                    "union fields that need dropping should be impossible: {assigned_ty}"
588                                );
589                            }
590                        } else {
591                            self.requires_unsafe(expr.span, AccessToUnionField);
592                        }
593                    }
594                }
595            }
596            ExprKind::Assign { lhs, rhs } | ExprKind::AssignOp { lhs, rhs, .. } => {
597                let lhs = &self.thir[lhs];
598
599                // Check for accesses to union fields. Don't have any
600                // special handling for AssignOp since it causes a read *and*
601                // write to lhs.
602                if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
    ExprKind::Assign { .. } => true,
    _ => false,
}matches!(expr.kind, ExprKind::Assign { .. }) {
603                    self.assignment_info = Some(lhs.ty);
604                    visit::walk_expr(self, lhs);
605                    self.assignment_info = None;
606                    visit::walk_expr(self, &self.thir()[rhs]);
607                    return; // We have already visited everything by now.
608                }
609            }
610            ExprKind::PlaceUnwrapUnsafeBinder { .. }
611            | ExprKind::ValueUnwrapUnsafeBinder { .. }
612            | ExprKind::WrapUnsafeBinder { .. } => {
613                self.requires_unsafe(expr.span, UnsafeBinderCast);
614            }
615            _ => {}
616        }
617        visit::walk_expr(self, expr);
618    }
619}
620
621#[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)]
622enum SafetyContext {
623    Safe,
624    BuiltinUnsafeBlock,
625    UnsafeFn,
626    UnsafeBlock { span: Span, hir_id: HirId, used: bool, nested_used_blocks: Vec<NestedUsedBlock> },
627}
628
629#[derive(#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for NestedUsedBlock { }
#[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)]
630struct NestedUsedBlock {
631    hir_id: HirId,
632    span: Span,
633}
634
635struct UnusedUnsafeWarning {
636    hir_id: HirId,
637    block_span: Span,
638    enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
639}
640
641#[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::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,
            UnsafeOpKind::CallDropExplicitly(__self_0) =>
                UnsafeOpKind::CallDropExplicitly(::core::clone::Clone::clone(__self_0)),
        }
    }
}Clone, #[automatically_derived]
impl ::core::marker::StructuralPartialEq for UnsafeOpKind { }
#[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,
                (UnsafeOpKind::CallDropExplicitly(__self_0),
                    UnsafeOpKind::CallDropExplicitly(__arg1_0)) =>
                    __self_0 == __arg1_0,
                _ => true,
            }
    }
}PartialEq)]
642enum UnsafeOpKind {
643    CallToUnsafeFunction(Option<DefId>),
644    UseOfInlineAssembly,
645    InitializingTypeWithUnsafeField,
646    UseOfMutableStatic,
647    UseOfExternStatic,
648    UseOfUnsafeField,
649    DerefOfRawPointer,
650    AccessToUnionField,
651    MutationOfLayoutConstrainedField,
652    BorrowOfLayoutConstrainedField,
653    CallToFunctionWith {
654        function: DefId,
655        /// Target features enabled in callee's `#[target_feature]` but missing in
656        /// caller's `#[target_feature]`.
657        missing: Vec<Symbol>,
658        /// Target features in `missing` that are enabled at compile time
659        /// (e.g., with `-C target-feature`).
660        build_enabled: Vec<Symbol>,
661    },
662    UnsafeBinderCast,
663    /// Calling `Drop::drop` or `Drop::pin_drop` explicitly.
664    CallDropExplicitly(DefId),
665}
666
667use UnsafeOpKind::*;
668
669impl UnsafeOpKind {
670    fn emit_unsafe_op_in_unsafe_fn_lint(
671        &self,
672        tcx: TyCtxt<'_>,
673        hir_id: HirId,
674        span: Span,
675        suggest_unsafe_block: bool,
676    ) {
677        if tcx.hir_opt_delegation_sig_id(hir_id.owner.def_id).is_some() {
678            // The body of the delegation item is synthesized, so it makes no sense
679            // to emit this lint.
680            return;
681        }
682        let parent_id = tcx.hir_get_parent_item(hir_id);
683        let parent_owner = tcx.hir_owner_node(parent_id);
684        let should_suggest = parent_owner.fn_sig().is_some_and(|sig| {
685            // Do not suggest for safe target_feature functions
686            #[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))
687        });
688        let unsafe_not_inherited_note = if should_suggest {
689            suggest_unsafe_block.then(|| {
690                let body_span = tcx.hir_body(parent_owner.body_id().unwrap()).value.span;
691                UnsafeNotInheritedLintNote {
692                    signature_span: tcx.def_span(parent_id.def_id),
693                    body_span,
694                }
695            })
696        } else {
697            None
698        };
699        // FIXME: ideally we would want to trim the def paths, but this is not
700        // feasible with the current lint emission API (see issue #106126).
701        match self {
702            CallToUnsafeFunction(Some(did)) => tcx.emit_node_span_lint(
703                UNSAFE_OP_IN_UNSAFE_FN,
704                hir_id,
705                span,
706                UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
707                    span,
708                    function: { let _guard = NoTrimmedGuard::new(); tcx.def_path_str(*did) }with_no_trimmed_paths!(tcx.def_path_str(*did)),
709                    unsafe_not_inherited_note,
710                },
711            ),
712            CallToUnsafeFunction(None) => tcx.emit_node_span_lint(
713                UNSAFE_OP_IN_UNSAFE_FN,
714                hir_id,
715                span,
716                UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
717                    span,
718                    unsafe_not_inherited_note,
719                },
720            ),
721            UseOfInlineAssembly => tcx.emit_node_span_lint(
722                UNSAFE_OP_IN_UNSAFE_FN,
723                hir_id,
724                span,
725                UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
726                    span,
727                    unsafe_not_inherited_note,
728                },
729            ),
730            InitializingTypeWithUnsafeField => tcx.emit_node_span_lint(
731                UNSAFE_OP_IN_UNSAFE_FN,
732                hir_id,
733                span,
734                UnsafeOpInUnsafeFnInitializingTypeWithUnsafeFieldRequiresUnsafe {
735                    span,
736                    unsafe_not_inherited_note,
737                },
738            ),
739            UseOfMutableStatic => tcx.emit_node_span_lint(
740                UNSAFE_OP_IN_UNSAFE_FN,
741                hir_id,
742                span,
743                UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
744                    span,
745                    unsafe_not_inherited_note,
746                },
747            ),
748            UseOfExternStatic => tcx.emit_node_span_lint(
749                UNSAFE_OP_IN_UNSAFE_FN,
750                hir_id,
751                span,
752                UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
753                    span,
754                    unsafe_not_inherited_note,
755                },
756            ),
757            UseOfUnsafeField => tcx.emit_node_span_lint(
758                UNSAFE_OP_IN_UNSAFE_FN,
759                hir_id,
760                span,
761                UnsafeOpInUnsafeFnUseOfUnsafeFieldRequiresUnsafe {
762                    span,
763                    unsafe_not_inherited_note,
764                },
765            ),
766            DerefOfRawPointer => tcx.emit_node_span_lint(
767                UNSAFE_OP_IN_UNSAFE_FN,
768                hir_id,
769                span,
770                UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
771                    span,
772                    unsafe_not_inherited_note,
773                },
774            ),
775            AccessToUnionField => tcx.emit_node_span_lint(
776                UNSAFE_OP_IN_UNSAFE_FN,
777                hir_id,
778                span,
779                UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
780                    span,
781                    unsafe_not_inherited_note,
782                },
783            ),
784            MutationOfLayoutConstrainedField => tcx.emit_node_span_lint(
785                UNSAFE_OP_IN_UNSAFE_FN,
786                hir_id,
787                span,
788                UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
789                    span,
790                    unsafe_not_inherited_note,
791                },
792            ),
793            BorrowOfLayoutConstrainedField => tcx.emit_node_span_lint(
794                UNSAFE_OP_IN_UNSAFE_FN,
795                hir_id,
796                span,
797                UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
798                    span,
799                    unsafe_not_inherited_note,
800                },
801            ),
802            CallToFunctionWith { function, missing, build_enabled } => tcx.emit_node_span_lint(
803                UNSAFE_OP_IN_UNSAFE_FN,
804                hir_id,
805                span,
806                UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
807                    span,
808                    function: { let _guard = NoTrimmedGuard::new(); tcx.def_path_str(*function) }with_no_trimmed_paths!(tcx.def_path_str(*function)),
809                    missing_target_features: DiagArgValue::StrListSepByAnd(
810                        missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
811                    ),
812                    missing_target_features_count: missing.len(),
813                    note: !build_enabled.is_empty(),
814                    build_target_features: DiagArgValue::StrListSepByAnd(
815                        build_enabled
816                            .iter()
817                            .map(|feature| Cow::from(feature.to_string()))
818                            .collect(),
819                    ),
820                    build_target_features_count: build_enabled.len(),
821                    unsafe_not_inherited_note,
822                },
823            ),
824            UnsafeBinderCast => tcx.emit_node_span_lint(
825                UNSAFE_OP_IN_UNSAFE_FN,
826                hir_id,
827                span,
828                UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe {
829                    span,
830                    unsafe_not_inherited_note,
831                },
832            ),
833            CallDropExplicitly(_) => {
834                bug_impl(Some(span),
    format_args!("`Drop::drop` or `Drop::pin_drop` should not be called explicitly"),
    Location::caller())span_bug!(span, "`Drop::drop` or `Drop::pin_drop` should not be called explicitly")
835            }
836        }
837    }
838
839    fn emit_requires_unsafe_err(
840        &self,
841        tcx: TyCtxt<'_>,
842        span: Span,
843        hir_context: HirId,
844        unsafe_op_in_unsafe_fn_allowed: bool,
845    ) {
846        let note_non_inherited = tcx.hir_parent_iter(hir_context).find(|(id, node)| {
847            if let hir::Node::Expr(block) = node
848                && let hir::ExprKind::Block(block, _) = block.kind
849                && let hir::BlockCheckMode::UnsafeBlock(_) = block.rules
850            {
851                true
852            } else if let Some(sig) = tcx.hir_fn_sig_by_hir_id(*id)
853                && #[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))
854            {
855                true
856            } else {
857                false
858            }
859        });
860        let unsafe_not_inherited_note = if let Some((id, _)) = note_non_inherited {
861            let span = tcx.hir_span(id);
862            let span = tcx.sess.source_map().guess_head_span(span);
863            Some(UnsafeNotInheritedNote { span })
864        } else {
865            None
866        };
867
868        let dcx = tcx.dcx();
869        match self {
870            CallToUnsafeFunction(Some(did)) if unsafe_op_in_unsafe_fn_allowed => {
871                dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
872                    span,
873                    unsafe_not_inherited_note,
874                    function: tcx.def_path_str(*did),
875                });
876            }
877            CallToUnsafeFunction(Some(did)) => {
878                dcx.emit_err(CallToUnsafeFunctionRequiresUnsafe {
879                    span,
880                    unsafe_not_inherited_note,
881                    function: tcx.def_path_str(*did),
882                });
883            }
884            CallToUnsafeFunction(None) if unsafe_op_in_unsafe_fn_allowed => {
885                dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
886                    span,
887                    unsafe_not_inherited_note,
888                });
889            }
890            CallToUnsafeFunction(None) => {
891                dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless {
892                    span,
893                    unsafe_not_inherited_note,
894                });
895            }
896            UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
897                dcx.emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
898                    span,
899                    unsafe_not_inherited_note,
900                });
901            }
902            UseOfInlineAssembly => {
903                dcx.emit_err(UseOfInlineAssemblyRequiresUnsafe { span, unsafe_not_inherited_note });
904            }
905            InitializingTypeWithUnsafeField if unsafe_op_in_unsafe_fn_allowed => {
906                dcx.emit_err(
907                    InitializingTypeWithUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
908                        span,
909                        unsafe_not_inherited_note,
910                    },
911                );
912            }
913            InitializingTypeWithUnsafeField => {
914                dcx.emit_err(InitializingTypeWithUnsafeFieldRequiresUnsafe {
915                    span,
916                    unsafe_not_inherited_note,
917                });
918            }
919            UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
920                dcx.emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
921                    span,
922                    unsafe_not_inherited_note,
923                });
924            }
925            UseOfMutableStatic => {
926                dcx.emit_err(UseOfMutableStaticRequiresUnsafe { span, unsafe_not_inherited_note });
927            }
928            UseOfExternStatic if unsafe_op_in_unsafe_fn_allowed => {
929                dcx.emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
930                    span,
931                    unsafe_not_inherited_note,
932                });
933            }
934            UseOfExternStatic => {
935                dcx.emit_err(UseOfExternStaticRequiresUnsafe { span, unsafe_not_inherited_note });
936            }
937            UseOfUnsafeField if unsafe_op_in_unsafe_fn_allowed => {
938                dcx.emit_err(UseOfUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
939                    span,
940                    unsafe_not_inherited_note,
941                });
942            }
943            UseOfUnsafeField => {
944                dcx.emit_err(UseOfUnsafeFieldRequiresUnsafe { span, unsafe_not_inherited_note });
945            }
946            DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => {
947                dcx.emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
948                    span,
949                    unsafe_not_inherited_note,
950                });
951            }
952            DerefOfRawPointer => {
953                dcx.emit_err(DerefOfRawPointerRequiresUnsafe { span, unsafe_not_inherited_note });
954            }
955            AccessToUnionField if unsafe_op_in_unsafe_fn_allowed => {
956                dcx.emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
957                    span,
958                    unsafe_not_inherited_note,
959                });
960            }
961            AccessToUnionField => {
962                dcx.emit_err(AccessToUnionFieldRequiresUnsafe { span, unsafe_not_inherited_note });
963            }
964            MutationOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
965                dcx.emit_err(
966                    MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
967                        span,
968                        unsafe_not_inherited_note,
969                    },
970                );
971            }
972            MutationOfLayoutConstrainedField => {
973                dcx.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe {
974                    span,
975                    unsafe_not_inherited_note,
976                });
977            }
978            BorrowOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
979                dcx.emit_err(
980                    BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
981                        span,
982                        unsafe_not_inherited_note,
983                    },
984                );
985            }
986            BorrowOfLayoutConstrainedField => {
987                dcx.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe {
988                    span,
989                    unsafe_not_inherited_note,
990                });
991            }
992            CallToFunctionWith { function, missing, build_enabled }
993                if unsafe_op_in_unsafe_fn_allowed =>
994            {
995                dcx.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
996                    span,
997                    missing_target_features: DiagArgValue::StrListSepByAnd(
998                        missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
999                    ),
1000                    missing_target_features_count: missing.len(),
1001                    note: !build_enabled.is_empty(),
1002                    build_target_features: DiagArgValue::StrListSepByAnd(
1003                        build_enabled
1004                            .iter()
1005                            .map(|feature| Cow::from(feature.to_string()))
1006                            .collect(),
1007                    ),
1008                    build_target_features_count: build_enabled.len(),
1009                    unsafe_not_inherited_note,
1010                    function: tcx.def_path_str(*function),
1011                });
1012            }
1013            CallToFunctionWith { function, missing, build_enabled } => {
1014                dcx.emit_err(CallToFunctionWithRequiresUnsafe {
1015                    span,
1016                    missing_target_features: DiagArgValue::StrListSepByAnd(
1017                        missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
1018                    ),
1019                    missing_target_features_count: missing.len(),
1020                    note: !build_enabled.is_empty(),
1021                    build_target_features: DiagArgValue::StrListSepByAnd(
1022                        build_enabled
1023                            .iter()
1024                            .map(|feature| Cow::from(feature.to_string()))
1025                            .collect(),
1026                    ),
1027                    build_target_features_count: build_enabled.len(),
1028                    unsafe_not_inherited_note,
1029                    function: tcx.def_path_str(*function),
1030                });
1031            }
1032            UnsafeBinderCast if unsafe_op_in_unsafe_fn_allowed => {
1033                dcx.emit_err(UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1034                    span,
1035                    unsafe_not_inherited_note,
1036                });
1037            }
1038            UnsafeBinderCast => {
1039                dcx.emit_err(UnsafeBinderCastRequiresUnsafe { span, unsafe_not_inherited_note });
1040            }
1041            CallDropExplicitly(did) => {
1042                dcx.emit_err(CallDropExplicitlyRequiresUnsafe {
1043                    span,
1044                    unsafe_not_inherited_note,
1045                    function: tcx.def_path_str(*did),
1046                });
1047            }
1048        }
1049    }
1050}
1051
1052pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
1053    // Closures and inline consts are handled by their owner, if it has a body
1054    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()));
1055    // Also, don't safety check custom MIR
1056    if {
    {
        'done:
            {
            for i in ::rustc_attr_ir::HasAttrs::get_attrs(def, &tcx) {
                #[allow(unused_imports)]
                use ::rustc_attr_ir::AttributeKind::*;
                let i: &::rustc_attr_ir::Attribute = i;
                match i {
                    ::rustc_attr_ir::Attribute::Parsed(CustomMir(..)) => {
                        break 'done Some(());
                    }
                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, def, CustomMir(..) => ()).is_some() {
1057        return;
1058    }
1059
1060    let Ok((thir, expr)) = tcx.thir_body(def) else { return };
1061    // Runs all other queries that depend on THIR.
1062    tcx.ensure_done().mir_built(def);
1063    let thir = if tcx.sess.opts.unstable_opts.no_steal_thir {
1064        &thir.borrow()
1065    } else {
1066        // We don't have other use for the THIR. Steal it to reduce memory usage.
1067        &thir.steal()
1068    };
1069
1070    let hir_id = tcx.local_def_id_to_hir_id(def);
1071    let safety_context = tcx.hir_fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
1072        match fn_sig.header.safety {
1073            // We typeck the body as safe, but otherwise treat it as unsafe everywhere else.
1074            // Call sites to other SafeTargetFeatures functions are checked explicitly and don't need
1075            // to care about safety of the body.
1076            hir::HeaderSafety::SafeTargetFeatures => SafetyContext::Safe,
1077            hir::HeaderSafety::Normal(safety) => match safety {
1078                hir::Safety::Unsafe => SafetyContext::UnsafeFn,
1079                hir::Safety::Safe => SafetyContext::Safe,
1080            },
1081        }
1082    });
1083    let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
1084    let mut warnings = Vec::new();
1085    let mut visitor = UnsafetyVisitor {
1086        tcx,
1087        thir,
1088        safety_context,
1089        hir_context: hir_id,
1090        body_target_features,
1091        assignment_info: None,
1092        in_union_destructure: false,
1093        typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build(tcx, def),
1094        inside_adt: false,
1095        warnings: &mut warnings,
1096        suggest_unsafe_block: true,
1097    };
1098    // params in THIR may be unsafe, e.g. a union pattern.
1099    for param in &thir.params {
1100        if let Some(param_pat) = param.pat.as_deref() {
1101            visitor.visit_pat(param_pat);
1102        }
1103    }
1104    // Visit the body.
1105    visitor.visit_expr(&thir[expr]);
1106
1107    warnings.sort_by_key(|w| w.block_span);
1108    for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings {
1109        let block_span = tcx.sess.source_map().guess_head_span(block_span);
1110        tcx.emit_node_span_lint(
1111            UNUSED_UNSAFE,
1112            hir_id,
1113            block_span,
1114            UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
1115        );
1116    }
1117}