1use std::borrow::Cow;
2use std::mem;
3
4use rustc_ast::AsmMacro;
5use rustc_data_structures::stack::ensure_sufficient_stack;
6use rustc_errors::DiagArgValue;
7use rustc_hir::def::DefKind;
8use rustc_hir::{self as hir, BindingMode, ByRef, HirId, Mutability, find_attr};
9use rustc_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
10use rustc_middle::span_bug;
11use rustc_middle::thir::visit::Visitor;
12use rustc_middle::thir::*;
13use rustc_middle::ty::print::with_no_trimmed_paths;
14use rustc_middle::ty::{self, Ty, TyCtxt};
15use rustc_session::lint::Level;
16use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
17use rustc_span::def_id::{DefId, LocalDefId};
18use rustc_span::{Span, Symbol};
19
20use crate::errors::*;
21
22struct UnsafetyVisitor<'a, 'tcx> {
23 tcx: TyCtxt<'tcx>,
24 thir: &'a Thir<'tcx>,
25 hir_context: HirId,
28 safety_context: SafetyContext,
31 body_target_features: &'tcx [TargetFeature],
34 assignment_info: Option<Ty<'tcx>>,
37 in_union_destructure: bool,
38 typing_env: ty::TypingEnv<'tcx>,
39 inside_adt: bool,
40 warnings: &'a mut Vec<UnusedUnsafeWarning>,
41
42 suggest_unsafe_block: bool,
45}
46
47impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
48 fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&mut Self)) {
49 let prev_context = mem::replace(&mut self.safety_context, safety_context);
50
51 f(self);
52
53 let safety_context = mem::replace(&mut self.safety_context, prev_context);
54 if let SafetyContext::UnsafeBlock { used, span, hir_id, nested_used_blocks } =
55 safety_context
56 {
57 if !used {
58 self.warn_unused_unsafe(hir_id, span, None);
59
60 if let SafetyContext::UnsafeBlock {
61 nested_used_blocks: ref mut prev_nested_used_blocks,
62 ..
63 } = self.safety_context
64 {
65 prev_nested_used_blocks.extend(nested_used_blocks);
66 }
67 } else {
68 for block in nested_used_blocks {
69 self.warn_unused_unsafe(
70 block.hir_id,
71 block.span,
72 Some(UnusedUnsafeEnclosing::Block {
73 span: self.tcx.sess.source_map().guess_head_span(span),
74 }),
75 );
76 }
77
78 match self.safety_context {
79 SafetyContext::UnsafeBlock {
80 nested_used_blocks: ref mut prev_nested_used_blocks,
81 ..
82 } => {
83 prev_nested_used_blocks.push(NestedUsedBlock { hir_id, span });
84 }
85 _ => (),
86 }
87 }
88 }
89 }
90
91 fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool {
92 match kind {
93 &UnsafeOpKind::CallToUnsafeFunction(Some(id))
96 if !span.at_least_rust_2024()
97 && 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) =>
98 {
99 let sm = self.tcx.sess.source_map();
100 let guarantee = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("that {0}", suggestion))
})format!("that {}", suggestion);
101 let suggestion = sm
102 .indentation_before(span)
103 .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))
104 .unwrap_or_default();
105
106 self.tcx.emit_node_span_lint(
107 DEPRECATED_SAFE_2024,
108 self.hir_context,
109 span,
110 CallToDeprecatedSafeFnRequiresUnsafe {
111 span,
112 function: { let _guard = NoTrimmedGuard::new(); self.tcx.def_path_str(id) }with_no_trimmed_paths!(self.tcx.def_path_str(id)),
113 sub: CallToDeprecatedSafeFnRequiresUnsafeSub {
114 start_of_line_suggestion: suggestion,
115 start_of_line: sm.span_extend_to_line(span).shrink_to_lo(),
116 left: span.shrink_to_lo(),
117 right: span.shrink_to_hi(),
118 guarantee,
119 },
120 },
121 );
122 true
123 }
124 _ => false,
125 }
126 }
127
128 fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
129 let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed();
130 match self.safety_context {
131 SafetyContext::BuiltinUnsafeBlock => {}
132 SafetyContext::UnsafeBlock { ref mut used, .. } => {
133 *used = true;
138 }
139 SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
140 SafetyContext::UnsafeFn => {
141 let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind);
142 if !deprecated_safe_fn {
143 kind.emit_unsafe_op_in_unsafe_fn_lint(
145 self.tcx,
146 self.hir_context,
147 span,
148 self.suggest_unsafe_block,
149 );
150 self.suggest_unsafe_block = false;
151 }
152 }
153 SafetyContext::Safe => {
154 let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind);
155 if !deprecated_safe_fn {
156 kind.emit_requires_unsafe_err(
157 self.tcx,
158 span,
159 self.hir_context,
160 unsafe_op_in_unsafe_fn_allowed,
161 );
162 }
163 }
164 }
165 }
166
167 fn warn_unused_unsafe(
168 &mut self,
169 hir_id: HirId,
170 block_span: Span,
171 enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
172 ) {
173 self.warnings.push(UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe });
174 }
175
176 fn unsafe_op_in_unsafe_fn_allowed(&self) -> bool {
178 self.tcx.lint_level_at_node(UNSAFE_OP_IN_UNSAFE_FN, self.hir_context).level == Level::Allow
179 }
180
181 fn visit_inner_body(&mut self, def: LocalDefId) {
183 if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
184 self.tcx.ensure_done().mir_built(def);
186 let inner_thir = if self.tcx.sess.opts.unstable_opts.no_steal_thir {
187 &inner_thir.borrow()
188 } else {
189 &inner_thir.steal()
191 };
192 let hir_context = self.tcx.local_def_id_to_hir_id(def);
193 let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe);
194 let mut inner_visitor = UnsafetyVisitor {
195 tcx: self.tcx,
196 thir: inner_thir,
197 hir_context,
198 safety_context,
199 body_target_features: self.body_target_features,
200 assignment_info: self.assignment_info,
201 in_union_destructure: false,
202 typing_env: self.typing_env,
203 inside_adt: false,
204 warnings: self.warnings,
205 suggest_unsafe_block: self.suggest_unsafe_block,
206 };
207 for param in &inner_thir.params {
209 if let Some(param_pat) = param.pat.as_deref() {
210 inner_visitor.visit_pat(param_pat);
211 }
212 }
213 inner_visitor.visit_expr(&inner_thir[expr]);
215 self.safety_context = inner_visitor.safety_context;
217 }
218 }
219}
220
221impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
222 fn thir(&self) -> &'a Thir<'tcx> {
223 self.thir
224 }
225
226 fn visit_block(&mut self, block: &'a Block) {
227 match block.safety_mode {
228 BlockSafety::BuiltinUnsafe => {
231 self.in_safety_context(SafetyContext::BuiltinUnsafeBlock, |this| {
232 visit::walk_block(this, block)
233 });
234 }
235 BlockSafety::ExplicitUnsafe(hir_id) => {
236 let used = #[allow(non_exhaustive_omitted_patterns)] match self.tcx.lint_level_at_node(UNUSED_UNSAFE,
hir_id).level {
Level::Allow => true,
_ => false,
}matches!(
237 self.tcx.lint_level_at_node(UNUSED_UNSAFE, hir_id).level,
238 Level::Allow
239 );
240 self.in_safety_context(
241 SafetyContext::UnsafeBlock {
242 span: block.span,
243 hir_id,
244 used,
245 nested_used_blocks: Vec::new(),
246 },
247 |this| visit::walk_block(this, block),
248 );
249 }
250 BlockSafety::Safe => {
251 visit::walk_block(self, block);
252 }
253 }
254 }
255
256 fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
257 if self.in_union_destructure {
258 match pat.kind {
259 PatKind::Missing => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
260 PatKind::Binding { .. }
262 | PatKind::Constant { .. }
264 | PatKind::Variant { .. }
265 | PatKind::Leaf { .. }
266 | PatKind::Deref { .. }
267 | PatKind::DerefPattern { .. }
268 | PatKind::Range { .. }
269 | PatKind::Slice { .. }
270 | PatKind::Array { .. }
271 | PatKind::Guard { .. }
272 | PatKind::Never => {
274 self.requires_unsafe(pat.span, AccessToUnionField);
275 return; }
277 PatKind::Wild |
279 PatKind::Or { .. } |
281 PatKind::Error(_) => {}
282 }
283 };
284
285 match &pat.kind {
286 PatKind::Leaf { subpatterns, .. } => {
287 if let ty::Adt(adt_def, ..) = pat.ty.kind() {
288 for pat in subpatterns {
289 if adt_def.non_enum_variant().fields[pat.field].safety.is_unsafe() {
290 self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
291 }
292 }
293 if adt_def.is_union() {
294 let old_in_union_destructure =
295 std::mem::replace(&mut self.in_union_destructure, true);
296 visit::walk_pat(self, pat);
297 self.in_union_destructure = old_in_union_destructure;
298 } else {
299 visit::walk_pat(self, pat);
300 }
301 } else {
302 visit::walk_pat(self, pat);
303 }
304 }
305 PatKind::Variant { adt_def, args: _, variant_index, subpatterns } => {
306 for pat in subpatterns {
307 let field = &pat.field;
308 if adt_def.variant(*variant_index).fields[*field].safety.is_unsafe() {
309 self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
310 }
311 }
312 visit::walk_pat(self, pat);
313 }
314 PatKind::Binding { mode: BindingMode(ByRef::Yes(_, rm), _), ty, .. } => {
315 if self.inside_adt {
316 let ty::Ref(_, ty, _) = ty.kind() else {
317 ::rustc_middle::util::bug::span_bug_fmt(pat.span,
format_args!("ByRef::Yes in pattern, but found non-reference type {0}",
ty));span_bug!(
318 pat.span,
319 "ByRef::Yes in pattern, but found non-reference type {}",
320 ty
321 );
322 };
323 match rm {
324 Mutability::Not => {
325 if !ty.is_freeze(self.tcx, self.typing_env) {
326 self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
327 }
328 }
329 Mutability::Mut { .. } => {
330 self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
331 }
332 }
333 }
334 visit::walk_pat(self, pat);
335 }
336 PatKind::Deref { .. } | PatKind::DerefPattern { .. } => {
337 let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
338 visit::walk_pat(self, pat);
339 self.inside_adt = old_inside_adt;
340 }
341 _ => {
342 visit::walk_pat(self, pat);
343 }
344 }
345 }
346
347 fn visit_expr(&mut self, expr: &'a Expr<'tcx>) {
348 match expr.kind {
350 ExprKind::Field { .. }
351 | ExprKind::VarRef { .. }
352 | ExprKind::UpvarRef { .. }
353 | ExprKind::Scope { .. }
354 | ExprKind::Cast { .. } => {}
355
356 ExprKind::RawBorrow { .. }
357 | ExprKind::Adt { .. }
358 | ExprKind::Array { .. }
359 | ExprKind::Binary { .. }
360 | ExprKind::Block { .. }
361 | ExprKind::Borrow { .. }
362 | ExprKind::Literal { .. }
363 | ExprKind::NamedConst { .. }
364 | ExprKind::NonHirLiteral { .. }
365 | ExprKind::ZstLiteral { .. }
366 | ExprKind::ConstParam { .. }
367 | ExprKind::ConstBlock { .. }
368 | ExprKind::Deref { .. }
369 | ExprKind::Index { .. }
370 | ExprKind::NeverToAny { .. }
371 | ExprKind::PlaceTypeAscription { .. }
372 | ExprKind::ValueTypeAscription { .. }
373 | ExprKind::PlaceUnwrapUnsafeBinder { .. }
374 | ExprKind::ValueUnwrapUnsafeBinder { .. }
375 | ExprKind::WrapUnsafeBinder { .. }
376 | ExprKind::PointerCoercion { .. }
377 | ExprKind::Repeat { .. }
378 | ExprKind::StaticRef { .. }
379 | ExprKind::ThreadLocalRef { .. }
380 | ExprKind::Tuple { .. }
381 | ExprKind::Unary { .. }
382 | ExprKind::Call { .. }
383 | ExprKind::ByUse { .. }
384 | ExprKind::Assign { .. }
385 | ExprKind::AssignOp { .. }
386 | ExprKind::Break { .. }
387 | ExprKind::Closure { .. }
388 | ExprKind::Continue { .. }
389 | ExprKind::ConstContinue { .. }
390 | ExprKind::Return { .. }
391 | ExprKind::Become { .. }
392 | ExprKind::Yield { .. }
393 | ExprKind::Loop { .. }
394 | ExprKind::LoopMatch { .. }
395 | ExprKind::Let { .. }
396 | ExprKind::Match { .. }
397 | ExprKind::If { .. }
398 | ExprKind::InlineAsm { .. }
399 | ExprKind::LogicalOp { .. }
400 | ExprKind::Use { .. } => {
401 self.assignment_info = None;
405 }
406 };
407 match expr.kind {
408 ExprKind::Scope { value, hir_id, region_scope: _ } => {
409 let prev_id = self.hir_context;
410 self.hir_context = hir_id;
411 ensure_sufficient_stack(|| {
412 self.visit_expr(&self.thir[value]);
413 });
414 self.hir_context = prev_id;
415 return; }
417 ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
418 let fn_ty = self.thir[fun].ty;
419 let sig = fn_ty.fn_sig(self.tcx);
420 let (callee_features, safe_target_features): (&[_], _) = match *fn_ty.kind() {
421 ty::FnDef(func_id, ..) => {
422 let cg_attrs = self.tcx.codegen_fn_attrs(func_id);
423 (&cg_attrs.target_features, cg_attrs.safe_target_features)
424 }
425 _ => (&[], false),
426 };
427 if sig.safety().is_unsafe() && !safe_target_features {
428 let func_id = if let ty::FnDef(func_id, _) = fn_ty.kind() {
429 Some(*func_id)
430 } else {
431 None
432 };
433 self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
434 } else if let &ty::FnDef(func_did, _) = fn_ty.kind() {
435 if !self
436 .tcx
437 .is_target_feature_call_safe(callee_features, self.body_target_features)
438 {
439 let missing: Vec<_> = callee_features
440 .iter()
441 .copied()
442 .filter(|feature| {
443 feature.kind == TargetFeatureKind::Enabled
444 && !self
445 .body_target_features
446 .iter()
447 .any(|body_feature| body_feature.name == feature.name)
448 })
449 .map(|feature| feature.name)
450 .collect();
451 let build_enabled = self
452 .tcx
453 .sess
454 .target_features
455 .iter()
456 .copied()
457 .filter(|feature| missing.contains(feature))
458 .collect();
459 self.requires_unsafe(
460 expr.span,
461 CallToFunctionWith { function: func_did, missing, build_enabled },
462 );
463 }
464 }
465 }
466 ExprKind::RawBorrow { arg, .. } => {
467 if let ExprKind::Scope { value: arg, .. } = self.thir[arg].kind
468 && let ExprKind::Deref { arg } = self.thir[arg].kind
469 {
470 visit::walk_expr(self, &self.thir[arg]);
473 return;
474 }
475
476 let mut peeled = arg;
480 while let ExprKind::Scope { value: arg, .. } = self.thir[peeled].kind
481 && let ExprKind::Field { lhs, name: _, variant_index: _ } = self.thir[arg].kind
482 && let ty::Adt(def, _) = &self.thir[lhs].ty.kind()
483 && def.is_union()
484 {
485 peeled = lhs;
486 }
487 visit::walk_expr(self, &self.thir[peeled]);
488 return;
490 }
491 ExprKind::Deref { arg } => {
492 if let ExprKind::StaticRef { def_id, .. } | ExprKind::ThreadLocalRef(def_id) =
493 self.thir[arg].kind
494 {
495 if self.tcx.is_mutable_static(def_id) {
496 self.requires_unsafe(expr.span, UseOfMutableStatic);
497 } else if self.tcx.is_foreign_item(def_id) {
498 match self.tcx.def_kind(def_id) {
499 DefKind::Static { safety: hir::Safety::Safe, .. } => {}
500 _ => self.requires_unsafe(expr.span, UseOfExternStatic),
501 }
502 }
503 } else if self.thir[arg].ty.is_raw_ptr() {
504 self.requires_unsafe(expr.span, DerefOfRawPointer);
505 }
506 }
507 ExprKind::InlineAsm(box InlineAsmExpr {
508 asm_macro: asm_macro @ (AsmMacro::Asm | AsmMacro::NakedAsm),
509 ref operands,
510 template: _,
511 options: _,
512 line_spans: _,
513 }) => {
514 if let AsmMacro::Asm = asm_macro {
517 self.requires_unsafe(expr.span, UseOfInlineAssembly);
518 }
519
520 for op in &**operands {
523 use rustc_middle::thir::InlineAsmOperand::*;
524 match op {
525 In { expr, reg: _ }
526 | Out { expr: Some(expr), reg: _, late: _ }
527 | InOut { expr, reg: _, late: _ } => self.visit_expr(&self.thir()[*expr]),
528 SplitInOut { in_expr, out_expr, reg: _, late: _ } => {
529 self.visit_expr(&self.thir()[*in_expr]);
530 if let Some(out_expr) = out_expr {
531 self.visit_expr(&self.thir()[*out_expr]);
532 }
533 }
534 Out { expr: None, reg: _, late: _ }
535 | Const { value: _, span: _ }
536 | SymFn { value: _ }
537 | SymStatic { def_id: _ } => {}
538 Label { block } => {
539 self.in_safety_context(SafetyContext::Safe, |this| {
544 visit::walk_block(this, &this.thir()[*block])
545 });
546 }
547 }
548 }
549 return;
550 }
551 ExprKind::Adt(box AdtExpr {
552 adt_def,
553 variant_index,
554 args: _,
555 user_ty: _,
556 fields: _,
557 base: _,
558 }) => {
559 if adt_def.variant(variant_index).has_unsafe_fields() {
560 self.requires_unsafe(expr.span, InitializingTypeWithUnsafeField)
561 }
562 }
563 ExprKind::Closure(box ClosureExpr {
564 closure_id,
565 args: _,
566 upvars: _,
567 movability: _,
568 fake_reads: _,
569 }) => {
570 self.visit_inner_body(closure_id);
571 }
572 ExprKind::ConstBlock { did, args: _ } => {
573 let def_id = did.expect_local();
574 self.visit_inner_body(def_id);
575 }
576 ExprKind::Field { lhs, variant_index, name } => {
577 let lhs = &self.thir[lhs];
578 if let ty::Adt(adt_def, _) = lhs.ty.kind() {
579 if adt_def.variant(variant_index).fields[name].safety.is_unsafe() {
580 self.requires_unsafe(expr.span, UseOfUnsafeField);
581 } else if adt_def.is_union() {
582 if let Some(assigned_ty) = self.assignment_info {
583 if assigned_ty.needs_drop(self.tcx, self.typing_env) {
584 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!(
587 self.tcx.dcx().has_errors().is_some(),
588 "union fields that need dropping should be impossible: {assigned_ty}"
589 );
590 }
591 } else {
592 self.requires_unsafe(expr.span, AccessToUnionField);
593 }
594 }
595 }
596 }
597 ExprKind::Assign { lhs, rhs } | ExprKind::AssignOp { lhs, rhs, .. } => {
598 let lhs = &self.thir[lhs];
599
600 if #[allow(non_exhaustive_omitted_patterns)] match expr.kind {
ExprKind::Assign { .. } => true,
_ => false,
}matches!(expr.kind, ExprKind::Assign { .. }) {
604 self.assignment_info = Some(lhs.ty);
605 visit::walk_expr(self, lhs);
606 self.assignment_info = None;
607 visit::walk_expr(self, &self.thir()[rhs]);
608 return; }
610 }
611 ExprKind::PlaceUnwrapUnsafeBinder { .. }
612 | ExprKind::ValueUnwrapUnsafeBinder { .. }
613 | ExprKind::WrapUnsafeBinder { .. } => {
614 self.requires_unsafe(expr.span, UnsafeBinderCast);
615 }
616 _ => {}
617 }
618 visit::walk_expr(self, expr);
619 }
620}
621
622#[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)]
623enum SafetyContext {
624 Safe,
625 BuiltinUnsafeBlock,
626 UnsafeFn,
627 UnsafeBlock { span: Span, hir_id: HirId, used: bool, nested_used_blocks: Vec<NestedUsedBlock> },
628}
629
630#[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)]
631struct NestedUsedBlock {
632 hir_id: HirId,
633 span: Span,
634}
635
636struct UnusedUnsafeWarning {
637 hir_id: HirId,
638 block_span: Span,
639 enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
640}
641
642#[derive(#[automatically_derived]
impl ::core::clone::Clone for UnsafeOpKind {
#[inline]
fn clone(&self) -> UnsafeOpKind {
match self {
UnsafeOpKind::CallToUnsafeFunction(__self_0) =>
UnsafeOpKind::CallToUnsafeFunction(::core::clone::Clone::clone(__self_0)),
UnsafeOpKind::UseOfInlineAssembly =>
UnsafeOpKind::UseOfInlineAssembly,
UnsafeOpKind::InitializingTypeWithUnsafeField =>
UnsafeOpKind::InitializingTypeWithUnsafeField,
UnsafeOpKind::UseOfMutableStatic =>
UnsafeOpKind::UseOfMutableStatic,
UnsafeOpKind::UseOfExternStatic =>
UnsafeOpKind::UseOfExternStatic,
UnsafeOpKind::UseOfUnsafeField => UnsafeOpKind::UseOfUnsafeField,
UnsafeOpKind::DerefOfRawPointer =>
UnsafeOpKind::DerefOfRawPointer,
UnsafeOpKind::AccessToUnionField =>
UnsafeOpKind::AccessToUnionField,
UnsafeOpKind::MutationOfLayoutConstrainedField =>
UnsafeOpKind::MutationOfLayoutConstrainedField,
UnsafeOpKind::BorrowOfLayoutConstrainedField =>
UnsafeOpKind::BorrowOfLayoutConstrainedField,
UnsafeOpKind::CallToFunctionWith {
function: __self_0, missing: __self_1, build_enabled: __self_2
} =>
UnsafeOpKind::CallToFunctionWith {
function: ::core::clone::Clone::clone(__self_0),
missing: ::core::clone::Clone::clone(__self_1),
build_enabled: ::core::clone::Clone::clone(__self_2),
},
UnsafeOpKind::UnsafeBinderCast => UnsafeOpKind::UnsafeBinderCast,
}
}
}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)]
643enum UnsafeOpKind {
644 CallToUnsafeFunction(Option<DefId>),
645 UseOfInlineAssembly,
646 InitializingTypeWithUnsafeField,
647 UseOfMutableStatic,
648 UseOfExternStatic,
649 UseOfUnsafeField,
650 DerefOfRawPointer,
651 AccessToUnionField,
652 MutationOfLayoutConstrainedField,
653 BorrowOfLayoutConstrainedField,
654 CallToFunctionWith {
655 function: DefId,
656 missing: Vec<Symbol>,
659 build_enabled: Vec<Symbol>,
662 },
663 UnsafeBinderCast,
664}
665
666use UnsafeOpKind::*;
667
668impl UnsafeOpKind {
669 fn emit_unsafe_op_in_unsafe_fn_lint(
670 &self,
671 tcx: TyCtxt<'_>,
672 hir_id: HirId,
673 span: Span,
674 suggest_unsafe_block: bool,
675 ) {
676 if tcx.hir_opt_delegation_sig_id(hir_id.owner.def_id).is_some() {
677 return;
680 }
681 let parent_id = tcx.hir_get_parent_item(hir_id);
682 let parent_owner = tcx.hir_owner_node(parent_id);
683 let should_suggest = parent_owner.fn_sig().is_some_and(|sig| {
684 #[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))
686 });
687 let unsafe_not_inherited_note = if should_suggest {
688 suggest_unsafe_block.then(|| {
689 let body_span = tcx.hir_body(parent_owner.body_id().unwrap()).value.span;
690 UnsafeNotInheritedLintNote {
691 signature_span: tcx.def_span(parent_id.def_id),
692 body_span,
693 }
694 })
695 } else {
696 None
697 };
698 match self {
701 CallToUnsafeFunction(Some(did)) => tcx.emit_node_span_lint(
702 UNSAFE_OP_IN_UNSAFE_FN,
703 hir_id,
704 span,
705 UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
706 span,
707 function: { let _guard = NoTrimmedGuard::new(); tcx.def_path_str(*did) }with_no_trimmed_paths!(tcx.def_path_str(*did)),
708 unsafe_not_inherited_note,
709 },
710 ),
711 CallToUnsafeFunction(None) => tcx.emit_node_span_lint(
712 UNSAFE_OP_IN_UNSAFE_FN,
713 hir_id,
714 span,
715 UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
716 span,
717 unsafe_not_inherited_note,
718 },
719 ),
720 UseOfInlineAssembly => tcx.emit_node_span_lint(
721 UNSAFE_OP_IN_UNSAFE_FN,
722 hir_id,
723 span,
724 UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
725 span,
726 unsafe_not_inherited_note,
727 },
728 ),
729 InitializingTypeWithUnsafeField => tcx.emit_node_span_lint(
730 UNSAFE_OP_IN_UNSAFE_FN,
731 hir_id,
732 span,
733 UnsafeOpInUnsafeFnInitializingTypeWithUnsafeFieldRequiresUnsafe {
734 span,
735 unsafe_not_inherited_note,
736 },
737 ),
738 UseOfMutableStatic => tcx.emit_node_span_lint(
739 UNSAFE_OP_IN_UNSAFE_FN,
740 hir_id,
741 span,
742 UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
743 span,
744 unsafe_not_inherited_note,
745 },
746 ),
747 UseOfExternStatic => tcx.emit_node_span_lint(
748 UNSAFE_OP_IN_UNSAFE_FN,
749 hir_id,
750 span,
751 UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
752 span,
753 unsafe_not_inherited_note,
754 },
755 ),
756 UseOfUnsafeField => tcx.emit_node_span_lint(
757 UNSAFE_OP_IN_UNSAFE_FN,
758 hir_id,
759 span,
760 UnsafeOpInUnsafeFnUseOfUnsafeFieldRequiresUnsafe {
761 span,
762 unsafe_not_inherited_note,
763 },
764 ),
765 DerefOfRawPointer => tcx.emit_node_span_lint(
766 UNSAFE_OP_IN_UNSAFE_FN,
767 hir_id,
768 span,
769 UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
770 span,
771 unsafe_not_inherited_note,
772 },
773 ),
774 AccessToUnionField => tcx.emit_node_span_lint(
775 UNSAFE_OP_IN_UNSAFE_FN,
776 hir_id,
777 span,
778 UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
779 span,
780 unsafe_not_inherited_note,
781 },
782 ),
783 MutationOfLayoutConstrainedField => tcx.emit_node_span_lint(
784 UNSAFE_OP_IN_UNSAFE_FN,
785 hir_id,
786 span,
787 UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
788 span,
789 unsafe_not_inherited_note,
790 },
791 ),
792 BorrowOfLayoutConstrainedField => tcx.emit_node_span_lint(
793 UNSAFE_OP_IN_UNSAFE_FN,
794 hir_id,
795 span,
796 UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
797 span,
798 unsafe_not_inherited_note,
799 },
800 ),
801 CallToFunctionWith { function, missing, build_enabled } => tcx.emit_node_span_lint(
802 UNSAFE_OP_IN_UNSAFE_FN,
803 hir_id,
804 span,
805 UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
806 span,
807 function: { let _guard = NoTrimmedGuard::new(); tcx.def_path_str(*function) }with_no_trimmed_paths!(tcx.def_path_str(*function)),
808 missing_target_features: DiagArgValue::StrListSepByAnd(
809 missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
810 ),
811 missing_target_features_count: missing.len(),
812 note: !build_enabled.is_empty(),
813 build_target_features: DiagArgValue::StrListSepByAnd(
814 build_enabled
815 .iter()
816 .map(|feature| Cow::from(feature.to_string()))
817 .collect(),
818 ),
819 build_target_features_count: build_enabled.len(),
820 unsafe_not_inherited_note,
821 },
822 ),
823 UnsafeBinderCast => tcx.emit_node_span_lint(
824 UNSAFE_OP_IN_UNSAFE_FN,
825 hir_id,
826 span,
827 UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe {
828 span,
829 unsafe_not_inherited_note,
830 },
831 ),
832 }
833 }
834
835 fn emit_requires_unsafe_err(
836 &self,
837 tcx: TyCtxt<'_>,
838 span: Span,
839 hir_context: HirId,
840 unsafe_op_in_unsafe_fn_allowed: bool,
841 ) {
842 let note_non_inherited = tcx.hir_parent_iter(hir_context).find(|(id, node)| {
843 if let hir::Node::Expr(block) = node
844 && let hir::ExprKind::Block(block, _) = block.kind
845 && let hir::BlockCheckMode::UnsafeBlock(_) = block.rules
846 {
847 true
848 } else if let Some(sig) = tcx.hir_fn_sig_by_hir_id(*id)
849 && #[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))
850 {
851 true
852 } else {
853 false
854 }
855 });
856 let unsafe_not_inherited_note = if let Some((id, _)) = note_non_inherited {
857 let span = tcx.hir_span(id);
858 let span = tcx.sess.source_map().guess_head_span(span);
859 Some(UnsafeNotInheritedNote { span })
860 } else {
861 None
862 };
863
864 let dcx = tcx.dcx();
865 match self {
866 CallToUnsafeFunction(Some(did)) if unsafe_op_in_unsafe_fn_allowed => {
867 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
868 span,
869 unsafe_not_inherited_note,
870 function: tcx.def_path_str(*did),
871 });
872 }
873 CallToUnsafeFunction(Some(did)) => {
874 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafe {
875 span,
876 unsafe_not_inherited_note,
877 function: tcx.def_path_str(*did),
878 });
879 }
880 CallToUnsafeFunction(None) if unsafe_op_in_unsafe_fn_allowed => {
881 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
882 span,
883 unsafe_not_inherited_note,
884 });
885 }
886 CallToUnsafeFunction(None) => {
887 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless {
888 span,
889 unsafe_not_inherited_note,
890 });
891 }
892 UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
893 dcx.emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
894 span,
895 unsafe_not_inherited_note,
896 });
897 }
898 UseOfInlineAssembly => {
899 dcx.emit_err(UseOfInlineAssemblyRequiresUnsafe { span, unsafe_not_inherited_note });
900 }
901 InitializingTypeWithUnsafeField if unsafe_op_in_unsafe_fn_allowed => {
902 dcx.emit_err(
903 InitializingTypeWithUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
904 span,
905 unsafe_not_inherited_note,
906 },
907 );
908 }
909 InitializingTypeWithUnsafeField => {
910 dcx.emit_err(InitializingTypeWithUnsafeFieldRequiresUnsafe {
911 span,
912 unsafe_not_inherited_note,
913 });
914 }
915 UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
916 dcx.emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
917 span,
918 unsafe_not_inherited_note,
919 });
920 }
921 UseOfMutableStatic => {
922 dcx.emit_err(UseOfMutableStaticRequiresUnsafe { span, unsafe_not_inherited_note });
923 }
924 UseOfExternStatic if unsafe_op_in_unsafe_fn_allowed => {
925 dcx.emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
926 span,
927 unsafe_not_inherited_note,
928 });
929 }
930 UseOfExternStatic => {
931 dcx.emit_err(UseOfExternStaticRequiresUnsafe { span, unsafe_not_inherited_note });
932 }
933 UseOfUnsafeField if unsafe_op_in_unsafe_fn_allowed => {
934 dcx.emit_err(UseOfUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
935 span,
936 unsafe_not_inherited_note,
937 });
938 }
939 UseOfUnsafeField => {
940 dcx.emit_err(UseOfUnsafeFieldRequiresUnsafe { span, unsafe_not_inherited_note });
941 }
942 DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => {
943 dcx.emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
944 span,
945 unsafe_not_inherited_note,
946 });
947 }
948 DerefOfRawPointer => {
949 dcx.emit_err(DerefOfRawPointerRequiresUnsafe { span, unsafe_not_inherited_note });
950 }
951 AccessToUnionField if unsafe_op_in_unsafe_fn_allowed => {
952 dcx.emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
953 span,
954 unsafe_not_inherited_note,
955 });
956 }
957 AccessToUnionField => {
958 dcx.emit_err(AccessToUnionFieldRequiresUnsafe { span, unsafe_not_inherited_note });
959 }
960 MutationOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
961 dcx.emit_err(
962 MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
963 span,
964 unsafe_not_inherited_note,
965 },
966 );
967 }
968 MutationOfLayoutConstrainedField => {
969 dcx.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe {
970 span,
971 unsafe_not_inherited_note,
972 });
973 }
974 BorrowOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
975 dcx.emit_err(
976 BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
977 span,
978 unsafe_not_inherited_note,
979 },
980 );
981 }
982 BorrowOfLayoutConstrainedField => {
983 dcx.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe {
984 span,
985 unsafe_not_inherited_note,
986 });
987 }
988 CallToFunctionWith { function, missing, build_enabled }
989 if unsafe_op_in_unsafe_fn_allowed =>
990 {
991 dcx.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
992 span,
993 missing_target_features: DiagArgValue::StrListSepByAnd(
994 missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
995 ),
996 missing_target_features_count: missing.len(),
997 note: !build_enabled.is_empty(),
998 build_target_features: DiagArgValue::StrListSepByAnd(
999 build_enabled
1000 .iter()
1001 .map(|feature| Cow::from(feature.to_string()))
1002 .collect(),
1003 ),
1004 build_target_features_count: build_enabled.len(),
1005 unsafe_not_inherited_note,
1006 function: tcx.def_path_str(*function),
1007 });
1008 }
1009 CallToFunctionWith { function, missing, build_enabled } => {
1010 dcx.emit_err(CallToFunctionWithRequiresUnsafe {
1011 span,
1012 missing_target_features: DiagArgValue::StrListSepByAnd(
1013 missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
1014 ),
1015 missing_target_features_count: missing.len(),
1016 note: !build_enabled.is_empty(),
1017 build_target_features: DiagArgValue::StrListSepByAnd(
1018 build_enabled
1019 .iter()
1020 .map(|feature| Cow::from(feature.to_string()))
1021 .collect(),
1022 ),
1023 build_target_features_count: build_enabled.len(),
1024 unsafe_not_inherited_note,
1025 function: tcx.def_path_str(*function),
1026 });
1027 }
1028 UnsafeBinderCast if unsafe_op_in_unsafe_fn_allowed => {
1029 dcx.emit_err(UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1030 span,
1031 unsafe_not_inherited_note,
1032 });
1033 }
1034 UnsafeBinderCast => {
1035 dcx.emit_err(UnsafeBinderCastRequiresUnsafe { span, unsafe_not_inherited_note });
1036 }
1037 }
1038 }
1039}
1040
1041pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
1042 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()));
1044 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() {
1046 return;
1047 }
1048
1049 let Ok((thir, expr)) = tcx.thir_body(def) else { return };
1050 tcx.ensure_done().mir_built(def);
1052 let thir = if tcx.sess.opts.unstable_opts.no_steal_thir {
1053 &thir.borrow()
1054 } else {
1055 &thir.steal()
1057 };
1058
1059 let hir_id = tcx.local_def_id_to_hir_id(def);
1060 let safety_context = tcx.hir_fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
1061 match fn_sig.header.safety {
1062 hir::HeaderSafety::SafeTargetFeatures => SafetyContext::Safe,
1066 hir::HeaderSafety::Normal(safety) => match safety {
1067 hir::Safety::Unsafe => SafetyContext::UnsafeFn,
1068 hir::Safety::Safe => SafetyContext::Safe,
1069 },
1070 }
1071 });
1072 let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
1073 let mut warnings = Vec::new();
1074 let mut visitor = UnsafetyVisitor {
1075 tcx,
1076 thir,
1077 safety_context,
1078 hir_context: hir_id,
1079 body_target_features,
1080 assignment_info: None,
1081 in_union_destructure: false,
1082 typing_env: ty::TypingEnv::non_body_analysis(tcx, def),
1084 inside_adt: false,
1085 warnings: &mut warnings,
1086 suggest_unsafe_block: true,
1087 };
1088 for param in &thir.params {
1090 if let Some(param_pat) = param.pat.as_deref() {
1091 visitor.visit_pat(param_pat);
1092 }
1093 }
1094 visitor.visit_expr(&thir[expr]);
1096
1097 warnings.sort_by_key(|w| w.block_span);
1098 for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings {
1099 let block_span = tcx.sess.source_map().guess_head_span(block_span);
1100 tcx.emit_node_span_lint(
1101 UNUSED_UNSAFE,
1102 hir_id,
1103 block_span,
1104 UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
1105 );
1106 }
1107}