Skip to content

Commit e3c43e6

Browse files
committed
Auto merge of rust-lang#94255 - b-naber:use-mir-constant-in-thir, r=oli-obk
Use mir constant in thir instead of ty::Const This is blocked on rust-lang#94059 (does include its changes, the first two commits in this PR correspond to those changes) and rust-lang#93800 being reinstated (which had to be reverted). Mainly opening since `@lcnr` offered to give some feedback and maybe also for a perf-run (if necessary). This currently contains a lot of duplication since some of the logic of `ty::Const` had to be copied to `mir::ConstantKind`, but with the introduction of valtrees a lot of that functionality will disappear from `ty::Const`. Only the last commit contains changes that need to be reviewed here. Did leave some `FIXME` comments regarding future implementation decisions and some things that might be incorrectly implemented. r? `@oli-obk`
2 parents b768f24 + 3be987e commit e3c43e6

File tree

17 files changed

+227
-55
lines changed

17 files changed

+227
-55
lines changed

compiler/rustc_middle/src/mir/mod.rs

+162-9
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::{GenericArg, 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;
@@ -2921,6 +2921,16 @@ impl<'tcx> ConstantKind<'tcx> {
29212921
}
29222922
}
29232923

2924+
pub fn try_val(&self) -> Option<ConstValue<'tcx>> {
2925+
match self {
2926+
ConstantKind::Ty(c) => match c.val() {
2927+
ty::ConstKind::Value(v) => Some(v),
2928+
_ => None,
2929+
},
2930+
ConstantKind::Val(v, _) => Some(*v),
2931+
}
2932+
}
2933+
29242934
#[inline]
29252935
pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> {
29262936
match self {
@@ -2949,6 +2959,32 @@ impl<'tcx> ConstantKind<'tcx> {
29492959
self.try_to_scalar_int()?.try_into().ok()
29502960
}
29512961

2962+
#[inline]
2963+
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
2964+
match self {
2965+
Self::Ty(c) => {
2966+
// FIXME Need to use a different evaluation function that directly returns a `ConstValue`
2967+
// if evaluation succeeds and does not create a ValTree first
2968+
if let Some(val) = c.val().try_eval(tcx, param_env) {
2969+
match val {
2970+
Ok(val) => Self::Val(val, c.ty()),
2971+
Err(_) => Self::Ty(tcx.const_error(self.ty())),
2972+
}
2973+
} else {
2974+
self
2975+
}
2976+
}
2977+
Self::Val(_, _) => self,
2978+
}
2979+
}
2980+
2981+
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
2982+
#[inline]
2983+
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
2984+
self.try_eval_bits(tcx, param_env, ty)
2985+
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
2986+
}
2987+
29522988
#[inline]
29532989
pub fn try_eval_bits(
29542990
&self,
@@ -2983,25 +3019,142 @@ impl<'tcx> ConstantKind<'tcx> {
29833019
}
29843020
}
29853021

3022+
pub fn from_bits(
3023+
tcx: TyCtxt<'tcx>,
3024+
bits: u128,
3025+
param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
3026+
) -> Self {
3027+
let size = tcx
3028+
.layout_of(param_env_ty)
3029+
.unwrap_or_else(|e| {
3030+
bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e)
3031+
})
3032+
.size;
3033+
let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
3034+
3035+
Self::Val(cv, param_env_ty.value)
3036+
}
3037+
29863038
pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
29873039
let cv = ConstValue::from_bool(v);
29883040
Self::Val(cv, tcx.types.bool)
29893041
}
29903042

2991-
pub fn from_zero_sized(ty: Ty<'tcx>) -> Self {
3043+
pub fn zero_sized(ty: Ty<'tcx>) -> Self {
29923044
let cv = ConstValue::Scalar(Scalar::ZST);
29933045
Self::Val(cv, ty)
29943046
}
29953047

29963048
pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
29973049
let ty = tcx.types.usize;
2998-
let size = tcx
2999-
.layout_of(ty::ParamEnv::empty().and(ty))
3000-
.unwrap_or_else(|e| bug!("could not compute layout for {:?}: {:?}", ty, e))
3001-
.size;
3002-
let cv = ConstValue::Scalar(Scalar::from_uint(n as u128, size));
3050+
Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
3051+
}
30033052

3004-
Self::Val(cv, ty)
3053+
/// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
3054+
/// converted to a constant, everything else becomes `Unevaluated`.
3055+
pub fn from_anon_const(
3056+
tcx: TyCtxt<'tcx>,
3057+
def_id: LocalDefId,
3058+
param_env: ty::ParamEnv<'tcx>,
3059+
) -> Self {
3060+
Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env)
3061+
}
3062+
3063+
#[instrument(skip(tcx), level = "debug")]
3064+
fn from_opt_const_arg_anon_const(
3065+
tcx: TyCtxt<'tcx>,
3066+
def: ty::WithOptConstParam<LocalDefId>,
3067+
param_env: ty::ParamEnv<'tcx>,
3068+
) -> Self {
3069+
let body_id = match tcx.hir().get_by_def_id(def.did) {
3070+
hir::Node::AnonConst(ac) => ac.body,
3071+
_ => span_bug!(
3072+
tcx.def_span(def.did.to_def_id()),
3073+
"from_anon_const can only process anonymous constants"
3074+
),
3075+
};
3076+
3077+
let expr = &tcx.hir().body(body_id).value;
3078+
debug!(?expr);
3079+
3080+
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
3081+
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
3082+
let expr = match &expr.kind {
3083+
hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
3084+
block.expr.as_ref().unwrap()
3085+
}
3086+
_ => expr,
3087+
};
3088+
3089+
let ty = tcx.type_of(def.def_id_for_type_of());
3090+
3091+
// FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
3092+
// does not provide the parents generics to anonymous constants. We still allow generic const
3093+
// parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
3094+
// ever try to substitute the generic parameters in their bodies.
3095+
//
3096+
// While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does
3097+
// cause issues if we were to remove that special-case and try to evaluate the constant instead.
3098+
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
3099+
match expr.kind {
3100+
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
3101+
// Find the name and index of the const parameter by indexing the generics of
3102+
// the parent item and construct a `ParamConst`.
3103+
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
3104+
let item_id = tcx.hir().get_parent_node(hir_id);
3105+
let item_def_id = tcx.hir().local_def_id(item_id);
3106+
let generics = tcx.generics_of(item_def_id.to_def_id());
3107+
let index = generics.param_def_id_to_index[&def_id];
3108+
let name = tcx.hir().name(hir_id);
3109+
let ty_const = tcx.mk_const(ty::ConstS {
3110+
val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
3111+
ty,
3112+
});
3113+
3114+
return Self::Ty(ty_const);
3115+
}
3116+
_ => {}
3117+
}
3118+
3119+
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
3120+
let parent_substs = if let Some(parent_hir_id) = tcx.hir().find_parent_node(hir_id) {
3121+
if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) {
3122+
InternalSubsts::identity_for_item(tcx, parent_did.to_def_id())
3123+
} else {
3124+
tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
3125+
}
3126+
} else {
3127+
tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
3128+
};
3129+
debug!(?parent_substs);
3130+
3131+
let did = def.did.to_def_id();
3132+
let child_substs = InternalSubsts::identity_for_item(tcx, did);
3133+
let substs = tcx.mk_substs(parent_substs.into_iter().chain(child_substs.into_iter()));
3134+
debug!(?substs);
3135+
3136+
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
3137+
let span = tcx.hir().span(hir_id);
3138+
let uneval = ty::Unevaluated::new(def.to_global(), substs);
3139+
debug!(?span, ?param_env);
3140+
3141+
match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
3142+
Ok(val) => Self::Val(val, ty),
3143+
Err(_) => {
3144+
// Error was handled in `const_eval_resolve`. Here we just create a
3145+
// new unevaluated const and error hard later in codegen
3146+
let ty_const = tcx.mk_const(ty::ConstS {
3147+
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
3148+
def: def.to_global(),
3149+
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
3150+
promoted: None,
3151+
}),
3152+
ty,
3153+
});
3154+
3155+
Self::Ty(ty_const)
3156+
}
3157+
}
30053158
}
30063159
}
30073160

compiler/rustc_middle/src/thir.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ use rustc_middle::infer::canonical::Canonical;
1919
use rustc_middle::middle::region;
2020
use rustc_middle::mir::interpret::AllocId;
2121
use rustc_middle::mir::{
22-
BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
22+
self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
2323
};
2424
use rustc_middle::ty::adjustment::PointerCast;
2525
use rustc_middle::ty::subst::SubstsRef;
26-
use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType};
26+
use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType};
2727
use rustc_middle::ty::{
2828
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
2929
};
@@ -375,7 +375,7 @@ pub enum ExprKind<'tcx> {
375375
/// An array literal constructed from one repeated element, e.g. `[1; 5]`.
376376
Repeat {
377377
value: ExprId,
378-
count: Const<'tcx>,
378+
count: ty::Const<'tcx>,
379379
},
380380
/// An array, e.g. `[a, b, c, d]`.
381381
Array {
@@ -522,7 +522,7 @@ pub enum InlineAsmOperand<'tcx> {
522522
out_expr: Option<ExprId>,
523523
},
524524
Const {
525-
value: Const<'tcx>,
525+
value: mir::ConstantKind<'tcx>,
526526
span: Span,
527527
},
528528
SymFn {

compiler/rustc_middle/src/thir/visit.rs

+9
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized {
2424
fn visit_pat(&mut self, pat: &Pat<'tcx>) {
2525
walk_pat(self, pat);
2626
}
27+
28+
// Note: We don't have visitors for `ty::Const` and `mir::ConstantKind`
29+
// (even though these types occur in THIR) for consistency and to reduce confusion,
30+
// since the lazy creation of constants during thir construction causes most
31+
// 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that
32+
// stage (they are mostly still identified by `DefId` or `hir::Lit`, see
33+
// the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
34+
// You have to manually visit `ty::Const` and `mir::ConstantKind` through the
35+
// other `visit*` functions.
2736
}
2837

2938
pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {

compiler/rustc_middle/src/ty/consts/kind.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,8 @@ impl<'tcx> ConstKind<'tcx> {
126126
#[inline]
127127
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
128128
/// return `None`.
129-
pub(super) fn try_eval(
129+
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
130+
pub fn try_eval(
130131
self,
131132
tcx: TyCtxt<'tcx>,
132133
param_env: ParamEnv<'tcx>,

compiler/rustc_mir_build/src/build/cfg.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ impl<'tcx> CFG<'tcx> {
7373
Rvalue::Use(Operand::Constant(Box::new(Constant {
7474
span: source_info.span,
7575
user_ty: None,
76-
literal: ConstantKind::from_zero_sized(tcx.types.unit),
76+
literal: ConstantKind::zero_sized(tcx.types.unit),
7777
}))),
7878
);
7979
}

compiler/rustc_mir_build/src/build/expr/as_constant.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,10 @@
22
33
use crate::build::Builder;
44
use crate::thir::constant::parse_float;
5-
use rustc_ast::ast;
5+
use rustc_ast as ast;
66
use rustc_hir::def_id::DefId;
7-
use rustc_middle::mir::interpret::{
8-
Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
9-
};
7+
use rustc_middle::mir::interpret::Allocation;
8+
use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
109
use rustc_middle::mir::*;
1110
use rustc_middle::thir::*;
1211
use rustc_middle::ty::subst::SubstsRef;
@@ -32,11 +31,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
3231
}
3332
ExprKind::Literal { lit, neg } => {
3433
let literal =
35-
match lit_to_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
34+
match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
3635
Ok(c) => c,
3736
Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)),
3837
Err(LitToConstError::TypeError) => {
39-
bug!("encountered type error in `lit_to_constant")
38+
bug!("encountered type error in `lit_to_mir_constant")
4039
}
4140
};
4241

@@ -90,7 +89,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
9089
}
9190
}
9291

93-
crate fn lit_to_constant<'tcx>(
92+
#[instrument(skip(tcx, lit_input))]
93+
fn lit_to_mir_constant<'tcx>(
9494
tcx: TyCtxt<'tcx>,
9595
lit_input: LitToConstInput<'tcx>,
9696
) -> Result<ConstantKind<'tcx>, LitToConstError> {

compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
322322
block.and(Rvalue::Use(Operand::Constant(Box::new(Constant {
323323
span: expr_span,
324324
user_ty: None,
325-
literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit).into(),
325+
literal: ConstantKind::zero_sized(this.tcx.types.unit),
326326
}))))
327327
}
328328
ExprKind::Yield { .. }
@@ -552,7 +552,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
552552
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
553553
let param_ty = ty::ParamEnv::empty().and(ty);
554554
let size = self.tcx.layout_of(param_ty).unwrap().size;
555-
let literal = ty::Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
555+
let literal = ConstantKind::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
556556

557557
self.literal_operand(span, literal)
558558
}
@@ -563,7 +563,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
563563
let param_ty = ty::ParamEnv::empty().and(ty);
564564
let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
565565
let n = 1 << (bits - 1);
566-
let literal = ty::Const::from_bits(self.tcx, n, param_ty);
566+
let literal = ConstantKind::from_bits(self.tcx, n, param_ty);
567567

568568
self.literal_operand(span, literal)
569569
}

compiler/rustc_mir_build/src/build/matches/test.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
264264
);
265265
} else if let [success, fail] = *make_target_blocks(self) {
266266
assert_eq!(value.ty(), ty);
267-
let expect = self.literal_operand(test.span, value);
267+
let expect = self.literal_operand(test.span, value.into());
268268
let val = Operand::Copy(place);
269269
self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
270270
} else {
@@ -277,8 +277,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
277277
let target_blocks = make_target_blocks(self);
278278

279279
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
280-
let lo = self.literal_operand(test.span, lo);
281-
let hi = self.literal_operand(test.span, hi);
280+
let lo = self.literal_operand(test.span, lo.into());
281+
let hi = self.literal_operand(test.span, hi.into());
282282
let val = Operand::Copy(place);
283283

284284
let [success, fail] = *target_blocks else {
@@ -370,7 +370,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
370370
place: Place<'tcx>,
371371
mut ty: Ty<'tcx>,
372372
) {
373-
let mut expect = self.literal_operand(source_info.span, value);
373+
let mut expect = self.literal_operand(source_info.span, value.into());
374374
let mut val = Operand::Copy(place);
375375

376376
// If we're using `b"..."` as a pattern, we need to insert an
@@ -823,7 +823,7 @@ fn trait_method<'tcx>(
823823
method_name: Symbol,
824824
self_ty: Ty<'tcx>,
825825
params: &[GenericArg<'tcx>],
826-
) -> ty::Const<'tcx> {
826+
) -> ConstantKind<'tcx> {
827827
let substs = tcx.mk_substs_trait(self_ty, params);
828828

829829
// The unhygienic comparison here is acceptable because this is only
@@ -836,5 +836,6 @@ fn trait_method<'tcx>(
836836

837837
let method_ty = tcx.type_of(item.def_id);
838838
let method_ty = method_ty.subst(tcx, substs);
839-
ty::Const::zero_sized(tcx, method_ty)
839+
840+
ConstantKind::zero_sized(method_ty)
840841
}

0 commit comments

Comments
 (0)