promoted is still left in 2 places
This commit is contained in:
parent
03dafa7da3
commit
7fb1c22da1
22 changed files with 333 additions and 280 deletions
|
|
@ -1913,9 +1913,6 @@ pub enum PlaceBase<'tcx> {
|
|||
|
||||
/// static or static mut variable
|
||||
Static(Box<Static<'tcx>>),
|
||||
|
||||
/// Constant code promoted to an injected static
|
||||
Promoted(Box<(Promoted, Ty<'tcx>)>),
|
||||
}
|
||||
|
||||
/// The `DefId` of a static, along with its normalized type (which is
|
||||
|
|
@ -1924,11 +1921,13 @@ pub enum PlaceBase<'tcx> {
|
|||
pub struct Static<'tcx> {
|
||||
pub def_id: DefId,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub promoted: Option<Promoted>,
|
||||
}
|
||||
|
||||
impl_stable_hash_for!(struct Static<'tcx> {
|
||||
def_id,
|
||||
ty
|
||||
ty,
|
||||
promoted
|
||||
});
|
||||
|
||||
/// The `Projection` data structure defines things of the form `B.x`
|
||||
|
|
@ -2048,7 +2047,7 @@ impl<'tcx> Place<'tcx> {
|
|||
match self {
|
||||
Place::Base(PlaceBase::Local(local)) => Some(*local),
|
||||
Place::Projection(box Projection { base, elem: _ }) => base.base_local(),
|
||||
Place::Base(PlaceBase::Promoted(..)) | Place::Base(PlaceBase::Static(..)) => None,
|
||||
Place::Base(PlaceBase::Static(..)) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2059,18 +2058,22 @@ impl<'tcx> Debug for Place<'tcx> {
|
|||
|
||||
match *self {
|
||||
Base(PlaceBase::Local(id)) => write!(fmt, "{:?}", id),
|
||||
Base(PlaceBase::Static(box self::Static { def_id, ty })) => write!(
|
||||
fmt,
|
||||
"({}: {:?})",
|
||||
ty::tls::with(|tcx| tcx.def_path_str(def_id)),
|
||||
ty
|
||||
),
|
||||
Base(PlaceBase::Promoted(ref promoted)) => write!(
|
||||
fmt,
|
||||
"({:?}: {:?})",
|
||||
promoted.0,
|
||||
promoted.1
|
||||
),
|
||||
Base(PlaceBase::Static(box self::Static { def_id, ty, promoted })) => {
|
||||
match promoted {
|
||||
None => write!(
|
||||
fmt,
|
||||
"({}: {:?})",
|
||||
ty::tls::with(|tcx| tcx.def_path_str(def_id)),
|
||||
ty
|
||||
),
|
||||
Some(pr) => write!(
|
||||
fmt,
|
||||
"({:?}: {:?})",
|
||||
pr,
|
||||
ty
|
||||
),
|
||||
}
|
||||
},
|
||||
Projection(ref data) => match data.elem {
|
||||
ProjectionElem::Downcast(ref adt_def, index) => {
|
||||
write!(fmt, "({:?} as {})", data.base, adt_def.variants[index].ident)
|
||||
|
|
|
|||
|
|
@ -160,7 +160,6 @@ impl<'tcx> Place<'tcx> {
|
|||
match *self {
|
||||
Place::Base(PlaceBase::Local(index)) =>
|
||||
PlaceTy::Ty { ty: local_decls.local_decls()[index].ty },
|
||||
Place::Base(PlaceBase::Promoted(ref data)) => PlaceTy::Ty { ty: data.1 },
|
||||
Place::Base(PlaceBase::Static(ref data)) =>
|
||||
PlaceTy::Ty { ty: data.ty },
|
||||
Place::Projection(ref proj) =>
|
||||
|
|
|
|||
|
|
@ -737,11 +737,18 @@ macro_rules! make_mir_visitor {
|
|||
self.visit_local(local, context, location);
|
||||
}
|
||||
Place::Base(PlaceBase::Static(static_)) => {
|
||||
match static_.promoted {
|
||||
None => {
|
||||
self.visit_static(static_, context, location);
|
||||
}
|
||||
Some(_) => {
|
||||
self.visit_ty(
|
||||
& $($mutability)? static_.ty, TyContext::Location(location)
|
||||
);
|
||||
}
|
||||
}
|
||||
self.visit_static(static_, context, location);
|
||||
}
|
||||
Place::Base(PlaceBase::Promoted(promoted)) => {
|
||||
self.visit_ty(& $($mutability)? promoted.1, TyContext::Location(location));
|
||||
},
|
||||
Place::Projection(proj) => {
|
||||
self.visit_projection(proj, context, location);
|
||||
}
|
||||
|
|
@ -752,7 +759,7 @@ macro_rules! make_mir_visitor {
|
|||
static_: & $($mutability)? Static<'tcx>,
|
||||
_context: PlaceContext<'tcx>,
|
||||
location: Location) {
|
||||
let Static { def_id, ty } = static_;
|
||||
let Static { def_id, ty, promoted: _ } = static_;
|
||||
self.visit_def_id(def_id, location);
|
||||
self.visit_ty(ty, TyContext::Location(location));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1598,14 +1598,18 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
including_downcast: &IncludingDowncast,
|
||||
) -> Result<(), ()> {
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Promoted(_)) => {
|
||||
buf.push_str("promoted");
|
||||
}
|
||||
Place::Base(PlaceBase::Local(local)) => {
|
||||
self.append_local_to_string(local, buf)?;
|
||||
}
|
||||
Place::Base(PlaceBase::Static(ref static_)) => {
|
||||
buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
|
||||
match static_.promoted {
|
||||
Some(_) => {
|
||||
buf.push_str("promoted");
|
||||
}
|
||||
None => {
|
||||
buf.push_str(&self.infcx.tcx.item_name(static_.def_id).to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
Place::Projection(ref proj) => {
|
||||
match proj.elem {
|
||||
|
|
@ -1744,8 +1748,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
let local = &self.mir.local_decls[local];
|
||||
self.describe_field_from_ty(&local.ty, field)
|
||||
}
|
||||
Place::Base(PlaceBase::Promoted(ref prom)) =>
|
||||
self.describe_field_from_ty(&prom.1, field),
|
||||
Place::Base(PlaceBase::Static(ref static_)) =>
|
||||
self.describe_field_from_ty(&static_.ty, field),
|
||||
Place::Projection(ref proj) => match proj.elem {
|
||||
|
|
@ -1828,8 +1830,7 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
let tcx = self.infcx.tcx;
|
||||
match place {
|
||||
Place::Base(PlaceBase::Local(_)) |
|
||||
Place::Base(PlaceBase::Static(_)) |
|
||||
Place::Base(PlaceBase::Promoted(_)) => {
|
||||
Place::Base(PlaceBase::Static(_)) => {
|
||||
StorageDeadOrDrop::LocalStorageDead
|
||||
}
|
||||
Place::Projection(box PlaceProjection { base, elem }) => {
|
||||
|
|
|
|||
|
|
@ -1226,8 +1226,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
Operand::Move(Place::Base(PlaceBase::Static(..)))
|
||||
| Operand::Copy(Place::Base(PlaceBase::Static(..)))
|
||||
| Operand::Move(Place::Base(PlaceBase::Promoted(..)))
|
||||
| Operand::Copy(Place::Base(PlaceBase::Promoted(..)))
|
||||
| Operand::Constant(..) => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -1310,12 +1308,16 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
//
|
||||
// FIXME: allow thread-locals to borrow other thread locals?
|
||||
let (might_be_alive, will_be_dropped) = match root_place {
|
||||
Place::Base(PlaceBase::Promoted(_)) => (true, false),
|
||||
Place::Base(PlaceBase::Static(_)) => {
|
||||
// Thread-locals might be dropped after the function exits, but
|
||||
// "true" statics will never be.
|
||||
let is_thread_local = self.is_place_thread_local(&root_place);
|
||||
(true, is_thread_local)
|
||||
Place::Base(PlaceBase::Static(st)) => {
|
||||
match st.promoted {
|
||||
None => {
|
||||
// Thread-locals might be dropped after the function exits, but
|
||||
// "true" statics will never be.
|
||||
let is_thread_local = self.is_place_thread_local(&root_place);
|
||||
(true, is_thread_local)
|
||||
}
|
||||
Some(_) => (true, false),
|
||||
}
|
||||
}
|
||||
Place::Base(PlaceBase::Local(_)) => {
|
||||
// Locals are always dropped at function exit, and if they
|
||||
|
|
@ -1578,7 +1580,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
match *last_prefix {
|
||||
Place::Base(PlaceBase::Local(_)) => panic!("should have move path for every Local"),
|
||||
Place::Projection(_) => panic!("PrefixSet::All meant don't stop for Projection"),
|
||||
Place::Base(PlaceBase::Promoted(_)) |
|
||||
Place::Base(PlaceBase::Static(_)) => Err(NoMovePathFound::ReachedStatic),
|
||||
}
|
||||
}
|
||||
|
|
@ -1605,7 +1606,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
let mut place = place;
|
||||
loop {
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Promoted(_)) |
|
||||
Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => {
|
||||
// assigning to `x` does not require `x` be initialized.
|
||||
break;
|
||||
|
|
@ -1953,10 +1953,6 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
self.used_mut_upvars.push(field);
|
||||
}
|
||||
}
|
||||
RootPlace {
|
||||
place: Place::Base(PlaceBase::Promoted(..)),
|
||||
is_local_mutation_allowed: _,
|
||||
} => {}
|
||||
RootPlace {
|
||||
place: Place::Base(PlaceBase::Static(..)),
|
||||
is_local_mutation_allowed: _,
|
||||
|
|
@ -1994,18 +1990,28 @@ impl<'cx, 'gcx, 'tcx> MirBorrowckCtxt<'cx, 'gcx, 'tcx> {
|
|||
}
|
||||
// The rules for promotion are made by `qualify_consts`, there wouldn't even be a
|
||||
// `Place::Promoted` if the promotion weren't 100% legal. So we just forward this
|
||||
Place::Base(PlaceBase::Promoted(_)) => Ok(RootPlace {
|
||||
place,
|
||||
is_local_mutation_allowed,
|
||||
}),
|
||||
// Place::Base(PlaceBase::Promoted(_)) => Ok(RootPlace {
|
||||
// place,
|
||||
// is_local_mutation_allowed,
|
||||
// }),
|
||||
Place::Base(PlaceBase::Static(ref static_)) => {
|
||||
if self.infcx.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
|
||||
Err(place)
|
||||
} else {
|
||||
Ok(RootPlace {
|
||||
place,
|
||||
is_local_mutation_allowed,
|
||||
})
|
||||
match static_.promoted {
|
||||
Some(_) => {
|
||||
Ok(RootPlace {
|
||||
place,
|
||||
is_local_mutation_allowed,
|
||||
})
|
||||
}
|
||||
None => {
|
||||
if self.infcx.tcx.is_static(static_.def_id) != Some(hir::Mutability::MutMutable) {
|
||||
Err(place)
|
||||
} else {
|
||||
Ok(RootPlace {
|
||||
place,
|
||||
is_local_mutation_allowed,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Place::Projection(ref proj) => {
|
||||
|
|
|
|||
|
|
@ -129,16 +129,19 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
Place::Base(PlaceBase::Promoted(_)) => unreachable!(),
|
||||
|
||||
Place::Base(PlaceBase::Static(box Static { def_id, ty: _ })) => {
|
||||
if let Place::Base(PlaceBase::Static(_)) = access_place {
|
||||
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
|
||||
reason = String::new();
|
||||
} else {
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
let static_name = &self.infcx.tcx.item_name(*def_id);
|
||||
reason = format!(", as `{}` is an immutable static item", static_name);
|
||||
Place::Base(PlaceBase::Static(box Static { def_id, ty: _, promoted })) => {
|
||||
match promoted {
|
||||
Some(_) => unreachable!(),
|
||||
None => {
|
||||
if let Place::Base(PlaceBase::Static(_)) = access_place {
|
||||
item_msg = format!("immutable static item `{}`", access_place_desc.unwrap());
|
||||
reason = String::new();
|
||||
} else {
|
||||
item_msg = format!("`{}`", access_place_desc.unwrap());
|
||||
let static_name = &self.infcx.tcx.item_name(*def_id);
|
||||
reason = format!(", as `{}` is an immutable static item", static_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -453,51 +453,55 @@ impl<'a, 'b, 'gcx, 'tcx> TypeVerifier<'a, 'b, 'gcx, 'tcx> {
|
|||
Place::Base(PlaceBase::Local(index)) => PlaceTy::Ty {
|
||||
ty: self.mir.local_decls[index].ty,
|
||||
},
|
||||
Place::Base(PlaceBase::Promoted(box (index, sty))) => {
|
||||
let sty = self.sanitize_type(place, sty);
|
||||
Place::Base(PlaceBase::Static(box Static { def_id, ty: sty, promoted })) => {
|
||||
match promoted {
|
||||
Some(pr) => {
|
||||
let sty = self.sanitize_type(place, sty);
|
||||
|
||||
if !self.errors_reported {
|
||||
let promoted_mir = &self.mir.promoted[index];
|
||||
self.sanitize_promoted(promoted_mir, location);
|
||||
if !self.errors_reported {
|
||||
let promoted_mir = &self.mir.promoted[pr];
|
||||
self.sanitize_promoted(promoted_mir, location);
|
||||
|
||||
let promoted_ty = promoted_mir.return_ty();
|
||||
let promoted_ty = promoted_mir.return_ty();
|
||||
|
||||
if let Err(terr) = self.cx.eq_types(
|
||||
sty,
|
||||
promoted_ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
place,
|
||||
"bad promoted type ({:?}: {:?}): {:?}",
|
||||
promoted_ty,
|
||||
sty,
|
||||
terr
|
||||
);
|
||||
};
|
||||
if let Err(terr) = self.cx.eq_types(
|
||||
sty,
|
||||
promoted_ty,
|
||||
location.to_locations(),
|
||||
ConstraintCategory::Boring,
|
||||
) {
|
||||
span_mirbug!(
|
||||
self,
|
||||
place,
|
||||
"bad promoted type ({:?}: {:?}): {:?}",
|
||||
promoted_ty,
|
||||
sty,
|
||||
terr
|
||||
);
|
||||
};
|
||||
}
|
||||
PlaceTy::Ty { ty: sty }
|
||||
}
|
||||
None => {
|
||||
let sty = self.sanitize_type(place, sty);
|
||||
let ty = self.tcx().type_of(def_id);
|
||||
let ty = self.cx.normalize(ty, location);
|
||||
if let Err(terr) =
|
||||
self.cx
|
||||
.eq_types(ty, sty, location.to_locations(), ConstraintCategory::Boring)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
place,
|
||||
"bad static type ({:?}: {:?}): {:?}",
|
||||
ty,
|
||||
sty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
PlaceTy::Ty { ty: sty }
|
||||
}
|
||||
}
|
||||
PlaceTy::Ty { ty: sty }
|
||||
}
|
||||
Place::Base(PlaceBase::Static(box Static { def_id, ty: sty })) => {
|
||||
let sty = self.sanitize_type(place, sty);
|
||||
let ty = self.tcx().type_of(def_id);
|
||||
let ty = self.cx.normalize(ty, location);
|
||||
if let Err(terr) =
|
||||
self.cx
|
||||
.eq_types(ty, sty, location.to_locations(), ConstraintCategory::Boring)
|
||||
{
|
||||
span_mirbug!(
|
||||
self,
|
||||
place,
|
||||
"bad static type ({:?}: {:?}): {:?}",
|
||||
ty,
|
||||
sty,
|
||||
terr
|
||||
);
|
||||
}
|
||||
PlaceTy::Ty { ty: sty }
|
||||
}
|
||||
Place::Projection(ref proj) => {
|
||||
let base_context = if context.is_mutating_use() {
|
||||
|
|
|
|||
|
|
@ -138,7 +138,6 @@ pub(super) fn is_active<'tcx>(
|
|||
/// This is called for all Yield statements on movable generators
|
||||
pub(super) fn borrow_of_local_data<'tcx>(place: &Place<'tcx>) -> bool {
|
||||
match place {
|
||||
Place::Base(PlaceBase::Promoted(_)) |
|
||||
Place::Base(PlaceBase::Static(..)) => false,
|
||||
Place::Base(PlaceBase::Local(..)) => true,
|
||||
Place::Projection(box proj) => {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,6 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
|||
locals_state_at_exit: &LocalsStateAtExit,
|
||||
) -> bool {
|
||||
match self {
|
||||
Place::Base(PlaceBase::Promoted(_)) => false,
|
||||
|
||||
// If a local variable is immutable, then we only need to track borrows to guard
|
||||
// against two kinds of errors:
|
||||
// * The variable being dropped while still borrowed (e.g., because the fn returns
|
||||
|
|
@ -52,7 +50,12 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
|||
}
|
||||
}
|
||||
Place::Base(PlaceBase::Static(static_)) => {
|
||||
tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
|
||||
match static_.promoted {
|
||||
Some(_) => false,
|
||||
None => {
|
||||
tcx.is_static(static_.def_id) == Some(hir::Mutability::MutMutable)
|
||||
}
|
||||
}
|
||||
}
|
||||
Place::Projection(proj) => match proj.elem {
|
||||
ProjectionElem::Field(..)
|
||||
|
|
@ -88,7 +91,6 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> {
|
|||
loop {
|
||||
match p {
|
||||
Place::Projection(pi) => p = &pi.base,
|
||||
Place::Base(PlaceBase::Promoted(_)) |
|
||||
Place::Base(PlaceBase::Static(_)) => return None,
|
||||
Place::Base(PlaceBase::Local(l)) => return Some(*l),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,7 +338,6 @@ fn unroll_place<'tcx, R>(
|
|||
op,
|
||||
),
|
||||
|
||||
Place::Base(PlaceBase::Promoted(_)) |
|
||||
Place::Base(PlaceBase::Local(_)) | Place::Base(PlaceBase::Static(_)) => {
|
||||
let list = PlaceComponents {
|
||||
component: place,
|
||||
|
|
@ -371,41 +370,45 @@ fn place_element_conflict<'a, 'gcx: 'tcx, 'tcx>(
|
|||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(Place::Base(PlaceBase::Static(static1)), Place::Base(PlaceBase::Static(static2))) => {
|
||||
if static1.def_id != static2.def_id {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC");
|
||||
Overlap::Disjoint
|
||||
} else if tcx.is_static(static1.def_id) == Some(hir::Mutability::MutMutable) {
|
||||
// We ignore mutable statics - they can only be unsafe code.
|
||||
debug!("place_element_conflict: IGNORE-STATIC-MUT");
|
||||
Overlap::Disjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC");
|
||||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
}
|
||||
(Place::Base(PlaceBase::Promoted(p1)), Place::Base(PlaceBase::Promoted(p2))) => {
|
||||
if p1.0 == p2.0 {
|
||||
if let ty::Array(_, size) = p1.1.sty {
|
||||
if size.unwrap_usize(tcx) == 0 {
|
||||
// Ignore conflicts with promoted [T; 0].
|
||||
debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
|
||||
return Overlap::Disjoint;
|
||||
(Place::Base(PlaceBase::Static(s1)), Place::Base(PlaceBase::Static(s2))) => {
|
||||
match (s1.promoted, s2.promoted) {
|
||||
(None, None) => {
|
||||
if s1.def_id != s2.def_id {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC");
|
||||
Overlap::Disjoint
|
||||
} else if tcx.is_static(s1.def_id) == Some(hir::Mutability::MutMutable) {
|
||||
// We ignore mutable statics - they can only be unsafe code.
|
||||
debug!("place_element_conflict: IGNORE-STATIC-MUT");
|
||||
Overlap::Disjoint
|
||||
} else {
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-STATIC");
|
||||
Overlap::EqualOrDisjoint
|
||||
}
|
||||
},
|
||||
(Some(p1), Some(p2)) => {
|
||||
if p1 == p2 {
|
||||
if let ty::Array(_, size) =s1.ty.sty {
|
||||
if size.unwrap_usize(tcx) == 0 {
|
||||
// Ignore conflicts with promoted [T; 0].
|
||||
debug!("place_element_conflict: IGNORE-LEN-0-PROMOTED");
|
||||
return Overlap::Disjoint;
|
||||
}
|
||||
}
|
||||
// the same promoted - base case, equal
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
// different promoteds - base case, disjoint
|
||||
debug!("place_element_conflict: DISJOINT-PROMOTED");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
},
|
||||
(p1_, p2_) => {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
// the same promoted - base case, equal
|
||||
debug!("place_element_conflict: DISJOINT-OR-EQ-PROMOTED");
|
||||
Overlap::EqualOrDisjoint
|
||||
} else {
|
||||
// different promoteds - base case, disjoint
|
||||
debug!("place_element_conflict: DISJOINT-PROMOTED");
|
||||
Overlap::Disjoint
|
||||
}
|
||||
}
|
||||
(Place::Base(PlaceBase::Local(_)), Place::Base(PlaceBase::Promoted(_))) |
|
||||
(Place::Base(PlaceBase::Promoted(_)), Place::Base(PlaceBase::Local(_))) |
|
||||
(Place::Base(PlaceBase::Promoted(_)), Place::Base(PlaceBase::Static(_))) |
|
||||
(Place::Base(PlaceBase::Static(_)), Place::Base(PlaceBase::Promoted(_))) |
|
||||
(Place::Base(PlaceBase::Local(_)), Place::Base(PlaceBase::Static(_))) |
|
||||
(Place::Base(PlaceBase::Static(_)), Place::Base(PlaceBase::Local(_))) => {
|
||||
debug!("place_element_conflict: DISJOINT-STATIC-LOCAL-PROMOTED");
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ impl<'tcx> IsPrefixOf<'tcx> for Place<'tcx> {
|
|||
}
|
||||
|
||||
match *cursor {
|
||||
Place::Base(PlaceBase::Promoted(_)) |
|
||||
Place::Base(PlaceBase::Local(_)) |
|
||||
Place::Base(PlaceBase::Static(_)) => return false,
|
||||
Place::Projection(ref proj) => {
|
||||
|
|
@ -87,7 +86,6 @@ impl<'cx, 'gcx, 'tcx> Iterator for Prefixes<'cx, 'gcx, 'tcx> {
|
|||
|
||||
'cursor: loop {
|
||||
let proj = match *cursor {
|
||||
Place::Base(PlaceBase::Promoted(_)) |
|
||||
Place::Base(PlaceBase::Local(_)) | // search yielded this leaf
|
||||
Place::Base(PlaceBase::Static(_)) => {
|
||||
self.next = None;
|
||||
|
|
|
|||
|
|
@ -128,6 +128,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||
ExprKind::StaticRef { id } => block.and(Place::Base(PlaceBase::Static(Box::new(Static {
|
||||
def_id: id,
|
||||
ty: expr.ty,
|
||||
promoted: None,
|
||||
})))),
|
||||
|
||||
ExprKind::PlaceTypeAscription { source, user_ty } => {
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@ struct BorrowedLocalsVisitor<'b, 'c: 'b> {
|
|||
fn find_local<'tcx>(place: &Place<'tcx>) -> Option<Local> {
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Local(l)) => Some(l),
|
||||
Place::Base(PlaceBase::Promoted(_)) |
|
||||
Place::Base(PlaceBase::Static(..)) => None,
|
||||
Place::Projection(ref proj) => {
|
||||
match proj.elem {
|
||||
|
|
|
|||
|
|
@ -97,7 +97,6 @@ impl<'b, 'a, 'gcx, 'tcx> Gatherer<'b, 'a, 'gcx, 'tcx> {
|
|||
debug!("lookup({:?})", place);
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Local(local)) => Ok(self.builder.data.rev_lookup.locals[local]),
|
||||
Place::Base(PlaceBase::Promoted(..)) |
|
||||
Place::Base(PlaceBase::Static(..)) => {
|
||||
Err(MoveError::cannot_move_out_of(self.loc, Static))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -286,7 +286,6 @@ impl<'tcx> MovePathLookup<'tcx> {
|
|||
pub fn find(&self, place: &Place<'tcx>) -> LookupResult {
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Local(local)) => LookupResult::Exact(self.locals[local]),
|
||||
Place::Base(PlaceBase::Promoted(_)) |
|
||||
Place::Base(PlaceBase::Static(..)) => LookupResult::Parent(None),
|
||||
Place::Projection(ref proj) => {
|
||||
match self.find(&proj.base) {
|
||||
|
|
|
|||
|
|
@ -583,35 +583,38 @@ where
|
|||
use rustc::mir::Place::*;
|
||||
use rustc::mir::PlaceBase;
|
||||
Ok(match *mir_place {
|
||||
Base(PlaceBase::Promoted(ref promoted)) => {
|
||||
let instance = self.frame().instance;
|
||||
self.const_eval_raw(GlobalId {
|
||||
instance,
|
||||
promoted: Some(promoted.0),
|
||||
})?
|
||||
}
|
||||
|
||||
Base(PlaceBase::Static(ref static_)) => {
|
||||
assert!(!static_.ty.needs_subst());
|
||||
let layout = self.layout_of(static_.ty)?;
|
||||
let instance = ty::Instance::mono(*self.tcx, static_.def_id);
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None
|
||||
};
|
||||
// Just create a lazy reference, so we can support recursive statics.
|
||||
// tcx takes are of assigning every static one and only one unique AllocId.
|
||||
// When the data here is ever actually used, memory will notice,
|
||||
// and it knows how to deal with alloc_id that are present in the
|
||||
// global table but not in its local memory: It calls back into tcx through
|
||||
// a query, triggering the CTFE machinery to actually turn this lazy reference
|
||||
// into a bunch of bytes. IOW, statics are evaluated with CTFE even when
|
||||
// this EvalContext uses another Machine (e.g., in miri). This is what we
|
||||
// want! This way, computing statics works concistently between codegen
|
||||
// and miri: They use the same query to eventually obtain a `ty::Const`
|
||||
// and use that for further computation.
|
||||
let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
|
||||
MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
|
||||
match static_.promoted {
|
||||
Some(promoted) => {
|
||||
let instance = self.frame().instance;
|
||||
self.const_eval_raw(GlobalId {
|
||||
instance,
|
||||
promoted: Some(promoted),
|
||||
})?
|
||||
}
|
||||
None => {
|
||||
assert!(!static_.ty.needs_subst());
|
||||
let layout = self.layout_of(static_.ty)?;
|
||||
let instance = ty::Instance::mono(*self.tcx, static_.def_id);
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: None
|
||||
};
|
||||
// Just create a lazy reference, so we can support recursive statics.
|
||||
// tcx takes are of assigning every static one and only one unique AllocId.
|
||||
// When the data here is ever actually used, memory will notice,
|
||||
// and it knows how to deal with alloc_id that are present in the
|
||||
// global table but not in its local memory: It calls back into tcx through
|
||||
// a query, triggering the CTFE machinery to actually turn this lazy reference
|
||||
// into a bunch of bytes. IOW, statics are evaluated with CTFE even when
|
||||
// this EvalContext uses another Machine (e.g., in miri). This is what we
|
||||
// want! This way, computing statics works concistently between codegen
|
||||
// and miri: They use the same query to eventually obtain a `ty::Const`
|
||||
// and use that for further computation.
|
||||
let alloc = self.tcx.alloc_map.lock().intern_static(cid.instance.def_id());
|
||||
MPlaceTy::from_aligned_ptr(Pointer::from(alloc).with_default_tag(), layout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => bug!("eval_place_to_mplace called on {:?}", mir_place),
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ fn is_stable<'tcx>(
|
|||
match *place {
|
||||
// Locals and statics have stable addresses, for sure
|
||||
Base(PlaceBase::Local { .. }) |
|
||||
Base(PlaceBase::Promoted { .. }) |
|
||||
Base(PlaceBase::Static { .. }) =>
|
||||
true,
|
||||
// Recurse for projections
|
||||
|
|
|
|||
|
|
@ -300,29 +300,33 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> {
|
|||
&Place::Base(PlaceBase::Local(..)) => {
|
||||
// locals are safe
|
||||
}
|
||||
&Place::Base(PlaceBase::Promoted(_)) => {
|
||||
bug!("unsafety checking should happen before promotion")
|
||||
}
|
||||
&Place::Base(PlaceBase::Static(box Static { def_id, ty: _ })) => {
|
||||
if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) {
|
||||
self.require_unsafe("use of mutable static",
|
||||
"mutable statics can be mutated by multiple threads: aliasing violations \
|
||||
or data races will cause undefined behavior",
|
||||
UnsafetyViolationKind::General);
|
||||
} else if self.tcx.is_foreign_item(def_id) {
|
||||
let source_info = self.source_info;
|
||||
let lint_root =
|
||||
self.source_scope_local_data[source_info.scope].lint_root;
|
||||
self.register_violations(&[UnsafetyViolation {
|
||||
source_info,
|
||||
description: Symbol::intern("use of extern static").as_interned_str(),
|
||||
details:
|
||||
Symbol::intern("extern statics are not controlled by the Rust type \
|
||||
system: invalid data, aliasing violations or data \
|
||||
races will cause undefined behavior")
|
||||
.as_interned_str(),
|
||||
kind: UnsafetyViolationKind::ExternStatic(lint_root)
|
||||
}], &[]);
|
||||
&Place::Base(PlaceBase::Static(box Static { def_id, ty: _, promoted })) => {
|
||||
match promoted {
|
||||
Some(..) => {
|
||||
bug!("unsafety checking should happen before promotion")
|
||||
}
|
||||
None => {
|
||||
if self.tcx.is_static(def_id) == Some(hir::Mutability::MutMutable) {
|
||||
self.require_unsafe("use of mutable static",
|
||||
"mutable statics can be mutated by multiple threads: aliasing violations \
|
||||
or data races will cause undefined behavior",
|
||||
UnsafetyViolationKind::General);
|
||||
} else if self.tcx.is_foreign_item(def_id) {
|
||||
let source_info = self.source_info;
|
||||
let lint_root =
|
||||
self.source_scope_local_data[source_info.scope].lint_root;
|
||||
self.register_violations(&[UnsafetyViolation {
|
||||
source_info,
|
||||
description: Symbol::intern("use of extern static").as_interned_str(),
|
||||
details:
|
||||
Symbol::intern("extern statics are not controlled by the Rust type \
|
||||
system: invalid data, aliasing violations or data \
|
||||
races will cause undefined behavior")
|
||||
.as_interned_str(),
|
||||
kind: UnsafetyViolationKind::ExternStatic(lint_root)
|
||||
}], &[]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -282,25 +282,31 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
|
|||
// an `Index` projection would throw us off-track.
|
||||
_ => None,
|
||||
},
|
||||
Place::Base(PlaceBase::Promoted(ref promoted)) => {
|
||||
let generics = self.tcx.generics_of(self.source.def_id());
|
||||
if generics.requires_monomorphization(self.tcx) {
|
||||
// FIXME: can't handle code with generics
|
||||
return None;
|
||||
Place::Base(PlaceBase::Static(ref static_)) => {
|
||||
match static_.promoted {
|
||||
Some(promoted) => {
|
||||
let generics = self.tcx.generics_of(self.source.def_id());
|
||||
if generics.requires_monomorphization(self.tcx) {
|
||||
// FIXME: can't handle code with generics
|
||||
return None;
|
||||
}
|
||||
let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
|
||||
let instance = Instance::new(self.source.def_id(), substs);
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: Some(promoted),
|
||||
};
|
||||
// cannot use `const_eval` here, because that would require having the MIR
|
||||
// for the current function available, but we're producing said MIR right now
|
||||
let res = self.use_ecx(source_info, |this| {
|
||||
eval_promoted(this.tcx, cid, this.mir, this.param_env)
|
||||
})?;
|
||||
trace!("evaluated promoted {:?} to {:?}", promoted, res);
|
||||
Some((res.into(), source_info.span))
|
||||
}
|
||||
None => None
|
||||
}
|
||||
let substs = InternalSubsts::identity_for_item(self.tcx, self.source.def_id());
|
||||
let instance = Instance::new(self.source.def_id(), substs);
|
||||
let cid = GlobalId {
|
||||
instance,
|
||||
promoted: Some(promoted.0),
|
||||
};
|
||||
// cannot use `const_eval` here, because that would require having the MIR
|
||||
// for the current function available, but we're producing said MIR right now
|
||||
let res = self.use_ecx(source_info, |this| {
|
||||
eval_promoted(this.tcx, cid, this.mir, this.param_env)
|
||||
})?;
|
||||
trace!("evaluated promoted {:?} to {:?}", promoted, res);
|
||||
Some((res.into(), source_info.span))
|
||||
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -692,12 +692,16 @@ impl<'a, 'tcx> MutVisitor<'tcx> for Integrator<'a, 'tcx> {
|
|||
// Return pointer; update the place itself
|
||||
*place = self.destination.clone();
|
||||
},
|
||||
Place::Base(PlaceBase::Promoted(ref mut promoted)) => {
|
||||
if let Some(p) = self.promoted_map.get(promoted.0).cloned() {
|
||||
promoted.0 = p;
|
||||
Place::Base(PlaceBase::Static(ref mut static_)) => {
|
||||
match static_.promoted {
|
||||
Some(promoted) => {
|
||||
if let Some(p) = self.promoted_map.get(promoted).cloned() {
|
||||
static_.promoted = Some(p);
|
||||
}
|
||||
}
|
||||
None => self.super_place(place, _ctxt, _location)
|
||||
}
|
||||
},
|
||||
_ => self.super_place(place, _ctxt, _location),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -188,8 +188,12 @@ trait Qualif {
|
|||
fn in_place(cx: &ConstCx<'_, 'tcx>, place: &Place<'tcx>) -> bool {
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Local(local)) => Self::in_local(cx, local),
|
||||
Place::Base(PlaceBase::Promoted(_)) => bug!("qualifying already promoted MIR"),
|
||||
Place::Base(PlaceBase::Static(ref static_)) => Self::in_static(cx, static_),
|
||||
Place::Base(PlaceBase::Static(ref static_)) => {
|
||||
match static_.promoted {
|
||||
Some(..) => bug!("qualifying already promoted MIR"),
|
||||
None => Self::in_static(cx, static_),
|
||||
}
|
||||
},
|
||||
Place::Projection(ref proj) => Self::in_projection(cx, proj),
|
||||
}
|
||||
}
|
||||
|
|
@ -768,17 +772,20 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
|
|||
);
|
||||
dest = &proj.base;
|
||||
},
|
||||
Place::Base(PlaceBase::Promoted(..)) =>
|
||||
bug!("promoteds don't exist yet during promotion"),
|
||||
Place::Base(PlaceBase::Static(..)) => {
|
||||
// Catch more errors in the destination. `visit_place` also checks that we
|
||||
// do not try to access statics from constants or try to mutate statics
|
||||
self.visit_place(
|
||||
dest,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
location
|
||||
);
|
||||
return;
|
||||
Place::Base(PlaceBase::Static(st)) => {
|
||||
match st.promoted {
|
||||
Some(..) => bug!("promoteds don't exist yet during promotion"),
|
||||
None => {
|
||||
// Catch more errors in the destination. `visit_place` also checks that we
|
||||
// do not try to access statics from constants or try to mutate statics
|
||||
self.visit_place(
|
||||
dest,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store),
|
||||
location
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
@ -919,51 +926,55 @@ impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
|
|||
debug!("visit_place: place={:?} context={:?} location={:?}", place, context, location);
|
||||
self.super_place(place, context, location);
|
||||
match *place {
|
||||
Place::Base(PlaceBase::Local(_)) |
|
||||
Place::Base(PlaceBase::Promoted(_)) => {}
|
||||
Place::Base(PlaceBase::Local(_)) => {}
|
||||
Place::Base(PlaceBase::Static(ref global)) => {
|
||||
if self.tcx
|
||||
.get_attrs(global.def_id)
|
||||
.iter()
|
||||
.any(|attr| attr.check_name("thread_local")) {
|
||||
if self.mode != Mode::Fn {
|
||||
span_err!(self.tcx.sess, self.span, E0625,
|
||||
"thread-local statics cannot be \
|
||||
accessed at compile-time");
|
||||
}
|
||||
return;
|
||||
}
|
||||
match global.promoted {
|
||||
Some(..) => {}
|
||||
None => {
|
||||
if self.tcx
|
||||
.get_attrs(global.def_id)
|
||||
.iter()
|
||||
.any(|attr| attr.check_name("thread_local")) {
|
||||
if self.mode != Mode::Fn {
|
||||
span_err!(self.tcx.sess, self.span, E0625,
|
||||
"thread-local statics cannot be \
|
||||
accessed at compile-time");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Only allow statics (not consts) to refer to other statics.
|
||||
if self.mode == Mode::Static || self.mode == Mode::StaticMut {
|
||||
if self.mode == Mode::Static && context.is_mutating_use() {
|
||||
// this is not strictly necessary as miri will also bail out
|
||||
// For interior mutability we can't really catch this statically as that
|
||||
// goes through raw pointers and intermediate temporaries, so miri has
|
||||
// to catch this anyway
|
||||
self.tcx.sess.span_err(
|
||||
self.span,
|
||||
"cannot mutate statics in the initializer of another static",
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
unleash_miri!(self);
|
||||
// Only allow statics (not consts) to refer to other statics.
|
||||
if self.mode == Mode::Static || self.mode == Mode::StaticMut {
|
||||
if self.mode == Mode::Static && context.is_mutating_use() {
|
||||
// this is not strictly necessary as miri will also bail out
|
||||
// For interior mutability we can't really catch this statically as that
|
||||
// goes through raw pointers and intermediate temporaries, so miri has
|
||||
// to catch this anyway
|
||||
self.tcx.sess.span_err(
|
||||
self.span,
|
||||
"cannot mutate statics in the initializer of another static",
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
unleash_miri!(self);
|
||||
|
||||
if self.mode != Mode::Fn {
|
||||
let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
|
||||
"{}s cannot refer to statics, use \
|
||||
a constant instead", self.mode);
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"Static and const variables can refer to other const variables. But a \
|
||||
const variable cannot refer to a static variable."
|
||||
);
|
||||
err.help(
|
||||
"To fix this, the value can be extracted as a const and then used."
|
||||
);
|
||||
if self.mode != Mode::Fn {
|
||||
let mut err = struct_span_err!(self.tcx.sess, self.span, E0013,
|
||||
"{}s cannot refer to statics, use \
|
||||
a constant instead", self.mode);
|
||||
if self.tcx.sess.teach(&err.get_code().unwrap()) {
|
||||
err.note(
|
||||
"Static and const variables can refer to other const variables. But a \
|
||||
const variable cannot refer to a static variable."
|
||||
);
|
||||
err.help(
|
||||
"To fix this, the value can be extracted as a const and then used."
|
||||
);
|
||||
}
|
||||
err.emit()
|
||||
}
|
||||
}
|
||||
err.emit()
|
||||
}
|
||||
}
|
||||
Place::Projection(ref proj) => {
|
||||
|
|
|
|||
|
|
@ -256,10 +256,13 @@ fn check_place(
|
|||
) -> McfResult {
|
||||
match place {
|
||||
Place::Base(PlaceBase::Local(_)) => Ok(()),
|
||||
// promoteds are always fine, they are essentially constants
|
||||
Place::Base(PlaceBase::Promoted(_)) => Ok(()),
|
||||
Place::Base(PlaceBase::Static(_)) =>
|
||||
Err((span, "cannot access `static` items in const fn".into())),
|
||||
Place::Base(PlaceBase::Static(st)) => {
|
||||
match st.promoted {
|
||||
// promoteds are always fine, they are essentially constants
|
||||
Some(..) => Ok(()),
|
||||
None => Err((span, "cannot access `static` items in const fn".into())),
|
||||
}
|
||||
}
|
||||
Place::Projection(proj) => {
|
||||
match proj.elem {
|
||||
| ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue