Skip to content

Commit c89f2c7

Browse files
committed
Do not automatically DerefMut ManuallyDrop through union references
1 parent 78865ca commit c89f2c7

3 files changed

Lines changed: 81 additions & 7 deletions

File tree

compiler/rustc_hir_typeck/src/place_op.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,9 +285,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
285285
// Clear previous flag; after a pointer indirection it does not apply any more.
286286
inside_union = false;
287287
}
288-
if source.is_union() {
289-
inside_union = true;
290-
}
291288
// Fix up the autoderefs. Autorefs can only occur immediately preceding
292289
// overloaded place ops, and will be fixed by them in order to get
293290
// the correct region.
@@ -335,6 +332,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
335332
}
336333
self.typeck_results.borrow_mut().adjustments_mut().insert(expr.hir_id, adjustments);
337334
}
335+
// Now that any autoderef of this expression component is complete, if it resolved to a
336+
// `union` then remember we're inside a `union` as we iterate over subsequent expression
337+
// components. If this test were performed prior to autoderef resolution, it would only
338+
// detect expression components of the (owned) `union` type and not references thereto.
339+
// See <https://github.com/rust-lang/rust/issues/141621>.
340+
if source.is_union() {
341+
inside_union = true;
342+
}
338343

339344
match expr.kind {
340345
hir::ExprKind::Index(base_expr, ..) => {

tests/ui/union/union-deref.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,26 @@ fn main() {
1616
unsafe { (*u.f).0.push(0) }; // explicit deref, this compiles
1717
unsafe { u.f.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
1818

19+
unsafe { (*(&mut u).f).0 = Vec::new() }; // explicit deref, this compiles
20+
unsafe { (&mut u).f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
21+
unsafe { &mut (*(&mut u).f).0 }; // explicit deref, this compiles
22+
unsafe { &mut (&mut u).f.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
23+
unsafe { (*(&mut u).f).0.push(0) }; // explicit deref, this compiles
24+
unsafe { (&mut u).f.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
25+
26+
1927
let mut u : U2<Vec<i32>> = U2 { x: () };
2028
unsafe { (*u.f.0).0 = Vec::new() }; // explicit deref, this compiles
2129
unsafe { u.f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
2230
unsafe { &mut (*u.f.0).0 }; // explicit deref, this compiles
2331
unsafe { &mut u.f.0.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
2432
unsafe { (*u.f.0).0.push(0) }; // explicit deref, this compiles
2533
unsafe { u.f.0.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
34+
35+
unsafe { (*(&mut u).f.0).0 = Vec::new() }; // explicit deref, this compiles
36+
unsafe { (&mut u).f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
37+
unsafe { &mut (*(&mut u).f.0).0 }; // explicit deref, this compiles
38+
unsafe { &mut (&mut u).f.0.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
39+
unsafe { (*(&mut u).f.0).0.push(0) }; // explicit deref, this compiles
40+
unsafe { (&mut u).f.0.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
2641
}

tests/ui/union/union-deref.stderr

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,34 @@ LL | unsafe { u.f.0.push(0) };
2626
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
2727

2828
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
29-
--> $DIR/union-deref.rs:21:14
29+
--> $DIR/union-deref.rs:20:14
30+
|
31+
LL | unsafe { (&mut u).f.0 = Vec::new() };
32+
| ^^^^^^^^^^
33+
|
34+
= help: writing to this reference calls the destructor for the old value
35+
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
36+
37+
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
38+
--> $DIR/union-deref.rs:22:19
39+
|
40+
LL | unsafe { &mut (&mut u).f.0 };
41+
| ^^^^^^^^^^
42+
|
43+
= help: writing to this reference calls the destructor for the old value
44+
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
45+
46+
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
47+
--> $DIR/union-deref.rs:24:14
48+
|
49+
LL | unsafe { (&mut u).f.0.push(0) };
50+
| ^^^^^^^^^^
51+
|
52+
= help: writing to this reference calls the destructor for the old value
53+
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
54+
55+
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
56+
--> $DIR/union-deref.rs:29:14
3057
|
3158
LL | unsafe { u.f.0.0 = Vec::new() };
3259
| ^^^^^
@@ -35,7 +62,7 @@ LL | unsafe { u.f.0.0 = Vec::new() };
3562
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
3663

3764
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
38-
--> $DIR/union-deref.rs:23:19
65+
--> $DIR/union-deref.rs:31:19
3966
|
4067
LL | unsafe { &mut u.f.0.0 };
4168
| ^^^^^
@@ -44,13 +71,40 @@ LL | unsafe { &mut u.f.0.0 };
4471
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
4572

4673
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
47-
--> $DIR/union-deref.rs:25:14
74+
--> $DIR/union-deref.rs:33:14
4875
|
4976
LL | unsafe { u.f.0.0.push(0) };
5077
| ^^^^^
5178
|
5279
= help: writing to this reference calls the destructor for the old value
5380
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
5481

55-
error: aborting due to 6 previous errors
82+
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
83+
--> $DIR/union-deref.rs:36:14
84+
|
85+
LL | unsafe { (&mut u).f.0.0 = Vec::new() };
86+
| ^^^^^^^^^^^^
87+
|
88+
= help: writing to this reference calls the destructor for the old value
89+
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
90+
91+
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
92+
--> $DIR/union-deref.rs:38:19
93+
|
94+
LL | unsafe { &mut (&mut u).f.0.0 };
95+
| ^^^^^^^^^^^^
96+
|
97+
= help: writing to this reference calls the destructor for the old value
98+
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
99+
100+
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
101+
--> $DIR/union-deref.rs:40:14
102+
|
103+
LL | unsafe { (&mut u).f.0.0.push(0) };
104+
| ^^^^^^^^^^^^
105+
|
106+
= help: writing to this reference calls the destructor for the old value
107+
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
108+
109+
error: aborting due to 12 previous errors
56110

0 commit comments

Comments
 (0)