Deduplicate promote_consts::Validator
and check_consts::Item
This commit is contained in:
parent
8a462ff24a
commit
748bbf259a
@ -12,7 +12,6 @@
|
||||
//! initialization and can otherwise silence errors, if
|
||||
//! move analysis runs after promotion on broken MIR.
|
||||
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::interpret::ConstValue;
|
||||
@ -30,7 +29,7 @@ use rustc_target::spec::abi::Abi;
|
||||
|
||||
use std::{iter, mem, usize};
|
||||
|
||||
use crate::transform::check_consts::{qualifs, Item as ConstCx};
|
||||
use crate::transform::check_consts::{qualifs, Item, ConstKind};
|
||||
|
||||
/// State of a temporary during collection and promotion.
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
||||
@ -224,18 +223,13 @@ pub fn collect_temps_and_candidates(
|
||||
(collector.temps, collector.candidates)
|
||||
}
|
||||
|
||||
/// Checks whether locals that appear in a promotion context (`Candidate`) are actually promotable.
|
||||
///
|
||||
/// This wraps an `Item`, and has access to all fields of that `Item` via `Deref` coercion.
|
||||
struct Validator<'a, 'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
param_env: ty::ParamEnv<'tcx>,
|
||||
body: &'a Body<'tcx>,
|
||||
is_static: bool,
|
||||
is_static_mut: bool,
|
||||
is_non_const_fn: bool,
|
||||
item: Item<'a, 'tcx>,
|
||||
temps: &'a IndexVec<Local, TempState>,
|
||||
|
||||
// FIXME(eddyb) deduplicate the data in this vs other fields.
|
||||
const_cx: ConstCx<'a, 'tcx>,
|
||||
|
||||
/// Explicit promotion happens e.g. for constant arguments declared via
|
||||
/// `rustc_args_required_const`.
|
||||
/// Implicit promotion has almost the same rules, except that disallows `const fn`
|
||||
@ -245,6 +239,14 @@ struct Validator<'a, 'tcx> {
|
||||
explicit: bool,
|
||||
}
|
||||
|
||||
impl std::ops::Deref for Validator<'a, 'tcx> {
|
||||
type Target = Item<'a, 'tcx>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.item
|
||||
}
|
||||
}
|
||||
|
||||
struct Unpromotable;
|
||||
|
||||
impl<'tcx> Validator<'_, 'tcx> {
|
||||
@ -317,13 +319,14 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
if self.qualif_local::<qualifs::NeedsDrop>(base) {
|
||||
return Err(Unpromotable);
|
||||
}
|
||||
|
||||
if let BorrowKind::Mut { .. } = kind {
|
||||
let ty = place.ty(self.body, self.tcx).ty;
|
||||
|
||||
// In theory, any zero-sized value could be borrowed
|
||||
// mutably without consequences. However, only &mut []
|
||||
// is allowed right now, and only in functions.
|
||||
if self.is_static_mut {
|
||||
if self.const_kind == Some(ConstKind::StaticMut) {
|
||||
// Inside a `static mut`, &mut [...] is also allowed.
|
||||
match ty.kind {
|
||||
ty::Array(..) | ty::Slice(_) => {}
|
||||
@ -333,7 +336,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
// FIXME(eddyb) the `self.is_non_const_fn` condition
|
||||
// seems unnecessary, given that this is merely a ZST.
|
||||
match len.try_eval_usize(self.tcx, self.param_env) {
|
||||
Some(0) if self.is_non_const_fn => {},
|
||||
Some(0) if self.const_kind.is_none() => {},
|
||||
_ => return Err(Unpromotable),
|
||||
}
|
||||
} else {
|
||||
@ -386,7 +389,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
let statement = &self.body[loc.block].statements[loc.statement_index];
|
||||
match &statement.kind {
|
||||
StatementKind::Assign(box(_, rhs)) => {
|
||||
Q::in_rvalue(&self.const_cx, per_local, rhs)
|
||||
Q::in_rvalue(&self.item, per_local, rhs)
|
||||
}
|
||||
_ => {
|
||||
span_bug!(statement.source_info.span, "{:?} is not an assignment",
|
||||
@ -398,7 +401,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
match &terminator.kind {
|
||||
TerminatorKind::Call { func, args, .. } => {
|
||||
let return_ty = self.body.local_decls[local].ty;
|
||||
Q::in_call(&self.const_cx, per_local, func, args, return_ty)
|
||||
Q::in_call(&self.item, per_local, func, args, return_ty)
|
||||
}
|
||||
kind => {
|
||||
span_bug!(terminator.source_info.span, "{:?} not promotable", kind);
|
||||
@ -462,8 +465,8 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
} => {
|
||||
// Only allow statics (not consts) to refer to other statics.
|
||||
// FIXME(eddyb) does this matter at all for promotion?
|
||||
let allowed = self.is_static || self.is_static_mut;
|
||||
if !allowed {
|
||||
let is_static = self.const_kind.map_or(false, |k| k.is_static());
|
||||
if !is_static {
|
||||
return Err(Unpromotable);
|
||||
}
|
||||
|
||||
@ -490,7 +493,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
}
|
||||
|
||||
ProjectionElem::Field(..) => {
|
||||
if self.is_non_const_fn {
|
||||
if self.const_kind.is_none() {
|
||||
let base_ty =
|
||||
Place::ty_from(place.base, proj_base, self.body, self.tcx).ty;
|
||||
if let Some(def) = base_ty.ty_adt_def() {
|
||||
@ -545,7 +548,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
|
||||
fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> {
|
||||
match *rvalue {
|
||||
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.is_non_const_fn => {
|
||||
Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.const_kind.is_none() => {
|
||||
let operand_ty = operand.ty(self.body, self.tcx);
|
||||
let cast_in = CastTy::from_ty(operand_ty).expect("bad input type for cast");
|
||||
let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast");
|
||||
@ -559,7 +562,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
Rvalue::BinaryOp(op, ref lhs, _) if self.is_non_const_fn => {
|
||||
Rvalue::BinaryOp(op, ref lhs, _) if self.const_kind.is_none() => {
|
||||
if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind {
|
||||
assert!(op == BinOp::Eq || op == BinOp::Ne ||
|
||||
op == BinOp::Le || op == BinOp::Lt ||
|
||||
@ -600,17 +603,17 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
// In theory, any zero-sized value could be borrowed
|
||||
// mutably without consequences. However, only &mut []
|
||||
// is allowed right now, and only in functions.
|
||||
if self.is_static_mut {
|
||||
if self.const_kind == Some(ConstKind::StaticMut) {
|
||||
// Inside a `static mut`, &mut [...] is also allowed.
|
||||
match ty.kind {
|
||||
ty::Array(..) | ty::Slice(_) => {}
|
||||
_ => return Err(Unpromotable),
|
||||
}
|
||||
} else if let ty::Array(_, len) = ty.kind {
|
||||
// FIXME(eddyb) the `self.is_non_const_fn` condition
|
||||
// seems unnecessary, given that this is merely a ZST.
|
||||
// FIXME(eddyb): We only return `Unpromotable` for `&mut []` inside a
|
||||
// const context which seems unnecessary given that this is merely a ZST.
|
||||
match len.try_eval_usize(self.tcx, self.param_env) {
|
||||
Some(0) if self.is_non_const_fn => {},
|
||||
Some(0) if self.const_kind.is_none() => {},
|
||||
_ => return Err(Unpromotable),
|
||||
}
|
||||
} else {
|
||||
@ -683,7 +686,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
) -> Result<(), Unpromotable> {
|
||||
let fn_ty = callee.ty(self.body, self.tcx);
|
||||
|
||||
if !self.explicit && self.is_non_const_fn {
|
||||
if !self.explicit && self.const_kind.is_none() {
|
||||
if let ty::FnDef(def_id, _) = fn_ty.kind {
|
||||
// Never promote runtime `const fn` calls of
|
||||
// functions without `#[rustc_promotable]`.
|
||||
@ -714,6 +717,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(eddyb) remove the differences for promotability in `static`, `const`, `const fn`.
|
||||
pub fn validate_candidates(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
body: &Body<'tcx>,
|
||||
@ -722,33 +726,11 @@ pub fn validate_candidates(
|
||||
candidates: &[Candidate],
|
||||
) -> Vec<Candidate> {
|
||||
let mut validator = Validator {
|
||||
tcx,
|
||||
param_env: tcx.param_env(def_id),
|
||||
body,
|
||||
is_static: false,
|
||||
is_static_mut: false,
|
||||
is_non_const_fn: false,
|
||||
item: Item::new(tcx, def_id, body),
|
||||
temps,
|
||||
|
||||
const_cx: ConstCx::new(tcx, def_id, body),
|
||||
|
||||
explicit: false,
|
||||
};
|
||||
|
||||
// FIXME(eddyb) remove the distinctions that make this necessary.
|
||||
let id = tcx.hir().as_local_hir_id(def_id).unwrap();
|
||||
match tcx.hir().body_owner_kind(id) {
|
||||
hir::BodyOwnerKind::Closure => validator.is_non_const_fn = true,
|
||||
hir::BodyOwnerKind::Fn => {
|
||||
if !tcx.is_const_fn(def_id) {
|
||||
validator.is_non_const_fn = true;
|
||||
}
|
||||
},
|
||||
hir::BodyOwnerKind::Static(hir::MutImmutable) => validator.is_static = true,
|
||||
hir::BodyOwnerKind::Static(hir::MutMutable) => validator.is_static_mut = true,
|
||||
_ => {}
|
||||
}
|
||||
|
||||
candidates.iter().copied().filter(|&candidate| {
|
||||
validator.explicit = match candidate {
|
||||
Candidate::Ref(_) |
|
||||
|
Loading…
x
Reference in New Issue
Block a user