ide_diagnostics/handlers/
missing_unsafe.rs1use hir::db::ExpandDatabase;
2use hir::{UnsafeLint, UnsafetyReason};
3use ide_db::text_edit::TextEdit;
4use ide_db::{assists::Assist, source_change::SourceChange};
5use syntax::{AstNode, match_ast};
6use syntax::{SyntaxNode, ast};
7
8use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, fix};
9
10pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic {
14 let code = match d.lint {
15 UnsafeLint::HardError => DiagnosticCode::RustcHardError("E0133"),
16 UnsafeLint::UnsafeOpInUnsafeFn => DiagnosticCode::RustcLint("unsafe_op_in_unsafe_fn"),
17 UnsafeLint::DeprecatedSafe2024 => DiagnosticCode::RustcLint("deprecated_safe_2024"),
18 };
19 let operation = display_unsafety_reason(d.reason);
20 Diagnostic::new_with_syntax_node_ptr(
21 ctx,
22 code,
23 format!("{operation} is unsafe and requires an unsafe function or block"),
24 d.node.map(|it| it.into()),
25 )
26 .stable()
27 .with_fixes(fixes(ctx, d))
28}
29
30fn display_unsafety_reason(reason: UnsafetyReason) -> &'static str {
31 match reason {
32 UnsafetyReason::UnionField => "access to union field",
33 UnsafetyReason::UnsafeFnCall => "call to unsafe function",
34 UnsafetyReason::InlineAsm => "use of inline assembly",
35 UnsafetyReason::RawPtrDeref => "dereference of raw pointer",
36 UnsafetyReason::MutableStatic => "use of mutable static",
37 UnsafetyReason::ExternStatic => "use of extern static",
38 }
39}
40
41fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Option<Vec<Assist>> {
42 if d.node.file_id.is_macro() {
44 return None;
45 }
46
47 let root = ctx.sema.db.parse_or_expand(d.node.file_id);
48 let node = d.node.value.to_node(&root);
49 let expr = node.syntax().ancestors().find_map(ast::Expr::cast)?;
50
51 let node_to_add_unsafe_block = pick_best_node_to_add_unsafe_block(&expr)?;
52
53 let mut replacement = format!("unsafe {{ {} }}", node_to_add_unsafe_block.text());
54 if let Some(expr) = ast::Expr::cast(node_to_add_unsafe_block.clone())
55 && needs_parentheses(&expr)
56 {
57 replacement = format!("({replacement})");
58 }
59 let edit = TextEdit::replace(node_to_add_unsafe_block.text_range(), replacement);
60 let source_change = SourceChange::from_text_edit(
61 d.node.file_id.original_file(ctx.sema.db).file_id(ctx.sema.db),
62 edit,
63 );
64 Some(vec![fix("add_unsafe", "Add unsafe block", source_change, expr.syntax().text_range())])
65}
66
67fn pick_best_node_to_add_unsafe_block(unsafe_expr: &ast::Expr) -> Option<SyntaxNode> {
79 for (node, parent) in
85 unsafe_expr.syntax().ancestors().zip(unsafe_expr.syntax().ancestors().skip(1))
86 {
87 match_ast! {
88 match parent {
89 ast::MethodCallExpr(_) => continue,
95 ast::FieldExpr(_) => continue,
96 ast::RefExpr(_) => continue,
97 ast::BinExpr(it) => {
98 let is_left_hand_side_of_assignment = {
102 if let Some(ast::BinaryOp::Assignment { .. }) = it.op_kind() {
103 it.lhs().map(|lhs| lhs.syntax().text_range().contains_range(node.text_range())).unwrap_or(false)
104 } else {
105 false
106 }
107 };
108 if !is_left_hand_side_of_assignment {
109 return Some(node);
110 }
111 },
112 _ => { return Some(node); }
113
114 }
115 }
116 }
117 None
118}
119
120fn needs_parentheses(expr: &ast::Expr) -> bool {
121 let node = expr.syntax();
122 node.ancestors()
123 .skip(1)
124 .take_while(|it| it.text_range().start() == node.text_range().start())
125 .map_while(ast::Expr::cast)
126 .last()
127 .and_then(|it| Some(it.syntax().parent()?.kind()))
128 .is_some_and(|kind| ast::ExprStmt::can_cast(kind) || ast::StmtList::can_cast(kind))
129}
130
131#[cfg(test)]
132mod tests {
133 use crate::tests::{check_diagnostics, check_fix, check_no_fix};
134
135 #[test]
136 fn missing_unsafe_diagnostic_with_raw_ptr() {
137 check_diagnostics(
138 r#"
139//- minicore: sized
140fn main() {
141 let x = &5_usize as *const usize;
142 unsafe { let _y = *x; }
143 let _z = *x;
144} //^^💡 error: dereference of raw pointer is unsafe and requires an unsafe function or block
145"#,
146 )
147 }
148
149 #[test]
150 fn missing_unsafe_diagnostic_with_unsafe_call() {
151 check_diagnostics(
152 r#"
153//- minicore: sized
154struct HasUnsafe;
155
156impl HasUnsafe {
157 unsafe fn unsafe_fn(&self) {
158 let x = &5_usize as *const usize;
159 let _y = unsafe {*x};
160 }
161}
162
163unsafe fn unsafe_fn() {
164 let x = &5_usize as *const usize;
165 let _y = unsafe {*x};
166}
167
168fn main() {
169 unsafe_fn();
170 //^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
171 HasUnsafe.unsafe_fn();
172 //^^^^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
173 unsafe {
174 unsafe_fn();
175 HasUnsafe.unsafe_fn();
176 }
177}
178"#,
179 );
180 }
181
182 #[test]
183 fn missing_unsafe_diagnostic_with_static_mut() {
184 check_diagnostics(
185 r#"
186//- minicore: copy
187
188struct Ty {
189 a: u8,
190}
191
192static mut STATIC_MUT: Ty = Ty { a: 0 };
193
194fn main() {
195 let _x = STATIC_MUT.a;
196 //^^^^^^^^^^💡 error: use of mutable static is unsafe and requires an unsafe function or block
197 unsafe {
198 let _x = STATIC_MUT.a;
199 }
200}
201"#,
202 );
203 }
204
205 #[test]
206 fn missing_unsafe_diagnostic_with_extern_static() {
207 check_diagnostics(
208 r#"
209//- minicore: copy
210
211extern "C" {
212 static EXTERN: i32;
213 static mut EXTERN_MUT: i32;
214}
215
216fn main() {
217 let _x = EXTERN;
218 //^^^^^^💡 error: use of extern static is unsafe and requires an unsafe function or block
219 let _x = EXTERN_MUT;
220 //^^^^^^^^^^💡 error: use of mutable static is unsafe and requires an unsafe function or block
221 unsafe {
222 let _x = EXTERN;
223 let _x = EXTERN_MUT;
224 }
225}
226"#,
227 );
228 }
229
230 #[test]
231 fn no_unsafe_diagnostic_with_addr_of_static() {
232 check_diagnostics(
233 r#"
234//- minicore: copy, addr_of
235
236use core::ptr::{addr_of, addr_of_mut};
237
238extern "C" {
239 static EXTERN: i32;
240 static mut EXTERN_MUT: i32;
241}
242static mut STATIC_MUT: i32 = 0;
243
244fn main() {
245 let _x = addr_of!(EXTERN);
246 let _x = addr_of!(EXTERN_MUT);
247 let _x = addr_of!(STATIC_MUT);
248 let _x = addr_of_mut!(EXTERN_MUT);
249 let _x = addr_of_mut!(STATIC_MUT);
250}
251"#,
252 );
253 }
254
255 #[test]
256 fn no_missing_unsafe_diagnostic_with_safe_intrinsic() {
257 check_diagnostics(
258 r#"
259#[rustc_intrinsic]
260pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
261#[rustc_intrinsic]
262pub unsafe fn floorf32(x: f32) -> f32; // Unsafe intrinsic
263
264fn main() {
265 let _ = bitreverse(12);
266 let _ = floorf32(12.0);
267 //^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
268}
269"#,
270 );
271 }
272
273 #[test]
274 fn no_missing_unsafe_diagnostic_with_legacy_safe_intrinsic() {
275 check_diagnostics(
276 r#"
277extern "rust-intrinsic" {
278 #[rustc_safe_intrinsic]
279 pub fn bitreverse(x: u32) -> u32; // Safe intrinsic
280 pub fn floorf32(x: f32) -> f32; // Unsafe intrinsic
281}
282
283fn main() {
284 let _ = bitreverse(12);
285 let _ = floorf32(12.0);
286 //^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
287}
288"#,
289 );
290 }
291
292 #[test]
293 fn no_missing_unsafe_diagnostic_with_deprecated_safe_2024() {
294 check_diagnostics(
295 r#"
296#[rustc_deprecated_safe_2024]
297fn set_var() {}
298
299#[rustc_deprecated_safe_2024(audit_that = "something")]
300fn set_var2() {}
301
302fn main() {
303 set_var();
304 set_var2();
305}
306"#,
307 );
308 }
309
310 #[test]
311 fn add_unsafe_block_when_dereferencing_a_raw_pointer() {
312 check_fix(
313 r#"
314//- minicore: sized
315fn main() {
316 let x = &5_usize as *const usize;
317 let _z = *x$0;
318}
319"#,
320 r#"
321fn main() {
322 let x = &5_usize as *const usize;
323 let _z = unsafe { *x };
324}
325"#,
326 );
327 }
328
329 #[test]
330 fn add_unsafe_block_when_calling_unsafe_function() {
331 check_fix(
332 r#"
333//- minicore: sized
334unsafe fn func() {
335 let x = &5_usize as *const usize;
336 let z = *x;
337}
338fn main() {
339 func$0();
340}
341"#,
342 r#"
343unsafe fn func() {
344 let x = &5_usize as *const usize;
345 let z = *x;
346}
347fn main() {
348 unsafe { func() };
349}
350"#,
351 )
352 }
353
354 #[test]
355 fn add_unsafe_block_when_calling_unsafe_method() {
356 check_fix(
357 r#"
358//- minicore: sized
359struct S(usize);
360impl S {
361 unsafe fn func(&self) {
362 let x = &self.0 as *const usize;
363 let _z = unsafe { *x };
364 }
365}
366fn main() {
367 let s = S(5);
368 s.func$0();
369}
370"#,
371 r#"
372struct S(usize);
373impl S {
374 unsafe fn func(&self) {
375 let x = &self.0 as *const usize;
376 let _z = unsafe { *x };
377 }
378}
379fn main() {
380 let s = S(5);
381 unsafe { s.func() };
382}
383"#,
384 )
385 }
386
387 #[test]
388 fn add_unsafe_block_when_accessing_mutable_static() {
389 check_fix(
390 r#"
391//- minicore: copy
392struct Ty {
393 a: u8,
394}
395
396static mut STATIC_MUT: Ty = Ty { a: 0 };
397
398fn main() {
399 let _x = STATIC_MUT$0.a;
400}
401"#,
402 r#"
403struct Ty {
404 a: u8,
405}
406
407static mut STATIC_MUT: Ty = Ty { a: 0 };
408
409fn main() {
410 let _x = unsafe { STATIC_MUT.a };
411}
412"#,
413 )
414 }
415
416 #[test]
417 fn add_unsafe_block_when_calling_unsafe_intrinsic() {
418 check_fix(
419 r#"
420extern "rust-intrinsic" {
421 pub fn floorf32(x: f32) -> f32;
422}
423
424fn main() {
425 let _ = floorf32$0(12.0);
426}
427"#,
428 r#"
429extern "rust-intrinsic" {
430 pub fn floorf32(x: f32) -> f32;
431}
432
433fn main() {
434 let _ = unsafe { floorf32(12.0) };
435}
436"#,
437 )
438 }
439
440 #[test]
441 fn unsafe_expr_as_a_receiver_of_a_method_call() {
442 check_fix(
443 r#"
444unsafe fn foo() -> String {
445 "string".to_string()
446}
447
448fn main() {
449 foo$0().len();
450}
451"#,
452 r#"
453unsafe fn foo() -> String {
454 "string".to_string()
455}
456
457fn main() {
458 unsafe { foo().len() };
459}
460"#,
461 )
462 }
463
464 #[test]
465 fn raw_deref_on_union_field() {
466 check_diagnostics(
467 r#"
468fn main() {
469
470 union U {
471 a: u8
472 }
473 let x = U { a: 3 };
474
475 let a = &raw mut x.a;
476
477 union U1 {
478 a: u8
479 }
480 let x = U1 { a: 3 };
481
482 let a = x.a;
483 // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
484
485
486 let b = &raw const x.a;
487
488 let tmp = Vec::from([1, 2, 3]);
489
490 let c = &raw const tmp[x.a];
491 // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
492
493 union URef {
494 p: &'static mut i32,
495 }
496
497 fn deref_union_field(u: URef) {
498 // Not an assignment but an access to the union field!
499 *(u.p) = 13;
500 // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
501 }
502}
503"#,
504 )
505 }
506
507 #[test]
508 fn unsafe_expr_as_an_argument_of_a_method_call() {
509 check_fix(
510 r#"
511static mut STATIC_MUT: u8 = 0;
512
513fn main() {
514 let mut v = vec![];
515 v.push(STATIC_MUT$0);
516}
517"#,
518 r#"
519static mut STATIC_MUT: u8 = 0;
520
521fn main() {
522 let mut v = vec![];
523 v.push(unsafe { STATIC_MUT });
524}
525"#,
526 )
527 }
528
529 #[test]
530 fn unsafe_expr_as_left_hand_side_of_assignment() {
531 check_fix(
532 r#"
533static mut STATIC_MUT: u8 = 0;
534
535fn main() {
536 STATIC_MUT$0 = 1;
537}
538"#,
539 r#"
540static mut STATIC_MUT: u8 = 0;
541
542fn main() {
543 unsafe { STATIC_MUT = 1 };
544}
545"#,
546 )
547 }
548
549 #[test]
550 fn unsafe_expr_as_right_hand_side_of_assignment() {
551 check_fix(
552 r#"
553//- minicore: copy
554static mut STATIC_MUT: u8 = 0;
555
556fn main() {
557 let _x;
558 _x = STATIC_MUT$0;
559}
560"#,
561 r#"
562static mut STATIC_MUT: u8 = 0;
563
564fn main() {
565 let _x;
566 _x = unsafe { STATIC_MUT };
567}
568"#,
569 )
570 }
571
572 #[test]
573 fn unsafe_expr_in_binary_plus() {
574 check_fix(
575 r#"
576//- minicore: copy
577static mut STATIC_MUT: u8 = 0;
578
579fn main() {
580 let _x = STATIC_MUT$0 + 1;
581}
582"#,
583 r#"
584static mut STATIC_MUT: u8 = 0;
585
586fn main() {
587 let _x = unsafe { STATIC_MUT } + 1;
588}
589"#,
590 )
591 }
592
593 #[test]
594 fn needs_parentheses_for_unambiguous() {
595 check_fix(
596 r#"
597//- minicore: copy
598static mut STATIC_MUT: u8 = 0;
599
600fn foo() -> u8 {
601 STATIC_MUT$0 * 2
602}
603"#,
604 r#"
605static mut STATIC_MUT: u8 = 0;
606
607fn foo() -> u8 {
608 (unsafe { STATIC_MUT }) * 2
609}
610"#,
611 )
612 }
613
614 #[test]
615 fn ref_to_unsafe_expr() {
616 check_fix(
617 r#"
618static mut STATIC_MUT: u8 = 0;
619
620fn main() {
621 let _x = &STATIC_MUT$0;
622}
623"#,
624 r#"
625static mut STATIC_MUT: u8 = 0;
626
627fn main() {
628 let _x = unsafe { &STATIC_MUT };
629}
630"#,
631 )
632 }
633
634 #[test]
635 fn ref_ref_to_unsafe_expr() {
636 check_fix(
637 r#"
638static mut STATIC_MUT: u8 = 0;
639
640fn main() {
641 let _x = &&STATIC_MUT$0;
642}
643"#,
644 r#"
645static mut STATIC_MUT: u8 = 0;
646
647fn main() {
648 let _x = unsafe { &&STATIC_MUT };
649}
650"#,
651 )
652 }
653
654 #[test]
655 fn unsafe_expr_in_macro_call() {
656 check_no_fix(
657 r#"
658unsafe fn foo() -> u8 {
659 0
660}
661
662fn main() {
663 let x = format!("foo: {}", foo$0());
664}
665 "#,
666 )
667 }
668
669 #[test]
670 fn rustc_deprecated_safe_2024() {
671 check_diagnostics(
672 r#"
673//- /ed2021.rs crate:ed2021 edition:2021
674#[rustc_deprecated_safe_2024]
675unsafe fn deprecated_safe() -> u8 {
676 0
677}
678
679//- /ed2024.rs crate:ed2024 edition:2024
680#[rustc_deprecated_safe_2024]
681unsafe fn deprecated_safe() -> u8 {
682 0
683}
684
685//- /dep1.rs crate:dep1 deps:ed2021,ed2024 edition:2021
686fn main() {
687 ed2021::deprecated_safe();
688 ed2024::deprecated_safe();
689}
690
691//- /dep2.rs crate:dep2 deps:ed2021,ed2024 edition:2024
692fn main() {
693 ed2021::deprecated_safe();
694 // ^^^^^^^^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
695 ed2024::deprecated_safe();
696 // ^^^^^^^^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
697}
698
699//- /dep3.rs crate:dep3 deps:ed2021,ed2024 edition:2021
700#![warn(deprecated_safe)]
701
702fn main() {
703 ed2021::deprecated_safe();
704 // ^^^^^^^^^^^^^^^^^^^^^^^^^💡 warn: call to unsafe function is unsafe and requires an unsafe function or block
705 ed2024::deprecated_safe();
706 // ^^^^^^^^^^^^^^^^^^^^^^^^^💡 warn: call to unsafe function is unsafe and requires an unsafe function or block
707}
708 "#,
709 )
710 }
711
712 #[test]
713 fn orphan_unsafe_format_args() {
714 check_diagnostics(
716 r#"
717//- minicore: fmt_before_1_89_0
718fn foo() {
719 let p = 0xDEADBEEF as *const i32;
720 format_args!("", *p);
721 // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block
722}
723 "#,
724 );
725
726 check_diagnostics(
727 r#"
728//- minicore: fmt
729fn foo() {
730 let p = 0xDEADBEEF as *const i32;
731 format_args!("", *p);
732 // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block
733}
734 "#,
735 );
736 }
737
738 #[test]
739 fn unsafe_op_in_unsafe_fn_allowed_by_default_in_edition_2021() {
740 check_diagnostics(
741 r#"
742//- /lib.rs crate:foo edition:2021
743unsafe fn foo(p: *mut i32) {
744 *p = 123;
745}
746 "#,
747 );
748 check_diagnostics(
749 r#"
750//- /lib.rs crate:foo edition:2021
751#![deny(warnings)]
752unsafe fn foo(p: *mut i32) {
753 *p = 123;
754}
755 "#,
756 );
757 }
758
759 #[test]
760 fn unsafe_op_in_unsafe_fn_warn_by_default_in_edition_2024() {
761 check_diagnostics(
762 r#"
763//- /lib.rs crate:foo edition:2024
764unsafe fn foo(p: *mut i32) {
765 *p = 123;
766 //^^💡 warn: dereference of raw pointer is unsafe and requires an unsafe function or block
767}
768 "#,
769 );
770 check_diagnostics(
771 r#"
772//- /lib.rs crate:foo edition:2024
773#![deny(warnings)]
774unsafe fn foo(p: *mut i32) {
775 *p = 123;
776 //^^💡 error: dereference of raw pointer is unsafe and requires an unsafe function or block
777}
778 "#,
779 );
780 }
781
782 #[test]
783 fn unsafe_op_in_unsafe_fn() {
784 check_diagnostics(
785 r#"
786#![warn(unsafe_op_in_unsafe_fn)]
787unsafe fn foo(p: *mut i32) {
788 *p = 123;
789 //^^💡 warn: dereference of raw pointer is unsafe and requires an unsafe function or block
790}
791 "#,
792 )
793 }
794
795 #[test]
796 fn no_unsafe_diagnostic_with_safe_kw() {
797 check_diagnostics(
798 r#"
799unsafe extern {
800 pub safe fn f();
801
802 pub unsafe fn g();
803
804 pub fn h();
805
806 pub safe static S1: i32;
807
808 pub unsafe static S2: i32;
809
810 pub static S3: i32;
811}
812
813fn main() {
814 f();
815 g();
816 //^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
817 h();
818 //^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
819
820 let _ = S1;
821 let _ = S2;
822 //^^💡 error: use of extern static is unsafe and requires an unsafe function or block
823 let _ = S3;
824 //^^💡 error: use of extern static is unsafe and requires an unsafe function or block
825}
826"#,
827 );
828 }
829
830 #[test]
831 fn no_unsafe_diagnostic_when_destructuring_union_with_wildcard() {
832 check_diagnostics(
833 r#"
834union Union { field: i32 }
835fn foo(v: &Union) {
836 let Union { field: _ } = v;
837 let Union { field: _ | _ } = v;
838 Union { field: _ } = *v;
839}
840"#,
841 );
842 }
843
844 #[test]
845 fn union_destructuring() {
846 check_diagnostics(
847 r#"
848union Union { field: u8 }
849fn foo(v @ Union { field: _field }: &Union) {
850 // ^^^^^^ error: access to union field is unsafe and requires an unsafe function or block
851 let Union { mut field } = v;
852 // ^^^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block
853 let Union { field: 0..=255 } = v;
854 // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block
855 let Union { field: 0
856 // ^💡 error: access to union field is unsafe and requires an unsafe function or block
857 | 1..=255 } = v;
858 // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block
859 Union { field } = *v;
860 // ^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block
861 match v {
862 Union { field: _field } => {}
863 // ^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block
864 }
865 if let Union { field: _field } = v {}
866 // ^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block
867 (|&Union { field }| { _ = field; })(v);
868 // ^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block
869}
870"#,
871 );
872 }
873
874 #[test]
875 fn union_field_access() {
876 check_diagnostics(
877 r#"
878union Union { field: u8 }
879fn foo(v: &Union) {
880 v.field;
881 // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block
882}
883"#,
884 );
885 }
886
887 #[test]
888 fn inline_asm() {
889 check_diagnostics(
890 r#"
891//- minicore: asm
892fn foo() {
893 core::arch::asm!("");
894 // ^^^^ error: use of inline assembly is unsafe and requires an unsafe function or block
895}
896"#,
897 );
898 }
899
900 #[test]
901 fn unsafe_op_in_unsafe_fn_dismissed_in_signature() {
902 check_diagnostics(
903 r#"
904#![warn(unsafe_op_in_unsafe_fn)]
905union Union { field: u32 }
906unsafe fn foo(Union { field: _field }: Union) {}
907 "#,
908 )
909 }
910
911 #[test]
912 fn union_assignment_allowed() {
913 check_diagnostics(
914 r#"
915union Union { field: u32 }
916fn foo(mut v: Union) {
917 v.field = 123;
918 (v.field,) = (123,);
919 *&mut v.field = 123;
920 // ^^^^^^^💡 error: access to union field is unsafe and requires an unsafe function or block
921}
922struct Struct { field: u32 }
923union Union2 { field: Struct }
924fn bar(mut v: Union2) {
925 v.field.field = 123;
926}
927
928 "#,
929 )
930 }
931
932 #[test]
933 fn raw_ref_reborrow_is_safe() {
934 check_diagnostics(
935 r#"
936fn main() {
937 let ptr: *mut i32;
938 let _addr = &raw const *ptr;
939
940 let local = 1;
941 let ptr = &local as *const i32;
942 let _addr = &raw const *ptr;
943}
944"#,
945 )
946 }
947
948 #[test]
949 fn target_feature() {
950 check_diagnostics(
951 r#"
952#[target_feature(enable = "avx")]
953fn foo() {}
954
955#[target_feature(enable = "avx2")]
956fn bar() {
957 foo();
958}
959
960fn baz() {
961 foo();
962 // ^^^^^ 💡 error: call to unsafe function is unsafe and requires an unsafe function or block
963}
964 "#,
965 );
966 }
967
968 #[test]
969 fn unsafe_fn_ptr_call() {
970 check_diagnostics(
971 r#"
972fn f(it: unsafe fn()){
973 it();
974 // ^^^^ 💡 error: call to unsafe function is unsafe and requires an unsafe function or block
975}
976 "#,
977 );
978 }
979
980 #[test]
981 fn unsafe_call_in_const_expr() {
982 check_diagnostics(
983 r#"
984unsafe fn f() {}
985fn main() {
986 const { f(); };
987 // ^^^ 💡 error: call to unsafe function is unsafe and requires an unsafe function or block
988}
989 "#,
990 );
991 }
992
993 #[test]
994 fn asm_label() {
995 check_diagnostics(
996 r#"
997//- minicore: asm
998fn foo() {
999 unsafe {
1000 core::arch::asm!(
1001 "jmp {}",
1002 label {
1003 let p = 0xDEADBEAF as *mut u8;
1004 *p = 3;
1005 // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block
1006 },
1007 );
1008 }
1009}
1010 "#,
1011 );
1012 }
1013
1014 #[test]
1015 fn regression_19823() {
1016 check_diagnostics(
1017 r#"
1018pub trait FooTrait {
1019 unsafe fn method1();
1020 unsafe fn method2();
1021}
1022
1023unsafe fn some_unsafe_fn() {}
1024
1025macro_rules! impl_foo {
1026 () => {
1027 unsafe fn method1() {
1028 some_unsafe_fn();
1029 }
1030 unsafe fn method2() {
1031 some_unsafe_fn();
1032 }
1033 };
1034}
1035
1036pub struct S1;
1037#[allow(unsafe_op_in_unsafe_fn)]
1038impl FooTrait for S1 {
1039 unsafe fn method1() {
1040 some_unsafe_fn();
1041 }
1042
1043 unsafe fn method2() {
1044 some_unsafe_fn();
1045 }
1046}
1047
1048pub struct S2;
1049#[allow(unsafe_op_in_unsafe_fn)]
1050impl FooTrait for S2 {
1051 impl_foo!();
1052}
1053 "#,
1054 );
1055 }
1056
1057 #[test]
1058 fn no_false_positive_on_format_args_since_1_89_0() {
1059 check_diagnostics(
1060 r#"
1061//- minicore: fmt
1062fn test() {
1063 let foo = 10;
1064 let bar = true;
1065 let _x = format_args!("{} {0} {} {last}", foo, bar, last = "!");
1066}
1067 "#,
1068 );
1069 }
1070
1071 #[test]
1072 fn naked_asm_is_safe() {
1073 check_diagnostics(
1074 r#"
1075#[rustc_builtin_macro]
1076macro_rules! naked_asm { () => {} }
1077
1078#[unsafe(naked)]
1079extern "C" fn naked() {
1080 naked_asm!("");
1081}
1082 "#,
1083 );
1084 }
1085
1086 #[test]
1087 fn target_feature_safe_on_wasm() {
1088 check_diagnostics(
1089 r#"
1090//- target_arch: wasm32
1091
1092#[target_feature(enable = "simd128")]
1093fn requires_target_feature() {}
1094
1095fn main() {
1096 requires_target_feature();
1097}
1098 "#,
1099 );
1100 }
1101
1102 #[test]
1103 fn multiple_target_feature_enable() {
1104 check_diagnostics(
1105 r#"
1106#[target_feature(enable = "avx2,fma")]
1107fn foo() {}
1108
1109#[target_feature(enable = "avx2", enable = "fma")]
1110fn bar() {
1111 foo();
1112}
1113 "#,
1114 );
1115 }
1116}