Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Promote references to constants instead of statics #67000

Merged
merged 23 commits into from
Jan 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a59abfa
Revert const_eval call to use const_eval_raw to avoid const validatio…
spastorino Dec 31, 2019
1688719
Promote `Ref`s to constants instead of static
spastorino Nov 22, 2019
2508f17
Promote `Repeat`s to constants instead of statics
spastorino Dec 10, 2019
32fe477
Promote `Argument`s to constants instead of statics
spastorino Dec 11, 2019
6aa4b5a
Add promoted_operand closure to reuse code across different
spastorino Dec 11, 2019
6f2c702
Remove StaticKind::Promoted
spastorino Dec 11, 2019
b63597d
Remove StaticKind
spastorino Dec 11, 2019
fb2f0ec
Use if let instead of match with one meaningful arm
spastorino Dec 11, 2019
9e70c47
Remove unused param_env parameter
spastorino Dec 11, 2019
fd5aa32
Remove Static from PlaceBase
spastorino Dec 11, 2019
5d9b399
Remove PlaceBase enum and make Place base field be local: Local
spastorino Dec 11, 2019
a9de4f1
Fix print const on librustdoc
spastorino Dec 13, 2019
7f3459a
No need to use local.into here
spastorino Dec 13, 2019
a5715a3
Use re_erased instead of re_static
spastorino Dec 19, 2019
8533caa
Make Place Copy
spastorino Dec 19, 2019
1565612
Add span_bug that notes that shuffle indices must be constant
spastorino Dec 19, 2019
36b1756
Do not store lint_root
spastorino Jan 1, 2020
6e1bbff
Promoteds also need param envs.
oli-obk Jan 8, 2020
ecd5852
Errors in promoteds may only cause lints not hard errors
oli-obk Jan 8, 2020
050146f
Add regression tests for promotion mir expansion
oli-obk Jan 9, 2020
43313d5
Remove an outdated comment
oli-obk Jan 9, 2020
a5d8ab7
Rebase fallout
oli-obk Jan 9, 2020
e51eccd
Make codegen tests wordsize independent
oli-obk Jan 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/librustc/mir/interpret/queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,16 @@ impl<'tcx> TyCtxt<'tcx> {
param_env: ty::ParamEnv<'tcx>,
def_id: DefId,
substs: SubstsRef<'tcx>,
promoted: Option<mir::Promoted>,
span: Option<Span>,
) -> ConstEvalResult<'tcx> {
let instance = ty::Instance::resolve(self, param_env, def_id, substs);
if let Some(instance) = instance {
self.const_eval_instance(param_env, instance, span)
if let Some(promoted) = promoted {
self.const_eval_promoted(param_env, instance, promoted)
} else {
self.const_eval_instance(param_env, instance, span)
}
} else {
Err(ErrorHandled::TooGeneric)
}
Expand All @@ -63,11 +68,11 @@ impl<'tcx> TyCtxt<'tcx> {
/// Evaluate a promoted constant.
pub fn const_eval_promoted(
self,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
promoted: mir::Promoted,
) -> ConstEvalResult<'tcx> {
let cid = GlobalId { instance, promoted: Some(promoted) };
let param_env = ty::ParamEnv::reveal_all();
self.const_eval_validated(param_env.and(cid))
}
}
169 changes: 25 additions & 144 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,16 @@ pub struct Body<'tcx> {

/// A span representing this MIR, for error reporting.
pub span: Span,

/// The user may be writing e.g. &[(SOME_CELL, 42)][i].1 and this would get promoted, because
/// we'd statically know that no thing with interior mutability will ever be available to the
/// user without some serious unsafe code. Now this means that our promoted is actually
/// &[(SOME_CELL, 42)] and the MIR using it will do the &promoted[i].1 projection because the
/// index may be a runtime value. Such a promoted value is illegal because it has reachable
/// interior mutability. This flag just makes this situation very obvious where the previous
/// implementation without the flag hid this situation silently.
/// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components.
pub ignore_interior_mut_in_const_validation: bool,
spastorino marked this conversation as resolved.
Show resolved Hide resolved
}

impl<'tcx> Body<'tcx> {
Expand Down Expand Up @@ -202,6 +212,7 @@ impl<'tcx> Body<'tcx> {
spread_arg: None,
var_debug_info,
span,
ignore_interior_mut_in_const_validation: false,
control_flow_destroyed,
}
}
Expand Down Expand Up @@ -1642,68 +1653,16 @@ impl Debug for Statement<'_> {

/// A path to a value; something that can be evaluated without
/// changing or disturbing program state.
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, HashStable)]
pub struct Place<'tcx> {
pub base: PlaceBase<'tcx>,
pub local: Local,

/// projection out of a place (access a field, deref a pointer, etc)
pub projection: &'tcx List<PlaceElem<'tcx>>,
}

impl<'tcx> rustc_serialize::UseSpecializedDecodable for Place<'tcx> {}

#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable, HashStable)]
pub enum PlaceBase<'tcx> {
/// local variable
Local(Local),

/// static or static mut variable
Static(Box<Static<'tcx>>),
}

/// We store the normalized type to avoid requiring normalization when reading MIR
#[derive(
Clone,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
RustcEncodable,
RustcDecodable,
HashStable
)]
pub struct Static<'tcx> {
pub ty: Ty<'tcx>,
pub kind: StaticKind<'tcx>,
/// The `DefId` of the item this static was declared in. For promoted values, usually, this is
/// the same as the `DefId` of the `mir::Body` containing the `Place` this promoted appears in.
/// However, after inlining, that might no longer be the case as inlined `Place`s are copied
/// into the calling frame.
pub def_id: DefId,
}

#[derive(
Clone,
Debug,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
HashStable,
RustcEncodable,
RustcDecodable
)]
pub enum StaticKind<'tcx> {
/// Promoted references consist of an id (`Promoted`) and the substs necessary to monomorphize
/// it. Usually, these substs are just the identity substs for the item. However, the inliner
/// will adjust these substs when it inlines a function based on the substs at the callsite.
Promoted(Promoted, SubstsRef<'tcx>),
Static,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(RustcEncodable, RustcDecodable, HashStable)]
pub enum ProjectionElem<V, T> {
Expand Down Expand Up @@ -1791,14 +1750,14 @@ rustc_index::newtype_index! {

#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PlaceRef<'a, 'tcx> {
pub base: &'a PlaceBase<'tcx>,
pub local: &'a Local,
spastorino marked this conversation as resolved.
Show resolved Hide resolved
pub projection: &'a [PlaceElem<'tcx>],
}

impl<'tcx> Place<'tcx> {
// FIXME change this to a const fn by also making List::empty a const fn.
pub fn return_place() -> Place<'tcx> {
Place { base: PlaceBase::Local(RETURN_PLACE), projection: List::empty() }
Place { local: RETURN_PLACE, projection: List::empty() }
}

/// Returns `true` if this `Place` contains a `Deref` projection.
Expand All @@ -1815,10 +1774,8 @@ impl<'tcx> Place<'tcx> {
// FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
pub fn local_or_deref_local(&self) -> Option<Local> {
match self.as_ref() {
PlaceRef { base: &PlaceBase::Local(local), projection: &[] }
| PlaceRef { base: &PlaceBase::Local(local), projection: &[ProjectionElem::Deref] } => {
Some(local)
}
PlaceRef { local, projection: &[] }
| PlaceRef { local, projection: &[ProjectionElem::Deref] } => Some(*local),
_ => None,
}
}
Expand All @@ -1830,19 +1787,13 @@ impl<'tcx> Place<'tcx> {
}

pub fn as_ref(&self) -> PlaceRef<'_, 'tcx> {
PlaceRef { base: &self.base, projection: &self.projection }
PlaceRef { local: &self.local, projection: &self.projection }
}
}

impl From<Local> for Place<'_> {
fn from(local: Local) -> Self {
Place { base: local.into(), projection: List::empty() }
}
}

impl From<Local> for PlaceBase<'_> {
fn from(local: Local) -> Self {
PlaceBase::Local(local)
Place { local, projection: List::empty() }
}
}

Expand All @@ -1853,10 +1804,8 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
// FIXME: can we safely swap the semantics of `fn base_local` below in here instead?
pub fn local_or_deref_local(&self) -> Option<Local> {
match self {
spastorino marked this conversation as resolved.
Show resolved Hide resolved
PlaceRef { base: PlaceBase::Local(local), projection: [] }
| PlaceRef { base: PlaceBase::Local(local), projection: [ProjectionElem::Deref] } => {
Some(*local)
}
PlaceRef { local, projection: [] }
| PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(**local),
_ => None,
}
}
Expand All @@ -1865,7 +1814,7 @@ impl<'a, 'tcx> PlaceRef<'a, 'tcx> {
/// projections, return `Some(_X)`.
pub fn as_local(&self) -> Option<Local> {
match self {
PlaceRef { base: PlaceBase::Local(l), projection: [] } => Some(*l),
PlaceRef { local, projection: [] } => Some(**local),
_ => None,
}
}
Expand All @@ -1887,7 +1836,7 @@ impl Debug for Place<'_> {
}
}

write!(fmt, "{:?}", self.base)?;
write!(fmt, "{:?}", self.local)?;

for elem in self.projection.iter() {
match elem {
Expand Down Expand Up @@ -1931,22 +1880,6 @@ impl Debug for Place<'_> {
}
}

impl Debug for PlaceBase<'_> {
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
match *self {
PlaceBase::Local(id) => write!(fmt, "{:?}", id),
PlaceBase::Static(box self::Static { ty, kind: StaticKind::Static, def_id }) => {
write!(fmt, "({}: {:?})", ty::tls::with(|tcx| tcx.def_path_str(def_id)), ty)
}
PlaceBase::Static(box self::Static {
ty,
kind: StaticKind::Promoted(promoted, _),
def_id: _,
}) => write!(fmt, "({:?}: {:?})", promoted, ty),
}
}
}

///////////////////////////////////////////////////////////////////////////
// Scopes

Expand Down Expand Up @@ -3007,27 +2940,11 @@ impl<'tcx> TypeFoldable<'tcx> for GeneratorKind {

impl<'tcx> TypeFoldable<'tcx> for Place<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
Place { base: self.base.fold_with(folder), projection: self.projection.fold_with(folder) }
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
self.base.visit_with(visitor) || self.projection.visit_with(visitor)
}
}

impl<'tcx> TypeFoldable<'tcx> for PlaceBase<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
match self {
PlaceBase::Local(local) => PlaceBase::Local(local.fold_with(folder)),
PlaceBase::Static(static_) => PlaceBase::Static(static_.fold_with(folder)),
}
Place { local: self.local.fold_with(folder), projection: self.projection.fold_with(folder) }
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match self {
PlaceBase::Local(local) => local.visit_with(visitor),
PlaceBase::Static(static_) => (**static_).visit_with(visitor),
}
self.local.visit_with(visitor) || self.projection.visit_with(visitor)
}
}

Expand All @@ -3042,42 +2959,6 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List<PlaceElem<'tcx>> {
}
}

impl<'tcx> TypeFoldable<'tcx> for Static<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
Static {
ty: self.ty.fold_with(folder),
kind: self.kind.fold_with(folder),
def_id: self.def_id,
}
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
let Static { ty, kind, def_id: _ } = self;

ty.visit_with(visitor) || kind.visit_with(visitor)
}
}

impl<'tcx> TypeFoldable<'tcx> for StaticKind<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
match self {
StaticKind::Promoted(promoted, substs) => {
StaticKind::Promoted(promoted.fold_with(folder), substs.fold_with(folder))
}
StaticKind::Static => StaticKind::Static,
}
}

fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match self {
StaticKind::Promoted(promoted, substs) => {
promoted.visit_with(visitor) || substs.visit_with(visitor)
}
StaticKind::Static => false,
}
}
}

impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> {
fn super_fold_with<F: TypeFolder<'tcx>>(&self, folder: &mut F) -> Self {
use crate::mir::Rvalue::*;
Expand Down
20 changes: 5 additions & 15 deletions src/librustc/mir/tcx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ impl<'tcx> PlaceTy<'tcx> {

impl<'tcx> Place<'tcx> {
pub fn ty_from<D>(
base: &PlaceBase<'tcx>,
local: &Local,
projection: &[PlaceElem<'tcx>],
local_decls: &D,
tcx: TyCtxt<'tcx>,
Expand All @@ -124,26 +124,16 @@ impl<'tcx> Place<'tcx> {
{
projection
.iter()
.fold(base.ty(local_decls), |place_ty, elem| place_ty.projection_ty(tcx, elem))
.fold(PlaceTy::from_ty(local_decls.local_decls()[*local].ty), |place_ty, elem| {
place_ty.projection_ty(tcx, elem)
})
}

pub fn ty<D>(&self, local_decls: &D, tcx: TyCtxt<'tcx>) -> PlaceTy<'tcx>
where
D: HasLocalDecls<'tcx>,
{
Place::ty_from(&self.base, &self.projection, local_decls, tcx)
}
}

impl<'tcx> PlaceBase<'tcx> {
pub fn ty<D>(&self, local_decls: &D) -> PlaceTy<'tcx>
where
D: HasLocalDecls<'tcx>,
{
match self {
PlaceBase::Local(index) => PlaceTy::from_ty(local_decls.local_decls()[*index].ty),
PlaceBase::Static(data) => PlaceTy::from_ty(data.ty),
}
Place::ty_from(&self.local, &self.projection, local_decls, tcx)
}
}

Expand Down
Loading