mirror of
https://github.com/rust-lang/rust.git
synced 2025-05-04 22:17:38 +00:00
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`
This commit is contained in:
commit
08095fc1f8
@ -1760,12 +1760,11 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
|
|||||||
self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow);
|
self.borrow(assignee_place, diag_expr_id, ty::BorrowKind::MutBorrow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/// Truncate `place` so that an `unsafe` block isn't required to capture it.
|
||||||
/// Truncate projections so that following rules are obeyed by the captured `place`:
|
|
||||||
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
|
/// - No projections are applied to raw pointers, since these require unsafe blocks. We capture
|
||||||
/// them completely.
|
/// them completely.
|
||||||
/// - No Index projections are captured, since arrays are captured completely.
|
/// - No projections are applied on top of Union ADTs, since these require unsafe blocks.
|
||||||
fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
|
fn restrict_precision_for_unsafe(mut place: Place<'tcx>) -> Place<'tcx> {
|
||||||
if place.projections.is_empty() {
|
if place.projections.is_empty() {
|
||||||
// Nothing to do here
|
// Nothing to do here
|
||||||
return place;
|
return place;
|
||||||
@ -1776,18 +1775,45 @@ fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
|
|||||||
return place;
|
return place;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut truncated_length = usize::MAX;
|
if place.base_ty.is_union() {
|
||||||
|
place.projections.truncate(0);
|
||||||
|
return place;
|
||||||
|
}
|
||||||
|
|
||||||
for (i, proj) in place.projections.iter().enumerate() {
|
for (i, proj) in place.projections.iter().enumerate() {
|
||||||
if proj.ty.is_unsafe_ptr() {
|
if proj.ty.is_unsafe_ptr() {
|
||||||
// Don't apply any projections on top of an unsafe ptr
|
// Don't apply any projections on top of an unsafe ptr.
|
||||||
truncated_length = truncated_length.min(i + 1);
|
place.projections.truncate(i + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if proj.ty.is_union() {
|
||||||
|
// Don't capture preicse fields of a union.
|
||||||
|
place.projections.truncate(i + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
place
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Truncate projections so that following rules are obeyed by the captured `place`:
|
||||||
|
/// - No Index projections are captured, since arrays are captured completely.
|
||||||
|
/// - No unsafe block is required to capture `place`
|
||||||
|
/// Truncate projections so that following rules are obeyed by the captured `place`:
|
||||||
|
fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
|
||||||
|
place = restrict_precision_for_unsafe(place);
|
||||||
|
|
||||||
|
if place.projections.is_empty() {
|
||||||
|
// Nothing to do here
|
||||||
|
return place;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, proj) in place.projections.iter().enumerate() {
|
||||||
match proj.kind {
|
match proj.kind {
|
||||||
ProjectionKind::Index => {
|
ProjectionKind::Index => {
|
||||||
// Arrays are completely captured, so we drop Index projections
|
// Arrays are completely captured, so we drop Index projections
|
||||||
truncated_length = truncated_length.min(i);
|
place.projections.truncate(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
ProjectionKind::Deref => {}
|
ProjectionKind::Deref => {}
|
||||||
@ -1796,10 +1822,6 @@ fn restrict_capture_precision<'tcx>(mut place: Place<'tcx>) -> Place<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let length = place.projections.len().min(truncated_length);
|
|
||||||
|
|
||||||
place.projections.truncate(length);
|
|
||||||
|
|
||||||
place
|
place
|
||||||
}
|
}
|
||||||
|
|
||||||
|
26
src/test/ui/closures/2229_closure_analysis/issue-87378.rs
Normal file
26
src/test/ui/closures/2229_closure_analysis/issue-87378.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
|
// edition:2021
|
||||||
|
|
||||||
|
// Test that any precise capture on a union is truncated because it's unsafe to do so.
|
||||||
|
|
||||||
|
union Union {
|
||||||
|
value: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let u = Union { value: 42 };
|
||||||
|
|
||||||
|
let c = #[rustc_capture_analysis]
|
||||||
|
//~^ ERROR: attributes on expressions are experimental
|
||||||
|
//~| NOTE: see issue #15701 <https://github.com/rust-lang/rust/issues/15701>
|
||||||
|
|| {
|
||||||
|
//~^ ERROR: First Pass analysis includes:
|
||||||
|
//~| ERROR: Min Capture analysis includes:
|
||||||
|
unsafe { u.value }
|
||||||
|
//~^ NOTE: Capturing u[(0, 0)] -> ImmBorrow
|
||||||
|
//~| NOTE: Min Capture u[] -> ImmBorrow
|
||||||
|
};
|
||||||
|
|
||||||
|
c();
|
||||||
|
}
|
@ -0,0 +1,48 @@
|
|||||||
|
error[E0658]: attributes on expressions are experimental
|
||||||
|
--> $DIR/issue-87378.rs:14:13
|
||||||
|
|
|
||||||
|
LL | let c = #[rustc_capture_analysis]
|
||||||
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
= note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information
|
||||||
|
= help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable
|
||||||
|
|
||||||
|
error: First Pass analysis includes:
|
||||||
|
--> $DIR/issue-87378.rs:17:5
|
||||||
|
|
|
||||||
|
LL | / || {
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | unsafe { u.value }
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | };
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
note: Capturing u[(0, 0)] -> ImmBorrow
|
||||||
|
--> $DIR/issue-87378.rs:20:17
|
||||||
|
|
|
||||||
|
LL | unsafe { u.value }
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: Min Capture analysis includes:
|
||||||
|
--> $DIR/issue-87378.rs:17:5
|
||||||
|
|
|
||||||
|
LL | / || {
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | unsafe { u.value }
|
||||||
|
LL | |
|
||||||
|
LL | |
|
||||||
|
LL | | };
|
||||||
|
| |_____^
|
||||||
|
|
|
||||||
|
note: Min Capture u[] -> ImmBorrow
|
||||||
|
--> $DIR/issue-87378.rs:20:17
|
||||||
|
|
|
||||||
|
LL | unsafe { u.value }
|
||||||
|
| ^^^^^^^
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0658`.
|
@ -0,0 +1,16 @@
|
|||||||
|
// edition:2021
|
||||||
|
// check-pass
|
||||||
|
|
||||||
|
union Union {
|
||||||
|
value: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let u = Union { value: 42 };
|
||||||
|
|
||||||
|
let c = || {
|
||||||
|
unsafe { u.value }
|
||||||
|
};
|
||||||
|
|
||||||
|
c();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user