1
Fork 0

Auto merge of #94255 - b-naber:use-mir-constant-in-thir, r=oli-obk

Use mir constant in thir instead of ty::Const

This is blocked on https://github.com/rust-lang/rust/pull/94059 (does include its changes, the first two commits in this PR correspond to those changes) and https://github.com/rust-lang/rust/pull/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`
This commit is contained in:
bors 2022-04-13 07:50:56 +00:00
commit e3c43e64ec
17 changed files with 227 additions and 55 deletions

View file

@ -9,13 +9,13 @@ use crate::ty::adjustment::PointerCast;
use crate::ty::codec::{TyDecoder, TyEncoder}; use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor}; use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeVisitor};
use crate::ty::print::{FmtPrinter, Printer}; use crate::ty::print::{FmtPrinter, Printer};
use crate::ty::subst::{Subst, SubstsRef}; use crate::ty::subst::{GenericArg, InternalSubsts, Subst, SubstsRef};
use crate::ty::{self, List, Ty, TyCtxt}; use crate::ty::{self, List, Ty, TyCtxt};
use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex}; use crate::ty::{AdtDef, InstanceDef, Region, ScalarInt, UserTypeAnnotationIndex};
use rustc_errors::ErrorGuaranteed; use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::{CtorKind, Namespace}; use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX};
use rustc_hir::{self, GeneratorKind}; use rustc_hir::{self, GeneratorKind};
use rustc_hir::{self as hir, HirId}; use rustc_hir::{self as hir, HirId};
use rustc_session::Session; use rustc_session::Session;
@ -2921,6 +2921,16 @@ impl<'tcx> ConstantKind<'tcx> {
} }
} }
pub fn try_val(&self) -> Option<ConstValue<'tcx>> {
match self {
ConstantKind::Ty(c) => match c.val() {
ty::ConstKind::Value(v) => Some(v),
_ => None,
},
ConstantKind::Val(v, _) => Some(*v),
}
}
#[inline] #[inline]
pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> { pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> {
match self { match self {
@ -2949,6 +2959,32 @@ impl<'tcx> ConstantKind<'tcx> {
self.try_to_scalar_int()?.try_into().ok() self.try_to_scalar_int()?.try_into().ok()
} }
#[inline]
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
match self {
Self::Ty(c) => {
// FIXME Need to use a different evaluation function that directly returns a `ConstValue`
// if evaluation succeeds and does not create a ValTree first
if let Some(val) = c.val().try_eval(tcx, param_env) {
match val {
Ok(val) => Self::Val(val, c.ty()),
Err(_) => Self::Ty(tcx.const_error(self.ty())),
}
} else {
self
}
}
Self::Val(_, _) => self,
}
}
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
#[inline]
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
self.try_eval_bits(tcx, param_env, ty)
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
}
#[inline] #[inline]
pub fn try_eval_bits( pub fn try_eval_bits(
&self, &self,
@ -2983,25 +3019,142 @@ impl<'tcx> ConstantKind<'tcx> {
} }
} }
pub fn from_bits(
tcx: TyCtxt<'tcx>,
bits: u128,
param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
) -> Self {
let size = tcx
.layout_of(param_env_ty)
.unwrap_or_else(|e| {
bug!("could not compute layout for {:?}: {:?}", param_env_ty.value, e)
})
.size;
let cv = ConstValue::Scalar(Scalar::from_uint(bits, size));
Self::Val(cv, param_env_ty.value)
}
pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self { pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
let cv = ConstValue::from_bool(v); let cv = ConstValue::from_bool(v);
Self::Val(cv, tcx.types.bool) Self::Val(cv, tcx.types.bool)
} }
pub fn from_zero_sized(ty: Ty<'tcx>) -> Self { pub fn zero_sized(ty: Ty<'tcx>) -> Self {
let cv = ConstValue::Scalar(Scalar::ZST); let cv = ConstValue::Scalar(Scalar::ZST);
Self::Val(cv, ty) Self::Val(cv, ty)
} }
pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self { pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
let ty = tcx.types.usize; let ty = tcx.types.usize;
let size = tcx Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
.layout_of(ty::ParamEnv::empty().and(ty)) }
.unwrap_or_else(|e| bug!("could not compute layout for {:?}: {:?}", ty, e))
.size;
let cv = ConstValue::Scalar(Scalar::from_uint(n as u128, size));
Self::Val(cv, ty) /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
/// converted to a constant, everything else becomes `Unevaluated`.
pub fn from_anon_const(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env)
}
#[instrument(skip(tcx), level = "debug")]
fn from_opt_const_arg_anon_const(
tcx: TyCtxt<'tcx>,
def: ty::WithOptConstParam<LocalDefId>,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
let body_id = match tcx.hir().get_by_def_id(def.did) {
hir::Node::AnonConst(ac) => ac.body,
_ => span_bug!(
tcx.def_span(def.did.to_def_id()),
"from_anon_const can only process anonymous constants"
),
};
let expr = &tcx.hir().body(body_id).value;
debug!(?expr);
// Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments
// currently have to be wrapped in curly brackets, so it's necessary to special-case.
let expr = match &expr.kind {
hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => {
block.expr.as_ref().unwrap()
}
_ => expr,
};
let ty = tcx.type_of(def.def_id_for_type_of());
// FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
// does not provide the parents generics to anonymous constants. We still allow generic const
// parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to
// ever try to substitute the generic parameters in their bodies.
//
// While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does
// cause issues if we were to remove that special-case and try to evaluate the constant instead.
use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath};
match expr.kind {
ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => {
// Find the name and index of the const parameter by indexing the generics of
// the parent item and construct a `ParamConst`.
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
let item_id = tcx.hir().get_parent_node(hir_id);
let item_def_id = tcx.hir().local_def_id(item_id);
let generics = tcx.generics_of(item_def_id.to_def_id());
let index = generics.param_def_id_to_index[&def_id];
let name = tcx.hir().name(hir_id);
let ty_const = tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
ty,
});
return Self::Ty(ty_const);
}
_ => {}
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
let parent_substs = if let Some(parent_hir_id) = tcx.hir().find_parent_node(hir_id) {
if let Some(parent_did) = tcx.hir().opt_local_def_id(parent_hir_id) {
InternalSubsts::identity_for_item(tcx, parent_did.to_def_id())
} else {
tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
}
} else {
tcx.mk_substs(Vec::<GenericArg<'tcx>>::new().into_iter())
};
debug!(?parent_substs);
let did = def.did.to_def_id();
let child_substs = InternalSubsts::identity_for_item(tcx, did);
let substs = tcx.mk_substs(parent_substs.into_iter().chain(child_substs.into_iter()));
debug!(?substs);
let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
let span = tcx.hir().span(hir_id);
let uneval = ty::Unevaluated::new(def.to_global(), substs);
debug!(?span, ?param_env);
match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
Ok(val) => Self::Val(val, ty),
Err(_) => {
// Error was handled in `const_eval_resolve`. Here we just create a
// new unevaluated const and error hard later in codegen
let ty_const = tcx.mk_const(ty::ConstS {
val: ty::ConstKind::Unevaluated(ty::Unevaluated {
def: def.to_global(),
substs: InternalSubsts::identity_for_item(tcx, def.did.to_def_id()),
promoted: None,
}),
ty,
});
Self::Ty(ty_const)
}
}
} }
} }

View file

@ -19,11 +19,11 @@ use rustc_middle::infer::canonical::Canonical;
use rustc_middle::middle::region; use rustc_middle::middle::region;
use rustc_middle::mir::interpret::AllocId; use rustc_middle::mir::interpret::AllocId;
use rustc_middle::mir::{ use rustc_middle::mir::{
BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection, self, BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection,
}; };
use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType}; use rustc_middle::ty::{self, AdtDef, Ty, UpvarSubsts, UserType};
use rustc_middle::ty::{ use rustc_middle::ty::{
CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
}; };
@ -375,7 +375,7 @@ pub enum ExprKind<'tcx> {
/// An array literal constructed from one repeated element, e.g. `[1; 5]`. /// An array literal constructed from one repeated element, e.g. `[1; 5]`.
Repeat { Repeat {
value: ExprId, value: ExprId,
count: Const<'tcx>, count: ty::Const<'tcx>,
}, },
/// An array, e.g. `[a, b, c, d]`. /// An array, e.g. `[a, b, c, d]`.
Array { Array {
@ -522,7 +522,7 @@ pub enum InlineAsmOperand<'tcx> {
out_expr: Option<ExprId>, out_expr: Option<ExprId>,
}, },
Const { Const {
value: Const<'tcx>, value: mir::ConstantKind<'tcx>,
span: Span, span: Span,
}, },
SymFn { SymFn {

View file

@ -24,6 +24,15 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized {
fn visit_pat(&mut self, pat: &Pat<'tcx>) { fn visit_pat(&mut self, pat: &Pat<'tcx>) {
walk_pat(self, pat); walk_pat(self, pat);
} }
// Note: We don't have visitors for `ty::Const` and `mir::ConstantKind`
// (even though these types occur in THIR) for consistency and to reduce confusion,
// since the lazy creation of constants during thir construction causes most
// 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that
// stage (they are mostly still identified by `DefId` or `hir::Lit`, see
// the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
// You have to manually visit `ty::Const` and `mir::ConstantKind` through the
// other `visit*` functions.
} }
pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) {

View file

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

View file

@ -73,7 +73,7 @@ impl<'tcx> CFG<'tcx> {
Rvalue::Use(Operand::Constant(Box::new(Constant { Rvalue::Use(Operand::Constant(Box::new(Constant {
span: source_info.span, span: source_info.span,
user_ty: None, user_ty: None,
literal: ConstantKind::from_zero_sized(tcx.types.unit), literal: ConstantKind::zero_sized(tcx.types.unit),
}))), }))),
); );
} }

View file

@ -2,11 +2,10 @@
use crate::build::Builder; use crate::build::Builder;
use crate::thir::constant::parse_float; use crate::thir::constant::parse_float;
use rustc_ast::ast; use rustc_ast as ast;
use rustc_hir::def_id::DefId; use rustc_hir::def_id::DefId;
use rustc_middle::mir::interpret::{ use rustc_middle::mir::interpret::Allocation;
Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
};
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::thir::*; use rustc_middle::thir::*;
use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::subst::SubstsRef;
@ -32,11 +31,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
ExprKind::Literal { lit, neg } => { ExprKind::Literal { lit, neg } => {
let literal = let literal =
match lit_to_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) { match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
Ok(c) => c, Ok(c) => c,
Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)), Err(LitToConstError::Reported) => ConstantKind::Ty(tcx.const_error(ty)),
Err(LitToConstError::TypeError) => { Err(LitToConstError::TypeError) => {
bug!("encountered type error in `lit_to_constant") bug!("encountered type error in `lit_to_mir_constant")
} }
}; };
@ -90,7 +89,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} }
} }
crate fn lit_to_constant<'tcx>( #[instrument(skip(tcx, lit_input))]
fn lit_to_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>, lit_input: LitToConstInput<'tcx>,
) -> Result<ConstantKind<'tcx>, LitToConstError> { ) -> Result<ConstantKind<'tcx>, LitToConstError> {

View file

@ -322,7 +322,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block.and(Rvalue::Use(Operand::Constant(Box::new(Constant { block.and(Rvalue::Use(Operand::Constant(Box::new(Constant {
span: expr_span, span: expr_span,
user_ty: None, user_ty: None,
literal: ty::Const::zero_sized(this.tcx, this.tcx.types.unit).into(), literal: ConstantKind::zero_sized(this.tcx.types.unit),
})))) }))))
} }
ExprKind::Yield { .. } ExprKind::Yield { .. }
@ -552,7 +552,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { fn neg_1_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let param_ty = ty::ParamEnv::empty().and(ty); let param_ty = ty::ParamEnv::empty().and(ty);
let size = self.tcx.layout_of(param_ty).unwrap().size; let size = self.tcx.layout_of(param_ty).unwrap().size;
let literal = ty::Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty); let literal = ConstantKind::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
self.literal_operand(span, literal) self.literal_operand(span, literal)
} }
@ -563,7 +563,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let param_ty = ty::ParamEnv::empty().and(ty); let param_ty = ty::ParamEnv::empty().and(ty);
let bits = self.tcx.layout_of(param_ty).unwrap().size.bits(); let bits = self.tcx.layout_of(param_ty).unwrap().size.bits();
let n = 1 << (bits - 1); let n = 1 << (bits - 1);
let literal = ty::Const::from_bits(self.tcx, n, param_ty); let literal = ConstantKind::from_bits(self.tcx, n, param_ty);
self.literal_operand(span, literal) self.literal_operand(span, literal)
} }

View file

@ -264,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
); );
} else if let [success, fail] = *make_target_blocks(self) { } else if let [success, fail] = *make_target_blocks(self) {
assert_eq!(value.ty(), ty); assert_eq!(value.ty(), ty);
let expect = self.literal_operand(test.span, value); let expect = self.literal_operand(test.span, value.into());
let val = Operand::Copy(place); let val = Operand::Copy(place);
self.compare(block, success, fail, source_info, BinOp::Eq, expect, val); self.compare(block, success, fail, source_info, BinOp::Eq, expect, val);
} else { } else {
@ -277,8 +277,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let target_blocks = make_target_blocks(self); let target_blocks = make_target_blocks(self);
// Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons. // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
let lo = self.literal_operand(test.span, lo); let lo = self.literal_operand(test.span, lo.into());
let hi = self.literal_operand(test.span, hi); let hi = self.literal_operand(test.span, hi.into());
let val = Operand::Copy(place); let val = Operand::Copy(place);
let [success, fail] = *target_blocks else { let [success, fail] = *target_blocks else {
@ -370,7 +370,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: Place<'tcx>, place: Place<'tcx>,
mut ty: Ty<'tcx>, mut ty: Ty<'tcx>,
) { ) {
let mut expect = self.literal_operand(source_info.span, value); let mut expect = self.literal_operand(source_info.span, value.into());
let mut val = Operand::Copy(place); let mut val = Operand::Copy(place);
// If we're using `b"..."` as a pattern, we need to insert an // If we're using `b"..."` as a pattern, we need to insert an
@ -823,7 +823,7 @@ fn trait_method<'tcx>(
method_name: Symbol, method_name: Symbol,
self_ty: Ty<'tcx>, self_ty: Ty<'tcx>,
params: &[GenericArg<'tcx>], params: &[GenericArg<'tcx>],
) -> ty::Const<'tcx> { ) -> ConstantKind<'tcx> {
let substs = tcx.mk_substs_trait(self_ty, params); let substs = tcx.mk_substs_trait(self_ty, params);
// The unhygienic comparison here is acceptable because this is only // The unhygienic comparison here is acceptable because this is only
@ -836,5 +836,6 @@ fn trait_method<'tcx>(
let method_ty = tcx.type_of(item.def_id); let method_ty = tcx.type_of(item.def_id);
let method_ty = method_ty.subst(tcx, substs); let method_ty = method_ty.subst(tcx, substs);
ty::Const::zero_sized(tcx, method_ty)
ConstantKind::zero_sized(method_ty)
} }

View file

@ -3,6 +3,7 @@
use crate::build::Builder; use crate::build::Builder;
use rustc_middle::mir;
use rustc_middle::mir::*; use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty}; use rustc_middle::ty::{self, Ty};
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
@ -25,8 +26,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Convenience function for creating a literal operand, one /// Convenience function for creating a literal operand, one
/// without any user type annotation. /// without any user type annotation.
crate fn literal_operand(&mut self, span: Span, literal: ty::Const<'tcx>) -> Operand<'tcx> { crate fn literal_operand(
let literal = literal.into(); &mut self,
span: Span,
literal: mir::ConstantKind<'tcx>,
) -> Operand<'tcx> {
let constant = Box::new(Constant { span, user_ty: None, literal }); let constant = Box::new(Constant { span, user_ty: None, literal });
Operand::Constant(constant) Operand::Constant(constant)
} }
@ -34,7 +38,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Returns a zero literal operand for the appropriate type, works for // Returns a zero literal operand for the appropriate type, works for
// bool, char and integers. // bool, char and integers.
crate fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> { crate fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
let literal = ty::Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty)); let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
self.literal_operand(span, literal) self.literal_operand(span, literal)
} }

View file

@ -8,7 +8,7 @@ use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
use rustc_middle::middle::region; use rustc_middle::middle::region;
use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp}; use rustc_middle::mir::{self, BinOp, BorrowKind, Field, UnOp};
use rustc_middle::thir::*; use rustc_middle::thir::*;
use rustc_middle::ty::adjustment::{ use rustc_middle::ty::adjustment::{
Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast, Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast,
@ -491,7 +491,11 @@ impl<'tcx> Cx<'tcx> {
hir::InlineAsmOperand::Const { ref anon_const } => { hir::InlineAsmOperand::Const { ref anon_const } => {
let anon_const_def_id = let anon_const_def_id =
self.tcx.hir().local_def_id(anon_const.hir_id); self.tcx.hir().local_def_id(anon_const.hir_id);
let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); let value = mir::ConstantKind::from_anon_const(
self.tcx,
anon_const_def_id,
self.param_env,
);
let span = self.tcx.hir().span(anon_const.hir_id); let span = self.tcx.hir().span(anon_const.hir_id);
InlineAsmOperand::Const { value, span } InlineAsmOperand::Const { value, span }

View file

@ -55,7 +55,7 @@ use rustc_hir::{HirId, RangeEnd};
use rustc_middle::mir::Field; use rustc_middle::mir::Field;
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange}; use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Const, Ty, TyCtxt, VariantDef}; use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
use rustc_middle::{middle::stability::EvalResult, mir::interpret::ConstValue}; use rustc_middle::{middle::stability::EvalResult, mir::interpret::ConstValue};
use rustc_session::lint; use rustc_session::lint;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
@ -136,7 +136,7 @@ impl IntRange {
fn from_const<'tcx>( fn from_const<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
value: Const<'tcx>, value: ty::Const<'tcx>,
) -> Option<IntRange> { ) -> Option<IntRange> {
let ty = value.ty(); let ty = value.ty();
if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) { if let Some((target_size, bias)) = Self::integral_size_and_signed_bias(tcx, ty) {
@ -829,7 +829,8 @@ impl<'tcx> Constructor<'tcx> {
} }
} }
(Str(self_val), Str(other_val)) => { (Str(self_val), Str(other_val)) => {
// FIXME: there's probably a more direct way of comparing for equality // FIXME Once valtrees are available we can directly use the bytes
// in the `Str` variant of the valtree for the comparison here.
match compare_const_vals( match compare_const_vals(
pcx.cx.tcx, pcx.cx.tcx,
*self_val, *self_val,

View file

@ -488,9 +488,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) { match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) {
Ok(value) => { Ok(value) => {
let const_ = let const_ = ty::Const::from_value(self.tcx, value, ty);
ty::Const::from_value(self.tcx, value, self.typeck_results.node_type(id));
let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation); let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation);
if !is_associated_const { if !is_associated_const {
@ -585,7 +583,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let lit_input = let lit_input =
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
match self.tcx.at(expr.span).lit_to_const(lit_input) { match self.tcx.at(expr.span).lit_to_const(lit_input) {
Ok(val) => *self.const_to_pat(val, expr.hir_id, lit.span, false).kind, Ok(constant) => *self.const_to_pat(constant, expr.hir_id, lit.span, false).kind,
Err(LitToConstError::Reported) => PatKind::Wild, Err(LitToConstError::Reported) => PatKind::Wild,
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
} }
@ -739,6 +737,7 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
} }
} }
#[instrument(skip(tcx), level = "debug")]
crate fn compare_const_vals<'tcx>( crate fn compare_const_vals<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
a: ty::Const<'tcx>, a: ty::Const<'tcx>,
@ -746,8 +745,6 @@ crate fn compare_const_vals<'tcx>(
param_env: ty::ParamEnv<'tcx>, param_env: ty::ParamEnv<'tcx>,
ty: Ty<'tcx>, ty: Ty<'tcx>,
) -> Option<Ordering> { ) -> Option<Ordering> {
trace!("compare_const_vals: {:?}, {:?}", a, b);
let from_bool = |v: bool| v.then_some(Ordering::Equal); let from_bool = |v: bool| v.then_some(Ordering::Equal);
let fallback = || from_bool(a == b); let fallback = || from_bool(a == b);

View file

@ -765,10 +765,7 @@ fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
/// `is_under_guard` is used to inform if the pattern has a guard. If it /// `is_under_guard` is used to inform if the pattern has a guard. If it
/// has one it must not be inserted into the matrix. This shouldn't be /// has one it must not be inserted into the matrix. This shouldn't be
/// relied on for soundness. /// relied on for soundness.
#[instrument( #[instrument(level = "debug", skip(cx, matrix, hir_id))]
level = "debug",
skip(cx, matrix, witness_preference, hir_id, is_under_guard, is_top_level)
)]
fn is_useful<'p, 'tcx>( fn is_useful<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>, cx: &MatchCheckCtxt<'p, 'tcx>,
matrix: &Matrix<'p, 'tcx>, matrix: &Matrix<'p, 'tcx>,
@ -800,6 +797,7 @@ fn is_useful<'p, 'tcx>(
let ty = v.head().ty(); let ty = v.head().ty();
let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span());
let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
// If the first pattern is an or-pattern, expand it. // If the first pattern is an or-pattern, expand it.
@ -809,9 +807,11 @@ fn is_useful<'p, 'tcx>(
// We try each or-pattern branch in turn. // We try each or-pattern branch in turn.
let mut matrix = matrix.clone(); let mut matrix = matrix.clone();
for v in v.expand_or_pat() { for v in v.expand_or_pat() {
debug!(?v);
let usefulness = ensure_sufficient_stack(|| { let usefulness = ensure_sufficient_stack(|| {
is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false) is_useful(cx, &matrix, &v, witness_preference, hir_id, is_under_guard, false)
}); });
debug!(?usefulness);
ret.extend(usefulness); ret.extend(usefulness);
// If pattern has a guard don't add it to the matrix. // If pattern has a guard don't add it to the matrix.
if !is_under_guard { if !is_under_guard {
@ -822,6 +822,7 @@ fn is_useful<'p, 'tcx>(
} }
} else { } else {
let v_ctor = v.head().ctor(); let v_ctor = v.head().ctor();
debug!(?v_ctor);
if let Constructor::IntRange(ctor_range) = &v_ctor { if let Constructor::IntRange(ctor_range) = &v_ctor {
// Lint on likely incorrect range patterns (#63987) // Lint on likely incorrect range patterns (#63987)
ctor_range.lint_overlapping_range_endpoints( ctor_range.lint_overlapping_range_endpoints(
@ -895,7 +896,7 @@ fn is_useful<'p, 'tcx>(
} }
/// The arm of a match expression. /// The arm of a match expression.
#[derive(Clone, Copy)] #[derive(Clone, Copy, Debug)]
crate struct MatchArm<'p, 'tcx> { crate struct MatchArm<'p, 'tcx> {
/// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`. /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`.
crate pat: &'p DeconstructedPat<'p, 'tcx>, crate pat: &'p DeconstructedPat<'p, 'tcx>,
@ -928,6 +929,7 @@ crate struct UsefulnessReport<'p, 'tcx> {
/// ///
/// Note: the input patterns must have been lowered through /// Note: the input patterns must have been lowered through
/// `check_match::MatchVisitor::lower_pattern`. /// `check_match::MatchVisitor::lower_pattern`.
#[instrument(skip(cx, arms), level = "debug")]
crate fn compute_match_usefulness<'p, 'tcx>( crate fn compute_match_usefulness<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>, cx: &MatchCheckCtxt<'p, 'tcx>,
arms: &[MatchArm<'p, 'tcx>], arms: &[MatchArm<'p, 'tcx>],
@ -939,6 +941,7 @@ crate fn compute_match_usefulness<'p, 'tcx>(
.iter() .iter()
.copied() .copied()
.map(|arm| { .map(|arm| {
debug!(?arm);
let v = PatStack::from_pattern(arm.pat); let v = PatStack::from_pattern(arm.pat);
is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true); is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true);
if !arm.has_guard { if !arm.has_guard {

View file

@ -634,6 +634,7 @@ pub(super) fn thir_abstract_const<'tcx>(
} }
} }
#[instrument(skip(tcx), level = "debug")]
pub(super) fn try_unify_abstract_consts<'tcx>( pub(super) fn try_unify_abstract_consts<'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
(a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>), (a, b): (ty::Unevaluated<'tcx, ()>, ty::Unevaluated<'tcx, ()>),

View file

@ -40,10 +40,8 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0,
None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?, None => miri_to_const(ty.numeric_max_val(cx.tcx)?)?,
}; };
let lhs_val = lhs_const.int_value(cx, ty)?; let lhs_val = lhs_const.int_value(cx, ty)?;
let rhs_val = rhs_const.int_value(cx, ty)?; let rhs_val = rhs_const.int_value(cx, ty)?;
let rhs_bound = match range_end { let rhs_bound = match range_end {
RangeEnd::Included => EndBound::Included(rhs_val), RangeEnd::Included => EndBound::Included(rhs_val),
RangeEnd::Excluded => EndBound::Excluded(rhs_val), RangeEnd::Excluded => EndBound::Excluded(rhs_val),

View file

@ -53,7 +53,7 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply {
fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) {
if_chain! { if_chain! {
if let ExprKind::Lit(ref l) = lit.kind; if let ExprKind::Lit(ref l) = lit.kind;
if consts::lit_to_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1); if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1);
if cx.typeck_results().expr_ty(exp).is_integral(); if cx.typeck_results().expr_ty(exp).is_integral();
then { then {

View file

@ -179,7 +179,7 @@ impl Constant {
} }
/// Parses a `LitKind` to a `Constant`. /// Parses a `LitKind` to a `Constant`.
pub fn lit_to_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant {
match *lit { match *lit {
LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Str(ref is, _) => Constant::Str(is.to_string()),
LitKind::Byte(b) => Constant::Int(u128::from(b)), LitKind::Byte(b) => Constant::Int(u128::from(b)),
@ -301,7 +301,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
if is_direct_expn_of(e.span, "cfg").is_some() { if is_direct_expn_of(e.span, "cfg").is_some() {
None None
} else { } else {
Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))) Some(lit_to_mir_constant(&lit.node, self.typeck_results.expr_ty_opt(e)))
} }
}, },
ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec), ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec),