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

Add simpler entry points to const eval for common usages. #66877

Merged
merged 1 commit into from
Dec 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 3 additions & 1 deletion src/librustc/mir/interpret/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ mod error;
mod value;
mod allocation;
mod pointer;
mod queries;

pub use self::error::{
InterpErrorInfo, InterpResult, InterpError, AssertMessage, ConstEvalErr, struct_error,
Expand All @@ -116,9 +117,10 @@ pub use self::pointer::{Pointer, PointerArithmetic, CheckInAllocMsg};

use crate::mir;
use crate::hir::def_id::DefId;
use crate::ty::{self, TyCtxt, Instance, subst::GenericArgKind};
use crate::ty::{self, TyCtxt, Instance};
use crate::ty::codec::TyDecoder;
use crate::ty::layout::{self, Size};
use crate::ty::subst::GenericArgKind;
use std::io;
use std::fmt;
use std::num::NonZeroU32;
Expand Down
89 changes: 89 additions & 0 deletions src/librustc/mir/interpret/queries.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use super::{ConstEvalResult, ErrorHandled, GlobalId};

use crate::mir;
use crate::hir::def_id::DefId;
use crate::ty::{self, TyCtxt};
use crate::ty::subst::{InternalSubsts, SubstsRef};
use syntax_pos::Span;


impl<'tcx> TyCtxt<'tcx> {

/// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> {
// In some situations def_id will have substitutions within scope, but they aren't allowed
// to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any og them are
// encountered.
let substs = InternalSubsts::identity_for_item(self, def_id);
let instance = ty::Instance::new(def_id, substs);
let cid = GlobalId {
instance,
promoted: None,
};
let param_env = self.param_env(def_id);
self.const_eval_validated(param_env.and(cid))
}

/// Resolves and evaluates a constant.
///
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
/// substitutions and environment are used to resolve the constant. Alternatively if the
/// constant has generic parameters in scope the substitutions are used to evaluate the value of
/// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
/// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
/// returned.
pub fn const_eval_resolve(
self,
param_env: ty::ParamEnv<'tcx>,
def_id: DefId,
substs: SubstsRef<'tcx>,
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)
} else {
Err(ErrorHandled::TooGeneric)
}
}

pub fn const_eval_instance(
self,
param_env: ty::ParamEnv<'tcx>,
instance: ty::Instance<'tcx>,
span: Option<Span>
) -> ConstEvalResult<'tcx> {
let cid = GlobalId {
instance,
promoted: None,
};
if let Some(span) = span {
self.at(span).const_eval_validated(param_env.and(cid))
} else {
self.const_eval_validated(param_env.and(cid))
}
}

/// Evaluate a promoted constant.
pub fn const_eval_promoted(
self,
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))
}
}
11 changes: 9 additions & 2 deletions src/librustc/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,8 @@ rustc_queries! {
///
/// **Do not use this** outside const eval. Const eval uses this to break query cycles
/// during validation. Please add a comment to every use site explaining why using
/// `const_eval` isn't sufficient.
/// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable
/// form to be used outside of const eval.
query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> ConstEvalRawResult<'tcx> {
no_force
Expand All @@ -460,7 +461,13 @@ rustc_queries! {

/// Results of evaluating const items or constants embedded in
/// other items (such as enum variant explicit discriminants).
query const_eval(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
///
/// In contrast to `const_eval_raw` this performs some validation on the constant, and
/// returns a proper constant that is usable by the rest of the compiler.
///
/// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`,
/// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_promoted`.
query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
-> ConstEvalResult<'tcx> {
no_force
desc { |tcx|
Expand Down
29 changes: 7 additions & 22 deletions src/librustc/traits/fulfill.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::infer::{InferCtxt, ShallowResolver};
use crate::mir::interpret::{GlobalId, ErrorHandled};
use crate::ty::{self, Ty, TypeFoldable, ToPolyTraitRef};
use crate::ty::error::ExpectedFound;
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
Expand Down Expand Up @@ -501,27 +500,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
ProcessResult::Unchanged
} else {
if !substs.has_local_value() {
let instance = ty::Instance::resolve(
self.selcx.tcx(),
obligation.param_env,
def_id,
substs,
);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None,
};
match self.selcx.tcx().at(obligation.cause.span)
.const_eval(obligation.param_env.and(cid)) {
Ok(_) => ProcessResult::Changed(vec![]),
Err(err) => ProcessResult::Error(
CodeSelectionError(ConstEvalFailure(err)))
}
} else {
ProcessResult::Error(CodeSelectionError(
ConstEvalFailure(ErrorHandled::TooGeneric)
))
match self.selcx.tcx().const_eval_resolve(obligation.param_env,
def_id,
substs,
Some(obligation.cause.span)) {
Ok(_) => ProcessResult::Changed(vec![]),
Err(err) => ProcessResult::Error(
CodeSelectionError(ConstEvalFailure(err)))
}
} else {
pending_obligation.stalled_on =
Expand Down
22 changes: 6 additions & 16 deletions src/librustc/traits/select.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ use crate::dep_graph::{DepKind, DepNodeIndex};
use crate::hir::def_id::DefId;
use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
use crate::middle::lang_items;
use crate::mir::interpret::GlobalId;
use crate::ty::fast_reject;
use crate::ty::relate::TypeRelation;
use crate::ty::subst::{Subst, SubstsRef};
Expand Down Expand Up @@ -820,22 +819,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}

ty::Predicate::ConstEvaluatable(def_id, substs) => {
let tcx = self.tcx();
if !(obligation.param_env, substs).has_local_value() {
let param_env = obligation.param_env;
let instance =
ty::Instance::resolve(tcx, param_env, def_id, substs);
if let Some(instance) = instance {
let cid = GlobalId {
instance,
promoted: None,
};
match self.tcx().const_eval(param_env.and(cid)) {
Ok(_) => Ok(EvaluatedToOk),
Err(_) => Ok(EvaluatedToErr),
}
} else {
Ok(EvaluatedToErr)
match self.tcx().const_eval_resolve(obligation.param_env,
def_id,
substs,
None) {
Ok(_) => Ok(EvaluatedToOk),
Err(_) => Ok(EvaluatedToErr),
}
} else {
// Inference variables still left in param_env or substs.
Expand Down
10 changes: 2 additions & 8 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::middle::cstore::CrateStoreDyn;
use crate::middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
use crate::mir::ReadOnlyBodyAndCache;
use crate::mir::interpret::{GlobalId, ErrorHandled};
use crate::mir::interpret::ErrorHandled;
use crate::mir::GeneratorLayout;
use crate::session::CrateDisambiguator;
use crate::traits::{self, Reveal};
Expand Down Expand Up @@ -2344,13 +2344,7 @@ impl<'tcx> AdtDef {
pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option<Discr<'tcx>> {
let param_env = tcx.param_env(expr_did);
let repr_type = self.repr.discr_type();
let substs = InternalSubsts::identity_for_item(tcx, expr_did);
let instance = ty::Instance::new(expr_did, substs);
let cid = GlobalId {
instance,
promoted: None
};
match tcx.const_eval(param_env.and(cid)) {
match tcx.const_eval_poly(expr_did) {
Ok(val) => {
// FIXME: Find the right type and use it instead of `val.ty` here
if let Some(b) = val.try_eval_bits(tcx, param_env, val.ty) {
Expand Down
12 changes: 4 additions & 8 deletions src/librustc/ty/sty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::ty::{self, AdtDef, Discr, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFolda
use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv};
use crate::ty::layout::VariantIdx;
use crate::util::captures::Captures;
use crate::mir::interpret::{Scalar, GlobalId};
use crate::mir::interpret::Scalar;

use polonius_engine::Atom;
use rustc_index::vec::Idx;
Expand Down Expand Up @@ -2340,13 +2340,9 @@ impl<'tcx> Const<'tcx> {

let (param_env, substs) = param_env_and_substs.into_parts();

// try to resolve e.g. associated constants to their definition on an impl
let instance = ty::Instance::resolve(tcx, param_env, did, substs)?;
let gid = GlobalId {
instance,
promoted: None,
};
tcx.const_eval(param_env.and(gid)).ok()
// try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const.
tcx.const_eval_resolve(param_env, did, substs, None).ok()
};

match self.val {
Expand Down
10 changes: 2 additions & 8 deletions src/librustc_codegen_llvm/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::value::Value;
use libc::c_uint;
use rustc::hir::def_id::DefId;
use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint,
Pointer, ErrorHandled, GlobalId};
Pointer, ErrorHandled};
use rustc::mir::mono::MonoItem;
use rustc::hir::Node;
use rustc_target::abi::HasDataLayout;
Expand Down Expand Up @@ -81,13 +81,7 @@ pub fn codegen_static_initializer(
cx: &CodegenCx<'ll, 'tcx>,
def_id: DefId,
) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> {
let instance = ty::Instance::mono(cx.tcx, def_id);
let cid = GlobalId {
instance,
promoted: None,
};
let param_env = ty::ParamEnv::reveal_all();
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
let static_ = cx.tcx.const_eval_poly(def_id)?;

let alloc = match static_.val {
ty::ConstKind::Value(ConstValue::ByRef {
Expand Down
9 changes: 3 additions & 6 deletions src/librustc_codegen_llvm/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use rustc_codegen_ssa::glue;
use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types};
use rustc::ty::{self, Ty};
use rustc::ty::layout::{self, FnAbiExt, LayoutOf, HasTyCtxt, Primitive};
use rustc::mir::interpret::GlobalId;
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
use rustc::hir;
use rustc_target::abi::HasDataLayout;
Expand Down Expand Up @@ -202,11 +201,9 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
"needs_drop" |
"type_id" |
"type_name" => {
let gid = GlobalId {
instance,
promoted: None,
};
let ty_name = self.tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).unwrap();
let ty_name = self.tcx
.const_eval_instance(ty::ParamEnv::reveal_all(), instance, None)
.unwrap();
OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self)
}
"init" => {
Expand Down
7 changes: 1 addition & 6 deletions src/librustc_codegen_ssa/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,12 +638,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
projection: &[],
} = place.as_ref()
{
let param_env = ty::ParamEnv::reveal_all();
let cid = mir::interpret::GlobalId {
instance: self.instance,
promoted: Some(promoted),
};
let c = bx.tcx().const_eval(param_env.and(cid));
let c = bx.tcx().const_eval_promoted(self.instance, promoted);
let (llval, ty) = self.simd_shuffle_indices(
&bx,
terminator.source_info.span,
Expand Down
19 changes: 8 additions & 11 deletions src/librustc_codegen_ssa/mir/constant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
match constant.literal.val {
ty::ConstKind::Unevaluated(def_id, substs) => {
let substs = self.monomorphize(&substs);
let instance = ty::Instance::resolve(
self.cx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs,
).unwrap();
let cid = mir::interpret::GlobalId {
instance,
promoted: None,
};
self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid)).map_err(|err| {
self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
err
})
self.cx.tcx()
.const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, None)
.map_err(|err| {
self.cx.tcx().sess.span_err(
constant.span,
"erroneous constant encountered");
err
})
},
_ => Ok(self.monomorphize(&constant.literal)),
}
Expand Down
7 changes: 1 addition & 6 deletions src/librustc_codegen_ssa/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -473,14 +473,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}),
projection: [],
} => {
let param_env = ty::ParamEnv::reveal_all();
let instance = Instance::new(*def_id, self.monomorphize(substs));
let cid = mir::interpret::GlobalId {
instance: instance,
promoted: Some(*promoted),
};
let layout = cx.layout_of(self.monomorphize(&ty));
match bx.tcx().const_eval(param_env.and(cid)) {
match bx.tcx().const_eval_promoted(instance, *promoted) {
Ok(val) => match val.val {
ty::ConstKind::Value(mir::interpret::ConstValue::ByRef {
alloc, offset
Expand Down
12 changes: 1 addition & 11 deletions src/librustc_lint/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1134,19 +1134,9 @@ declare_lint_pass!(

fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) {
let def_id = cx.tcx.hir().body_owner_def_id(body_id);
let param_env = if cx.tcx.is_static(def_id) {
// Use the same param_env as `codegen_static_initializer`, to reuse the cache.
ty::ParamEnv::reveal_all()
} else {
cx.tcx.param_env(def_id)
};
let cid = ::rustc::mir::interpret::GlobalId {
instance: ty::Instance::mono(cx.tcx, def_id),
promoted: None
};
// trigger the query once for all constants since that will already report the errors
// FIXME: Use ensure here
let _ = cx.tcx.const_eval(param_env.and(cid));
let _ = cx.tcx.const_eval_poly(def_id);
}

impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst {
Expand Down
Loading