Skip to content

Commit 0181b7a

Browse files
committed
allow raw borrow on just union field access
1 parent f98b622 commit 0181b7a

File tree

4 files changed

+88
-1
lines changed

4 files changed

+88
-1
lines changed

1

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
allow raw borrow on just union field access
2+
3+
# Please enter the commit message for your changes. Lines starting
4+
# with '#' will be ignored, and an empty message aborts the commit.
5+
#
6+
# Date: Mon May 26 16:39:53 2025 +0500
7+
#
8+
# interactive rebase in progress; onto f98b6220c4
9+
# Last commands done (2 commands done):
10+
# pick fb6416e94e allow raw borrow on just union field access
11+
# squash 3be875810d temp
12+
# No commands remaining.
13+
# You are currently rebasing branch 'unsafegate' on 'f98b6220c4'.
14+
#
15+
# Changes to be committed:
16+
# modified: crates/hir-ty/src/diagnostics/unsafe_check.rs
17+
# modified: crates/ide-diagnostics/src/handlers/missing_unsafe.rs
18+
# modified: crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
19+
#

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

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

297297
return;
298298
}
299+
Expr::Field { .. } => {
300+
if self.is_union_field_access(*expr) {
301+
self.walk_union_field_for_raw_borrow(*expr);
302+
return;
303+
}
304+
}
299305
_ => (),
300306
}
301307
}
@@ -401,4 +407,31 @@ impl<'db> UnsafeVisitor<'db> {
401407
}
402408
}
403409
}
410+
411+
/// Check if an expression is accessing a union field
412+
fn is_union_field_access(&self, expr_id: ExprId) -> bool {
413+
matches!(
414+
self.infer.field_resolution(expr_id),
415+
Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. }))
416+
)
417+
}
418+
419+
/// Visit a union field access in the context of creating a raw reference
420+
/// This ensures we check safety of the base expression while allowing
421+
/// the raw pointer creation to the union field itself
422+
fn walk_union_field_for_raw_borrow(&mut self, expr_id: ExprId) {
423+
match &self.body.exprs[expr_id] {
424+
Expr::Field { expr, .. } => {
425+
// Visit the base expression (e.g., `self` in `self.field`) for safety,
426+
// but don't trigger the union field access error since we're just
427+
// creating a raw pointer, not actually reading the field
428+
self.walk_expr(*expr);
429+
}
430+
_ => {
431+
// If it's not a field access for some reason, fall back to normal walking
432+
// This shouldn't happen based on how this function is called
433+
self.body.walk_child_exprs_without_pats(expr_id, |child| self.walk_expr(child));
434+
}
435+
}
436+
}
404437
}

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)