Skip to content

Commit 285bb60

Browse files
committed
allow take union field addresses in safe rust
1 parent 187917f commit 285bb60

File tree

3 files changed

+60
-1
lines changed

3 files changed

+60
-1
lines changed

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,22 @@ impl<'db> UnsafeVisitor<'db> {
315315
}
316316
_ => (),
317317
}
318+
319+
let mut peeled = *expr;
320+
while let Expr::Field { expr: lhs, .. } = &self.body[peeled] {
321+
if let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) =
322+
self.infer.field_resolution(peeled)
323+
{
324+
peeled = *lhs;
325+
} else {
326+
break;
327+
}
328+
}
329+
330+
// Walk the peeled expression (the LHS of the union field chain)
331+
self.walk_expr(peeled);
332+
// Return so we don't recurse directly onto the union field access(es)
333+
return;
318334
}
319335
Expr::MethodCall { .. } => {
320336
if let Some((func, _)) = self.infer.method_resolution(current) {

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

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,49 @@ fn main() {
441441
)
442442
}
443443

444+
#[test]
445+
fn raw_deref_on_union_field() {
446+
check_diagnostics(
447+
r#"
448+
fn main() {
449+
450+
union U {
451+
a: u8
452+
}
453+
let x = U { a: 3 };
454+
455+
let a = &raw mut x.a;
456+
457+
union U1 {
458+
a: u8
459+
}
460+
let x = U1 { a: 3 };
461+
462+
let a = x.a;
463+
// ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
464+
465+
466+
let b = &raw const x.a;
467+
468+
let tmp = Vec::from([1, 2, 3]);
469+
470+
let c = &raw const tmp[x.a];
471+
// ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
472+
473+
union URef {
474+
p: &'static mut i32,
475+
}
476+
477+
fn deref_union_field(u: URef) {
478+
// Not an assignment but an access to the union field!
479+
*(u.p) = 13;
480+
// ^^^ 💡 error: access to union field is unsafe and requires an unsafe function or block
481+
}
482+
}
483+
"#,
484+
)
485+
}
486+
444487
#[test]
445488
fn unsafe_expr_as_an_argument_of_a_method_call() {
446489
check_fix(

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)