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