1
Fork 0

Auto merge of #78363 - RalfJung:promotion, r=oli-obk

remove this weird special case from promotion

Promotion has a special case to ignore interior mutability under some specific circumstances. The purpose of this PR is to figure out what changes if we remove that. Since `Cell::new` and friends only get promoted inside `const`/`static` initializers these days, it actually is not easy to exploit this case: you need something like
```rust
const TEST_INTERIOR_MUT: () = {
    // The "0." case is already ruled out by not permitting any interior mutability in `const`.
    let _val: &'static _ = &(Cell::new(1), 2).1;
};
```

I assume something like `&Some(&(Cell::new(1), 2).1)` would hit the nested case inside `validate_rvalue`... though I am not sure why that would not just trigger nested promotion, first promoting the inner reference and then the outer one?

Fixes https://github.com/rust-lang/rust/issues/67534 (by simply rejecting that code^^)

r? `@oli-obk` (but for now this is not meant to be merged!)
Cc `@rust-lang/wg-const-eval`
This commit is contained in:
bors 2020-12-09 09:13:54 +00:00
commit c0bfe3485f
4 changed files with 56 additions and 78 deletions

View file

@ -22,7 +22,7 @@ use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, List, TyCtxt, TypeFoldable};
use rustc_span::symbol::sym;
use rustc_span::{Span, DUMMY_SP};
use rustc_span::Span;
use rustc_index::vec::{Idx, IndexVec};
use rustc_target::spec::abi::Abi;
@ -326,41 +326,16 @@ impl<'tcx> Validator<'_, 'tcx> {
if place.projection.contains(&ProjectionElem::Deref) {
return Err(Unpromotable);
}
let mut has_mut_interior =
self.qualif_local::<qualifs::HasMutInterior>(place.local);
// HACK(eddyb) this should compute the same thing as
// `<HasMutInterior as Qualif>::in_projection` from
// `check_consts::qualifs` but without recursion.
if has_mut_interior {
// This allows borrowing fields which don't have
// `HasMutInterior`, from a type that does, e.g.:
// `let _: &'static _ = &(Cell::new(1), 2).1;`
let mut place_projection = &place.projection[..];
// FIXME(eddyb) use a forward loop instead of a reverse one.
while let &[ref proj_base @ .., elem] = place_projection {
// FIXME(eddyb) this is probably excessive, with
// the exception of `union` member accesses.
let ty =
Place::ty_from(place.local, proj_base, self.body, self.tcx)
.projection_ty(self.tcx, elem)
.ty;
if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) {
has_mut_interior = false;
break;
}
place_projection = proj_base;
}
if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
return Err(Unpromotable);
}
// FIXME(eddyb) this duplicates part of `validate_rvalue`.
let has_mut_interior =
self.qualif_local::<qualifs::HasMutInterior>(place.local);
if has_mut_interior {
return Err(Unpromotable);
}
if self.qualif_local::<qualifs::NeedsDrop>(place.local) {
return Err(Unpromotable);
}
if let BorrowKind::Mut { .. } = kind {
let ty = place.ty(self.body, self.tcx).ty;
@ -692,28 +667,7 @@ impl<'tcx> Validator<'_, 'tcx> {
self.validate_place(place)?;
// HACK(eddyb) this should compute the same thing as
// `<HasMutInterior as Qualif>::in_projection` from
// `check_consts::qualifs` but without recursion.
let mut has_mut_interior =
self.qualif_local::<qualifs::HasMutInterior>(place.local);
if has_mut_interior {
let mut place_projection = place.projection;
// FIXME(eddyb) use a forward loop instead of a reverse one.
while let &[ref proj_base @ .., elem] = place_projection {
// FIXME(eddyb) this is probably excessive, with
// the exception of `union` member accesses.
let ty = Place::ty_from(place.local, proj_base, self.body, self.tcx)
.projection_ty(self.tcx, elem)
.ty;
if ty.is_freeze(self.tcx.at(DUMMY_SP), self.param_env) {
has_mut_interior = false;
break;
}
place_projection = proj_base;
}
}
let has_mut_interior = self.qualif_local::<qualifs::HasMutInterior>(place.local);
if has_mut_interior {
return Err(Unpromotable);
}