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_middle::middle::codegen_fn_attrs::{TargetFeature, TargetFeatureKind};
10use rustc_middle::span_bug;
11use rustc_middle::thir::visit::Visitor;
12use rustc_middle::thir::*;
13use rustc_middle::ty::print::with_no_trimmed_paths;
14use rustc_middle::ty::{self, Ty, TyCtxt};
15use rustc_session::lint::builtin::{DEPRECATED_SAFE_2024, UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
16use rustc_span::def_id::{DefId, LocalDefId};
17use rustc_span::{Span, Symbol};
18
19use crate::diagnostics::*;
20
21struct UnsafetyVisitor<'a, 'tcx> {
22 tcx: TyCtxt<'tcx>,
23 thir: &'a Thir<'tcx>,
24 hir_context: HirId,
27 safety_context: SafetyContext,
30 body_target_features: &'tcx [TargetFeature],
33 assignment_info: Option<Ty<'tcx>>,
36 in_union_destructure: bool,
37 typing_env: ty::TypingEnv<'tcx>,
38 inside_adt: bool,
39 warnings: &'a mut Vec<UnusedUnsafeWarning>,
40
41 suggest_unsafe_block: bool,
44}
45
46impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
47 fn in_safety_context(&mut self, safety_context: SafetyContext, f: impl FnOnce(&mut Self)) {
48 let prev_context = mem::replace(&mut self.safety_context, safety_context);
49
50 f(self);
51
52 let safety_context = mem::replace(&mut self.safety_context, prev_context);
53 if let SafetyContext::UnsafeBlock { used, span, hir_id, nested_used_blocks } =
54 safety_context
55 {
56 if !used {
57 self.warn_unused_unsafe(hir_id, span, None);
58
59 if let SafetyContext::UnsafeBlock {
60 nested_used_blocks: ref mut prev_nested_used_blocks,
61 ..
62 } = self.safety_context
63 {
64 prev_nested_used_blocks.extend(nested_used_blocks);
65 }
66 } else {
67 for block in nested_used_blocks {
68 self.warn_unused_unsafe(
69 block.hir_id,
70 block.span,
71 Some(UnusedUnsafeEnclosing::Block {
72 span: self.tcx.sess.source_map().guess_head_span(span),
73 }),
74 );
75 }
76
77 match self.safety_context {
78 SafetyContext::UnsafeBlock {
79 nested_used_blocks: ref mut prev_nested_used_blocks,
80 ..
81 } => {
82 prev_nested_used_blocks.push(NestedUsedBlock { hir_id, span });
83 }
84 _ => (),
85 }
86 }
87 }
88 }
89
90 fn emit_deprecated_safe_fn_call(&self, span: Span, kind: &UnsafeOpKind) -> bool {
91 match kind {
92 &UnsafeOpKind::CallToUnsafeFunction(Some(id))
95 if !span.at_least_rust_2024()
96 && 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) =>
97 {
98 let sm = self.tcx.sess.source_map();
99 let guarantee = ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("that {0}", suggestion))
})format!("that {}", suggestion);
100 let suggestion = sm
101 .indentation_before(span)
102 .map(|indent| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}// FIXME: Audit that {1}.\n",
indent, suggestion))
})format!("{}// FIXME: Audit that {}.\n", indent, suggestion))
103 .unwrap_or_default();
104
105 self.tcx.emit_node_span_lint(
106 DEPRECATED_SAFE_2024,
107 self.hir_context,
108 span,
109 CallToDeprecatedSafeFnRequiresUnsafe {
110 span,
111 function: { let _guard = NoTrimmedGuard::new(); self.tcx.def_path_str(id) }with_no_trimmed_paths!(self.tcx.def_path_str(id)),
112 sub: CallToDeprecatedSafeFnRequiresUnsafeSub {
113 start_of_line_suggestion: suggestion,
114 start_of_line: sm.span_extend_to_line(span).shrink_to_lo(),
115 left: span.shrink_to_lo(),
116 right: span.shrink_to_hi(),
117 guarantee,
118 },
119 },
120 );
121 true
122 }
123 _ => false,
124 }
125 }
126
127 fn requires_unsafe(&mut self, span: Span, kind: UnsafeOpKind) {
128 let unsafe_op_in_unsafe_fn_allowed = self.unsafe_op_in_unsafe_fn_allowed();
129 match self.safety_context {
130 SafetyContext::BuiltinUnsafeBlock => {}
131 SafetyContext::UnsafeBlock { ref mut used, .. } => {
132 *used = true;
137 }
138 SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {}
139 SafetyContext::UnsafeFn => {
140 let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind);
141 if !deprecated_safe_fn {
142 kind.emit_unsafe_op_in_unsafe_fn_lint(
144 self.tcx,
145 self.hir_context,
146 span,
147 self.suggest_unsafe_block,
148 );
149 self.suggest_unsafe_block = false;
150 }
151 }
152 SafetyContext::Safe => {
153 let deprecated_safe_fn = self.emit_deprecated_safe_fn_call(span, &kind);
154 if !deprecated_safe_fn {
155 kind.emit_requires_unsafe_err(
156 self.tcx,
157 span,
158 self.hir_context,
159 unsafe_op_in_unsafe_fn_allowed,
160 );
161 }
162 }
163 }
164 }
165
166 fn warn_unused_unsafe(
167 &mut self,
168 hir_id: HirId,
169 block_span: Span,
170 enclosing_unsafe: Option<UnusedUnsafeEnclosing>,
171 ) {
172 self.warnings.push(UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe });
173 }
174
175 fn unsafe_op_in_unsafe_fn_allowed(&self) -> bool {
177 self.tcx.lint_level_spec_at_node(UNSAFE_OP_IN_UNSAFE_FN, self.hir_context).is_allow()
178 }
179
180 fn visit_inner_body(&mut self, def: LocalDefId) {
182 if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
183 self.tcx.ensure_done().mir_built(def);
185 let inner_thir = if self.tcx.sess.opts.unstable_opts.no_steal_thir {
186 &inner_thir.borrow()
187 } else {
188 &inner_thir.steal()
190 };
191 let hir_context = self.tcx.local_def_id_to_hir_id(def);
192 let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe);
193 let mut inner_visitor = UnsafetyVisitor {
194 tcx: self.tcx,
195 thir: inner_thir,
196 hir_context,
197 safety_context,
198 body_target_features: self.body_target_features,
199 assignment_info: self.assignment_info,
200 in_union_destructure: false,
201 typing_env: self.typing_env,
202 inside_adt: false,
203 warnings: self.warnings,
204 suggest_unsafe_block: self.suggest_unsafe_block,
205 };
206 for param in &inner_thir.params {
208 if let Some(param_pat) = param.pat.as_deref() {
209 inner_visitor.visit_pat(param_pat);
210 }
211 }
212 inner_visitor.visit_expr(&inner_thir[expr]);
214 self.safety_context = inner_visitor.safety_context;
216 }
217 }
218}
219
220impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
221 fn thir(&self) -> &'a Thir<'tcx> {
222 self.thir
223 }
224
225 fn visit_block(&mut self, block: &'a Block) {
226 match block.safety_mode {
227 BlockSafety::BuiltinUnsafe => {
230 self.in_safety_context(SafetyContext::BuiltinUnsafeBlock, |this| {
231 visit::walk_block(this, block)
232 });
233 }
234 BlockSafety::ExplicitUnsafe(hir_id) => {
235 let used = self.tcx.lint_level_spec_at_node(UNUSED_UNSAFE, hir_id).is_allow();
236 self.in_safety_context(
237 SafetyContext::UnsafeBlock {
238 span: block.span,
239 hir_id,
240 used,
241 nested_used_blocks: Vec::new(),
242 },
243 |this| visit::walk_block(this, block),
244 );
245 }
246 BlockSafety::Safe => {
247 visit::walk_block(self, block);
248 }
249 }
250 }
251
252 fn visit_pat(&mut self, pat: &'a Pat<'tcx>) {
253 if self.in_union_destructure {
254 match pat.kind {
255 PatKind::Missing => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
256 PatKind::Binding { .. }
258 | PatKind::Constant { .. }
260 | PatKind::Variant { .. }
261 | PatKind::Leaf { .. }
262 | PatKind::Deref { .. }
263 | PatKind::DerefPattern { .. }
264 | PatKind::Range { .. }
265 | PatKind::Slice { .. }
266 | PatKind::Array { .. }
267 | PatKind::Guard { .. }
268 | PatKind::Never => {
270 self.requires_unsafe(pat.span, AccessToUnionField);
271 return; }
273 PatKind::Wild |
275 PatKind::Or { .. } |
277 PatKind::Error(_) => {}
278 }
279 };
280
281 match &pat.kind {
282 PatKind::Leaf { subpatterns, .. } => {
283 if let ty::Adt(adt_def, ..) = pat.ty.kind() {
284 for pat in subpatterns {
285 if adt_def.non_enum_variant().fields[pat.field].safety.is_unsafe() {
286 self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
287 }
288 }
289 if adt_def.is_union() {
290 let old_in_union_destructure =
291 std::mem::replace(&mut self.in_union_destructure, true);
292 visit::walk_pat(self, pat);
293 self.in_union_destructure = old_in_union_destructure;
294 } else {
295 visit::walk_pat(self, pat);
296 }
297 } else {
298 visit::walk_pat(self, pat);
299 }
300 }
301 PatKind::Variant { adt_def, args: _, variant_index, subpatterns } => {
302 for pat in subpatterns {
303 let field = &pat.field;
304 if adt_def.variant(*variant_index).fields[*field].safety.is_unsafe() {
305 self.requires_unsafe(pat.pattern.span, UseOfUnsafeField);
306 }
307 }
308 visit::walk_pat(self, pat);
309 }
310 PatKind::Binding { mode: BindingMode(ByRef::Yes(_, rm), _), ty, .. } => {
311 if self.inside_adt {
312 let ty::Ref(_, ty, _) = ty.kind() else {
313 ::rustc_middle::util::bug::span_bug_fmt(pat.span,
format_args!("ByRef::Yes in pattern, but found non-reference type {0}",
ty));span_bug!(
314 pat.span,
315 "ByRef::Yes in pattern, but found non-reference type {}",
316 ty
317 );
318 };
319 match rm {
320 Mutability::Not => {
321 if !ty.is_freeze(self.tcx, self.typing_env) {
322 self.requires_unsafe(pat.span, BorrowOfLayoutConstrainedField);
323 }
324 }
325 Mutability::Mut { .. } => {
326 self.requires_unsafe(pat.span, MutationOfLayoutConstrainedField);
327 }
328 }
329 }
330 visit::walk_pat(self, pat);
331 }
332 PatKind::Deref { .. } | PatKind::DerefPattern { .. } => {
333 let old_inside_adt = std::mem::replace(&mut self.inside_adt, false);
334 visit::walk_pat(self, pat);
335 self.inside_adt = old_inside_adt;
336 }
337 _ => {
338 visit::walk_pat(self, pat);
339 }
340 }
341 }
342
343 fn visit_expr(&mut self, expr: &'a Expr<'tcx>) {
344 match expr.kind {
346 ExprKind::Field { .. }
347 | ExprKind::VarRef { .. }
348 | ExprKind::UpvarRef { .. }
349 | ExprKind::Scope { .. }
350 | ExprKind::Cast { .. } => {}
351
352 ExprKind::RawBorrow { .. }
353 | ExprKind::Adt { .. }
354 | ExprKind::Array { .. }
355 | ExprKind::Binary { .. }
356 | ExprKind::Block { .. }
357 | ExprKind::Borrow { .. }
358 | ExprKind::Literal { .. }
359 | ExprKind::NamedConst { .. }
360 | ExprKind::NonHirLiteral { .. }
361 | ExprKind::ZstLiteral { .. }
362 | ExprKind::ConstParam { .. }
363 | ExprKind::ConstBlock { .. }
364 | ExprKind::Deref { .. }
365 | ExprKind::Index { .. }
366 | ExprKind::NeverToAny { .. }
367 | ExprKind::PlaceTypeAscription { .. }
368 | ExprKind::ValueTypeAscription { .. }
369 | ExprKind::PlaceUnwrapUnsafeBinder { .. }
370 | ExprKind::ValueUnwrapUnsafeBinder { .. }
371 | ExprKind::WrapUnsafeBinder { .. }
372 | ExprKind::PointerCoercion { .. }
373 | ExprKind::Repeat { .. }
374 | ExprKind::StaticRef { .. }
375 | ExprKind::ThreadLocalRef { .. }
376 | ExprKind::Tuple { .. }
377 | ExprKind::Unary { .. }
378 | ExprKind::Call { .. }
379 | ExprKind::ByUse { .. }
380 | ExprKind::Assign { .. }
381 | ExprKind::AssignOp { .. }
382 | ExprKind::Break { .. }
383 | ExprKind::Closure { .. }
384 | ExprKind::Continue { .. }
385 | ExprKind::ConstContinue { .. }
386 | ExprKind::Return { .. }
387 | ExprKind::Become { .. }
388 | ExprKind::Yield { .. }
389 | ExprKind::Loop { .. }
390 | ExprKind::LoopMatch { .. }
391 | ExprKind::Let { .. }
392 | ExprKind::Match { .. }
393 | ExprKind::If { .. }
394 | ExprKind::InlineAsm { .. }
395 | ExprKind::LogicalOp { .. }
396 | ExprKind::Use { .. }
397 | ExprKind::Reborrow { .. } => {
398 self.assignment_info = None;
402 }
403 };
404 match expr.kind {
405 ExprKind::Scope { value, hir_id, region_scope: _ } => {
406 let prev_id = self.hir_context;
407 self.hir_context = hir_id;
408 self.visit_expr(&self.thir[value]);
409 self.hir_context = prev_id;
410 return; }
412 ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => {
413 let fn_ty = self.thir[fun].ty;
414 let sig = fn_ty.fn_sig(self.tcx);
415 let (callee_features, safe_target_features): (&[_], _) = match *fn_ty.kind() {
416 ty::FnDef(func_id, ..) => {
417 let cg_attrs = self.tcx.codegen_fn_attrs(func_id);
418 (&cg_attrs.target_features, cg_attrs.safe_target_features)
419 }
420 _ => (&[], false),
421 };
422 if sig.safety().is_unsafe() && !safe_target_features {
423 let func_id = if let ty::FnDef(func_id, _) = fn_ty.kind() {
424 Some(*func_id)
425 } else {
426 None
427 };
428 self.requires_unsafe(expr.span, CallToUnsafeFunction(func_id));
429 } else if let &ty::FnDef(func_did, _) = fn_ty.kind() {
430 if !self
431 .tcx
432 .is_target_feature_call_safe(callee_features, self.body_target_features)
433 {
434 let missing: Vec<_> = callee_features
435 .iter()
436 .copied()
437 .filter(|feature| {
438 feature.kind == TargetFeatureKind::Enabled
439 && !self
440 .body_target_features
441 .iter()
442 .any(|body_feature| body_feature.name == feature.name)
443 })
444 .map(|feature| feature.name)
445 .collect();
446 let build_enabled = self
447 .tcx
448 .sess
449 .internal_target_features
450 .iter()
451 .copied()
452 .filter(|feature| missing.contains(feature))
453 .collect();
454 self.requires_unsafe(
455 expr.span,
456 CallToFunctionWith { function: func_did, missing, build_enabled },
457 );
458 }
459 if let Some(trait_did) = self.tcx.trait_of_assoc(func_did)
460 && self.tcx.is_lang_item(trait_did, LangItem::Drop)
461 {
462 self.requires_unsafe(expr.span, CallDropExplicitly(func_did));
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(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(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(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,
UnsafeOpKind::CallDropExplicitly(__self_0) =>
UnsafeOpKind::CallDropExplicitly(::core::clone::Clone::clone(__self_0)),
}
}
}Clone, #[automatically_derived]
impl ::core::cmp::PartialEq for UnsafeOpKind {
#[inline]
fn eq(&self, other: &UnsafeOpKind) -> bool {
let __self_discr = ::core::intrinsics::discriminant_value(self);
let __arg1_discr = ::core::intrinsics::discriminant_value(other);
__self_discr == __arg1_discr &&
match (self, other) {
(UnsafeOpKind::CallToUnsafeFunction(__self_0),
UnsafeOpKind::CallToUnsafeFunction(__arg1_0)) =>
__self_0 == __arg1_0,
(UnsafeOpKind::CallToFunctionWith {
function: __self_0,
missing: __self_1,
build_enabled: __self_2 },
UnsafeOpKind::CallToFunctionWith {
function: __arg1_0,
missing: __arg1_1,
build_enabled: __arg1_2 }) =>
__self_0 == __arg1_0 && __self_1 == __arg1_1 &&
__self_2 == __arg1_2,
(UnsafeOpKind::CallDropExplicitly(__self_0),
UnsafeOpKind::CallDropExplicitly(__arg1_0)) =>
__self_0 == __arg1_0,
_ => true,
}
}
}PartialEq)]
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 CallDropExplicitly(DefId),
666}
667
668use UnsafeOpKind::*;
669
670impl UnsafeOpKind {
671 fn emit_unsafe_op_in_unsafe_fn_lint(
672 &self,
673 tcx: TyCtxt<'_>,
674 hir_id: HirId,
675 span: Span,
676 suggest_unsafe_block: bool,
677 ) {
678 if tcx.hir_opt_delegation_sig_id(hir_id.owner.def_id).is_some() {
679 return;
682 }
683 let parent_id = tcx.hir_get_parent_item(hir_id);
684 let parent_owner = tcx.hir_owner_node(parent_id);
685 let should_suggest = parent_owner.fn_sig().is_some_and(|sig| {
686 #[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))
688 });
689 let unsafe_not_inherited_note = if should_suggest {
690 suggest_unsafe_block.then(|| {
691 let body_span = tcx.hir_body(parent_owner.body_id().unwrap()).value.span;
692 UnsafeNotInheritedLintNote {
693 signature_span: tcx.def_span(parent_id.def_id),
694 body_span,
695 }
696 })
697 } else {
698 None
699 };
700 match self {
703 CallToUnsafeFunction(Some(did)) => tcx.emit_node_span_lint(
704 UNSAFE_OP_IN_UNSAFE_FN,
705 hir_id,
706 span,
707 UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafe {
708 span,
709 function: { let _guard = NoTrimmedGuard::new(); tcx.def_path_str(*did) }with_no_trimmed_paths!(tcx.def_path_str(*did)),
710 unsafe_not_inherited_note,
711 },
712 ),
713 CallToUnsafeFunction(None) => tcx.emit_node_span_lint(
714 UNSAFE_OP_IN_UNSAFE_FN,
715 hir_id,
716 span,
717 UnsafeOpInUnsafeFnCallToUnsafeFunctionRequiresUnsafeNameless {
718 span,
719 unsafe_not_inherited_note,
720 },
721 ),
722 UseOfInlineAssembly => tcx.emit_node_span_lint(
723 UNSAFE_OP_IN_UNSAFE_FN,
724 hir_id,
725 span,
726 UnsafeOpInUnsafeFnUseOfInlineAssemblyRequiresUnsafe {
727 span,
728 unsafe_not_inherited_note,
729 },
730 ),
731 InitializingTypeWithUnsafeField => tcx.emit_node_span_lint(
732 UNSAFE_OP_IN_UNSAFE_FN,
733 hir_id,
734 span,
735 UnsafeOpInUnsafeFnInitializingTypeWithUnsafeFieldRequiresUnsafe {
736 span,
737 unsafe_not_inherited_note,
738 },
739 ),
740 UseOfMutableStatic => tcx.emit_node_span_lint(
741 UNSAFE_OP_IN_UNSAFE_FN,
742 hir_id,
743 span,
744 UnsafeOpInUnsafeFnUseOfMutableStaticRequiresUnsafe {
745 span,
746 unsafe_not_inherited_note,
747 },
748 ),
749 UseOfExternStatic => tcx.emit_node_span_lint(
750 UNSAFE_OP_IN_UNSAFE_FN,
751 hir_id,
752 span,
753 UnsafeOpInUnsafeFnUseOfExternStaticRequiresUnsafe {
754 span,
755 unsafe_not_inherited_note,
756 },
757 ),
758 UseOfUnsafeField => tcx.emit_node_span_lint(
759 UNSAFE_OP_IN_UNSAFE_FN,
760 hir_id,
761 span,
762 UnsafeOpInUnsafeFnUseOfUnsafeFieldRequiresUnsafe {
763 span,
764 unsafe_not_inherited_note,
765 },
766 ),
767 DerefOfRawPointer => tcx.emit_node_span_lint(
768 UNSAFE_OP_IN_UNSAFE_FN,
769 hir_id,
770 span,
771 UnsafeOpInUnsafeFnDerefOfRawPointerRequiresUnsafe {
772 span,
773 unsafe_not_inherited_note,
774 },
775 ),
776 AccessToUnionField => tcx.emit_node_span_lint(
777 UNSAFE_OP_IN_UNSAFE_FN,
778 hir_id,
779 span,
780 UnsafeOpInUnsafeFnAccessToUnionFieldRequiresUnsafe {
781 span,
782 unsafe_not_inherited_note,
783 },
784 ),
785 MutationOfLayoutConstrainedField => tcx.emit_node_span_lint(
786 UNSAFE_OP_IN_UNSAFE_FN,
787 hir_id,
788 span,
789 UnsafeOpInUnsafeFnMutationOfLayoutConstrainedFieldRequiresUnsafe {
790 span,
791 unsafe_not_inherited_note,
792 },
793 ),
794 BorrowOfLayoutConstrainedField => tcx.emit_node_span_lint(
795 UNSAFE_OP_IN_UNSAFE_FN,
796 hir_id,
797 span,
798 UnsafeOpInUnsafeFnBorrowOfLayoutConstrainedFieldRequiresUnsafe {
799 span,
800 unsafe_not_inherited_note,
801 },
802 ),
803 CallToFunctionWith { function, missing, build_enabled } => tcx.emit_node_span_lint(
804 UNSAFE_OP_IN_UNSAFE_FN,
805 hir_id,
806 span,
807 UnsafeOpInUnsafeFnCallToFunctionWithRequiresUnsafe {
808 span,
809 function: { let _guard = NoTrimmedGuard::new(); tcx.def_path_str(*function) }with_no_trimmed_paths!(tcx.def_path_str(*function)),
810 missing_target_features: DiagArgValue::StrListSepByAnd(
811 missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
812 ),
813 missing_target_features_count: missing.len(),
814 note: !build_enabled.is_empty(),
815 build_target_features: DiagArgValue::StrListSepByAnd(
816 build_enabled
817 .iter()
818 .map(|feature| Cow::from(feature.to_string()))
819 .collect(),
820 ),
821 build_target_features_count: build_enabled.len(),
822 unsafe_not_inherited_note,
823 },
824 ),
825 UnsafeBinderCast => tcx.emit_node_span_lint(
826 UNSAFE_OP_IN_UNSAFE_FN,
827 hir_id,
828 span,
829 UnsafeOpInUnsafeFnUnsafeBinderCastRequiresUnsafe {
830 span,
831 unsafe_not_inherited_note,
832 },
833 ),
834 CallDropExplicitly(_) => {
835 ::rustc_middle::util::bug::span_bug_fmt(span,
format_args!("`Drop::drop` or `Drop::pin_drop` should not be called explicitly"))span_bug!(span, "`Drop::drop` or `Drop::pin_drop` should not be called explicitly")
836 }
837 }
838 }
839
840 fn emit_requires_unsafe_err(
841 &self,
842 tcx: TyCtxt<'_>,
843 span: Span,
844 hir_context: HirId,
845 unsafe_op_in_unsafe_fn_allowed: bool,
846 ) {
847 let note_non_inherited = tcx.hir_parent_iter(hir_context).find(|(id, node)| {
848 if let hir::Node::Expr(block) = node
849 && let hir::ExprKind::Block(block, _) = block.kind
850 && let hir::BlockCheckMode::UnsafeBlock(_) = block.rules
851 {
852 true
853 } else if let Some(sig) = tcx.hir_fn_sig_by_hir_id(*id)
854 && #[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))
855 {
856 true
857 } else {
858 false
859 }
860 });
861 let unsafe_not_inherited_note = if let Some((id, _)) = note_non_inherited {
862 let span = tcx.hir_span(id);
863 let span = tcx.sess.source_map().guess_head_span(span);
864 Some(UnsafeNotInheritedNote { span })
865 } else {
866 None
867 };
868
869 let dcx = tcx.dcx();
870 match self {
871 CallToUnsafeFunction(Some(did)) if unsafe_op_in_unsafe_fn_allowed => {
872 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
873 span,
874 unsafe_not_inherited_note,
875 function: tcx.def_path_str(*did),
876 });
877 }
878 CallToUnsafeFunction(Some(did)) => {
879 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafe {
880 span,
881 unsafe_not_inherited_note,
882 function: tcx.def_path_str(*did),
883 });
884 }
885 CallToUnsafeFunction(None) if unsafe_op_in_unsafe_fn_allowed => {
886 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeNamelessUnsafeOpInUnsafeFnAllowed {
887 span,
888 unsafe_not_inherited_note,
889 });
890 }
891 CallToUnsafeFunction(None) => {
892 dcx.emit_err(CallToUnsafeFunctionRequiresUnsafeNameless {
893 span,
894 unsafe_not_inherited_note,
895 });
896 }
897 UseOfInlineAssembly if unsafe_op_in_unsafe_fn_allowed => {
898 dcx.emit_err(UseOfInlineAssemblyRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
899 span,
900 unsafe_not_inherited_note,
901 });
902 }
903 UseOfInlineAssembly => {
904 dcx.emit_err(UseOfInlineAssemblyRequiresUnsafe { span, unsafe_not_inherited_note });
905 }
906 InitializingTypeWithUnsafeField if unsafe_op_in_unsafe_fn_allowed => {
907 dcx.emit_err(
908 InitializingTypeWithUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
909 span,
910 unsafe_not_inherited_note,
911 },
912 );
913 }
914 InitializingTypeWithUnsafeField => {
915 dcx.emit_err(InitializingTypeWithUnsafeFieldRequiresUnsafe {
916 span,
917 unsafe_not_inherited_note,
918 });
919 }
920 UseOfMutableStatic if unsafe_op_in_unsafe_fn_allowed => {
921 dcx.emit_err(UseOfMutableStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
922 span,
923 unsafe_not_inherited_note,
924 });
925 }
926 UseOfMutableStatic => {
927 dcx.emit_err(UseOfMutableStaticRequiresUnsafe { span, unsafe_not_inherited_note });
928 }
929 UseOfExternStatic if unsafe_op_in_unsafe_fn_allowed => {
930 dcx.emit_err(UseOfExternStaticRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
931 span,
932 unsafe_not_inherited_note,
933 });
934 }
935 UseOfExternStatic => {
936 dcx.emit_err(UseOfExternStaticRequiresUnsafe { span, unsafe_not_inherited_note });
937 }
938 UseOfUnsafeField if unsafe_op_in_unsafe_fn_allowed => {
939 dcx.emit_err(UseOfUnsafeFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
940 span,
941 unsafe_not_inherited_note,
942 });
943 }
944 UseOfUnsafeField => {
945 dcx.emit_err(UseOfUnsafeFieldRequiresUnsafe { span, unsafe_not_inherited_note });
946 }
947 DerefOfRawPointer if unsafe_op_in_unsafe_fn_allowed => {
948 dcx.emit_err(DerefOfRawPointerRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
949 span,
950 unsafe_not_inherited_note,
951 });
952 }
953 DerefOfRawPointer => {
954 dcx.emit_err(DerefOfRawPointerRequiresUnsafe { span, unsafe_not_inherited_note });
955 }
956 AccessToUnionField if unsafe_op_in_unsafe_fn_allowed => {
957 dcx.emit_err(AccessToUnionFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
958 span,
959 unsafe_not_inherited_note,
960 });
961 }
962 AccessToUnionField => {
963 dcx.emit_err(AccessToUnionFieldRequiresUnsafe { span, unsafe_not_inherited_note });
964 }
965 MutationOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
966 dcx.emit_err(
967 MutationOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
968 span,
969 unsafe_not_inherited_note,
970 },
971 );
972 }
973 MutationOfLayoutConstrainedField => {
974 dcx.emit_err(MutationOfLayoutConstrainedFieldRequiresUnsafe {
975 span,
976 unsafe_not_inherited_note,
977 });
978 }
979 BorrowOfLayoutConstrainedField if unsafe_op_in_unsafe_fn_allowed => {
980 dcx.emit_err(
981 BorrowOfLayoutConstrainedFieldRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
982 span,
983 unsafe_not_inherited_note,
984 },
985 );
986 }
987 BorrowOfLayoutConstrainedField => {
988 dcx.emit_err(BorrowOfLayoutConstrainedFieldRequiresUnsafe {
989 span,
990 unsafe_not_inherited_note,
991 });
992 }
993 CallToFunctionWith { function, missing, build_enabled }
994 if unsafe_op_in_unsafe_fn_allowed =>
995 {
996 dcx.emit_err(CallToFunctionWithRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
997 span,
998 missing_target_features: DiagArgValue::StrListSepByAnd(
999 missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
1000 ),
1001 missing_target_features_count: missing.len(),
1002 note: !build_enabled.is_empty(),
1003 build_target_features: DiagArgValue::StrListSepByAnd(
1004 build_enabled
1005 .iter()
1006 .map(|feature| Cow::from(feature.to_string()))
1007 .collect(),
1008 ),
1009 build_target_features_count: build_enabled.len(),
1010 unsafe_not_inherited_note,
1011 function: tcx.def_path_str(*function),
1012 });
1013 }
1014 CallToFunctionWith { function, missing, build_enabled } => {
1015 dcx.emit_err(CallToFunctionWithRequiresUnsafe {
1016 span,
1017 missing_target_features: DiagArgValue::StrListSepByAnd(
1018 missing.iter().map(|feature| Cow::from(feature.to_string())).collect(),
1019 ),
1020 missing_target_features_count: missing.len(),
1021 note: !build_enabled.is_empty(),
1022 build_target_features: DiagArgValue::StrListSepByAnd(
1023 build_enabled
1024 .iter()
1025 .map(|feature| Cow::from(feature.to_string()))
1026 .collect(),
1027 ),
1028 build_target_features_count: build_enabled.len(),
1029 unsafe_not_inherited_note,
1030 function: tcx.def_path_str(*function),
1031 });
1032 }
1033 UnsafeBinderCast if unsafe_op_in_unsafe_fn_allowed => {
1034 dcx.emit_err(UnsafeBinderCastRequiresUnsafeUnsafeOpInUnsafeFnAllowed {
1035 span,
1036 unsafe_not_inherited_note,
1037 });
1038 }
1039 UnsafeBinderCast => {
1040 dcx.emit_err(UnsafeBinderCastRequiresUnsafe { span, unsafe_not_inherited_note });
1041 }
1042 CallDropExplicitly(did) => {
1043 dcx.emit_err(CallDropExplicitlyRequiresUnsafe {
1044 span,
1045 unsafe_not_inherited_note,
1046 function: tcx.def_path_str(*did),
1047 });
1048 }
1049 }
1050 }
1051}
1052
1053pub(crate) fn check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
1054 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()));
1056 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() {
1058 return;
1059 }
1060
1061 let Ok((thir, expr)) = tcx.thir_body(def) else { return };
1062 tcx.ensure_done().mir_built(def);
1064 let thir = if tcx.sess.opts.unstable_opts.no_steal_thir {
1065 &thir.borrow()
1066 } else {
1067 &thir.steal()
1069 };
1070
1071 let hir_id = tcx.local_def_id_to_hir_id(def);
1072 let safety_context = tcx.hir_fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| {
1073 match fn_sig.header.safety {
1074 hir::HeaderSafety::SafeTargetFeatures => SafetyContext::Safe,
1078 hir::HeaderSafety::Normal(safety) => match safety {
1079 hir::Safety::Unsafe => SafetyContext::UnsafeFn,
1080 hir::Safety::Safe => SafetyContext::Safe,
1081 },
1082 }
1083 });
1084 let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
1085 let mut warnings = Vec::new();
1086 let mut visitor = UnsafetyVisitor {
1087 tcx,
1088 thir,
1089 safety_context,
1090 hir_context: hir_id,
1091 body_target_features,
1092 assignment_info: None,
1093 in_union_destructure: false,
1094 typing_env: ty::TypingEnv::post_typeck_until_borrowck_for_mir_build(tcx, def),
1095 inside_adt: false,
1096 warnings: &mut warnings,
1097 suggest_unsafe_block: true,
1098 };
1099 for param in &thir.params {
1101 if let Some(param_pat) = param.pat.as_deref() {
1102 visitor.visit_pat(param_pat);
1103 }
1104 }
1105 visitor.visit_expr(&thir[expr]);
1107
1108 warnings.sort_by_key(|w| w.block_span);
1109 for UnusedUnsafeWarning { hir_id, block_span, enclosing_unsafe } in warnings {
1110 let block_span = tcx.sess.source_map().guess_head_span(block_span);
1111 tcx.emit_node_span_lint(
1112 UNUSED_UNSAFE,
1113 hir_id,
1114 block_span,
1115 UnusedUnsafe { span: block_span, enclosing: enclosing_unsafe },
1116 );
1117 }
1118}