Skip to content

Commit 76384e1

Browse files
authored
Rollup merge of rust-lang#66877 - skinny121:const-eval-entry-points, r=oli-obk
Add simpler entry points to const eval for common usages. I found the `tcx.const_eval` API to be complex/awkward to work with, because of the inherent complexity from all of the different situations it is called from. Though it mainly used in one of the following ways: - Evaluates the value of a constant without any substitutions, e.g. evaluating a static, discriminant, etc. - Evaluates the value of a resolved instance of a constant. this happens when evaluating unevaluated constants or normalising trait constants. - Evaluates a promoted constant. This PR adds three new functions `const_eval_mono`, `const_eval_resolve`, and `const_eval_promoted` to `TyCtxt`, which each cater to one of the three ways `tcx.const_eval` is normally used.
2 parents 3982d35 + c010d84 commit 76384e1

File tree

23 files changed

+195
-253
lines changed

23 files changed

+195
-253
lines changed

src/librustc/mir/interpret/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ mod error;
101101
mod value;
102102
mod allocation;
103103
mod pointer;
104+
mod queries;
104105

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

117118
use crate::mir;
118119
use crate::hir::def_id::DefId;
119-
use crate::ty::{self, TyCtxt, Instance, subst::GenericArgKind};
120+
use crate::ty::{self, TyCtxt, Instance};
120121
use crate::ty::codec::TyDecoder;
121122
use crate::ty::layout::{self, Size};
123+
use crate::ty::subst::GenericArgKind;
122124
use std::io;
123125
use std::fmt;
124126
use std::num::NonZeroU32;

src/librustc/mir/interpret/queries.rs

+89
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
use super::{ConstEvalResult, ErrorHandled, GlobalId};
2+
3+
use crate::mir;
4+
use crate::hir::def_id::DefId;
5+
use crate::ty::{self, TyCtxt};
6+
use crate::ty::subst::{InternalSubsts, SubstsRef};
7+
use syntax_pos::Span;
8+
9+
10+
impl<'tcx> TyCtxt<'tcx> {
11+
12+
/// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
13+
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
14+
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
15+
pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> {
16+
// In some situations def_id will have substitutions within scope, but they aren't allowed
17+
// to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
18+
// into `const_eval` which will return `ErrorHandled::ToGeneric` if any og them are
19+
// encountered.
20+
let substs = InternalSubsts::identity_for_item(self, def_id);
21+
let instance = ty::Instance::new(def_id, substs);
22+
let cid = GlobalId {
23+
instance,
24+
promoted: None,
25+
};
26+
let param_env = self.param_env(def_id);
27+
self.const_eval_validated(param_env.and(cid))
28+
}
29+
30+
/// Resolves and evaluates a constant.
31+
///
32+
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
33+
/// substitutions and environment are used to resolve the constant. Alternatively if the
34+
/// constant has generic parameters in scope the substitutions are used to evaluate the value of
35+
/// the constant. For example in `fn foo<T>() { let _ = [0; bar::<T>()]; }` the repeat count
36+
/// constant `bar::<T>()` requires a substitution for `T`, if the substitution for `T` is still
37+
/// too generic for the constant to be evaluated then `Err(ErrorHandled::TooGeneric)` is
38+
/// returned.
39+
pub fn const_eval_resolve(
40+
self,
41+
param_env: ty::ParamEnv<'tcx>,
42+
def_id: DefId,
43+
substs: SubstsRef<'tcx>,
44+
span: Option<Span>
45+
) -> ConstEvalResult<'tcx> {
46+
let instance = ty::Instance::resolve(
47+
self,
48+
param_env,
49+
def_id,
50+
substs,
51+
);
52+
if let Some(instance) = instance {
53+
self.const_eval_instance(param_env, instance, span)
54+
} else {
55+
Err(ErrorHandled::TooGeneric)
56+
}
57+
}
58+
59+
pub fn const_eval_instance(
60+
self,
61+
param_env: ty::ParamEnv<'tcx>,
62+
instance: ty::Instance<'tcx>,
63+
span: Option<Span>
64+
) -> ConstEvalResult<'tcx> {
65+
let cid = GlobalId {
66+
instance,
67+
promoted: None,
68+
};
69+
if let Some(span) = span {
70+
self.at(span).const_eval_validated(param_env.and(cid))
71+
} else {
72+
self.const_eval_validated(param_env.and(cid))
73+
}
74+
}
75+
76+
/// Evaluate a promoted constant.
77+
pub fn const_eval_promoted(
78+
self,
79+
instance: ty::Instance<'tcx>,
80+
promoted: mir::Promoted
81+
) -> ConstEvalResult<'tcx> {
82+
let cid = GlobalId {
83+
instance,
84+
promoted: Some(promoted),
85+
};
86+
let param_env = ty::ParamEnv::reveal_all();
87+
self.const_eval_validated(param_env.and(cid))
88+
}
89+
}

src/librustc/query/mod.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,8 @@ rustc_queries! {
448448
///
449449
/// **Do not use this** outside const eval. Const eval uses this to break query cycles
450450
/// during validation. Please add a comment to every use site explaining why using
451-
/// `const_eval` isn't sufficient.
451+
/// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable
452+
/// form to be used outside of const eval.
452453
query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
453454
-> ConstEvalRawResult<'tcx> {
454455
no_force
@@ -460,7 +461,13 @@ rustc_queries! {
460461

461462
/// Results of evaluating const items or constants embedded in
462463
/// other items (such as enum variant explicit discriminants).
463-
query const_eval(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
464+
///
465+
/// In contrast to `const_eval_raw` this performs some validation on the constant, and
466+
/// returns a proper constant that is usable by the rest of the compiler.
467+
///
468+
/// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`,
469+
/// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_promoted`.
470+
query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>)
464471
-> ConstEvalResult<'tcx> {
465472
no_force
466473
desc { |tcx|

src/librustc/traits/fulfill.rs

+7-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use crate::infer::{InferCtxt, ShallowResolver};
2-
use crate::mir::interpret::{GlobalId, ErrorHandled};
32
use crate::ty::{self, Ty, TypeFoldable, ToPolyTraitRef};
43
use crate::ty::error::ExpectedFound;
54
use rustc_data_structures::obligation_forest::{DoCompleted, Error, ForestObligation};
@@ -501,27 +500,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> {
501500
ProcessResult::Unchanged
502501
} else {
503502
if !substs.has_local_value() {
504-
let instance = ty::Instance::resolve(
505-
self.selcx.tcx(),
506-
obligation.param_env,
507-
def_id,
508-
substs,
509-
);
510-
if let Some(instance) = instance {
511-
let cid = GlobalId {
512-
instance,
513-
promoted: None,
514-
};
515-
match self.selcx.tcx().at(obligation.cause.span)
516-
.const_eval(obligation.param_env.and(cid)) {
517-
Ok(_) => ProcessResult::Changed(vec![]),
518-
Err(err) => ProcessResult::Error(
519-
CodeSelectionError(ConstEvalFailure(err)))
520-
}
521-
} else {
522-
ProcessResult::Error(CodeSelectionError(
523-
ConstEvalFailure(ErrorHandled::TooGeneric)
524-
))
503+
match self.selcx.tcx().const_eval_resolve(obligation.param_env,
504+
def_id,
505+
substs,
506+
Some(obligation.cause.span)) {
507+
Ok(_) => ProcessResult::Changed(vec![]),
508+
Err(err) => ProcessResult::Error(
509+
CodeSelectionError(ConstEvalFailure(err)))
525510
}
526511
} else {
527512
pending_obligation.stalled_on =

src/librustc/traits/select.rs

+6-16
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ use crate::dep_graph::{DepKind, DepNodeIndex};
3333
use crate::hir::def_id::DefId;
3434
use crate::infer::{CombinedSnapshot, InferCtxt, InferOk, PlaceholderMap, TypeFreshener};
3535
use crate::middle::lang_items;
36-
use crate::mir::interpret::GlobalId;
3736
use crate::ty::fast_reject;
3837
use crate::ty::relate::TypeRelation;
3938
use crate::ty::subst::{Subst, SubstsRef};
@@ -820,22 +819,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
820819
}
821820

822821
ty::Predicate::ConstEvaluatable(def_id, substs) => {
823-
let tcx = self.tcx();
824822
if !(obligation.param_env, substs).has_local_value() {
825-
let param_env = obligation.param_env;
826-
let instance =
827-
ty::Instance::resolve(tcx, param_env, def_id, substs);
828-
if let Some(instance) = instance {
829-
let cid = GlobalId {
830-
instance,
831-
promoted: None,
832-
};
833-
match self.tcx().const_eval(param_env.and(cid)) {
834-
Ok(_) => Ok(EvaluatedToOk),
835-
Err(_) => Ok(EvaluatedToErr),
836-
}
837-
} else {
838-
Ok(EvaluatedToErr)
823+
match self.tcx().const_eval_resolve(obligation.param_env,
824+
def_id,
825+
substs,
826+
None) {
827+
Ok(_) => Ok(EvaluatedToOk),
828+
Err(_) => Ok(EvaluatedToErr),
839829
}
840830
} else {
841831
// Inference variables still left in param_env or substs.

src/librustc/ty/mod.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use crate::middle::cstore::CrateStoreDyn;
1919
use crate::middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem, FnOnceTraitLangItem};
2020
use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
2121
use crate::mir::ReadOnlyBodyAndCache;
22-
use crate::mir::interpret::{GlobalId, ErrorHandled};
22+
use crate::mir::interpret::ErrorHandled;
2323
use crate::mir::GeneratorLayout;
2424
use crate::session::CrateDisambiguator;
2525
use crate::traits::{self, Reveal};
@@ -2344,13 +2344,7 @@ impl<'tcx> AdtDef {
23442344
pub fn eval_explicit_discr(&self, tcx: TyCtxt<'tcx>, expr_did: DefId) -> Option<Discr<'tcx>> {
23452345
let param_env = tcx.param_env(expr_did);
23462346
let repr_type = self.repr.discr_type();
2347-
let substs = InternalSubsts::identity_for_item(tcx, expr_did);
2348-
let instance = ty::Instance::new(expr_did, substs);
2349-
let cid = GlobalId {
2350-
instance,
2351-
promoted: None
2352-
};
2353-
match tcx.const_eval(param_env.and(cid)) {
2347+
match tcx.const_eval_poly(expr_did) {
23542348
Ok(val) => {
23552349
// FIXME: Find the right type and use it instead of `val.ty` here
23562350
if let Some(b) = val.try_eval_bits(tcx, param_env, val.ty) {

src/librustc/ty/sty.rs

+4-8
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::ty::{self, AdtDef, Discr, DefIdTree, TypeFlags, Ty, TyCtxt, TypeFolda
1515
use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv};
1616
use crate::ty::layout::VariantIdx;
1717
use crate::util::captures::Captures;
18-
use crate::mir::interpret::{Scalar, GlobalId};
18+
use crate::mir::interpret::Scalar;
1919

2020
use polonius_engine::Atom;
2121
use rustc_index::vec::Idx;
@@ -2340,13 +2340,9 @@ impl<'tcx> Const<'tcx> {
23402340

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

2343-
// try to resolve e.g. associated constants to their definition on an impl
2344-
let instance = ty::Instance::resolve(tcx, param_env, did, substs)?;
2345-
let gid = GlobalId {
2346-
instance,
2347-
promoted: None,
2348-
};
2349-
tcx.const_eval(param_env.and(gid)).ok()
2343+
// try to resolve e.g. associated constants to their definition on an impl, and then
2344+
// evaluate the const.
2345+
tcx.const_eval_resolve(param_env, did, substs, None).ok()
23502346
};
23512347

23522348
match self.val {

src/librustc_codegen_llvm/consts.rs

+2-8
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::value::Value;
88
use libc::c_uint;
99
use rustc::hir::def_id::DefId;
1010
use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint,
11-
Pointer, ErrorHandled, GlobalId};
11+
Pointer, ErrorHandled};
1212
use rustc::mir::mono::MonoItem;
1313
use rustc::hir::Node;
1414
use rustc_target::abi::HasDataLayout;
@@ -81,13 +81,7 @@ pub fn codegen_static_initializer(
8181
cx: &CodegenCx<'ll, 'tcx>,
8282
def_id: DefId,
8383
) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> {
84-
let instance = ty::Instance::mono(cx.tcx, def_id);
85-
let cid = GlobalId {
86-
instance,
87-
promoted: None,
88-
};
89-
let param_env = ty::ParamEnv::reveal_all();
90-
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
84+
let static_ = cx.tcx.const_eval_poly(def_id)?;
9185

9286
let alloc = match static_.val {
9387
ty::ConstKind::Value(ConstValue::ByRef {

src/librustc_codegen_llvm/intrinsic.rs

+3-6
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use rustc_codegen_ssa::glue;
1414
use rustc_codegen_ssa::base::{to_immediate, wants_msvc_seh, compare_simd_types};
1515
use rustc::ty::{self, Ty};
1616
use rustc::ty::layout::{self, FnAbiExt, LayoutOf, HasTyCtxt, Primitive};
17-
use rustc::mir::interpret::GlobalId;
1817
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
1918
use rustc::hir;
2019
use rustc_target::abi::HasDataLayout;
@@ -202,11 +201,9 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
202201
"needs_drop" |
203202
"type_id" |
204203
"type_name" => {
205-
let gid = GlobalId {
206-
instance,
207-
promoted: None,
208-
};
209-
let ty_name = self.tcx.const_eval(ty::ParamEnv::reveal_all().and(gid)).unwrap();
204+
let ty_name = self.tcx
205+
.const_eval_instance(ty::ParamEnv::reveal_all(), instance, None)
206+
.unwrap();
210207
OperandRef::from_const(self, ty_name).immediate_or_packed_pair(self)
211208
}
212209
"init" => {

src/librustc_codegen_ssa/mir/block.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -638,12 +638,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
638638
projection: &[],
639639
} = place.as_ref()
640640
{
641-
let param_env = ty::ParamEnv::reveal_all();
642-
let cid = mir::interpret::GlobalId {
643-
instance: self.instance,
644-
promoted: Some(promoted),
645-
};
646-
let c = bx.tcx().const_eval(param_env.and(cid));
641+
let c = bx.tcx().const_eval_promoted(self.instance, promoted);
647642
let (llval, ty) = self.simd_shuffle_indices(
648643
&bx,
649644
terminator.source_info.span,

src/librustc_codegen_ssa/mir/constant.rs

+8-11
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
4343
match constant.literal.val {
4444
ty::ConstKind::Unevaluated(def_id, substs) => {
4545
let substs = self.monomorphize(&substs);
46-
let instance = ty::Instance::resolve(
47-
self.cx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs,
48-
).unwrap();
49-
let cid = mir::interpret::GlobalId {
50-
instance,
51-
promoted: None,
52-
};
53-
self.cx.tcx().const_eval(ty::ParamEnv::reveal_all().and(cid)).map_err(|err| {
54-
self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
55-
err
56-
})
46+
self.cx.tcx()
47+
.const_eval_resolve(ty::ParamEnv::reveal_all(), def_id, substs, None)
48+
.map_err(|err| {
49+
self.cx.tcx().sess.span_err(
50+
constant.span,
51+
"erroneous constant encountered");
52+
err
53+
})
5754
},
5855
_ => Ok(self.monomorphize(&constant.literal)),
5956
}

src/librustc_codegen_ssa/mir/place.rs

+1-6
Original file line numberDiff line numberDiff line change
@@ -473,14 +473,9 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
473473
}),
474474
projection: [],
475475
} => {
476-
let param_env = ty::ParamEnv::reveal_all();
477476
let instance = Instance::new(*def_id, self.monomorphize(substs));
478-
let cid = mir::interpret::GlobalId {
479-
instance: instance,
480-
promoted: Some(*promoted),
481-
};
482477
let layout = cx.layout_of(self.monomorphize(&ty));
483-
match bx.tcx().const_eval(param_env.and(cid)) {
478+
match bx.tcx().const_eval_promoted(instance, *promoted) {
484479
Ok(val) => match val.val {
485480
ty::ConstKind::Value(mir::interpret::ConstValue::ByRef {
486481
alloc, offset

src/librustc_lint/builtin.rs

+1-11
Original file line numberDiff line numberDiff line change
@@ -1143,19 +1143,9 @@ declare_lint_pass!(
11431143

11441144
fn check_const(cx: &LateContext<'_, '_>, body_id: hir::BodyId) {
11451145
let def_id = cx.tcx.hir().body_owner_def_id(body_id);
1146-
let param_env = if cx.tcx.is_static(def_id) {
1147-
// Use the same param_env as `codegen_static_initializer`, to reuse the cache.
1148-
ty::ParamEnv::reveal_all()
1149-
} else {
1150-
cx.tcx.param_env(def_id)
1151-
};
1152-
let cid = ::rustc::mir::interpret::GlobalId {
1153-
instance: ty::Instance::mono(cx.tcx, def_id),
1154-
promoted: None
1155-
};
11561146
// trigger the query once for all constants since that will already report the errors
11571147
// FIXME: Use ensure here
1158-
let _ = cx.tcx.const_eval(param_env.and(cid));
1148+
let _ = cx.tcx.const_eval_poly(def_id);
11591149
}
11601150

11611151
impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedBrokenConst {

0 commit comments

Comments
 (0)