Skip to content

Commit 08095fc

Browse files
committed
Auto merge of #87469 - sexxi-goose:union, r=nikomatsakis
2229: Don't capture preicese paths on top of a union - Accessing fields of a union require unsafe block - As part of 2229 we don't allow precision where we need an unsafe block to capture. Fixes: #87378 r? `@nikomatsakis`
2 parents fc24bce + 75edcd9 commit 08095fc

File tree

4 files changed

+124
-12
lines changed

4 files changed

+124
-12
lines changed

compiler/rustc_typeck/src/check/upvar.rs

+34-12
Original file line numberDiff line numberDiff line change
@@ -1760,12 +1760,11 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
17601760
self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow);
17611761
}
17621762
}
1763-
1764-
/// Truncate projections so that following rules are obeyed by the captured `place`:
1763+
/// Truncate `place` so that an `unsafe` block isn't required to capture it.
17651764
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
17661765
/// them completely.
1767-
/// - No Index projections are captured, since arrays are captured completely.
1768-
fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
1766+
/// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
1767+
fn restrict_precision_for_unsafe(mut place: Place<'tcx>) -> Place<'tcx> {
17691768
if place.projections.is_empty() {
17701769
// Nothing to do here
17711770
return place;
@@ -1776,18 +1775,45 @@ fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
17761775
return place;
17771776
}
17781777

1779-
let mut truncated_length = usize::MAX;
1778+
if place.base_ty.is_union() {
1779+
place.projections.truncate(0);
1780+
return place;
1781+
}
17801782

17811783
for (i, proj) in place.projections.iter().enumerate() {
17821784
if proj.ty.is_unsafe_ptr() {
1783-
// Don't apply any projections on top of an unsafe ptr
1784-
truncated_length = truncated_length.min(i + 1);
1785+
// Don't apply any projections on top of an unsafe ptr.
1786+
place.projections.truncate(i + 1);
17851787
break;
17861788
}
1789+
1790+
if proj.ty.is_union() {
1791+
// Don't capture preicse fields of a union.
1792+
place.projections.truncate(i + 1);
1793+
break;
1794+
}
1795+
}
1796+
1797+
place
1798+
}
1799+
1800+
/// Truncate projections so that following rules are obeyed by the captured `place`:
1801+
/// - No Index projections are captured, since arrays are captured completely.
1802+
/// - No unsafe block is required to capture `place`
1803+
/// Truncate projections so that following rules are obeyed by the captured `place`:
1804+
fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
1805+
place = restrict_precision_for_unsafe(place);
1806+
1807+
if place.projections.is_empty() {
1808+
// Nothing to do here
1809+
return place;
1810+
}
1811+
1812+
for (i, proj) in place.projections.iter().enumerate() {
17871813
match proj.kind {
17881814
ProjectionKind::Index => {
17891815
// Arrays are completely captured, so we drop Index projections
1790-
truncated_length = truncated_length.min(i);
1816+
place.projections.truncate(i);
17911817
break;
17921818
}
17931819
ProjectionKind::Deref => {}
@@ -1796,10 +1822,6 @@ fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
17961822
}
17971823
}
17981824

1799-
let length = place.projections.len().min(truncated_length);
1800-
1801-
place.projections.truncate(length);
1802-
18031825
place
18041826
}
18051827

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
#![feature(rustc_attrs)]
2+
3+
// edition:2021
4+
5+
// Test that any precise capture on a union is truncated because it's unsafe to do so.
6+
7+
union Union {
8+
value: u64,
9+
}
10+
11+
fn main() {
12+
let u = Union { value: 42 };
13+
14+
let c = #[rustc_capture_analysis]
15+
//~^ ERROR: attributes on expressions are experimental
16+
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
17+
|| {
18+
//~^ ERROR: First Pass analysis includes:
19+
//~| ERROR: Min Capture analysis includes:
20+
unsafe { u.value }
21+
//~^ NOTE: Capturing u[(0, 0)] -> ImmBorrow
22+
//~| NOTE: Min Capture u[] -> ImmBorrow
23+
};
24+
25+
c();
26+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
error[E0658]: attributes on expressions are experimental
2+
--> $DIR/issue-87378.rs:14:13
3+
|
4+
LL | let c = #[rustc_capture_analysis]
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^
6+
|
7+
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
8+
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
9+
10+
error: First Pass analysis includes:
11+
--> $DIR/issue-87378.rs:17:5
12+
|
13+
LL | / || {
14+
LL | |
15+
LL | |
16+
LL | | unsafe { u.value }
17+
LL | |
18+
LL | |
19+
LL | | };
20+
| |_____^
21+
|
22+
note: Capturing u[(0, 0)] -> ImmBorrow
23+
--> $DIR/issue-87378.rs:20:17
24+
|
25+
LL | unsafe { u.value }
26+
| ^^^^^^^
27+
28+
error: Min Capture analysis includes:
29+
--> $DIR/issue-87378.rs:17:5
30+
|
31+
LL | / || {
32+
LL | |
33+
LL | |
34+
LL | | unsafe { u.value }
35+
LL | |
36+
LL | |
37+
LL | | };
38+
| |_____^
39+
|
40+
note: Min Capture u[] -> ImmBorrow
41+
--> $DIR/issue-87378.rs:20:17
42+
|
43+
LL | unsafe { u.value }
44+
| ^^^^^^^
45+
46+
error: aborting due to 3 previous errors
47+
48+
For more information about this error, try `rustc --explain E0658`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// edition:2021
2+
// check-pass
3+
4+
union Union {
5+
value: u64,
6+
}
7+
8+
fn main() {
9+
let u = Union { value: 42 };
10+
11+
let c = || {
12+
unsafe { u.value }
13+
};
14+
15+
c();
16+
}

0 commit comments

Comments
 (0)