Rollup merge of #85934 - tmiasko:is-union, r=jackh726
Add `Ty::is_union` predicate
This commit is contained in:
commit
2fddcfda7a
10 changed files with 32 additions and 59 deletions
|
@ -1837,10 +1837,12 @@ impl<'tcx> TyS<'tcx> {
|
|||
|
||||
#[inline]
|
||||
pub fn is_enum(&self) -> bool {
|
||||
match self.kind() {
|
||||
Adt(adt_def, _) => adt_def.is_enum(),
|
||||
_ => false,
|
||||
}
|
||||
matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn is_union(&self) -> bool {
|
||||
matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
|
|
@ -1965,13 +1965,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||
// no move out from an earlier location) then this is an attempt at initialization
|
||||
// of the union - we should error in that case.
|
||||
let tcx = this.infcx.tcx;
|
||||
if let ty::Adt(def, _) = base.ty(this.body(), tcx).ty.kind() {
|
||||
if def.is_union() {
|
||||
if this.move_data.path_map[mpi].iter().any(|moi| {
|
||||
this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
if base.ty(this.body(), tcx).ty.is_union() {
|
||||
if this.move_data.path_map[mpi].iter().any(|moi| {
|
||||
this.move_data.moves[*moi].source.is_predecessor_of(location, this.body)
|
||||
}) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -331,17 +331,14 @@ fn place_projection_conflict<'tcx>(
|
|||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty;
|
||||
match ty.kind() {
|
||||
ty::Adt(def, _) if def.is_union() => {
|
||||
// Different fields of a union, we are basically stuck.
|
||||
debug!("place_element_conflict: STUCK-UNION");
|
||||
Overlap::Arbitrary
|
||||
}
|
||||
_ => {
|
||||
// Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
|
||||
debug!("place_element_conflict: DISJOINT-FIELD");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
if ty.is_union() {
|
||||
// Different fields of a union, we are basically stuck.
|
||||
debug!("place_element_conflict: STUCK-UNION");
|
||||
Overlap::Arbitrary
|
||||
} else {
|
||||
// Different fields of a struct (`a.x` vs. `a.y`). Disjoint!
|
||||
debug!("place_element_conflict: DISJOINT-FIELD");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -519,10 +519,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
|||
// Check if we are assigning into a field of a union, if so, lookup the place
|
||||
// of the union so it is marked as initialized again.
|
||||
if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() {
|
||||
if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() {
|
||||
if def.is_union() {
|
||||
place = place_base;
|
||||
}
|
||||
if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() {
|
||||
place = place_base;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -752,12 +752,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> {
|
|||
| ProjectionElem::Field(..)
|
||||
| ProjectionElem::Index(_) => {
|
||||
let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty;
|
||||
match base_ty.ty_adt_def() {
|
||||
Some(def) if def.is_union() => {
|
||||
self.check_op(ops::UnionAccess);
|
||||
}
|
||||
|
||||
_ => {}
|
||||
if base_ty.is_union() {
|
||||
self.check_op(ops::UnionAccess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -221,7 +221,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
}
|
||||
|
||||
let base_ty = base.ty(self.body, self.tcx).ty;
|
||||
if base_ty.ty_adt_def().map_or(false, |adt| adt.is_union()) {
|
||||
if base_ty.is_union() {
|
||||
// If we did not hit a `Deref` yet and the overall place use is an assignment, the
|
||||
// rules are different.
|
||||
let assign_to_field = !saw_deref
|
||||
|
|
|
@ -114,7 +114,7 @@ use rustc_middle::mir::{
|
|||
traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem,
|
||||
Rvalue, Statement, StatementKind, Terminator, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
||||
// Empirical measurements have resulted in some observations:
|
||||
// - Running on a body with a single block and 500 locals takes barely any time
|
||||
|
@ -910,17 +910,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> {
|
|||
|
||||
// Handle the "subtle case" described above by rejecting any `dest` that is or
|
||||
// projects through a union.
|
||||
let is_union = |ty: Ty<'_>| {
|
||||
if let ty::Adt(def, _) = ty.kind() {
|
||||
if def.is_union() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
};
|
||||
let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty);
|
||||
if is_union(place_ty.ty) {
|
||||
if place_ty.ty.is_union() {
|
||||
return;
|
||||
}
|
||||
for elem in dest.projection {
|
||||
|
@ -930,7 +921,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> {
|
|||
}
|
||||
|
||||
place_ty = place_ty.projection_ty(self.tcx, elem);
|
||||
if is_union(place_ty.ty) {
|
||||
if place_ty.ty.is_union() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -415,11 +415,9 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||
|
||||
ProjectionElem::Field(..) => {
|
||||
let base_ty = place_base.ty(self.body, self.tcx).ty;
|
||||
if let Some(def) = base_ty.ty_adt_def() {
|
||||
if base_ty.is_union() {
|
||||
// No promotion of union field accesses.
|
||||
if def.is_union() {
|
||||
return Err(Unpromotable);
|
||||
}
|
||||
return Err(Unpromotable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,21 +69,14 @@ fn involves_a_union<'tcx>(
|
|||
tcx: TyCtxt<'tcx>,
|
||||
) -> bool {
|
||||
let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty);
|
||||
if is_union(place_ty.ty) {
|
||||
if place_ty.ty.is_union() {
|
||||
return true;
|
||||
}
|
||||
for elem in place.projection {
|
||||
place_ty = place_ty.projection_ty(tcx, elem);
|
||||
if is_union(place_ty.ty) {
|
||||
if place_ty.ty.is_union() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
fn is_union(ty: Ty<'_>) -> bool {
|
||||
match ty.kind() {
|
||||
ty::Adt(def, _) if def.is_union() => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||
// Clear previous flag; after a pointer indirection it does not apply any more.
|
||||
inside_union = false;
|
||||
}
|
||||
if source.ty_adt_def().map_or(false, |adt| adt.is_union()) {
|
||||
if source.is_union() {
|
||||
inside_union = true;
|
||||
}
|
||||
// Fix up the autoderefs. Autorefs can only occur immediately preceding
|
||||
|
|
Loading…
Add table
Reference in a new issue