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