Skip to main content

rustc_mir_build/
check_unsafety.rs

1use std::borrow::Cow;
2use std::mem;
3use std::ops::Bound;
4
5use rustc_ast::AsmMacro;
6use rustc_data_structures::stack::ensure_sufficient_stack;
7use rustc_errors::DiagArgValue;
8use rustc_hir::def::DefKind;
9use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, find_attr};
10use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
11use rustc_middle::mir::BorrowKind;
12use rustc_middle::span_bug;
13use rustc_middle::thir::visit::Visitor;
14use rustc_middle::thir::*;
15use rustc_middle::ty::print::with_no_trimmed_paths;
16use rustc_middle::ty::{self, Ty, TyCtxt};
17use rustc_session::lint::Level;
18use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
19use rustc_span::def_id::{DefId, LocalDefId};
20use rustc_span::{Span, Symbol};
21
22use crate::builder::ExprCategory;
23use crate::errors::*;
24
25struct UnsafetyVisitor<'a, 'tcx> {
26    tcx: TyCtxt<'tcx>,
27    thir: &'a Thir<'tcx>,
28    /// The `HirId` of the current scope, which would be the `HirId`
29    /// of the current HIR node, modulo adjustments. Used for lint levels.
30    hir_context: HirId,
31    /// The current "safety context". This notably tracks whether we are in an
32    /// `unsafe` block, and whether it has been used.
33    safety_context: SafetyContext,
34    /// The `#[target_feature]` attributes of the body. Used for checking
35    /// calls to functions with `#[target_feature]` (RFC 2396).
36    body_target_features: &'tcx [TargetFeature],
37    /// When inside the LHS of an assignment to a field, this is the type
38    /// of the LHS and the span of the assignment expression.
39    assignment_info: Option<Ty<'tcx>>,
40    in_union_destructure: bool,
41    typing_env: ty::TypingEnv<'tcx>,
42    inside_adt: bool,
43    warnings: &'a mut Vec<UnusedUnsafeWarning>,
44
45    /// Flag to ensure that we only suggest wrapping the entire function body in
46    /// an unsafe block once.
47    suggest_unsafe_block: bool,
48}
49
50impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
51    fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&mut Self)) {
52        let prev_context = mem::replace(&mut self.safety_context, safety_context);
53
54        f(self);
55
56        let safety_context = mem::replace(&mut self.safety_context, prev_context);
57        if let SafetyContext::UnsafeBlock { used, span, hir_id, nested_used_blocks } =
58            safety_context
59        {
60            if !used {
61                self.warn_unused_unsafe(hir_id, span, None);
62
63                if let SafetyContext::UnsafeBlock {
64                    nested_used_blocks: ref mut prev_nested_used_blocks,
65                    ..
66                } = self.safety_context
67                {
68                    prev_nested_used_blocks.extend(nested_used_blocks);
69                }
70            } else {
71                for block in nested_used_blocks {
72                    self.warn_unused_unsafe(
73                        block.hir_id,
74                        block.span,
75                        Some(UnusedUnsafeEnclosing::Block {
76                            span: self.tcx.sess.source_map().guess_head_span(span),
77                        }),
78                    );
79                }
80
81                match self.safety_context {
82                    SafetyContext::UnsafeBlock {
83                        nested_used_blocks: ref mut prev_nested_used_blocks,
84                        ..
85                    } => {
86                        prev_nested_used_blocks.push(NestedUsedBlock { hir_id, span });
87                    }
88                    _ => (),
89                }
90            }
91        }
92    }
93
94    fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool {
95        match kind {
96            // Allow calls to deprecated-safe unsafe functions if the caller is
97            // from an edition before 2024.
98            &UnsafeOpKind::CallToUnsafeFunction(Some(id))
99                if !span.at_least_rust_2024()
100                    && let Some(suggestion) = {

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

    #[allow(deprecated)]
    {
        {
            'done:
                {
                for i in tcx.get_all_attrs(def) {
                    #[allow(unused_imports)]
                    use rustc_hir::attrs::AttributeKind::*;
                    let i: &rustc_hir::Attribute = i;
                    match i {
                        rustc_hir::Attribute::Parsed(CustomMir(..)) => {
                            break 'done Some(());
                        }
                        rustc_hir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }
}find_attr!(tcx, def, CustomMir(..) => ()).is_some() {
1149        return;
1150    }
1151
1152    let Ok((thir, expr)) = tcx.thir_body(def) else { return };
1153    // Runs all other queries that depend on THIR.
1154    tcx.ensure_done().mir_built(def);
1155    let thir = if tcx.sess.opts.unstable_opts.no_steal_thir {
1156        &thir.borrow()
1157    } else {
1158        // We don't have other use for the THIR. Steal it to reduce memory usage.
1159        &thir.steal()
1160    };
1161
1162    let hir_id = tcx.local_def_id_to_hir_id(def);
1163    let safety_context = tcx.hir_fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
1164        match fn_sig.header.safety {
1165            // We typeck the body as safe, but otherwise treat it as unsafe everywhere else.
1166            // Call sites to other SafeTargetFeatures functions are checked explicitly and don't need
1167            // to care about safety of the body.
1168            hir::HeaderSafety::SafeTargetFeatures => SafetyContext::Safe,
1169            hir::HeaderSafety::Normal(safety) => match safety {
1170                hir::Safety::Unsafe => SafetyContext::UnsafeFn,
1171                hir::Safety::Safe => SafetyContext::Safe,
1172            },
1173        }
1174    });
1175    let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
1176    let mut warnings = Vec::new();
1177    let mut visitor = UnsafetyVisitor {
1178        tcx,
1179        thir,
1180        safety_context,
1181        hir_context: hir_id,
1182        body_target_features,
1183        assignment_info: None,
1184        in_union_destructure: false,
1185        // FIXME(#132279): we're clearly in a body here.
1186        typing_env: ty::TypingEnv::non_body_analysis(tcx, def),
1187        inside_adt: false,
1188        warnings: &mut warnings,
1189        suggest_unsafe_block: true,
1190    };
1191    // params in THIR may be unsafe, e.g. a union pattern.
1192    for param in &thir.params {
1193        if let Some(param_pat) = param.pat.as_deref() {
1194            visitor.visit_pat(param_pat);
1195        }
1196    }
1197    // Visit the body.
1198    visitor.visit_expr(&thir[expr]);
1199
1200    warnings.sort_by_key(|w| w.block_span);
1201    for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings {
1202        let block_span = tcx.sess.source_map().guess_head_span(block_span);
1203        tcx.emit_node_span_lint(
1204            UNUSED_UNSAFE,
1205            hir_id,
1206            block_span,
1207            UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
1208        );
1209    }
1210}