Skip to content

Commit b38077e

Browse files
committed
change thir to use mir::ConstantKind instead of ty::Const
1 parent 9d84317 commit b38077e

File tree

29 files changed

+534
-112
lines changed

29 files changed

+534
-112
lines changed

Cargo.lock

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2327,7 +2327,6 @@ dependencies = [
23272327
"compiletest_rs",
23282328
"env_logger 0.9.0",
23292329
"getrandom 0.2.0",
2330-
"hex 0.4.2",
23312330
"libc",
23322331
"log",
23332332
"measureme 9.1.2",

compiler/rustc_const_eval/src/const_eval/mod.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,40 @@ pub(crate) fn try_destructure_const<'tcx>(
172172
Ok(mir::DestructuredConst { variant, fields })
173173
}
174174

175+
pub(crate) fn destructure_mir_constant<'tcx>(
176+
tcx: TyCtxt<'tcx>,
177+
param_env: ty::ParamEnv<'tcx>,
178+
val: mir::ConstantKind<'tcx>,
179+
) -> mir::DestructuredMirConstant<'tcx> {
180+
trace!("destructure_const: {:?}", val);
181+
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
182+
let op = ecx.mir_const_to_op(&val, None).unwrap();
183+
184+
// We go to `usize` as we cannot allocate anything bigger anyway.
185+
let (field_count, variant, down) = match val.ty().kind() {
186+
ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
187+
ty::Adt(def, _) if def.variants.is_empty() => {
188+
return mir::DestructuredMirConstant { variant: None, fields: &[] };
189+
}
190+
ty::Adt(def, _) => {
191+
let variant = ecx.read_discriminant(&op).unwrap().1;
192+
let down = ecx.operand_downcast(&op, variant).unwrap();
193+
(def.variants[variant].fields.len(), Some(variant), down)
194+
}
195+
ty::Tuple(substs) => (substs.len(), None, op),
196+
_ => bug!("cannot destructure constant {:?}", val),
197+
};
198+
199+
let fields_iter = (0..field_count).map(|i| {
200+
let field_op = ecx.operand_field(&down, i).unwrap();
201+
let val = op_to_const(&ecx, &field_op);
202+
mir::ConstantKind::Val(val, field_op.layout.ty)
203+
});
204+
let fields = tcx.arena.alloc_from_iter(fields_iter);
205+
206+
mir::DestructuredMirConstant { variant, fields }
207+
}
208+
175209
pub(crate) fn deref_const<'tcx>(
176210
tcx: TyCtxt<'tcx>,
177211
param_env: ty::ParamEnv<'tcx>,
@@ -207,3 +241,39 @@ pub(crate) fn deref_const<'tcx>(
207241

208242
tcx.mk_const(ty::ConstS { val: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
209243
}
244+
245+
#[instrument(skip(tcx), level = "debug")]
246+
pub(crate) fn deref_mir_constant<'tcx>(
247+
tcx: TyCtxt<'tcx>,
248+
param_env: ty::ParamEnv<'tcx>,
249+
val: mir::ConstantKind<'tcx>,
250+
) -> mir::ConstantKind<'tcx> {
251+
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
252+
let op = ecx.mir_const_to_op(&val, None).unwrap();
253+
let mplace = ecx.deref_operand(&op).unwrap();
254+
if let Some(alloc_id) = mplace.ptr.provenance {
255+
assert_eq!(
256+
tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().mutability,
257+
Mutability::Not,
258+
"deref_const cannot be used with mutable allocations as \
259+
that could allow pattern matching to observe mutable statics",
260+
);
261+
}
262+
263+
let ty = match mplace.meta {
264+
MemPlaceMeta::None => mplace.layout.ty,
265+
MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace),
266+
// In case of unsized types, figure out the real type behind.
267+
MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() {
268+
ty::Str => bug!("there's no sized equivalent of a `str`"),
269+
ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()),
270+
_ => bug!(
271+
"type {} should not have metadata, but had {:?}",
272+
mplace.layout.ty,
273+
mplace.meta
274+
),
275+
},
276+
};
277+
278+
mir::ConstantKind::Val(op_to_const(&ecx, &mplace.into()), ty)
279+
}

compiler/rustc_const_eval/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ pub fn provide(providers: &mut Providers) {
4545
let (param_env, value) = param_env_and_value.into_parts();
4646
const_eval::try_destructure_const(tcx, param_env, value).ok()
4747
};
48+
providers.destructure_mir_constant = |tcx, param_env_and_value| {
49+
let (param_env, value) = param_env_and_value.into_parts();
50+
const_eval::destructure_mir_constant(tcx, param_env, value)
51+
};
4852
providers.const_to_valtree = |tcx, param_env_and_value| {
4953
let (param_env, raw) = param_env_and_value.into_parts();
5054
const_eval::const_to_valtree(tcx, param_env, raw)
@@ -53,4 +57,8 @@ pub fn provide(providers: &mut Providers) {
5357
let (param_env, value) = param_env_and_value.into_parts();
5458
const_eval::deref_const(tcx, param_env, value)
5559
};
60+
providers.deref_mir_constant = |tcx, param_env_and_value| {
61+
let (param_env, value) = param_env_and_value.into_parts();
62+
const_eval::deref_mir_constant(tcx, param_env, value)
63+
}
5664
}

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 201 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ use crate::ty::adjustment::PointerCast;
99
use crate::ty::codec::{TyDecoder, TyEncoder};
1010
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
1111
use crate::ty::print::{FmtPrinter, Printer};
12-
use crate::ty::subst::{Subst, SubstsRef};
12+
use crate::ty::subst::{InternalSubsts, Subst, SubstsRef};
1313
use crate::ty::{self, List, Ty, TyCtxt};
1414
use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex};
1515

1616
use rustc_errors::ErrorGuaranteed;
1717
use rustc_hir::def::{CtorKind, Namespace};
18-
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
18+
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
1919
use rustc_hir::{self, GeneratorKind};
2020
use rustc_hir::{self as hir, HirId};
2121
use rustc_session::Session;
@@ -2664,6 +2664,16 @@ impl<'tcx> ConstantKind<'tcx> {
26642664
}
26652665
}
26662666

2667+
pub fn try_val(&self) -> Option<ConstValue<'tcx>> {
2668+
match self {
2669+
ConstantKind::Ty(c) => match c.val() {
2670+
ty::ConstKind::Value(v) => Some(v),
2671+
_ => None,
2672+
},
2673+
ConstantKind::Val(v, _) => Some(*v),
2674+
}
2675+
}
2676+
26672677
#[inline]
26682678
pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> {
26692679
match self {
@@ -2692,6 +2702,32 @@ impl<'tcx> ConstantKind<'tcx> {
26922702
self.try_to_scalar_int()?.try_into().ok()
26932703
}
26942704

2705+
#[inline]
2706+
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
2707+
match self {
2708+
Self::Ty(c) => {
2709+
// FIXME Need to use a different evaluation function that directly returns a `ConstValue`
2710+
// if evaluation succeeds and does not create a ValTree first
2711+
if let Some(val) = c.val().try_eval(tcx, param_env) {
2712+
match val {
2713+
Ok(val) => Self::Val(val, c.ty()),
2714+
Err(ErrorReported) => Self::Ty(tcx.const_error(self.ty())),
2715+
}
2716+
} else {
2717+
self
2718+
}
2719+
}
2720+
Self::Val(_, _) => self,
2721+
}
2722+
}
2723+
2724+
#[inline]
2725+
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
2726+
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
2727+
self.try_eval_bits(tcx, param_env, ty)
2728+
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
2729+
}
2730+
26952731
#[inline]
26962732
pub fn try_eval_bits(
26972733
&self,
@@ -2726,25 +2762,181 @@ impl<'tcx> ConstantKind<'tcx> {
27262762
}
27272763
}
27282764

2765+
pub fn from_bits(
2766+
tcx: TyCtxt<'tcx>,
2767+
bits: u128,
2768+
param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
2769+
) -> Self {
2770+
let size = tcx
2771+
.layout_of(param_env_ty)
2772+
.unwrap_or_else(|e| {
2773+
bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e)
2774+
})
2775+
.size;
2776+
let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
2777+
2778+
Self::Val(cv, param_env_ty.value)
2779+
}
2780+
27292781
pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
27302782
let cv = ConstValue::from_bool(v);
27312783
Self::Val(cv, tcx.types.bool)
27322784
}
27332785

2734-
pub fn from_zero_sized(ty: Ty<'tcx>) -> Self {
2786+
pub fn zero_sized(ty: Ty<'tcx>) -> Self {
27352787
let cv = ConstValue::Scalar(Scalar::ZST);
27362788
Self::Val(cv, ty)
27372789
}
27382790

27392791
pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
27402792
let ty = tcx.types.usize;
2741-
let size = tcx
2742-
.layout_of(ty::ParamEnv::empty().and(ty))
2743-
.unwrap_or_else(|e| bug!("could not compute layout for {:?}: {:?}", ty, e))
2744-
.size;
2745-
let cv = ConstValue::Scalar(Scalar::from_uint(n as u128, size));
2793+
Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
2794+
}
27462795

2747-
Self::Val(cv, ty)
2796+
#[instrument(skip(tcx), level = "debug")]
2797+
pub fn try_eval_lit_or_param(
2798+
tcx: TyCtxt<'tcx>,
2799+
ty: Ty<'tcx>,
2800+
expr: &'tcx hir::Expr<'tcx>,
2801+
) -> Option<Self> {
2802+
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
2803+
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
2804+
let expr = match &expr.kind {
2805+
hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
2806+
block.expr.as_ref().unwrap()
2807+
}
2808+
_ => expr,
2809+
};
2810+
2811+
let lit_input = match expr.kind {
2812+
hir::ExprKind::Lit(ref lit) => {
2813+
Some(interpret::LitToConstInput { lit: &lit.node, ty, neg: false })
2814+
}
2815+
hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind {
2816+
hir::ExprKind::Lit(ref lit) => {
2817+
Some(interpret::LitToConstInput { lit: &lit.node, ty, neg: true })
2818+
}
2819+
_ => None,
2820+
},
2821+
_ => None,
2822+
};
2823+
2824+
if let Some(lit_input) = lit_input {
2825+
// If an error occurred, ignore that it's a literal and leave reporting the error up to
2826+
// mir.
2827+
match tcx.at(expr.span).lit_to_mir_constant(lit_input) {
2828+
Ok(c) => return Some(c),
2829+
Err(e) => {
2830+
tcx.sess.delay_span_bug(
2831+
expr.span,
2832+
&format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
2833+
);
2834+
}
2835+
}
2836+
}
2837+
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
2838+
match expr.kind {
2839+
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
2840+
// Find the name and index of the const parameter by indexing the generics of
2841+
// the parent item and construct a `ParamConst`.
2842+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
2843+
let item_id = tcx.hir().get_parent_node(hir_id);
2844+
let item_def_id = tcx.hir().local_def_id(item_id);
2845+
let generics = tcx.generics_of(item_def_id.to_def_id());
2846+
let index = generics.param_def_id_to_index[&def_id];
2847+
let name = tcx.hir().name(hir_id);
2848+
let ty_const = tcx.mk_const(ty::ConstS {
2849+
val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
2850+
ty,
2851+
});
2852+
2853+
Some(Self::Ty(ty_const))
2854+
}
2855+
_ => None,
2856+
}
2857+
}
2858+
2859+
#[instrument(skip(tcx), level = "debug")]
2860+
pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
2861+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
2862+
2863+
let body_id = match tcx.hir().get(hir_id) {
2864+
hir::Node::AnonConst(ac) => ac.body,
2865+
_ => span_bug!(
2866+
tcx.def_span(def_id.to_def_id()),
2867+
"from_inline_const can only process anonymous constants"
2868+
),
2869+
};
2870+
2871+
let expr = &tcx.hir().body(body_id).value;
2872+
2873+
let ty = tcx.typeck(def_id).node_type(hir_id);
2874+
2875+
let ret = match Self::try_eval_lit_or_param(tcx, ty, expr) {
2876+
Some(v) => v,
2877+
None => {
2878+
let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id());
2879+
let parent_substs =
2880+
tcx.erase_regions(InternalSubsts::identity_for_item(tcx, typeck_root_def_id));
2881+
let substs = ty::InlineConstSubsts::new(
2882+
tcx,
2883+
ty::InlineConstSubstsParts { parent_substs, ty },
2884+
)
2885+
.substs;
2886+
let ty_const = tcx.mk_const(ty::ConstS {
2887+
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
2888+
def: ty::WithOptConstParam::unknown(def_id).to_global(),
2889+
substs,
2890+
promoted: None,
2891+
}),
2892+
ty,
2893+
});
2894+
2895+
Self::Ty(ty_const)
2896+
}
2897+
};
2898+
debug_assert!(!ret.has_free_regions());
2899+
ret
2900+
}
2901+
2902+
/// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
2903+
/// converted to a constant, everything else becomes `Unevaluated`.
2904+
pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
2905+
Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id))
2906+
}
2907+
2908+
#[instrument(skip(tcx), level = "debug")]
2909+
fn from_opt_const_arg_anon_const(
2910+
tcx: TyCtxt<'tcx>,
2911+
def: ty::WithOptConstParam<LocalDefId>,
2912+
) -> Self {
2913+
let body_id = match tcx.hir().get_by_def_id(def.did) {
2914+
hir::Node::AnonConst(ac) => ac.body,
2915+
_ => span_bug!(
2916+
tcx.def_span(def.did.to_def_id()),
2917+
"from_anon_const can only process anonymous constants"
2918+
),
2919+
};
2920+
2921+
let expr = &tcx.hir().body(body_id).value;
2922+
debug!(?expr);
2923+
2924+
let ty = tcx.type_of(def.def_id_for_type_of());
2925+
2926+
match Self::try_eval_lit_or_param(tcx, ty, expr) {
2927+
Some(v) => v,
2928+
None => {
2929+
let ty_const = tcx.mk_const(ty::ConstS {
2930+
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
2931+
def: def.to_global(),
2932+
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
2933+
promoted: None,
2934+
}),
2935+
ty,
2936+
});
2937+
Self::Ty(ty_const)
2938+
}
2939+
}
27482940
}
27492941
}
27502942

compiler/rustc_middle/src/mir/query.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Values computed by queries that use MIR.
22
3-
use crate::mir::{Body, Promoted};
3+
use crate::mir::{self, Body, Promoted};
44
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
55
use rustc_data_structures::stable_map::FxHashMap;
66
use rustc_data_structures::vec_map::VecMap;
@@ -421,6 +421,13 @@ pub struct DestructuredConst<'tcx> {
421421
pub fields: &'tcx [ty::Const<'tcx>],
422422
}
423423

424+
/// The constituent parts of an ADT or array.
425+
#[derive(Copy, Clone, Debug, HashStable)]
426+
pub struct DestructuredMirConstant<'tcx> {
427+
pub variant: Option<VariantIdx>,
428+
pub fields: &'tcx [mir::ConstantKind<'tcx>],
429+
}
430+
424431
/// Coverage information summarized from a MIR if instrumented for source code coverage (see
425432
/// compiler option `-Cinstrument-coverage`). This information is generated by the
426433
/// `InstrumentCoverage` MIR pass and can be retrieved via the `coverageinfo` query.

0 commit comments

Comments
 (0)