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