Skip to content

Commit 9d37cd8

Browse files
committed
Use BikeshedGuaranteedNoDrop to defend against union DerefMut coercions
1 parent 113aeac commit 9d37cd8

3 files changed

Lines changed: 40 additions & 28 deletions

File tree

compiler/rustc_hir_typeck/src/place_op.rs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_errors::Applicability;
2+
use rustc_hir::LangItem;
23
use rustc_hir_analysis::autoderef::Autoderef;
34
use rustc_infer::infer::InferOk;
45
use rustc_infer::traits::{Obligation, ObligationCauseCode};
@@ -8,7 +9,8 @@ use rustc_middle::ty::adjustment::{
89
PointerCoercion,
910
};
1011
use rustc_middle::ty::{self, Ty};
11-
use rustc_span::{Span, sym};
12+
use rustc_span::{DUMMY_SP, Span, sym};
13+
use rustc_trait_selection::infer::InferCtxtExt;
1214
use tracing::debug;
1315
use {rustc_ast as ast, rustc_hir as hir};
1416

@@ -312,14 +314,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
312314
};
313315
*deref = OverloadedDeref { mutbl, span: deref.span };
314316
self.enforce_context_effects(None, expr.span, method.def_id, method.args);
315-
// If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
317+
// If this is a union field, also throw an error for `DerefMut` of non `BikeshedGuaranteedNoDrop` (see RFC 2514).
316318
// This helps avoid accidental drops.
317319
if inside_union
318-
&& source.ty_adt_def().is_some_and(|adt| adt.is_manually_drop())
320+
&& !self
321+
.infcx
322+
.type_implements_trait(
323+
self.tcx.require_lang_item(
324+
LangItem::BikeshedGuaranteedNoDrop,
325+
DUMMY_SP,
326+
),
327+
[adjustment.target],
328+
self.param_env,
329+
)
330+
.must_apply_considering_regions()
319331
{
320332
self.dcx().struct_span_err(
321333
expr.span,
322-
"not automatically applying `DerefMut` on `ManuallyDrop` union field",
334+
"not automatically applying `DerefMut` through union field to target that might have `Drop` glue",
323335
)
324336
.with_help(
325337
"writing to this reference calls the destructor for the old value",

tests/ui/union/union-deref.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,32 +10,32 @@ union U2<T> { x:(), f: (ManuallyDrop<(T,)>,) }
1010
fn main() {
1111
let mut u : U1<Vec<i32>> = U1 { x: () };
1212
unsafe { (*u.f).0 = Vec::new() }; // explicit deref, this compiles
13-
unsafe { u.f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
13+
unsafe { u.f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
1414
unsafe { &mut (*u.f).0 }; // explicit deref, this compiles
15-
unsafe { &mut u.f.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
15+
unsafe { &mut u.f.0 }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
1616
unsafe { (*u.f).0.push(0) }; // explicit deref, this compiles
17-
unsafe { u.f.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
17+
unsafe { u.f.0.push(0) }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
1818

1919
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
20+
unsafe { (&mut u).f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
2121
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
22+
unsafe { &mut (&mut u).f.0 }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
2323
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
24+
unsafe { (&mut u).f.0.push(0) }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
2525

2626

2727
let mut u : U2<Vec<i32>> = U2 { x: () };
2828
unsafe { (*u.f.0).0 = Vec::new() }; // explicit deref, this compiles
29-
unsafe { u.f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
29+
unsafe { u.f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
3030
unsafe { &mut (*u.f.0).0 }; // explicit deref, this compiles
31-
unsafe { &mut u.f.0.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
31+
unsafe { &mut u.f.0.0 }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
3232
unsafe { (*u.f.0).0.push(0) }; // explicit deref, this compiles
33-
unsafe { u.f.0.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field
33+
unsafe { u.f.0.0.push(0) }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
3434

3535
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
36+
unsafe { (&mut u).f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
3737
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
38+
unsafe { &mut (&mut u).f.0.0 }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
3939
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
40+
unsafe { (&mut u).f.0.0.push(0) }; //~ERROR not automatically applying `DerefMut` through union field to target that might have `Drop` glue
4141
}

tests/ui/union/union-deref.stderr

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
1+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
22
--> $DIR/union-deref.rs:13:14
33
|
44
LL | unsafe { u.f.0 = Vec::new() };
@@ -7,7 +7,7 @@ LL | unsafe { u.f.0 = Vec::new() };
77
= help: writing to this reference calls the destructor for the old value
88
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
99

10-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
10+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
1111
--> $DIR/union-deref.rs:15:19
1212
|
1313
LL | unsafe { &mut u.f.0 };
@@ -16,7 +16,7 @@ LL | unsafe { &mut u.f.0 };
1616
= help: writing to this reference calls the destructor for the old value
1717
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
1818

19-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
19+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
2020
--> $DIR/union-deref.rs:17:14
2121
|
2222
LL | unsafe { u.f.0.push(0) };
@@ -25,7 +25,7 @@ LL | unsafe { u.f.0.push(0) };
2525
= help: writing to this reference calls the destructor for the old value
2626
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
2727

28-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
28+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
2929
--> $DIR/union-deref.rs:20:14
3030
|
3131
LL | unsafe { (&mut u).f.0 = Vec::new() };
@@ -34,7 +34,7 @@ LL | unsafe { (&mut u).f.0 = Vec::new() };
3434
= help: writing to this reference calls the destructor for the old value
3535
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
3636

37-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
37+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
3838
--> $DIR/union-deref.rs:22:19
3939
|
4040
LL | unsafe { &mut (&mut u).f.0 };
@@ -43,7 +43,7 @@ LL | unsafe { &mut (&mut u).f.0 };
4343
= help: writing to this reference calls the destructor for the old value
4444
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
4545

46-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
46+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
4747
--> $DIR/union-deref.rs:24:14
4848
|
4949
LL | unsafe { (&mut u).f.0.push(0) };
@@ -52,7 +52,7 @@ LL | unsafe { (&mut u).f.0.push(0) };
5252
= help: writing to this reference calls the destructor for the old value
5353
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
5454

55-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
55+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
5656
--> $DIR/union-deref.rs:29:14
5757
|
5858
LL | unsafe { u.f.0.0 = Vec::new() };
@@ -61,7 +61,7 @@ LL | unsafe { u.f.0.0 = Vec::new() };
6161
= help: writing to this reference calls the destructor for the old value
6262
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
6363

64-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
64+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
6565
--> $DIR/union-deref.rs:31:19
6666
|
6767
LL | unsafe { &mut u.f.0.0 };
@@ -70,7 +70,7 @@ LL | unsafe { &mut u.f.0.0 };
7070
= help: writing to this reference calls the destructor for the old value
7171
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
7272

73-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
73+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
7474
--> $DIR/union-deref.rs:33:14
7575
|
7676
LL | unsafe { u.f.0.0.push(0) };
@@ -79,7 +79,7 @@ LL | unsafe { u.f.0.0.push(0) };
7979
= help: writing to this reference calls the destructor for the old value
8080
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
8181

82-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
82+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
8383
--> $DIR/union-deref.rs:36:14
8484
|
8585
LL | unsafe { (&mut u).f.0.0 = Vec::new() };
@@ -88,7 +88,7 @@ LL | unsafe { (&mut u).f.0.0 = Vec::new() };
8888
= help: writing to this reference calls the destructor for the old value
8989
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
9090

91-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
91+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
9292
--> $DIR/union-deref.rs:38:19
9393
|
9494
LL | unsafe { &mut (&mut u).f.0.0 };
@@ -97,7 +97,7 @@ LL | unsafe { &mut (&mut u).f.0.0 };
9797
= help: writing to this reference calls the destructor for the old value
9898
= help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor
9999

100-
error: not automatically applying `DerefMut` on `ManuallyDrop` union field
100+
error: not automatically applying `DerefMut` through union field to target that might have `Drop` glue
101101
--> $DIR/union-deref.rs:40:14
102102
|
103103
LL | unsafe { (&mut u).f.0.0.push(0) };

0 commit comments

Comments
 (0)