Skip to main content

rustc_mir_build/
check_unsafety.rs

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