Skip to content

Commit 42f6e92

Browse files
committed
allow raw borrow on just union field access
1 parent f98b622 commit 42f6e92

File tree

3 files changed

+59
-1
lines changed

3 files changed

+59
-1
lines changed

crates/hir-ty/src/diagnostics/unsafe_check.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,29 @@ impl<'db> UnsafeVisitor<'db> {
296296

297297
return;
298298
}
299+
Expr::Field { .. } => {
300+
if matches!(
301+
self.infer.field_resolution(*expr),
302+
Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. }))
303+
) {
304+
match &self.body.exprs[*expr] {
305+
Expr::Field { expr, .. } => {
306+
// Visit the base expression (e.g., `self` in `self.field`) for safety,
307+
// but don't trigger the union field access error since we're just
308+
// creating a raw pointer, not actually reading the field
309+
self.walk_expr(*expr);
310+
}
311+
_ => {
312+
self.body.walk_child_exprs_without_pats(*expr, |child| {
313+
// If it's not a field access for some reason, fall back to normal walking
314+
// This shouldn't happen based on how this function is called
315+
self.walk_expr(child)
316+
});
317+
}
318+
}
319+
return;
320+
}
321+
}
299322
_ => (),
300323
}
301324
}

crates/ide-diagnostics/src/handlers/missing_unsafe.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,41 @@ fn bar(mut v: Union2) {
834834
)
835835
}
836836

837+
#[test]
838+
fn raw_deref_on_union_field() {
839+
check_diagnostics(
840+
r#"
841+
fn main() {
842+
union U1 {
843+
a: u8
844+
}
845+
let x = U1 { a: 3 };
846+
847+
let a = x.a;
848+
// ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
849+
850+
851+
let b = &raw const x.a;
852+
853+
let tmp = Vec::from([1, 2, 3]);
854+
855+
let c = &raw const tmp[x.a];
856+
// ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
857+
858+
union URef {
859+
p: &'static mut i32,
860+
}
861+
862+
fn deref_union_field(u: URef) {
863+
// Not an assignment but an access to the union field!
864+
*(u.p) = 13;
865+
// ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
866+
}
867+
}
868+
"#,
869+
)
870+
}
871+
837872
#[test]
838873
fn raw_ref_reborrow_is_safe() {
839874
check_diagnostics(

crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696

9797
<span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
9898
<span class="operator">&</span><span class="variable">u</span><span class="operator">.</span><span class="field unsafe">field</span><span class="semicolon">;</span>
99-
<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>
99+
<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>
100100
<span class="comment">// this should be safe!</span>
101101
<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>
102102
<span class="comment">// but not these</span>

0 commit comments

Comments
 (0)