Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-ty/src/diagnostics/unsafe_check.rs16
-rw-r--r--crates/ide-diagnostics/src/handlers/missing_unsafe.rs43
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html2
3 files changed, 60 insertions, 1 deletions
diff --git a/crates/hir-ty/src/diagnostics/unsafe_check.rs b/crates/hir-ty/src/diagnostics/unsafe_check.rs
index 3f04b72c2f..3c78f5ef38 100644
--- a/crates/hir-ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir-ty/src/diagnostics/unsafe_check.rs
@@ -315,6 +315,22 @@ impl<'db> UnsafeVisitor<'db> {
}
_ => (),
}
+
+ let mut peeled = *expr;
+ while let Expr::Field { expr: lhs, .. } = &self.body[peeled] {
+ if let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) =
+ self.infer.field_resolution(peeled)
+ {
+ peeled = *lhs;
+ } else {
+ break;
+ }
+ }
+
+ // Walk the peeled expression (the LHS of the union field chain)
+ self.walk_expr(peeled);
+ // Return so we don't recurse directly onto the union field access(es)
+ return;
}
Expr::MethodCall { .. } => {
if let Some((func, _)) = self.infer.method_resolution(current) {
diff --git a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 4bb64747f5..029ed18a4d 100644
--- a/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -442,6 +442,49 @@ fn main() {
}
#[test]
+ fn raw_deref_on_union_field() {
+ check_diagnostics(
+ r#"
+fn main() {
+
+ union U {
+ a: u8
+ }
+ let x = U { a: 3 };
+
+ let a = &raw mut x.a;
+
+ union U1 {
+ a: u8
+ }
+ let x = U1 { a: 3 };
+
+ let a = x.a;
+ // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
+
+
+ let b = &raw const x.a;
+
+ let tmp = Vec::from([1, 2, 3]);
+
+ let c = &raw const tmp[x.a];
+ // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
+
+ union URef {
+ p: &'static mut i32,
+ }
+
+ fn deref_union_field(u: URef) {
+ // Not an assignment but an access to the union field!
+ *(u.p) = 13;
+ // ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
+ }
+}
+"#,
+ )
+ }
+
+ #[test]
fn unsafe_expr_as_an_argument_of_a_method_call() {
check_fix(
r#"
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 828b8f762c..8339daf324 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -96,7 +96,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
<span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
<span class="operator">&</span><span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
- <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
+ <span class="operator">&</span><span class="keyword">raw</span> <span class="keyword const">const</span> <span class="variable">u</span><span class="operator">.</span><span class="field">field</span><span class="semicolon">;</span>
<span class="comment">// this should be safe!</span>
<span class="keyword">let</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="punctuation">_</span> <span class="brace">}</span><span class="semicolon">;</span>
<span class="comment">// but not these</span>