Skip to main content

ide_diagnostics/handlers/
trait_impl_incorrect_safety.rs

1use hir::InFile;
2use syntax::ast;
3
4use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext, Severity, adjusted_display_range};
5
6// Diagnostic: trait-impl-incorrect-safety
7//
8// Diagnoses incorrect safety annotations of trait impls.
9pub(crate) fn trait_impl_incorrect_safety(
10    ctx: &DiagnosticsContext<'_, '_>,
11    d: &hir::TraitImplIncorrectSafety,
12) -> Diagnostic {
13    Diagnostic::new(
14        DiagnosticCode::Ra("trait-impl-incorrect-safety", Severity::Error),
15        if d.should_be_safe {
16            "unsafe impl for safe trait"
17        } else {
18            "impl for unsafe trait needs to be unsafe"
19        },
20        adjusted_display_range::<ast::Impl>(
21            ctx,
22            InFile { file_id: d.file_id, value: d.impl_ },
23            &|impl_| {
24                if d.should_be_safe {
25                    Some(match (impl_.unsafe_token(), impl_.impl_token()) {
26                        (None, None) => return None,
27                        (None, Some(t)) | (Some(t), None) => t.text_range(),
28                        (Some(t1), Some(t2)) => t1.text_range().cover(t2.text_range()),
29                    })
30                } else {
31                    impl_.impl_token().map(|t| t.text_range())
32                }
33            },
34        ),
35    )
36    .stable()
37}
38
39#[cfg(test)]
40mod tests {
41    use crate::tests::check_diagnostics;
42
43    #[test]
44    fn simple() {
45        check_diagnostics(
46            r#"
47trait Safe {}
48unsafe trait Unsafe {}
49
50  impl Safe for () {}
51
52  impl Unsafe for () {}
53//^^^^  error: impl for unsafe trait needs to be unsafe
54
55  unsafe impl Safe for () {}
56//^^^^^^^^^^^ error: unsafe impl for safe trait
57
58  unsafe impl Unsafe for () {}
59"#,
60        );
61    }
62
63    #[test]
64    fn drop_may_dangle() {
65        check_diagnostics(
66            r#"
67#![feature(lang_items)]
68#[lang = "drop"]
69trait Drop {}
70struct S<T>;
71struct L<'l>;
72
73  impl<T> Drop for S<T> {}
74
75  impl<#[may_dangle] T> Drop for S<T> {}
76//^^^^ error: impl for unsafe trait needs to be unsafe
77
78  unsafe impl<T> Drop for S<T> {}
79//^^^^^^^^^^^ error: unsafe impl for safe trait
80
81  unsafe impl<#[may_dangle] T> Drop for S<T> {}
82
83  impl<'l> Drop for L<'l> {}
84
85  impl<#[may_dangle] 'l> Drop for L<'l> {}
86//^^^^ error: impl for unsafe trait needs to be unsafe
87
88  unsafe impl<'l> Drop for L<'l> {}
89//^^^^^^^^^^^ error: unsafe impl for safe trait
90
91  unsafe impl<#[may_dangle] 'l> Drop for L<'l> {}
92"#,
93        );
94    }
95
96    #[test]
97    fn negative() {
98        check_diagnostics(
99            r#"
100trait Trait {}
101
102  impl !Trait for () {}
103
104  unsafe impl !Trait for () {}
105//^^^^^^^^^^^ error: unsafe impl for safe trait
106
107unsafe trait UnsafeTrait {}
108
109  impl !UnsafeTrait for () {}
110
111  unsafe impl !UnsafeTrait for () {}
112//^^^^^^^^^^^ error: unsafe impl for safe trait
113
114"#,
115        );
116    }
117
118    #[test]
119    fn inherent() {
120        check_diagnostics(
121            r#"
122struct S;
123
124  impl S {}
125
126  unsafe impl S {}
127//^^^^^^^^^^^ error: unsafe impl for safe trait
128"#,
129        );
130    }
131
132    #[test]
133    fn unsafe_unresolved_trait() {
134        check_diagnostics(
135            r#"
136unsafe impl TestTrait for u32 {}
137        "#,
138        );
139    }
140}