mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Rollup merge of #115972 - RalfJung:const-consistency, r=oli-obk
rename mir::Constant -> mir::ConstOperand, mir::ConstKind -> mir::Const Also, be more consistent with the `to/eval_bits` methods... we had some that take a type and some that take a size, and then sometimes the one that takes a type is called `bits_for_ty`. Turns out that `ty::Const`/`mir::ConstKind` carry their type with them, so we don't need to even pass the type to those `eval_bits` functions at all. However this is not properly consistent yet: in `ty` we have most of the methods on `ty::Const`, but in `mir` we have them on `mir::ConstKind`. And indeed those two types are the ones that correspond to each other. So `mir::ConstantKind` should actually be renamed to `mir::Const`. But what to do with `mir::Constant`? It carries around a span, that's really more like a constant operand that appears as a MIR operand... it's more suited for `syntax.rs` than `consts.rs`, but the bigger question is, which name should it get if we want to align the `mir` and `ty` types? `ConstOperand`? `ConstOp`? `Literal`? It's not a literal but it has a field called `literal` so it would at least be consistently wrong-ish... ``@oli-obk`` any ideas?
This commit is contained in:
commit
208f6ed95c
@ -13,7 +13,7 @@ use rustc_index::IndexSlice;
|
|||||||
use rustc_infer::infer::LateBoundRegionConversionTime;
|
use rustc_infer::infer::LateBoundRegionConversionTime;
|
||||||
use rustc_middle::mir::tcx::PlaceTy;
|
use rustc_middle::mir::tcx::PlaceTy;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
AggregateKind, CallSource, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location,
|
AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
|
||||||
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
|
Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator,
|
||||||
TerminatorKind,
|
TerminatorKind,
|
||||||
};
|
};
|
||||||
@ -101,12 +101,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
|||||||
let terminator = self.body[location.block].terminator();
|
let terminator = self.body[location.block].terminator();
|
||||||
debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
|
debug!("add_moved_or_invoked_closure_note: terminator={:?}", terminator);
|
||||||
if let TerminatorKind::Call {
|
if let TerminatorKind::Call {
|
||||||
func: Operand::Constant(box Constant { literal, .. }),
|
func: Operand::Constant(box ConstOperand { const_, .. }),
|
||||||
args,
|
args,
|
||||||
..
|
..
|
||||||
} = &terminator.kind
|
} = &terminator.kind
|
||||||
{
|
{
|
||||||
if let ty::FnDef(id, _) = *literal.ty().kind() {
|
if let ty::FnDef(id, _) = *const_.ty().kind() {
|
||||||
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
|
debug!("add_moved_or_invoked_closure_note: id={:?}", id);
|
||||||
if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
|
if Some(self.infcx.tcx.parent(id)) == self.infcx.tcx.lang_items().fn_once_trait() {
|
||||||
let closure = match args.first() {
|
let closure = match args.first() {
|
||||||
|
@ -4,8 +4,7 @@ use crate::BorrowckInferCtxt;
|
|||||||
use rustc_index::IndexSlice;
|
use rustc_index::IndexSlice;
|
||||||
use rustc_infer::infer::NllRegionVariableOrigin;
|
use rustc_infer::infer::NllRegionVariableOrigin;
|
||||||
use rustc_middle::mir::visit::{MutVisitor, TyContext};
|
use rustc_middle::mir::visit::{MutVisitor, TyContext};
|
||||||
use rustc_middle::mir::Constant;
|
use rustc_middle::mir::{Body, ConstOperand, Location, Promoted};
|
||||||
use rustc_middle::mir::{Body, Location, Promoted};
|
|
||||||
use rustc_middle::ty::GenericArgsRef;
|
use rustc_middle::ty::GenericArgsRef;
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable};
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
@ -117,9 +116,9 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
|
fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, location: Location) {
|
||||||
let literal = constant.literal;
|
let const_ = constant.const_;
|
||||||
constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location));
|
constant.const_ = self.renumber_regions(const_, || RegionCtxt::Location(location));
|
||||||
debug!("constant: {:#?}", constant);
|
debug!("constant: {:#?}", constant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -302,11 +302,11 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||||||
self.sanitize_place(place, location, context);
|
self.sanitize_place(place, location, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
|
fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) {
|
||||||
debug!(?constant, ?location, "visit_constant");
|
debug!(?constant, ?location, "visit_constant");
|
||||||
|
|
||||||
self.super_constant(constant, location);
|
self.super_constant(constant, location);
|
||||||
let ty = self.sanitize_type(constant, constant.literal.ty());
|
let ty = self.sanitize_type(constant, constant.const_.ty());
|
||||||
|
|
||||||
self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| {
|
self.cx.infcx.tcx.for_each_free_region(&ty, |live_region| {
|
||||||
let live_region_vid =
|
let live_region_vid =
|
||||||
@ -328,7 +328,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||||||
|
|
||||||
if let Some(annotation_index) = constant.user_ty {
|
if let Some(annotation_index) = constant.user_ty {
|
||||||
if let Err(terr) = self.cx.relate_type_and_user_type(
|
if let Err(terr) = self.cx.relate_type_and_user_type(
|
||||||
constant.literal.ty(),
|
constant.const_.ty(),
|
||||||
ty::Variance::Invariant,
|
ty::Variance::Invariant,
|
||||||
&UserTypeProjection { base: annotation_index, projs: vec![] },
|
&UserTypeProjection { base: annotation_index, projs: vec![] },
|
||||||
locations,
|
locations,
|
||||||
@ -340,20 +340,20 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||||||
constant,
|
constant,
|
||||||
"bad constant user type {:?} vs {:?}: {:?}",
|
"bad constant user type {:?} vs {:?}: {:?}",
|
||||||
annotation,
|
annotation,
|
||||||
constant.literal.ty(),
|
constant.const_.ty(),
|
||||||
terr,
|
terr,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let tcx = self.tcx();
|
let tcx = self.tcx();
|
||||||
let maybe_uneval = match constant.literal {
|
let maybe_uneval = match constant.const_ {
|
||||||
ConstantKind::Ty(ct) => match ct.kind() {
|
Const::Ty(ct) => match ct.kind() {
|
||||||
ty::ConstKind::Unevaluated(_) => {
|
ty::ConstKind::Unevaluated(_) => {
|
||||||
bug!("should not encounter unevaluated ConstantKind::Ty here, got {:?}", ct)
|
bug!("should not encounter unevaluated Const::Ty here, got {:?}", ct)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
ConstantKind::Unevaluated(uv, _) => Some(uv),
|
Const::Unevaluated(uv, _) => Some(uv),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -384,7 +384,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||||||
check_err(self, promoted_body, ty, promoted_ty);
|
check_err(self, promoted_body, ty, promoted_ty);
|
||||||
} else {
|
} else {
|
||||||
self.cx.ascribe_user_type(
|
self.cx.ascribe_user_type(
|
||||||
constant.literal.ty(),
|
constant.const_.ty(),
|
||||||
UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }),
|
UserType::TypeOf(uv.def, UserArgs { args: uv.args, user_self_ty: None }),
|
||||||
locations.span(&self.cx.body),
|
locations.span(&self.cx.body),
|
||||||
);
|
);
|
||||||
@ -392,7 +392,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||||||
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
|
} else if let Some(static_def_id) = constant.check_static_ptr(tcx) {
|
||||||
let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity();
|
let unnormalized_ty = tcx.type_of(static_def_id).instantiate_identity();
|
||||||
let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
|
let normalized_ty = self.cx.normalize(unnormalized_ty, locations);
|
||||||
let literal_ty = constant.literal.ty().builtin_deref(true).unwrap().ty;
|
let literal_ty = constant.const_.ty().builtin_deref(true).unwrap().ty;
|
||||||
|
|
||||||
if let Err(terr) = self.cx.eq_types(
|
if let Err(terr) = self.cx.eq_types(
|
||||||
literal_ty,
|
literal_ty,
|
||||||
@ -404,7 +404,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ty::FnDef(def_id, args) = *constant.literal.ty().kind() {
|
if let ty::FnDef(def_id, args) = *constant.const_.ty().kind() {
|
||||||
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args);
|
let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, args);
|
||||||
self.cx.normalize_and_prove_instantiated_predicates(
|
self.cx.normalize_and_prove_instantiated_predicates(
|
||||||
def_id,
|
def_id,
|
||||||
@ -1801,9 +1801,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
|||||||
debug!(?op, ?location, "check_operand");
|
debug!(?op, ?location, "check_operand");
|
||||||
|
|
||||||
if let Operand::Constant(constant) = op {
|
if let Operand::Constant(constant) = op {
|
||||||
let maybe_uneval = match constant.literal {
|
let maybe_uneval = match constant.const_ {
|
||||||
ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
|
Const::Val(..) | Const::Ty(_) => None,
|
||||||
ConstantKind::Unevaluated(uv, _) => Some(uv),
|
Const::Unevaluated(uv, _) => Some(uv),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(uv) = maybe_uneval {
|
if let Some(uv) = maybe_uneval {
|
||||||
|
@ -64,9 +64,9 @@ pub(crate) fn codegen_tls_ref<'tcx>(
|
|||||||
|
|
||||||
pub(crate) fn eval_mir_constant<'tcx>(
|
pub(crate) fn eval_mir_constant<'tcx>(
|
||||||
fx: &FunctionCx<'_, '_, 'tcx>,
|
fx: &FunctionCx<'_, '_, 'tcx>,
|
||||||
constant: &Constant<'tcx>,
|
constant: &ConstOperand<'tcx>,
|
||||||
) -> (ConstValue<'tcx>, Ty<'tcx>) {
|
) -> (ConstValue<'tcx>, Ty<'tcx>) {
|
||||||
let cv = fx.monomorphize(constant.literal);
|
let cv = fx.monomorphize(constant.const_);
|
||||||
// This cannot fail because we checked all required_consts in advance.
|
// This cannot fail because we checked all required_consts in advance.
|
||||||
let val = cv
|
let val = cv
|
||||||
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
|
.eval(fx.tcx, ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||||
@ -76,7 +76,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
|
|||||||
|
|
||||||
pub(crate) fn codegen_constant_operand<'tcx>(
|
pub(crate) fn codegen_constant_operand<'tcx>(
|
||||||
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
fx: &mut FunctionCx<'_, '_, 'tcx>,
|
||||||
constant: &Constant<'tcx>,
|
constant: &ConstOperand<'tcx>,
|
||||||
) -> CValue<'tcx> {
|
) -> CValue<'tcx> {
|
||||||
let (const_val, ty) = eval_mir_constant(fx, constant);
|
let (const_val, ty) = eval_mir_constant(fx, constant);
|
||||||
codegen_const_value(fx, const_val, ty)
|
codegen_const_value(fx, const_val, ty)
|
||||||
|
@ -252,8 +252,8 @@ pub(crate) fn codegen_inline_asm<'tcx>(
|
|||||||
CInlineAsmOperand::Const { value }
|
CInlineAsmOperand::Const { value }
|
||||||
}
|
}
|
||||||
InlineAsmOperand::SymFn { ref value } => {
|
InlineAsmOperand::SymFn { ref value } => {
|
||||||
let literal = fx.monomorphize(value.literal);
|
let const_ = fx.monomorphize(value.const_);
|
||||||
if let ty::FnDef(def_id, args) = *literal.ty().kind() {
|
if let ty::FnDef(def_id, args) = *const_.ty().kind() {
|
||||||
let instance = ty::Instance::resolve_for_fn_ptr(
|
let instance = ty::Instance::resolve_for_fn_ptr(
|
||||||
fx.tcx,
|
fx.tcx,
|
||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
|
@ -660,12 +660,12 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
|
|||||||
}
|
}
|
||||||
_ => match ct.ty().kind() {
|
_ => match ct.ty().kind() {
|
||||||
ty::Int(ity) => {
|
ty::Int(ity) => {
|
||||||
let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
|
let bits = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||||
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
||||||
write!(output, "{val}")
|
write!(output, "{val}")
|
||||||
}
|
}
|
||||||
ty::Uint(_) => {
|
ty::Uint(_) => {
|
||||||
let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all(), ct.ty());
|
let val = ct.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||||
write!(output, "{val}")
|
write!(output, "{val}")
|
||||||
}
|
}
|
||||||
ty::Bool => {
|
ty::Bool => {
|
||||||
|
@ -1098,8 +1098,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
InlineAsmOperandRef::Const { string }
|
InlineAsmOperandRef::Const { string }
|
||||||
}
|
}
|
||||||
mir::InlineAsmOperand::SymFn { ref value } => {
|
mir::InlineAsmOperand::SymFn { ref value } => {
|
||||||
let literal = self.monomorphize(value.literal);
|
let const_ = self.monomorphize(value.const_);
|
||||||
if let ty::FnDef(def_id, args) = *literal.ty().kind() {
|
if let ty::FnDef(def_id, args) = *const_.ty().kind() {
|
||||||
let instance = ty::Instance::resolve_for_fn_ptr(
|
let instance = ty::Instance::resolve_for_fn_ptr(
|
||||||
bx.tcx(),
|
bx.tcx(),
|
||||||
ty::ParamEnv::reveal_all(),
|
ty::ParamEnv::reveal_all(),
|
||||||
|
@ -13,37 +13,37 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
pub fn eval_mir_constant_to_operand(
|
pub fn eval_mir_constant_to_operand(
|
||||||
&self,
|
&self,
|
||||||
bx: &mut Bx,
|
bx: &mut Bx,
|
||||||
constant: &mir::Constant<'tcx>,
|
constant: &mir::ConstOperand<'tcx>,
|
||||||
) -> OperandRef<'tcx, Bx::Value> {
|
) -> OperandRef<'tcx, Bx::Value> {
|
||||||
let val = self.eval_mir_constant(constant);
|
let val = self.eval_mir_constant(constant);
|
||||||
let ty = self.monomorphize(constant.ty());
|
let ty = self.monomorphize(constant.ty());
|
||||||
OperandRef::from_const(bx, val, ty)
|
OperandRef::from_const(bx, val, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_mir_constant(&self, constant: &mir::Constant<'tcx>) -> mir::ConstValue<'tcx> {
|
pub fn eval_mir_constant(&self, constant: &mir::ConstOperand<'tcx>) -> mir::ConstValue<'tcx> {
|
||||||
self.monomorphize(constant.literal)
|
self.monomorphize(constant.const_)
|
||||||
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
|
.eval(self.cx.tcx(), ty::ParamEnv::reveal_all(), Some(constant.span))
|
||||||
.expect("erroneous constant not captured by required_consts")
|
.expect("erroneous constant not captured by required_consts")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
|
/// This is a convenience helper for `simd_shuffle_indices`. It has the precondition
|
||||||
/// that the given `constant` is an `ConstantKind::Unevaluated` and must be convertible to
|
/// that the given `constant` is an `Const::Unevaluated` and must be convertible to
|
||||||
/// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
|
/// a `ValTree`. If you want a more general version of this, talk to `wg-const-eval` on zulip.
|
||||||
///
|
///
|
||||||
/// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees!
|
/// Note that this function is cursed, since usually MIR consts should not be evaluated to valtrees!
|
||||||
pub fn eval_unevaluated_mir_constant_to_valtree(
|
pub fn eval_unevaluated_mir_constant_to_valtree(
|
||||||
&self,
|
&self,
|
||||||
constant: &mir::Constant<'tcx>,
|
constant: &mir::ConstOperand<'tcx>,
|
||||||
) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> {
|
) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> {
|
||||||
let uv = match self.monomorphize(constant.literal) {
|
let uv = match self.monomorphize(constant.const_) {
|
||||||
mir::ConstantKind::Unevaluated(uv, _) => uv.shrink(),
|
mir::Const::Unevaluated(uv, _) => uv.shrink(),
|
||||||
mir::ConstantKind::Ty(c) => match c.kind() {
|
mir::Const::Ty(c) => match c.kind() {
|
||||||
// A constant that came from a const generic but was then used as an argument to old-style
|
// A constant that came from a const generic but was then used as an argument to old-style
|
||||||
// simd_shuffle (passing as argument instead of as a generic param).
|
// simd_shuffle (passing as argument instead of as a generic param).
|
||||||
rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)),
|
rustc_type_ir::ConstKind::Value(valtree) => return Ok(Some(valtree)),
|
||||||
other => span_bug!(constant.span, "{other:#?}"),
|
other => span_bug!(constant.span, "{other:#?}"),
|
||||||
},
|
},
|
||||||
// We should never encounter `ConstantKind::Val` unless MIR opts (like const prop) evaluate
|
// We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
|
||||||
// a constant and write that value back into `Operand`s. This could happen, but is unlikely.
|
// a constant and write that value back into `Operand`s. This could happen, but is unlikely.
|
||||||
// Also: all users of `simd_shuffle` are on unstable and already need to take a lot of care
|
// Also: all users of `simd_shuffle` are on unstable and already need to take a lot of care
|
||||||
// around intrinsics. For an issue to happen here, it would require a macro expanding to a
|
// around intrinsics. For an issue to happen here, it would require a macro expanding to a
|
||||||
@ -65,7 +65,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
pub fn simd_shuffle_indices(
|
pub fn simd_shuffle_indices(
|
||||||
&mut self,
|
&mut self,
|
||||||
bx: &Bx,
|
bx: &Bx,
|
||||||
constant: &mir::Constant<'tcx>,
|
constant: &mir::ConstOperand<'tcx>,
|
||||||
) -> (Bx::Value, Ty<'tcx>) {
|
) -> (Bx::Value, Ty<'tcx>) {
|
||||||
let ty = self.monomorphize(constant.ty());
|
let ty = self.monomorphize(constant.ty());
|
||||||
let val = self
|
let val = self
|
||||||
|
@ -1089,7 +1089,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
|
|
||||||
pub fn eval_mir_constant(
|
pub fn eval_mir_constant(
|
||||||
&self,
|
&self,
|
||||||
val: &mir::ConstantKind<'tcx>,
|
val: &mir::Const<'tcx>,
|
||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
layout: Option<TyAndLayout<'tcx>>,
|
layout: Option<TyAndLayout<'tcx>>,
|
||||||
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
) -> InterpResult<'tcx, OpTy<'tcx, M::Provenance>> {
|
||||||
|
@ -692,7 +692,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
|||||||
|
|
||||||
Constant(constant) => {
|
Constant(constant) => {
|
||||||
let c =
|
let c =
|
||||||
self.subst_from_current_frame_and_normalize_erasing_regions(constant.literal)?;
|
self.subst_from_current_frame_and_normalize_erasing_regions(constant.const_)?;
|
||||||
|
|
||||||
// This can still fail:
|
// This can still fail:
|
||||||
// * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
|
// * During ConstProp, with `TooGeneric` or since the `required_consts` were not all
|
||||||
|
@ -346,8 +346,8 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check the qualifs of the value of `const` items.
|
// Check the qualifs of the value of `const` items.
|
||||||
let uneval = match constant.literal {
|
let uneval = match constant.const_ {
|
||||||
ConstantKind::Ty(ct)
|
Const::Ty(ct)
|
||||||
if matches!(
|
if matches!(
|
||||||
ct.kind(),
|
ct.kind(),
|
||||||
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
|
ty::ConstKind::Param(_) | ty::ConstKind::Error(_) | ty::ConstKind::Value(_)
|
||||||
@ -355,11 +355,11 @@ where
|
|||||||
{
|
{
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
ConstantKind::Ty(c) => {
|
Const::Ty(c) => {
|
||||||
bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c)
|
bug!("expected ConstKind::Param or ConstKind::Value here, found {:?}", c)
|
||||||
}
|
}
|
||||||
ConstantKind::Unevaluated(uv, _) => Some(uv),
|
Const::Unevaluated(uv, _) => Some(uv),
|
||||||
ConstantKind::Val(..) => None,
|
Const::Val(..) => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(mir::UnevaluatedConst { def, args: _, promoted }) = uneval {
|
if let Some(mir::UnevaluatedConst { def, args: _, promoted }) = uneval {
|
||||||
@ -383,5 +383,5 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise use the qualifs of the type.
|
// Otherwise use the qualifs of the type.
|
||||||
Q::in_any_value_of_ty(cx, constant.literal.ty())
|
Q::in_any_value_of_ty(cx, constant.const_.ty())
|
||||||
}
|
}
|
||||||
|
@ -372,7 +372,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||||||
StatementKind::Assign(box (
|
StatementKind::Assign(box (
|
||||||
_,
|
_,
|
||||||
Rvalue::Use(Operand::Constant(c)),
|
Rvalue::Use(Operand::Constant(c)),
|
||||||
)) => c.literal.try_eval_target_usize(self.tcx, self.param_env),
|
)) => c.const_.try_eval_target_usize(self.tcx, self.param_env),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -554,7 +554,7 @@ impl<'tcx> Validator<'_, 'tcx> {
|
|||||||
// Integer division: the RHS must be a non-zero const.
|
// Integer division: the RHS must be a non-zero const.
|
||||||
let const_val = match rhs {
|
let const_val = match rhs {
|
||||||
Operand::Constant(c) => {
|
Operand::Constant(c) => {
|
||||||
c.literal.try_eval_bits(self.tcx, self.param_env, lhs_ty)
|
c.const_.try_eval_bits(self.tcx, self.param_env)
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
@ -766,10 +766,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||||||
if self.keep_original {
|
if self.keep_original {
|
||||||
rhs.clone()
|
rhs.clone()
|
||||||
} else {
|
} else {
|
||||||
let unit = Rvalue::Use(Operand::Constant(Box::new(Constant {
|
let unit = Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||||
span: statement.source_info.span,
|
span: statement.source_info.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::zero_sized(self.tcx.types.unit),
|
const_: Const::zero_sized(self.tcx.types.unit),
|
||||||
})));
|
})));
|
||||||
mem::replace(rhs, unit)
|
mem::replace(rhs, unit)
|
||||||
},
|
},
|
||||||
@ -844,10 +844,10 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
|
|||||||
let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def));
|
let args = tcx.erase_regions(GenericArgs::identity_for_item(tcx, def));
|
||||||
let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) };
|
let uneval = mir::UnevaluatedConst { def, args, promoted: Some(promoted_id) };
|
||||||
|
|
||||||
Operand::Constant(Box::new(Constant {
|
Operand::Constant(Box::new(ConstOperand {
|
||||||
span,
|
span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::Unevaluated(uneval, ty),
|
const_: Const::Unevaluated(uneval, ty),
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1041,8 +1041,8 @@ pub fn is_const_fn_in_array_repeat_expression<'tcx>(
|
|||||||
if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) =
|
if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) =
|
||||||
&block.terminator
|
&block.terminator
|
||||||
{
|
{
|
||||||
if let Operand::Constant(box Constant { literal, .. }) = func {
|
if let Operand::Constant(box ConstOperand { const_, .. }) = func {
|
||||||
if let ty::FnDef(def_id, _) = *literal.ty().kind() {
|
if let ty::FnDef(def_id, _) = *const_.ty().kind() {
|
||||||
if destination == place {
|
if destination == place {
|
||||||
if ccx.tcx.is_const_fn(def_id) {
|
if ccx.tcx.is_const_fn(def_id) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -6,13 +6,11 @@ use rustc_hir::{self as hir};
|
|||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::abi::{HasDataLayout, Size};
|
use rustc_target::abi::{HasDataLayout, Size};
|
||||||
|
|
||||||
use crate::mir::interpret::{
|
use crate::mir::interpret::{alloc_range, AllocId, ConstAllocation, ErrorHandled, Scalar};
|
||||||
alloc_range, AllocId, ConstAllocation, ErrorHandled, GlobalAlloc, Scalar,
|
|
||||||
};
|
|
||||||
use crate::mir::{pretty_print_const_value, Promoted};
|
use crate::mir::{pretty_print_const_value, Promoted};
|
||||||
|
use crate::ty::ScalarInt;
|
||||||
use crate::ty::{self, print::pretty_print_const, List, Ty, TyCtxt};
|
use crate::ty::{self, print::pretty_print_const, List, Ty, TyCtxt};
|
||||||
use crate::ty::{GenericArgs, GenericArgsRef};
|
use crate::ty::{GenericArgs, GenericArgsRef};
|
||||||
use crate::ty::{ScalarInt, UserTypeAnnotationIndex};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// Evaluated Constants
|
/// Evaluated Constants
|
||||||
@ -178,29 +176,10 @@ impl<'tcx> ConstValue<'tcx> {
|
|||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// Constants
|
/// Constants
|
||||||
///
|
|
||||||
/// Two constants are equal if they are the same constant. Note that
|
|
||||||
/// this does not necessarily mean that they are `==` in Rust. In
|
|
||||||
/// particular, one must be wary of `NaN`!
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
|
|
||||||
#[derive(TypeFoldable, TypeVisitable)]
|
|
||||||
pub struct Constant<'tcx> {
|
|
||||||
pub span: Span,
|
|
||||||
|
|
||||||
/// Optional user-given type: for something like
|
|
||||||
/// `collect::<Vec<_>>`, this would be present and would
|
|
||||||
/// indicate that `Vec<_>` was explicitly specified.
|
|
||||||
///
|
|
||||||
/// Needed for NLL to impose user-given type constraints.
|
|
||||||
pub user_ty: Option<UserTypeAnnotationIndex>,
|
|
||||||
|
|
||||||
pub literal: ConstantKind<'tcx>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable, Debug)]
|
||||||
#[derive(TypeFoldable, TypeVisitable)]
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
pub enum ConstantKind<'tcx> {
|
pub enum Const<'tcx> {
|
||||||
/// This constant came from the type system.
|
/// This constant came from the type system.
|
||||||
///
|
///
|
||||||
/// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`;
|
/// Any way of turning `ty::Const` into `ConstValue` should go through `valtree_to_const_val`;
|
||||||
@ -221,46 +200,27 @@ pub enum ConstantKind<'tcx> {
|
|||||||
Val(ConstValue<'tcx>, Ty<'tcx>),
|
Val(ConstValue<'tcx>, Ty<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Constant<'tcx> {
|
impl<'tcx> Const<'tcx> {
|
||||||
pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
|
|
||||||
match self.literal.try_to_scalar() {
|
|
||||||
Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
|
|
||||||
GlobalAlloc::Static(def_id) => {
|
|
||||||
assert!(!tcx.is_thread_local_static(def_id));
|
|
||||||
Some(def_id)
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
},
|
|
||||||
_ => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn ty(&self) -> Ty<'tcx> {
|
|
||||||
self.literal.ty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> ConstantKind<'tcx> {
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn ty(&self) -> Ty<'tcx> {
|
pub fn ty(&self) -> Ty<'tcx> {
|
||||||
match self {
|
match self {
|
||||||
ConstantKind::Ty(c) => c.ty(),
|
Const::Ty(c) => c.ty(),
|
||||||
ConstantKind::Val(_, ty) | ConstantKind::Unevaluated(_, ty) => *ty,
|
Const::Val(_, ty) | Const::Unevaluated(_, ty) => *ty,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn try_to_scalar(self) -> Option<Scalar> {
|
pub fn try_to_scalar(self) -> Option<Scalar> {
|
||||||
match self {
|
match self {
|
||||||
ConstantKind::Ty(c) => match c.kind() {
|
Const::Ty(c) => match c.kind() {
|
||||||
ty::ConstKind::Value(valtree) => match valtree {
|
ty::ConstKind::Value(valtree) => match valtree {
|
||||||
ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)),
|
ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)),
|
||||||
ty::ValTree::Branch(_) => None,
|
ty::ValTree::Branch(_) => None,
|
||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
ConstantKind::Val(val, _) => val.try_to_scalar(),
|
Const::Val(val, _) => val.try_to_scalar(),
|
||||||
ConstantKind::Unevaluated(..) => None,
|
Const::Unevaluated(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,17 +247,17 @@ impl<'tcx> ConstantKind<'tcx> {
|
|||||||
span: Option<Span>,
|
span: Option<Span>,
|
||||||
) -> Result<ConstValue<'tcx>, ErrorHandled> {
|
) -> Result<ConstValue<'tcx>, ErrorHandled> {
|
||||||
match self {
|
match self {
|
||||||
ConstantKind::Ty(c) => {
|
Const::Ty(c) => {
|
||||||
// We want to consistently have a "clean" value for type system constants (i.e., no
|
// We want to consistently have a "clean" value for type system constants (i.e., no
|
||||||
// data hidden in the padding), so we always go through a valtree here.
|
// data hidden in the padding), so we always go through a valtree here.
|
||||||
let val = c.eval(tcx, param_env, span)?;
|
let val = c.eval(tcx, param_env, span)?;
|
||||||
Ok(tcx.valtree_to_const_val((self.ty(), val)))
|
Ok(tcx.valtree_to_const_val((self.ty(), val)))
|
||||||
}
|
}
|
||||||
ConstantKind::Unevaluated(uneval, _) => {
|
Const::Unevaluated(uneval, _) => {
|
||||||
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
|
// FIXME: We might want to have a `try_eval`-like function on `Unevaluated`
|
||||||
tcx.const_eval_resolve(param_env, uneval, span)
|
tcx.const_eval_resolve(param_env, uneval, span)
|
||||||
}
|
}
|
||||||
ConstantKind::Val(val, _) => Ok(val),
|
Const::Val(val, _) => Ok(val),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,23 +292,18 @@ impl<'tcx> ConstantKind<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn try_eval_bits(
|
pub fn try_eval_bits(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Option<u128> {
|
||||||
&self,
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> Option<u128> {
|
|
||||||
let int = self.try_eval_scalar_int(tcx, param_env)?;
|
let int = self.try_eval_scalar_int(tcx, param_env)?;
|
||||||
assert_eq!(self.ty(), ty);
|
let size =
|
||||||
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
|
tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size;
|
||||||
int.to_bits(size).ok()
|
int.to_bits(size).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
|
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
|
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> u128 {
|
||||||
self.try_eval_bits(tcx, param_env, ty)
|
self.try_eval_bits(tcx, param_env)
|
||||||
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
|
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -416,7 +371,7 @@ impl<'tcx> ConstantKind<'tcx> {
|
|||||||
Self::Val(val, ty)
|
Self::Val(val, ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
|
/// Literals are converted to `Const::Val`, const generic parameters are eagerly
|
||||||
/// converted to a constant, everything else becomes `Unevaluated`.
|
/// converted to a constant, everything else becomes `Unevaluated`.
|
||||||
#[instrument(skip(tcx), level = "debug", ret)]
|
#[instrument(skip(tcx), level = "debug", ret)]
|
||||||
pub fn from_anon_const(
|
pub fn from_anon_const(
|
||||||
@ -552,29 +507,13 @@ impl<'tcx> UnevaluatedConst<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Debug for Constant<'tcx> {
|
impl<'tcx> Display for Const<'tcx> {
|
||||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(fmt, "{self}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Display for Constant<'tcx> {
|
|
||||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
|
||||||
match self.ty().kind() {
|
|
||||||
ty::FnDef(..) => {}
|
|
||||||
_ => write!(fmt, "const ")?,
|
|
||||||
}
|
|
||||||
Display::fmt(&self.literal, fmt)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'tcx> Display for ConstantKind<'tcx> {
|
|
||||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
ConstantKind::Ty(c) => pretty_print_const(c, fmt, true),
|
Const::Ty(c) => pretty_print_const(c, fmt, true),
|
||||||
ConstantKind::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
|
Const::Val(val, ty) => pretty_print_const_value(val, ty, fmt),
|
||||||
// FIXME(valtrees): Correctly print mir constants.
|
// FIXME(valtrees): Correctly print mir constants.
|
||||||
ConstantKind::Unevaluated(..) => {
|
Const::Unevaluated(..) => {
|
||||||
fmt.write_str("_")?;
|
fmt.write_str("_")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,7 @@ pub struct Body<'tcx> {
|
|||||||
|
|
||||||
/// Constants that are required to evaluate successfully for this MIR to be well-formed.
|
/// Constants that are required to evaluate successfully for this MIR to be well-formed.
|
||||||
/// We hold in this field all the constants we are not able to evaluate yet.
|
/// We hold in this field all the constants we are not able to evaluate yet.
|
||||||
pub required_consts: Vec<Constant<'tcx>>,
|
pub required_consts: Vec<ConstOperand<'tcx>>,
|
||||||
|
|
||||||
/// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
|
/// Does this body use generic parameters. This is used for the `ConstEvaluatable` check.
|
||||||
///
|
///
|
||||||
@ -585,12 +585,12 @@ impl<'tcx> Body<'tcx> {
|
|||||||
&self,
|
&self,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
normalize_const: impl Fn(ConstantKind<'tcx>) -> Result<ConstantKind<'tcx>, ErrorHandled>,
|
normalize_const: impl Fn(Const<'tcx>) -> Result<Const<'tcx>, ErrorHandled>,
|
||||||
) -> Result<(), ErrorHandled> {
|
) -> Result<(), ErrorHandled> {
|
||||||
// For now, the only thing we have to check is is to ensure that all the constants used in
|
// For now, the only thing we have to check is is to ensure that all the constants used in
|
||||||
// the body successfully evaluate.
|
// the body successfully evaluate.
|
||||||
for &const_ in &self.required_consts {
|
for &const_ in &self.required_consts {
|
||||||
let c = normalize_const(const_.literal)?;
|
let c = normalize_const(const_.const_)?;
|
||||||
c.eval(tcx, param_env, Some(const_.span))?;
|
c.eval(tcx, param_env, Some(const_.span))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1096,7 +1096,7 @@ impl<'tcx> LocalDecl<'tcx> {
|
|||||||
pub enum VarDebugInfoContents<'tcx> {
|
pub enum VarDebugInfoContents<'tcx> {
|
||||||
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
|
/// This `Place` only contains projection which satisfy `can_use_in_debuginfo`.
|
||||||
Place(Place<'tcx>),
|
Place(Place<'tcx>),
|
||||||
Const(Constant<'tcx>),
|
Const(ConstOperand<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
impl<'tcx> Debug for VarDebugInfoContents<'tcx> {
|
||||||
|
@ -696,6 +696,17 @@ impl Debug for Statement<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for NonDivergingIntrinsic<'_> {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Assume(op) => write!(f, "assume({op:?})"),
|
||||||
|
Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
|
||||||
|
write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'tcx> Debug for TerminatorKind<'tcx> {
|
impl<'tcx> Debug for TerminatorKind<'tcx> {
|
||||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
self.fmt_head(fmt)?;
|
self.fmt_head(fmt)?;
|
||||||
@ -1058,6 +1069,22 @@ impl<'tcx> Debug for Operand<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Debug for ConstOperand<'tcx> {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(fmt, "{self}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> Display for ConstOperand<'tcx> {
|
||||||
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
match self.ty().kind() {
|
||||||
|
ty::FnDef(..) => {}
|
||||||
|
_ => write!(fmt, "const ")?,
|
||||||
|
}
|
||||||
|
Display::fmt(&self.const_, fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Debug for Place<'_> {
|
impl Debug for Place<'_> {
|
||||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
self.as_ref().fmt(fmt)
|
self.as_ref().fmt(fmt)
|
||||||
@ -1184,10 +1211,10 @@ fn use_verbose(ty: Ty<'_>, fn_def: bool) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
||||||
fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) {
|
fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _location: Location) {
|
||||||
let Constant { span, user_ty, literal } = constant;
|
let ConstOperand { span, user_ty, const_ } = constant;
|
||||||
if use_verbose(literal.ty(), true) {
|
if use_verbose(const_.ty(), true) {
|
||||||
self.push("mir::Constant");
|
self.push("mir::ConstOperand");
|
||||||
self.push(&format!(
|
self.push(&format!(
|
||||||
"+ span: {}",
|
"+ span: {}",
|
||||||
self.tcx.sess.source_map().span_to_embeddable_string(*span)
|
self.tcx.sess.source_map().span_to_embeddable_string(*span)
|
||||||
@ -1209,8 +1236,8 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
|||||||
ty::ValTree::Branch(_) => "Branch(..)".to_string(),
|
ty::ValTree::Branch(_) => "Branch(..)".to_string(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let val = match literal {
|
let val = match const_ {
|
||||||
ConstantKind::Ty(ct) => match ct.kind() {
|
Const::Ty(ct) => match ct.kind() {
|
||||||
ty::ConstKind::Param(p) => format!("ty::Param({p})"),
|
ty::ConstKind::Param(p) => format!("ty::Param({p})"),
|
||||||
ty::ConstKind::Unevaluated(uv) => {
|
ty::ConstKind::Unevaluated(uv) => {
|
||||||
format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
|
format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,)
|
||||||
@ -1222,9 +1249,9 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
|||||||
ty::ConstKind::Placeholder(_)
|
ty::ConstKind::Placeholder(_)
|
||||||
| ty::ConstKind::Infer(_)
|
| ty::ConstKind::Infer(_)
|
||||||
| ty::ConstKind::Expr(_)
|
| ty::ConstKind::Expr(_)
|
||||||
| ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", literal),
|
| ty::ConstKind::Bound(..) => bug!("unexpected MIR constant: {:?}", const_),
|
||||||
},
|
},
|
||||||
ConstantKind::Unevaluated(uv, _) => {
|
Const::Unevaluated(uv, _) => {
|
||||||
format!(
|
format!(
|
||||||
"Unevaluated({}, {:?}, {:?})",
|
"Unevaluated({}, {:?}, {:?})",
|
||||||
self.tcx.def_path_str(uv.def),
|
self.tcx.def_path_str(uv.def),
|
||||||
@ -1232,13 +1259,13 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
|
|||||||
uv.promoted,
|
uv.promoted,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
ConstantKind::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)),
|
Const::Val(val, ty) => format!("Value({})", fmt_val(*val, *ty)),
|
||||||
};
|
};
|
||||||
|
|
||||||
// This reflects what `Const` looked liked before `val` was renamed
|
// This reflects what `Const` looked liked before `val` was renamed
|
||||||
// as `kind`. We print it like this to avoid having to update
|
// as `kind`. We print it like this to avoid having to update
|
||||||
// expected output in a lot of tests.
|
// expected output in a lot of tests.
|
||||||
self.push(&format!("+ literal: Const {{ ty: {}, val: {} }}", literal.ty(), val));
|
self.push(&format!("+ const_: Const {{ ty: {}, val: {} }}", const_.ty(), val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1312,10 +1339,10 @@ pub fn write_allocations<'tcx>(
|
|||||||
struct CollectAllocIds(BTreeSet<AllocId>);
|
struct CollectAllocIds(BTreeSet<AllocId>);
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for CollectAllocIds {
|
impl<'tcx> Visitor<'tcx> for CollectAllocIds {
|
||||||
fn visit_constant(&mut self, c: &Constant<'tcx>, _: Location) {
|
fn visit_constant(&mut self, c: &ConstOperand<'tcx>, _: Location) {
|
||||||
match c.literal {
|
match c.const_ {
|
||||||
ConstantKind::Ty(_) | ConstantKind::Unevaluated(..) => {}
|
Const::Ty(_) | Const::Unevaluated(..) => {}
|
||||||
ConstantKind::Val(val, _) => {
|
Const::Val(val, _) => {
|
||||||
self.0.extend(alloc_ids_from_const_val(val));
|
self.0.extend(alloc_ids_from_const_val(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/// Functionality for statements, operands, places, and things that appear in them.
|
/// Functionality for statements, operands, places, and things that appear in them.
|
||||||
use super::*;
|
use super::{interpret::GlobalAlloc, *};
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
// Statements
|
// Statements
|
||||||
@ -302,10 +302,10 @@ impl<'tcx> Operand<'tcx> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let ty = Ty::new_fn_def(tcx, def_id, args);
|
let ty = Ty::new_fn_def(tcx, def_id, args);
|
||||||
Operand::Constant(Box::new(Constant {
|
Operand::Constant(Box::new(ConstOperand {
|
||||||
span,
|
span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
|
const_: Const::Val(ConstValue::ZeroSized, ty),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -333,10 +333,10 @@ impl<'tcx> Operand<'tcx> {
|
|||||||
};
|
};
|
||||||
scalar_size == type_size
|
scalar_size == type_size
|
||||||
});
|
});
|
||||||
Operand::Constant(Box::new(Constant {
|
Operand::Constant(Box::new(ConstOperand {
|
||||||
span,
|
span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::Val(ConstValue::Scalar(val), ty),
|
const_: Const::Val(ConstValue::Scalar(val), ty),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -356,9 +356,9 @@ impl<'tcx> Operand<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a
|
/// Returns the `ConstOperand` that is the target of this `Operand`, or `None` if this `Operand` is a
|
||||||
/// place.
|
/// place.
|
||||||
pub fn constant(&self) -> Option<&Constant<'tcx>> {
|
pub fn constant(&self) -> Option<&ConstOperand<'tcx>> {
|
||||||
match self {
|
match self {
|
||||||
Operand::Constant(x) => Some(&**x),
|
Operand::Constant(x) => Some(&**x),
|
||||||
Operand::Copy(_) | Operand::Move(_) => None,
|
Operand::Copy(_) | Operand::Move(_) => None,
|
||||||
@ -370,11 +370,31 @@ impl<'tcx> Operand<'tcx> {
|
|||||||
/// While this is unlikely in general, it's the normal case of what you'll
|
/// While this is unlikely in general, it's the normal case of what you'll
|
||||||
/// find as the `func` in a [`TerminatorKind::Call`].
|
/// find as the `func` in a [`TerminatorKind::Call`].
|
||||||
pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> {
|
pub fn const_fn_def(&self) -> Option<(DefId, GenericArgsRef<'tcx>)> {
|
||||||
let const_ty = self.constant()?.literal.ty();
|
let const_ty = self.constant()?.const_.ty();
|
||||||
if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
|
if let ty::FnDef(def_id, args) = *const_ty.kind() { Some((def_id, args)) } else { None }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'tcx> ConstOperand<'tcx> {
|
||||||
|
pub fn check_static_ptr(&self, tcx: TyCtxt<'_>) -> Option<DefId> {
|
||||||
|
match self.const_.try_to_scalar() {
|
||||||
|
Some(Scalar::Ptr(ptr, _size)) => match tcx.global_alloc(ptr.provenance) {
|
||||||
|
GlobalAlloc::Static(def_id) => {
|
||||||
|
assert!(!tcx.is_thread_local_static(def_id));
|
||||||
|
Some(def_id)
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
},
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub fn ty(&self) -> Ty<'tcx> {
|
||||||
|
self.const_.ty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
/// Rvalues
|
/// Rvalues
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
//! This is in a dedicated file so that changes to this file can be reviewed more carefully.
|
//! This is in a dedicated file so that changes to this file can be reviewed more carefully.
|
||||||
//! The intention is that this file only contains datatype declarations, no code.
|
//! The intention is that this file only contains datatype declarations, no code.
|
||||||
|
|
||||||
use super::{BasicBlock, Constant, Local, UserTypeProjection};
|
use super::{BasicBlock, Const, Local, UserTypeProjection};
|
||||||
|
|
||||||
use crate::mir::coverage::{CodeRegion, CoverageKind};
|
use crate::mir::coverage::{CodeRegion, CoverageKind};
|
||||||
use crate::traits::Reveal;
|
use crate::traits::Reveal;
|
||||||
@ -439,17 +439,6 @@ pub enum NonDivergingIntrinsic<'tcx> {
|
|||||||
CopyNonOverlapping(CopyNonOverlapping<'tcx>),
|
CopyNonOverlapping(CopyNonOverlapping<'tcx>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for NonDivergingIntrinsic<'_> {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
Self::Assume(op) => write!(f, "assume({op:?})"),
|
|
||||||
Self::CopyNonOverlapping(CopyNonOverlapping { src, dst, count }) => {
|
|
||||||
write!(f, "copy_nonoverlapping(dst = {dst:?}, src = {src:?}, count = {count:?})")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Describes what kind of retag is to be performed.
|
/// Describes what kind of retag is to be performed.
|
||||||
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
|
#[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, Hash, HashStable)]
|
||||||
#[rustc_pass_by_value]
|
#[rustc_pass_by_value]
|
||||||
@ -913,10 +902,10 @@ pub enum InlineAsmOperand<'tcx> {
|
|||||||
out_place: Option<Place<'tcx>>,
|
out_place: Option<Place<'tcx>>,
|
||||||
},
|
},
|
||||||
Const {
|
Const {
|
||||||
value: Box<Constant<'tcx>>,
|
value: Box<ConstOperand<'tcx>>,
|
||||||
},
|
},
|
||||||
SymFn {
|
SymFn {
|
||||||
value: Box<Constant<'tcx>>,
|
value: Box<ConstOperand<'tcx>>,
|
||||||
},
|
},
|
||||||
SymStatic {
|
SymStatic {
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
@ -1136,7 +1125,22 @@ pub enum Operand<'tcx> {
|
|||||||
Move(Place<'tcx>),
|
Move(Place<'tcx>),
|
||||||
|
|
||||||
/// Constants are already semantically values, and remain unchanged.
|
/// Constants are already semantically values, and remain unchanged.
|
||||||
Constant(Box<Constant<'tcx>>),
|
Constant(Box<ConstOperand<'tcx>>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, Hash, HashStable)]
|
||||||
|
#[derive(TypeFoldable, TypeVisitable)]
|
||||||
|
pub struct ConstOperand<'tcx> {
|
||||||
|
pub span: Span,
|
||||||
|
|
||||||
|
/// Optional user-given type: for something like
|
||||||
|
/// `collect::<Vec<_>>`, this would be present and would
|
||||||
|
/// indicate that `Vec<_>` was explicitly specified.
|
||||||
|
///
|
||||||
|
/// Needed for NLL to impose user-given type constraints.
|
||||||
|
pub user_ty: Option<UserTypeAnnotationIndex>,
|
||||||
|
|
||||||
|
pub const_: Const<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -227,7 +227,7 @@ impl<'tcx> Operand<'tcx> {
|
|||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
&Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
|
&Operand::Copy(ref l) | &Operand::Move(ref l) => l.ty(local_decls, tcx).ty,
|
||||||
Operand::Constant(c) => c.literal.ty(),
|
Operand::Constant(c) => c.const_.ty(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -186,7 +186,7 @@ macro_rules! make_mir_visitor {
|
|||||||
|
|
||||||
fn visit_constant(
|
fn visit_constant(
|
||||||
&mut self,
|
&mut self,
|
||||||
constant: & $($mutability)? Constant<'tcx>,
|
constant: & $($mutability)? ConstOperand<'tcx>,
|
||||||
location: Location,
|
location: Location,
|
||||||
) {
|
) {
|
||||||
self.super_constant(constant, location);
|
self.super_constant(constant, location);
|
||||||
@ -870,20 +870,20 @@ macro_rules! make_mir_visitor {
|
|||||||
|
|
||||||
fn super_constant(
|
fn super_constant(
|
||||||
&mut self,
|
&mut self,
|
||||||
constant: & $($mutability)? Constant<'tcx>,
|
constant: & $($mutability)? ConstOperand<'tcx>,
|
||||||
location: Location
|
location: Location
|
||||||
) {
|
) {
|
||||||
let Constant {
|
let ConstOperand {
|
||||||
span,
|
span,
|
||||||
user_ty: _, // no visit method for this
|
user_ty: _, // no visit method for this
|
||||||
literal,
|
const_,
|
||||||
} = constant;
|
} = constant;
|
||||||
|
|
||||||
self.visit_span($(& $mutability)? *span);
|
self.visit_span($(& $mutability)? *span);
|
||||||
match literal {
|
match const_ {
|
||||||
ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location),
|
Const::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location),
|
||||||
ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
|
Const::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
|
||||||
ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
|
Const::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,9 +116,8 @@ impl EraseType for Result<ty::Const<'_>, mir::interpret::LitToConstError> {
|
|||||||
type Result = [u8; size_of::<Result<ty::Const<'static>, mir::interpret::LitToConstError>>()];
|
type Result = [u8; size_of::<Result<ty::Const<'static>, mir::interpret::LitToConstError>>()];
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EraseType for Result<mir::ConstantKind<'_>, mir::interpret::LitToConstError> {
|
impl EraseType for Result<mir::Const<'_>, mir::interpret::LitToConstError> {
|
||||||
type Result =
|
type Result = [u8; size_of::<Result<mir::Const<'static>, mir::interpret::LitToConstError>>()];
|
||||||
[u8; size_of::<Result<mir::ConstantKind<'static>, mir::interpret::LitToConstError>>()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
|
impl EraseType for Result<mir::ConstAlloc<'_>, mir::interpret::ErrorHandled> {
|
||||||
@ -311,7 +310,7 @@ macro_rules! tcx_lifetime {
|
|||||||
tcx_lifetime! {
|
tcx_lifetime! {
|
||||||
rustc_middle::hir::Owner,
|
rustc_middle::hir::Owner,
|
||||||
rustc_middle::middle::exported_symbols::ExportedSymbol,
|
rustc_middle::middle::exported_symbols::ExportedSymbol,
|
||||||
rustc_middle::mir::ConstantKind,
|
rustc_middle::mir::Const,
|
||||||
rustc_middle::mir::DestructuredConstant,
|
rustc_middle::mir::DestructuredConstant,
|
||||||
rustc_middle::mir::ConstAlloc,
|
rustc_middle::mir::ConstAlloc,
|
||||||
rustc_middle::mir::ConstValue,
|
rustc_middle::mir::ConstValue,
|
||||||
|
@ -416,7 +416,7 @@ impl<'tcx> Key for GenericArg<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Key for mir::ConstantKind<'tcx> {
|
impl<'tcx> Key for mir::Const<'tcx> {
|
||||||
type CacheSelector = DefaultCacheSelector<Self>;
|
type CacheSelector = DefaultCacheSelector<Self>;
|
||||||
|
|
||||||
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
fn default_span(&self, _: TyCtxt<'_>) -> Span {
|
||||||
|
@ -1101,7 +1101,7 @@ rustc_queries! {
|
|||||||
desc { "destructuring type level constant"}
|
desc { "destructuring type level constant"}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
|
/// Tries to destructure an `mir::Const` ADT or array into its variant index
|
||||||
/// and its field values. This should only be used for pretty printing.
|
/// and its field values. This should only be used for pretty printing.
|
||||||
query try_destructure_mir_constant_for_diagnostics(
|
query try_destructure_mir_constant_for_diagnostics(
|
||||||
key: (mir::ConstValue<'tcx>, Ty<'tcx>)
|
key: (mir::ConstValue<'tcx>, Ty<'tcx>)
|
||||||
|
@ -563,11 +563,11 @@ pub enum InlineAsmOperand<'tcx> {
|
|||||||
out_expr: Option<ExprId>,
|
out_expr: Option<ExprId>,
|
||||||
},
|
},
|
||||||
Const {
|
Const {
|
||||||
value: mir::ConstantKind<'tcx>,
|
value: mir::Const<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
SymFn {
|
SymFn {
|
||||||
value: mir::ConstantKind<'tcx>,
|
value: mir::Const<'tcx>,
|
||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
SymStatic {
|
SymStatic {
|
||||||
@ -739,7 +739,7 @@ pub enum PatKind<'tcx> {
|
|||||||
/// * Opaque constants, that must not be matched structurally. So anything that does not derive
|
/// * Opaque constants, that must not be matched structurally. So anything that does not derive
|
||||||
/// `PartialEq` and `Eq`.
|
/// `PartialEq` and `Eq`.
|
||||||
Constant {
|
Constant {
|
||||||
value: mir::ConstantKind<'tcx>,
|
value: mir::Const<'tcx>,
|
||||||
},
|
},
|
||||||
|
|
||||||
Range(Box<PatRange<'tcx>>),
|
Range(Box<PatRange<'tcx>>),
|
||||||
@ -769,8 +769,8 @@ pub enum PatKind<'tcx> {
|
|||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, HashStable)]
|
#[derive(Clone, Debug, PartialEq, HashStable)]
|
||||||
pub struct PatRange<'tcx> {
|
pub struct PatRange<'tcx> {
|
||||||
pub lo: mir::ConstantKind<'tcx>,
|
pub lo: mir::Const<'tcx>,
|
||||||
pub hi: mir::ConstantKind<'tcx>,
|
pub hi: mir::Const<'tcx>,
|
||||||
pub end: RangeEnd,
|
pub end: RangeEnd,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,13 +26,13 @@ pub trait Visitor<'a, 'tcx: 'a>: Sized {
|
|||||||
walk_pat(self, pat);
|
walk_pat(self, pat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: We don't have visitors for `ty::Const` and `mir::ConstantKind`
|
// Note: We don't have visitors for `ty::Const` and `mir::Const`
|
||||||
// (even though these types occur in THIR) for consistency and to reduce confusion,
|
// (even though these types occur in THIR) for consistency and to reduce confusion,
|
||||||
// since the lazy creation of constants during thir construction causes most
|
// since the lazy creation of constants during thir construction causes most
|
||||||
// 'constants' to not be of type `ty::Const` or `mir::ConstantKind` at that
|
// 'constants' to not be of type `ty::Const` or `mir::Const` at that
|
||||||
// stage (they are mostly still identified by `DefId` or `hir::Lit`, see
|
// stage (they are mostly still identified by `DefId` or `hir::Lit`, see
|
||||||
// the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
|
// the variants `Literal`, `NonHirLiteral` and `NamedConst` in `thir::ExprKind`).
|
||||||
// You have to manually visit `ty::Const` and `mir::ConstantKind` through the
|
// You have to manually visit `ty::Const` and `mir::Const` through the
|
||||||
// other `visit*` functions.
|
// other `visit*` functions.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -339,24 +339,19 @@ impl<'tcx> Const<'tcx> {
|
|||||||
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
|
/// Attempts to evaluate the given constant to bits. Can fail to evaluate in the presence of
|
||||||
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
|
/// generics (or erroneous code) or if the value can't be represented as bits (e.g. because it
|
||||||
/// contains const generic parameters or pointers).
|
/// contains const generic parameters or pointers).
|
||||||
pub fn try_eval_bits(
|
pub fn try_eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Option<u128> {
|
||||||
self,
|
|
||||||
tcx: TyCtxt<'tcx>,
|
|
||||||
param_env: ParamEnv<'tcx>,
|
|
||||||
ty: Ty<'tcx>,
|
|
||||||
) -> Option<u128> {
|
|
||||||
let int = self.try_eval_scalar_int(tcx, param_env)?;
|
let int = self.try_eval_scalar_int(tcx, param_env)?;
|
||||||
assert_eq!(self.ty(), ty);
|
let size =
|
||||||
let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
|
tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(self.ty())).ok()?.size;
|
||||||
// if `ty` does not depend on generic parameters, use an empty param_env
|
// if `ty` does not depend on generic parameters, use an empty param_env
|
||||||
int.to_bits(size).ok()
|
int.to_bits(size).ok()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
|
/// Panics if the value cannot be evaluated or doesn't contain a valid integer of the given type.
|
||||||
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: Ty<'tcx>) -> u128 {
|
pub fn eval_bits(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> u128 {
|
||||||
self.try_eval_bits(tcx, param_env, ty)
|
self.try_eval_bits(tcx, param_env)
|
||||||
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", ty, self))
|
.unwrap_or_else(|| bug!("expected bits of {:#?}, got {:#?}", self.ty(), self))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -17,8 +17,8 @@ pub fn find_self_call<'tcx>(
|
|||||||
&body[block].terminator
|
&body[block].terminator
|
||||||
{
|
{
|
||||||
debug!("find_self_call: func={:?}", func);
|
debug!("find_self_call: func={:?}", func);
|
||||||
if let Operand::Constant(box Constant { literal, .. }) = func {
|
if let Operand::Constant(box ConstOperand { const_, .. }) = func {
|
||||||
if let ty::FnDef(def_id, fn_args) = *literal.ty().kind() {
|
if let ty::FnDef(def_id, fn_args) = *const_.ty().kind() {
|
||||||
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
if let Some(ty::AssocItem { fn_has_self_parameter: true, .. }) =
|
||||||
tcx.opt_associated_item(def_id)
|
tcx.opt_associated_item(def_id)
|
||||||
{
|
{
|
||||||
|
@ -49,7 +49,7 @@ impl<'tcx> CFG<'tcx> {
|
|||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
temp: Place<'tcx>,
|
temp: Place<'tcx>,
|
||||||
constant: Constant<'tcx>,
|
constant: ConstOperand<'tcx>,
|
||||||
) {
|
) {
|
||||||
self.push_assign(
|
self.push_assign(
|
||||||
block,
|
block,
|
||||||
@ -70,10 +70,10 @@ impl<'tcx> CFG<'tcx> {
|
|||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
place,
|
place,
|
||||||
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||||
span: source_info.span,
|
span: source_info.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::zero_sized(tcx.types.unit),
|
const_: Const::zero_sized(tcx.types.unit),
|
||||||
}))),
|
}))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
|||||||
expected: "constant pattern".to_string(),
|
expected: "constant pattern".to_string(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
values.push(value.eval_bits(self.tcx, self.param_env, arm.pattern.ty));
|
values.push(value.eval_bits(self.tcx, self.param_env));
|
||||||
targets.push(self.parse_block(arm.body)?);
|
targets.push(self.parse_block(arm.body)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,12 +283,12 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
|||||||
ExprKind::StaticRef { alloc_id, ty, .. } => {
|
ExprKind::StaticRef { alloc_id, ty, .. } => {
|
||||||
let const_val =
|
let const_val =
|
||||||
ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
|
ConstValue::Scalar(Scalar::from_pointer((*alloc_id).into(), &self.tcx));
|
||||||
let literal = ConstantKind::Val(const_val, *ty);
|
let const_ = Const::Val(const_val, *ty);
|
||||||
|
|
||||||
Ok(Operand::Constant(Box::new(Constant {
|
Ok(Operand::Constant(Box::new(ConstOperand {
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal
|
const_
|
||||||
})))
|
})))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -301,7 +301,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
|
|||||||
| ExprKind::NonHirLiteral { .. }
|
| ExprKind::NonHirLiteral { .. }
|
||||||
| ExprKind::ConstBlock { .. } => Ok({
|
| ExprKind::ConstBlock { .. } => Ok({
|
||||||
let value = as_constant_inner(expr, |_| None, self.tcx);
|
let value = as_constant_inner(expr, |_| None, self.tcx);
|
||||||
value.literal.eval_bits(self.tcx, self.param_env, value.ty())
|
value.const_.eval_bits(self.tcx, self.param_env)
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@ use rustc_target::abi::Size;
|
|||||||
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
/// Compile `expr`, yielding a compile-time constant. Assumes that
|
/// Compile `expr`, yielding a compile-time constant. Assumes that
|
||||||
/// `expr` is a valid compile-time constant!
|
/// `expr` is a valid compile-time constant!
|
||||||
pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
|
pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> ConstOperand<'tcx> {
|
||||||
let this = self;
|
let this = self;
|
||||||
let tcx = this.tcx;
|
let tcx = this.tcx;
|
||||||
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
|
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
|
||||||
@ -42,62 +42,62 @@ pub fn as_constant_inner<'tcx>(
|
|||||||
expr: &Expr<'tcx>,
|
expr: &Expr<'tcx>,
|
||||||
push_cuta: impl FnMut(&Box<CanonicalUserType<'tcx>>) -> Option<UserTypeAnnotationIndex>,
|
push_cuta: impl FnMut(&Box<CanonicalUserType<'tcx>>) -> Option<UserTypeAnnotationIndex>,
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
) -> Constant<'tcx> {
|
) -> ConstOperand<'tcx> {
|
||||||
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
|
let Expr { ty, temp_lifetime: _, span, ref kind } = *expr;
|
||||||
match *kind {
|
match *kind {
|
||||||
ExprKind::Literal { lit, neg } => {
|
ExprKind::Literal { lit, neg } => {
|
||||||
let literal =
|
let const_ = match lit_to_mir_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(guar)) => {
|
Err(LitToConstError::Reported(guar)) => {
|
||||||
ConstantKind::Ty(ty::Const::new_error(tcx, guar, ty))
|
Const::Ty(ty::Const::new_error(tcx, guar, ty))
|
||||||
}
|
}
|
||||||
Err(LitToConstError::TypeError) => {
|
Err(LitToConstError::TypeError) => {
|
||||||
bug!("encountered type error in `lit_to_mir_constant`")
|
bug!("encountered type error in `lit_to_mir_constant`")
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Constant { span, user_ty: None, literal }
|
ConstOperand { span, user_ty: None, const_ }
|
||||||
}
|
}
|
||||||
ExprKind::NonHirLiteral { lit, ref user_ty } => {
|
ExprKind::NonHirLiteral { lit, ref user_ty } => {
|
||||||
let user_ty = user_ty.as_ref().and_then(push_cuta);
|
let user_ty = user_ty.as_ref().and_then(push_cuta);
|
||||||
|
|
||||||
let literal = ConstantKind::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
|
let const_ = Const::Val(ConstValue::Scalar(Scalar::Int(lit)), ty);
|
||||||
|
|
||||||
Constant { span, user_ty, literal }
|
ConstOperand { span, user_ty, const_ }
|
||||||
}
|
}
|
||||||
ExprKind::ZstLiteral { ref user_ty } => {
|
ExprKind::ZstLiteral { ref user_ty } => {
|
||||||
let user_ty = user_ty.as_ref().and_then(push_cuta);
|
let user_ty = user_ty.as_ref().and_then(push_cuta);
|
||||||
|
|
||||||
let literal = ConstantKind::Val(ConstValue::ZeroSized, ty);
|
let const_ = Const::Val(ConstValue::ZeroSized, ty);
|
||||||
|
|
||||||
Constant { span, user_ty, literal }
|
ConstOperand { span, user_ty, const_ }
|
||||||
}
|
}
|
||||||
ExprKind::NamedConst { def_id, args, ref user_ty } => {
|
ExprKind::NamedConst { def_id, args, ref user_ty } => {
|
||||||
let user_ty = user_ty.as_ref().and_then(push_cuta);
|
let user_ty = user_ty.as_ref().and_then(push_cuta);
|
||||||
|
|
||||||
let uneval = mir::UnevaluatedConst::new(def_id, args);
|
let uneval = mir::UnevaluatedConst::new(def_id, args);
|
||||||
let literal = ConstantKind::Unevaluated(uneval, ty);
|
let const_ = Const::Unevaluated(uneval, ty);
|
||||||
|
|
||||||
Constant { user_ty, span, literal }
|
ConstOperand { user_ty, span, const_ }
|
||||||
}
|
}
|
||||||
ExprKind::ConstParam { param, def_id: _ } => {
|
ExprKind::ConstParam { param, def_id: _ } => {
|
||||||
let const_param = ty::Const::new_param(tcx, param, expr.ty);
|
let const_param = ty::Const::new_param(tcx, param, expr.ty);
|
||||||
let literal = ConstantKind::Ty(const_param);
|
let const_ = Const::Ty(const_param);
|
||||||
|
|
||||||
Constant { user_ty: None, span, literal }
|
ConstOperand { user_ty: None, span, const_ }
|
||||||
}
|
}
|
||||||
ExprKind::ConstBlock { did: def_id, args } => {
|
ExprKind::ConstBlock { did: def_id, args } => {
|
||||||
let uneval = mir::UnevaluatedConst::new(def_id, args);
|
let uneval = mir::UnevaluatedConst::new(def_id, args);
|
||||||
let literal = ConstantKind::Unevaluated(uneval, ty);
|
let const_ = Const::Unevaluated(uneval, ty);
|
||||||
|
|
||||||
Constant { user_ty: None, span, literal }
|
ConstOperand { user_ty: None, span, const_ }
|
||||||
}
|
}
|
||||||
ExprKind::StaticRef { alloc_id, ty, .. } => {
|
ExprKind::StaticRef { alloc_id, ty, .. } => {
|
||||||
let const_val = ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &tcx));
|
let const_val = ConstValue::Scalar(Scalar::from_pointer(alloc_id.into(), &tcx));
|
||||||
let literal = ConstantKind::Val(const_val, ty);
|
let const_ = Const::Val(const_val, ty);
|
||||||
|
|
||||||
Constant { span, user_ty: None, literal }
|
ConstOperand { span, user_ty: None, const_ }
|
||||||
}
|
}
|
||||||
_ => span_bug!(span, "expression is not a valid constant {:?}", kind),
|
_ => span_bug!(span, "expression is not a valid constant {:?}", kind),
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ pub fn as_constant_inner<'tcx>(
|
|||||||
fn lit_to_mir_constant<'tcx>(
|
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<Const<'tcx>, LitToConstError> {
|
||||||
let LitToConstInput { lit, ty, neg } = lit_input;
|
let LitToConstInput { lit, ty, neg } = lit_input;
|
||||||
let trunc = |n| {
|
let trunc = |n| {
|
||||||
let param_ty = ty::ParamEnv::reveal_all().and(ty);
|
let param_ty = ty::ParamEnv::reveal_all().and(ty);
|
||||||
@ -173,5 +173,5 @@ fn lit_to_mir_constant<'tcx>(
|
|||||||
_ => return Err(LitToConstError::TypeError),
|
_ => return Err(LitToConstError::TypeError),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ConstantKind::Val(value, ty))
|
Ok(Const::Val(value, ty))
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
|
let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
|
||||||
let range_val =
|
let range_val =
|
||||||
ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
|
Const::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
|
||||||
let lit_op = this.literal_operand(expr.span, range_val);
|
let lit_op = this.literal_operand(expr.span, range_val);
|
||||||
let is_bin_op = this.temp(bool_ty, expr_span);
|
let is_bin_op = this.temp(bool_ty, expr_span);
|
||||||
this.cfg.push_assign(
|
this.cfg.push_assign(
|
||||||
@ -485,10 +485,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
|
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
|
||||||
block = unpack!(this.stmt_expr(block, expr, None));
|
block = unpack!(this.stmt_expr(block, expr, None));
|
||||||
block.and(Rvalue::Use(Operand::Constant(Box::new(Constant {
|
block.and(Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||||
span: expr_span,
|
span: expr_span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::zero_sized(this.tcx.types.unit),
|
const_: Const::zero_sized(this.tcx.types.unit),
|
||||||
}))))
|
}))))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -817,7 +817,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 = ConstantKind::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
|
let literal = Const::from_bits(self.tcx, size.unsigned_int_max(), param_ty);
|
||||||
|
|
||||||
self.literal_operand(span, literal)
|
self.literal_operand(span, literal)
|
||||||
}
|
}
|
||||||
@ -828,7 +828,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 = ConstantKind::from_bits(self.tcx, n, param_ty);
|
let literal = Const::from_bits(self.tcx, n, param_ty);
|
||||||
|
|
||||||
self.literal_operand(span, literal)
|
self.literal_operand(span, literal)
|
||||||
}
|
}
|
||||||
|
@ -114,10 +114,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
true_block,
|
true_block,
|
||||||
source_info,
|
source_info,
|
||||||
destination,
|
destination,
|
||||||
Constant {
|
ConstOperand {
|
||||||
span: expr_span,
|
span: expr_span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::from_bool(this.tcx, true),
|
const_: Const::from_bool(this.tcx, true),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -125,10 +125,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
false_block,
|
false_block,
|
||||||
source_info,
|
source_info,
|
||||||
destination,
|
destination,
|
||||||
Constant {
|
ConstOperand {
|
||||||
span: expr_span,
|
span: expr_span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::from_bool(this.tcx, false),
|
const_: Const::from_bool(this.tcx, false),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -186,10 +186,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
short_circuit,
|
short_circuit,
|
||||||
source_info,
|
source_info,
|
||||||
destination,
|
destination,
|
||||||
Constant {
|
ConstOperand {
|
||||||
span: expr.span,
|
span: expr.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::from_bool(this.tcx, constant),
|
const_: Const::from_bool(this.tcx, constant),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let rhs = unpack!(this.expr_into_dest(destination, continuation, &this.thir[rhs]));
|
let rhs = unpack!(this.expr_into_dest(destination, continuation, &this.thir[rhs]));
|
||||||
@ -433,12 +433,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
thir::InlineAsmOperand::Const { value, span } => {
|
thir::InlineAsmOperand::Const { value, span } => {
|
||||||
mir::InlineAsmOperand::Const {
|
mir::InlineAsmOperand::Const {
|
||||||
value: Box::new(Constant { span, user_ty: None, literal: value }),
|
value: Box::new(ConstOperand {
|
||||||
|
span,
|
||||||
|
user_ty: None,
|
||||||
|
const_: value,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thir::InlineAsmOperand::SymFn { value, span } => {
|
thir::InlineAsmOperand::SymFn { value, span } => {
|
||||||
mir::InlineAsmOperand::SymFn {
|
mir::InlineAsmOperand::SymFn {
|
||||||
value: Box::new(Constant { span, user_ty: None, literal: value }),
|
value: Box::new(ConstOperand {
|
||||||
|
span,
|
||||||
|
user_ty: None,
|
||||||
|
const_: value,
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
thir::InlineAsmOperand::SymStatic { def_id } => {
|
thir::InlineAsmOperand::SymStatic { def_id } => {
|
||||||
|
@ -1005,13 +1005,13 @@ enum TestKind<'tcx> {
|
|||||||
///
|
///
|
||||||
/// For `bool` we always generate two edges, one for `true` and one for
|
/// For `bool` we always generate two edges, one for `true` and one for
|
||||||
/// `false`.
|
/// `false`.
|
||||||
options: FxIndexMap<ConstantKind<'tcx>, u128>,
|
options: FxIndexMap<Const<'tcx>, u128>,
|
||||||
},
|
},
|
||||||
|
|
||||||
/// Test for equality with value, possibly after an unsizing coercion to
|
/// Test for equality with value, possibly after an unsizing coercion to
|
||||||
/// `ty`,
|
/// `ty`,
|
||||||
Eq {
|
Eq {
|
||||||
value: ConstantKind<'tcx>,
|
value: Const<'tcx>,
|
||||||
// Integer types are handled by `SwitchInt`, and constants with ADT
|
// Integer types are handled by `SwitchInt`, and constants with ADT
|
||||||
// types are converted back into patterns, so this can only be `&str`,
|
// types are converted back into patterns, so this can only be `&str`,
|
||||||
// `&[T]`, `f32` or `f64`.
|
// `&[T]`, `f32` or `f64`.
|
||||||
@ -1622,9 +1622,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
// may want to add cases based on the candidates that are
|
// may want to add cases based on the candidates that are
|
||||||
// available
|
// available
|
||||||
match test.kind {
|
match test.kind {
|
||||||
TestKind::SwitchInt { switch_ty, ref mut options } => {
|
TestKind::SwitchInt { switch_ty: _, ref mut options } => {
|
||||||
for candidate in candidates.iter() {
|
for candidate in candidates.iter() {
|
||||||
if !self.add_cases_to_switch(&match_place, candidate, switch_ty, options) {
|
if !self.add_cases_to_switch(&match_place, candidate, options) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,8 +85,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
test_place: &PlaceBuilder<'tcx>,
|
test_place: &PlaceBuilder<'tcx>,
|
||||||
candidate: &Candidate<'pat, 'tcx>,
|
candidate: &Candidate<'pat, 'tcx>,
|
||||||
switch_ty: Ty<'tcx>,
|
options: &mut FxIndexMap<Const<'tcx>, u128>,
|
||||||
options: &mut FxIndexMap<ConstantKind<'tcx>, u128>,
|
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place)
|
let Some(match_pair) = candidate.match_pairs.iter().find(|mp| mp.place == *test_place)
|
||||||
else {
|
else {
|
||||||
@ -95,9 +94,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
|
|
||||||
match match_pair.pattern.kind {
|
match match_pair.pattern.kind {
|
||||||
PatKind::Constant { value } => {
|
PatKind::Constant { value } => {
|
||||||
options
|
options.entry(value).or_insert_with(|| value.eval_bits(self.tcx, self.param_env));
|
||||||
.entry(value)
|
|
||||||
.or_insert_with(|| value.eval_bits(self.tcx, self.param_env, switch_ty));
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
PatKind::Variant { .. } => {
|
PatKind::Variant { .. } => {
|
||||||
@ -255,10 +252,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
TerminatorKind::Call {
|
TerminatorKind::Call {
|
||||||
func: Operand::Constant(Box::new(Constant {
|
func: Operand::Constant(Box::new(ConstOperand {
|
||||||
span: test.span,
|
span: test.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: method,
|
const_: method,
|
||||||
})),
|
})),
|
||||||
args: vec![Operand::Move(ref_string)],
|
args: vec![Operand::Move(ref_string)],
|
||||||
destination: ref_str,
|
destination: ref_str,
|
||||||
@ -388,7 +385,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
block: BasicBlock,
|
block: BasicBlock,
|
||||||
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
|
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
|
||||||
source_info: SourceInfo,
|
source_info: SourceInfo,
|
||||||
value: ConstantKind<'tcx>,
|
value: Const<'tcx>,
|
||||||
mut val: Place<'tcx>,
|
mut val: Place<'tcx>,
|
||||||
mut ty: Ty<'tcx>,
|
mut ty: Ty<'tcx>,
|
||||||
) {
|
) {
|
||||||
@ -485,7 +482,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
TerminatorKind::Call {
|
TerminatorKind::Call {
|
||||||
func: Operand::Constant(Box::new(Constant {
|
func: Operand::Constant(Box::new(ConstOperand {
|
||||||
span: source_info.span,
|
span: source_info.span,
|
||||||
|
|
||||||
// FIXME(#54571): This constant comes from user input (a
|
// FIXME(#54571): This constant comes from user input (a
|
||||||
@ -494,7 +491,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
// Need to experiment.
|
// Need to experiment.
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
|
|
||||||
literal: method,
|
const_: method,
|
||||||
})),
|
})),
|
||||||
args: vec![Operand::Copy(val), expect],
|
args: vec![Operand::Copy(val), expect],
|
||||||
destination: eq_result,
|
destination: eq_result,
|
||||||
@ -800,11 +797,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern)
|
span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn const_range_contains(
|
fn const_range_contains(&self, range: &PatRange<'tcx>, value: Const<'tcx>) -> Option<bool> {
|
||||||
&self,
|
|
||||||
range: &PatRange<'tcx>,
|
|
||||||
value: ConstantKind<'tcx>,
|
|
||||||
) -> Option<bool> {
|
|
||||||
use std::cmp::Ordering::*;
|
use std::cmp::Ordering::*;
|
||||||
|
|
||||||
// For performance, it's important to only do the second
|
// For performance, it's important to only do the second
|
||||||
@ -821,7 +814,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
fn values_not_contained_in_range(
|
fn values_not_contained_in_range(
|
||||||
&self,
|
&self,
|
||||||
range: &PatRange<'tcx>,
|
range: &PatRange<'tcx>,
|
||||||
options: &FxIndexMap<ConstantKind<'tcx>, u128>,
|
options: &FxIndexMap<Const<'tcx>, u128>,
|
||||||
) -> Option<bool> {
|
) -> Option<bool> {
|
||||||
for &val in options.keys() {
|
for &val in options.keys() {
|
||||||
if self.const_range_contains(range, val)? {
|
if self.const_range_contains(range, val)? {
|
||||||
@ -866,7 +859,7 @@ fn trait_method<'tcx>(
|
|||||||
trait_def_id: DefId,
|
trait_def_id: DefId,
|
||||||
method_name: Symbol,
|
method_name: Symbol,
|
||||||
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
|
args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
|
||||||
) -> ConstantKind<'tcx> {
|
) -> Const<'tcx> {
|
||||||
// The unhygienic comparison here is acceptable because this is only
|
// The unhygienic comparison here is acceptable because this is only
|
||||||
// used on known traits.
|
// used on known traits.
|
||||||
let item = tcx
|
let item = tcx
|
||||||
@ -877,5 +870,5 @@ fn trait_method<'tcx>(
|
|||||||
|
|
||||||
let method_ty = Ty::new_fn_def(tcx, item.def_id, args);
|
let method_ty = Ty::new_fn_def(tcx, item.def_id, args);
|
||||||
|
|
||||||
ConstantKind::zero_sized(method_ty)
|
Const::zero_sized(method_ty)
|
||||||
}
|
}
|
||||||
|
@ -25,19 +25,15 @@ 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.
|
||||||
pub(crate) fn literal_operand(
|
pub(crate) fn literal_operand(&mut self, span: Span, const_: Const<'tcx>) -> Operand<'tcx> {
|
||||||
&mut self,
|
let constant = Box::new(ConstOperand { span, user_ty: None, const_ });
|
||||||
span: Span,
|
|
||||||
literal: ConstantKind<'tcx>,
|
|
||||||
) -> Operand<'tcx> {
|
|
||||||
let constant = Box::new(Constant { span, user_ty: None, literal });
|
|
||||||
Operand::Constant(constant)
|
Operand::Constant(constant)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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.
|
||||||
pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
pub(crate) fn zero_literal(&mut self, span: Span, ty: Ty<'tcx>) -> Operand<'tcx> {
|
||||||
let literal = ConstantKind::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
|
let literal = Const::from_bits(self.tcx, 0, ty::ParamEnv::empty().and(ty));
|
||||||
|
|
||||||
self.literal_operand(span, literal)
|
self.literal_operand(span, literal)
|
||||||
}
|
}
|
||||||
@ -54,10 +50,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||||||
block,
|
block,
|
||||||
source_info,
|
source_info,
|
||||||
temp,
|
temp,
|
||||||
Constant {
|
ConstOperand {
|
||||||
span: source_info.span,
|
span: source_info.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::from_usize(self.tcx, value),
|
const_: Const::from_usize(self.tcx, value),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
temp
|
temp
|
||||||
|
@ -647,21 +647,15 @@ impl<'tcx> Cx<'tcx> {
|
|||||||
out_expr: out_expr.map(|expr| self.mirror_expr(expr)),
|
out_expr: out_expr.map(|expr| self.mirror_expr(expr)),
|
||||||
},
|
},
|
||||||
hir::InlineAsmOperand::Const { ref anon_const } => {
|
hir::InlineAsmOperand::Const { ref anon_const } => {
|
||||||
let value = mir::ConstantKind::from_anon_const(
|
let value =
|
||||||
tcx,
|
mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env);
|
||||||
anon_const.def_id,
|
|
||||||
self.param_env,
|
|
||||||
);
|
|
||||||
let span = tcx.def_span(anon_const.def_id);
|
let span = tcx.def_span(anon_const.def_id);
|
||||||
|
|
||||||
InlineAsmOperand::Const { value, span }
|
InlineAsmOperand::Const { value, span }
|
||||||
}
|
}
|
||||||
hir::InlineAsmOperand::SymFn { ref anon_const } => {
|
hir::InlineAsmOperand::SymFn { ref anon_const } => {
|
||||||
let value = mir::ConstantKind::from_anon_const(
|
let value =
|
||||||
tcx,
|
mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env);
|
||||||
anon_const.def_id,
|
|
||||||
self.param_env,
|
|
||||||
);
|
|
||||||
let span = tcx.def_span(anon_const.def_id);
|
let span = tcx.def_span(anon_const.def_id);
|
||||||
|
|
||||||
InlineAsmOperand::SymFn { value, span }
|
InlineAsmOperand::SymFn { value, span }
|
||||||
|
@ -27,7 +27,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
#[instrument(level = "debug", skip(self), ret)]
|
#[instrument(level = "debug", skip(self), ret)]
|
||||||
pub(super) fn const_to_pat(
|
pub(super) fn const_to_pat(
|
||||||
&self,
|
&self,
|
||||||
cv: mir::ConstantKind<'tcx>,
|
cv: mir::Const<'tcx>,
|
||||||
id: hir::HirId,
|
id: hir::HirId,
|
||||||
span: Span,
|
span: Span,
|
||||||
check_body_for_struct_match_violation: Option<DefId>,
|
check_body_for_struct_match_violation: Option<DefId>,
|
||||||
@ -104,7 +104,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||||||
|
|
||||||
fn to_pat(
|
fn to_pat(
|
||||||
&mut self,
|
&mut self,
|
||||||
cv: mir::ConstantKind<'tcx>,
|
cv: mir::Const<'tcx>,
|
||||||
check_body_for_struct_match_violation: Option<DefId>,
|
check_body_for_struct_match_violation: Option<DefId>,
|
||||||
) -> Box<Pat<'tcx>> {
|
) -> Box<Pat<'tcx>> {
|
||||||
trace!(self.treat_byte_string_as_slice);
|
trace!(self.treat_byte_string_as_slice);
|
||||||
@ -124,7 +124,7 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||||||
debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);
|
debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);
|
||||||
|
|
||||||
let inlined_const_as_pat = match cv {
|
let inlined_const_as_pat = match cv {
|
||||||
mir::ConstantKind::Ty(c) => match c.kind() {
|
mir::Const::Ty(c) => match c.kind() {
|
||||||
ty::ConstKind::Param(_)
|
ty::ConstKind::Param(_)
|
||||||
| ty::ConstKind::Infer(_)
|
| ty::ConstKind::Infer(_)
|
||||||
| ty::ConstKind::Bound(_, _)
|
| ty::ConstKind::Bound(_, _)
|
||||||
@ -144,10 +144,10 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
mir::ConstantKind::Unevaluated(_, _) => {
|
mir::Const::Unevaluated(_, _) => {
|
||||||
span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
|
span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
|
||||||
}
|
}
|
||||||
mir::ConstantKind::Val(_, _) => Box::new(Pat {
|
mir::Const::Val(_, _) => Box::new(Pat {
|
||||||
span: self.span,
|
span: self.span,
|
||||||
ty: cv.ty(),
|
ty: cv.ty(),
|
||||||
kind: PatKind::Constant { value: cv },
|
kind: PatKind::Constant { value: cv },
|
||||||
@ -385,9 +385,9 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||||||
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
|
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
|
||||||
// `&str` is represented as a valtree, let's keep using this
|
// `&str` is represented as a valtree, let's keep using this
|
||||||
// optimization for now.
|
// optimization for now.
|
||||||
ty::Str => PatKind::Constant {
|
ty::Str => {
|
||||||
value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)),
|
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
|
||||||
},
|
}
|
||||||
// Backwards compatibility hack: support references to non-structural types,
|
// Backwards compatibility hack: support references to non-structural types,
|
||||||
// but hard error if we aren't behind a double reference. We could just use
|
// but hard error if we aren't behind a double reference. We could just use
|
||||||
// the fallback code path below, but that would allow *more* of this fishy
|
// the fallback code path below, but that would allow *more* of this fishy
|
||||||
@ -445,9 +445,9 @@ impl<'tcx> ConstToPat<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => PatKind::Constant {
|
ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => {
|
||||||
value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)),
|
PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
|
||||||
},
|
}
|
||||||
ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(),
|
ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(),
|
||||||
_ => {
|
_ => {
|
||||||
self.saw_const_match_error.set(true);
|
self.saw_const_match_error.set(true);
|
||||||
|
@ -137,16 +137,16 @@ impl IntRange {
|
|||||||
fn from_constant<'tcx>(
|
fn from_constant<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
value: mir::ConstantKind<'tcx>,
|
value: mir::Const<'tcx>,
|
||||||
) -> Option<IntRange> {
|
) -> Option<IntRange> {
|
||||||
let ty = value.ty();
|
let ty = value.ty();
|
||||||
let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, ty)?;
|
let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, ty)?;
|
||||||
let val = match value {
|
let val = match value {
|
||||||
mir::ConstantKind::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
|
mir::Const::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
|
||||||
valtree.unwrap_leaf().to_bits(target_size).ok()
|
valtree.unwrap_leaf().to_bits(target_size).ok()
|
||||||
},
|
},
|
||||||
// This is a more general form of the previous case.
|
// This is a more general form of the previous case.
|
||||||
_ => value.try_eval_bits(tcx, param_env, ty),
|
_ => value.try_eval_bits(tcx, param_env),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
let val = val ^ bias;
|
let val = val ^ bias;
|
||||||
@ -225,8 +225,8 @@ impl IntRange {
|
|||||||
let (lo, hi) = (lo ^ bias, hi ^ bias);
|
let (lo, hi) = (lo ^ bias, hi ^ bias);
|
||||||
|
|
||||||
let env = ty::ParamEnv::empty().and(ty);
|
let env = ty::ParamEnv::empty().and(ty);
|
||||||
let lo_const = mir::ConstantKind::from_bits(tcx, lo, env);
|
let lo_const = mir::Const::from_bits(tcx, lo, env);
|
||||||
let hi_const = mir::ConstantKind::from_bits(tcx, hi, env);
|
let hi_const = mir::Const::from_bits(tcx, hi, env);
|
||||||
|
|
||||||
let kind = if lo == hi {
|
let kind = if lo == hi {
|
||||||
PatKind::Constant { value: lo_const }
|
PatKind::Constant { value: lo_const }
|
||||||
@ -619,9 +619,9 @@ pub(super) enum Constructor<'tcx> {
|
|||||||
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
|
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
|
||||||
IntRange(IntRange),
|
IntRange(IntRange),
|
||||||
/// Ranges of floating-point literal values (`2.0..=5.2`).
|
/// Ranges of floating-point literal values (`2.0..=5.2`).
|
||||||
FloatRange(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>, RangeEnd),
|
FloatRange(mir::Const<'tcx>, mir::Const<'tcx>, RangeEnd),
|
||||||
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
|
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
|
||||||
Str(mir::ConstantKind<'tcx>),
|
Str(mir::Const<'tcx>),
|
||||||
/// Array and slice patterns.
|
/// Array and slice patterns.
|
||||||
Slice(Slice),
|
Slice(Slice),
|
||||||
/// Constants that must not be matched structurally. They are treated as black
|
/// Constants that must not be matched structurally. They are treated as black
|
||||||
@ -1379,8 +1379,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
|
|||||||
let ty = lo.ty();
|
let ty = lo.ty();
|
||||||
ctor = if let Some(int_range) = IntRange::from_range(
|
ctor = if let Some(int_range) = IntRange::from_range(
|
||||||
cx.tcx,
|
cx.tcx,
|
||||||
lo.eval_bits(cx.tcx, cx.param_env, lo.ty()),
|
lo.eval_bits(cx.tcx, cx.param_env),
|
||||||
hi.eval_bits(cx.tcx, cx.param_env, hi.ty()),
|
hi.eval_bits(cx.tcx, cx.param_env),
|
||||||
ty,
|
ty,
|
||||||
&end,
|
&end,
|
||||||
) {
|
) {
|
||||||
|
@ -20,7 +20,7 @@ use rustc_index::Idx;
|
|||||||
use rustc_middle::mir::interpret::{
|
use rustc_middle::mir::interpret::{
|
||||||
ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar,
|
ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar,
|
||||||
};
|
};
|
||||||
use rustc_middle::mir::{self, ConstantKind, UserTypeProjection};
|
use rustc_middle::mir::{self, Const, UserTypeProjection};
|
||||||
use rustc_middle::mir::{BorrowKind, Mutability};
|
use rustc_middle::mir::{BorrowKind, Mutability};
|
||||||
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
|
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
|
||||||
use rustc_middle::ty::CanonicalUserTypeAnnotation;
|
use rustc_middle::ty::CanonicalUserTypeAnnotation;
|
||||||
@ -100,8 +100,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
fn lower_pattern_range(
|
fn lower_pattern_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
lo: mir::ConstantKind<'tcx>,
|
lo: mir::Const<'tcx>,
|
||||||
hi: mir::ConstantKind<'tcx>,
|
hi: mir::Const<'tcx>,
|
||||||
end: RangeEnd,
|
end: RangeEnd,
|
||||||
span: Span,
|
span: Span,
|
||||||
lo_expr: Option<&hir::Expr<'tcx>>,
|
lo_expr: Option<&hir::Expr<'tcx>>,
|
||||||
@ -131,7 +131,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
|
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
|
||||||
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||||
{
|
{
|
||||||
if lo.eval_bits(self.tcx, self.param_env, ty) != val {
|
if lo.eval_bits(self.tcx, self.param_env) != val {
|
||||||
lower_overflow = true;
|
lower_overflow = true;
|
||||||
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
|
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
|
||||||
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||||
{
|
{
|
||||||
if hi.eval_bits(self.tcx, self.param_env, ty) != val {
|
if hi.eval_bits(self.tcx, self.param_env) != val {
|
||||||
higher_overflow = true;
|
higher_overflow = true;
|
||||||
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||||
}
|
}
|
||||||
@ -162,7 +162,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
|
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
|
||||||
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||||
{
|
{
|
||||||
if lo.eval_bits(self.tcx, self.param_env, ty) != val {
|
if lo.eval_bits(self.tcx, self.param_env) != val {
|
||||||
lower_overflow = true;
|
lower_overflow = true;
|
||||||
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||||
}
|
}
|
||||||
@ -170,7 +170,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
|
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
|
||||||
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
|
||||||
{
|
{
|
||||||
if hi.eval_bits(self.tcx, self.param_env, ty) != val {
|
if hi.eval_bits(self.tcx, self.param_env) != val {
|
||||||
higher_overflow = true;
|
higher_overflow = true;
|
||||||
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
|
||||||
}
|
}
|
||||||
@ -191,18 +191,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
lo: Option<&PatKind<'tcx>>,
|
lo: Option<&PatKind<'tcx>>,
|
||||||
hi: Option<&PatKind<'tcx>>,
|
hi: Option<&PatKind<'tcx>>,
|
||||||
) -> Option<(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>)> {
|
) -> Option<(mir::Const<'tcx>, mir::Const<'tcx>)> {
|
||||||
match (lo, hi) {
|
match (lo, hi) {
|
||||||
(Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
|
(Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
|
||||||
Some((*lo, *hi))
|
Some((*lo, *hi))
|
||||||
}
|
}
|
||||||
(Some(PatKind::Constant { value: lo }), None) => {
|
(Some(PatKind::Constant { value: lo }), None) => {
|
||||||
let hi = ty.numeric_max_val(self.tcx)?;
|
let hi = ty.numeric_max_val(self.tcx)?;
|
||||||
Some((*lo, mir::ConstantKind::from_ty_const(hi, self.tcx)))
|
Some((*lo, mir::Const::from_ty_const(hi, self.tcx)))
|
||||||
}
|
}
|
||||||
(None, Some(PatKind::Constant { value: hi })) => {
|
(None, Some(PatKind::Constant { value: hi })) => {
|
||||||
let lo = ty.numeric_min_val(self.tcx)?;
|
let lo = ty.numeric_min_val(self.tcx)?;
|
||||||
Some((mir::ConstantKind::from_ty_const(lo, self.tcx), *hi))
|
Some((mir::Const::from_ty_const(lo, self.tcx), *hi))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
@ -525,8 +525,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
.tcx
|
.tcx
|
||||||
.const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span))
|
.const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span))
|
||||||
.map(|val| match val {
|
.map(|val| match val {
|
||||||
Some(valtree) => mir::ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
|
Some(valtree) => mir::Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
|
||||||
None => mir::ConstantKind::Val(
|
None => mir::Const::Val(
|
||||||
self.tcx
|
self.tcx
|
||||||
.const_eval_global_id(param_env_reveal_all, cid, Some(span))
|
.const_eval_global_id(param_env_reveal_all, cid, Some(span))
|
||||||
.expect("const_eval_global_id_for_typeck should have already failed"),
|
.expect("const_eval_global_id_for_typeck should have already failed"),
|
||||||
@ -608,7 +608,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
};
|
};
|
||||||
if let Some(lit_input) = lit_input {
|
if let Some(lit_input) = lit_input {
|
||||||
match tcx.at(expr.span).lit_to_const(lit_input) {
|
match tcx.at(expr.span).lit_to_const(lit_input) {
|
||||||
Ok(c) => return self.const_to_pat(ConstantKind::Ty(c), id, span, None).kind,
|
Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind,
|
||||||
// If an error occurred, ignore that it's a literal
|
// If an error occurred, ignore that it's a literal
|
||||||
// and leave reporting the error up to const eval of
|
// and leave reporting the error up to const eval of
|
||||||
// the unevaluated constant below.
|
// the unevaluated constant below.
|
||||||
@ -632,7 +632,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
|
self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
|
||||||
{
|
{
|
||||||
self.const_to_pat(
|
self.const_to_pat(
|
||||||
ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
|
Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
|
||||||
id,
|
id,
|
||||||
span,
|
span,
|
||||||
None,
|
None,
|
||||||
@ -641,7 +641,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
} else {
|
} else {
|
||||||
// If that fails, convert it to an opaque constant pattern.
|
// If that fails, convert it to an opaque constant pattern.
|
||||||
match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
|
match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
|
||||||
Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind,
|
Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind,
|
||||||
Err(ErrorHandled::TooGeneric(_)) => {
|
Err(ErrorHandled::TooGeneric(_)) => {
|
||||||
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
|
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
|
||||||
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
|
||||||
@ -678,7 +678,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
|||||||
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(constant) => {
|
Ok(constant) => {
|
||||||
self.const_to_pat(ConstantKind::Ty(constant), expr.hir_id, lit.span, None).kind
|
self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).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"),
|
||||||
@ -838,8 +838,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
|
|||||||
#[instrument(skip(tcx), level = "debug")]
|
#[instrument(skip(tcx), level = "debug")]
|
||||||
pub(crate) fn compare_const_vals<'tcx>(
|
pub(crate) fn compare_const_vals<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
a: mir::ConstantKind<'tcx>,
|
a: mir::Const<'tcx>,
|
||||||
b: mir::ConstantKind<'tcx>,
|
b: mir::Const<'tcx>,
|
||||||
param_env: ty::ParamEnv<'tcx>,
|
param_env: ty::ParamEnv<'tcx>,
|
||||||
) -> Option<Ordering> {
|
) -> Option<Ordering> {
|
||||||
assert_eq!(a.ty(), b.ty());
|
assert_eq!(a.ty(), b.ty());
|
||||||
@ -855,18 +855,18 @@ pub(crate) fn compare_const_vals<'tcx>(
|
|||||||
ty::Float(_) | ty::Int(_) => {} // require special handling, see below
|
ty::Float(_) | ty::Int(_) => {} // require special handling, see below
|
||||||
_ => match (a, b) {
|
_ => match (a, b) {
|
||||||
(
|
(
|
||||||
mir::ConstantKind::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty),
|
mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty),
|
||||||
mir::ConstantKind::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty),
|
mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty),
|
||||||
) => return Some(a.cmp(&b)),
|
) => return Some(a.cmp(&b)),
|
||||||
(mir::ConstantKind::Ty(a), mir::ConstantKind::Ty(b)) => {
|
(mir::Const::Ty(a), mir::Const::Ty(b)) => {
|
||||||
return Some(a.kind().cmp(&b.kind()));
|
return Some(a.kind().cmp(&b.kind()));
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let a = a.eval_bits(tcx, param_env, ty);
|
let a = a.eval_bits(tcx, param_env);
|
||||||
let b = b.eval_bits(tcx, param_env, ty);
|
let b = b.eval_bits(tcx, param_env);
|
||||||
|
|
||||||
use rustc_apfloat::Float;
|
use rustc_apfloat::Float;
|
||||||
match *ty.kind() {
|
match *ty.kind() {
|
||||||
|
@ -973,10 +973,10 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn constant_usize(&self, val: u16) -> Operand<'tcx> {
|
fn constant_usize(&self, val: u16) -> Operand<'tcx> {
|
||||||
Operand::Constant(Box::new(Constant {
|
Operand::Constant(Box::new(ConstOperand {
|
||||||
span: self.source_info.span,
|
span: self.source_info.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::from_usize(self.tcx(), val.into()),
|
const_: Const::from_usize(self.tcx(), val.into()),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ impl PeekCall {
|
|||||||
if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
|
if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } =
|
||||||
&terminator.kind
|
&terminator.kind
|
||||||
{
|
{
|
||||||
if let ty::FnDef(def_id, fn_args) = *func.literal.ty().kind() {
|
if let ty::FnDef(def_id, fn_args) = *func.const_.ty().kind() {
|
||||||
let name = tcx.item_name(def_id);
|
let name = tcx.item_name(def_id);
|
||||||
if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek {
|
if !tcx.is_intrinsic(def_id) || name != sym::rustc_peek {
|
||||||
return None;
|
return None;
|
||||||
|
@ -225,7 +225,7 @@ pub trait ValueAnalysis<'tcx> {
|
|||||||
|
|
||||||
fn handle_constant(
|
fn handle_constant(
|
||||||
&self,
|
&self,
|
||||||
constant: &Constant<'tcx>,
|
constant: &ConstOperand<'tcx>,
|
||||||
state: &mut State<Self::Value>,
|
state: &mut State<Self::Value>,
|
||||||
) -> Self::Value {
|
) -> Self::Value {
|
||||||
self.super_constant(constant, state)
|
self.super_constant(constant, state)
|
||||||
@ -233,7 +233,7 @@ pub trait ValueAnalysis<'tcx> {
|
|||||||
|
|
||||||
fn super_constant(
|
fn super_constant(
|
||||||
&self,
|
&self,
|
||||||
_constant: &Constant<'tcx>,
|
_constant: &ConstOperand<'tcx>,
|
||||||
_state: &mut State<Self::Value>,
|
_state: &mut State<Self::Value>,
|
||||||
) -> Self::Value {
|
) -> Self::Value {
|
||||||
Self::Value::TOP
|
Self::Value::TOP
|
||||||
|
@ -181,13 +181,10 @@ fn insert_alignment_check<'tcx>(
|
|||||||
// Subtract 1 from the alignment to get the alignment mask
|
// Subtract 1 from the alignment to get the alignment mask
|
||||||
let alignment_mask =
|
let alignment_mask =
|
||||||
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
|
local_decls.push(LocalDecl::with_source_info(tcx.types.usize, source_info)).into();
|
||||||
let one = Operand::Constant(Box::new(Constant {
|
let one = Operand::Constant(Box::new(ConstOperand {
|
||||||
span: source_info.span,
|
span: source_info.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::Val(
|
const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)), tcx.types.usize),
|
||||||
ConstValue::Scalar(Scalar::from_target_usize(1, &tcx)),
|
|
||||||
tcx.types.usize,
|
|
||||||
),
|
|
||||||
}));
|
}));
|
||||||
block_data.statements.push(Statement {
|
block_data.statements.push(Statement {
|
||||||
source_info,
|
source_info,
|
||||||
@ -213,13 +210,10 @@ fn insert_alignment_check<'tcx>(
|
|||||||
|
|
||||||
// Check if the alignment bits are all zero
|
// Check if the alignment bits are all zero
|
||||||
let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
|
let is_ok = local_decls.push(LocalDecl::with_source_info(tcx.types.bool, source_info)).into();
|
||||||
let zero = Operand::Constant(Box::new(Constant {
|
let zero = Operand::Constant(Box::new(ConstOperand {
|
||||||
span: source_info.span,
|
span: source_info.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::Val(
|
const_: Const::Val(ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)), tcx.types.usize),
|
||||||
ConstValue::Scalar(Scalar::from_target_usize(0, &tcx)),
|
|
||||||
tcx.types.usize,
|
|
||||||
),
|
|
||||||
}));
|
}));
|
||||||
block_data.statements.push(Statement {
|
block_data.statements.push(Statement {
|
||||||
source_info,
|
source_info,
|
||||||
|
@ -142,9 +142,9 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
|||||||
|
|
||||||
fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
|
fn visit_operand(&mut self, op: &Operand<'tcx>, location: Location) {
|
||||||
if let Operand::Constant(constant) = op {
|
if let Operand::Constant(constant) = op {
|
||||||
let maybe_uneval = match constant.literal {
|
let maybe_uneval = match constant.const_ {
|
||||||
ConstantKind::Val(..) | ConstantKind::Ty(_) => None,
|
Const::Val(..) | Const::Ty(_) => None,
|
||||||
ConstantKind::Unevaluated(uv, _) => Some(uv),
|
Const::Unevaluated(uv, _) => Some(uv),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(uv) = maybe_uneval {
|
if let Some(uv) = maybe_uneval {
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
use rustc_middle::{
|
use rustc_middle::{
|
||||||
mir::{
|
mir::{
|
||||||
visit::{PlaceContext, Visitor},
|
visit::{PlaceContext, Visitor},
|
||||||
Body, Constant, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents,
|
Body, ConstOperand, Local, Location, Operand, Rvalue, StatementKind, VarDebugInfoContents,
|
||||||
},
|
},
|
||||||
ty::TyCtxt,
|
ty::TyCtxt,
|
||||||
};
|
};
|
||||||
@ -45,7 +45,7 @@ struct LocalUseVisitor {
|
|||||||
local_assignment_locations: IndexVec<Local, Option<Location>>,
|
local_assignment_locations: IndexVec<Local, Option<Location>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> {
|
fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, ConstOperand<'tcx>)> {
|
||||||
let mut visitor = LocalUseVisitor {
|
let mut visitor = LocalUseVisitor {
|
||||||
local_mutating_uses: IndexVec::from_elem(0, &body.local_decls),
|
local_mutating_uses: IndexVec::from_elem(0, &body.local_decls),
|
||||||
local_assignment_locations: IndexVec::from_elem(None, &body.local_decls),
|
local_assignment_locations: IndexVec::from_elem(None, &body.local_decls),
|
||||||
|
@ -96,10 +96,10 @@ impl<'tcx> Visitor<'tcx> for ConstGotoOptimizationFinder<'_, 'tcx> {
|
|||||||
let (discr, targets) = target_bb_terminator.kind.as_switch()?;
|
let (discr, targets) = target_bb_terminator.kind.as_switch()?;
|
||||||
if discr.place() == Some(*place) {
|
if discr.place() == Some(*place) {
|
||||||
let switch_ty = place.ty(self.body.local_decls(), self.tcx).ty;
|
let switch_ty = place.ty(self.body.local_decls(), self.tcx).ty;
|
||||||
|
debug_assert_eq!(switch_ty, _const.ty());
|
||||||
// We now know that the Switch matches on the const place, and it is statementless
|
// We now know that the Switch matches on the const place, and it is statementless
|
||||||
// Now find which value in the Switch matches the const value.
|
// Now find which value in the Switch matches the const value.
|
||||||
let const_value =
|
let const_value = _const.const_.try_eval_bits(self.tcx, self.param_env)?;
|
||||||
_const.literal.try_eval_bits(self.tcx, self.param_env, switch_ty)?;
|
|
||||||
let target_to_use_in_goto = targets.target_for_value(const_value);
|
let target_to_use_in_goto = targets.target_for_value(const_value);
|
||||||
self.optimizations.push(OptimizationToApply {
|
self.optimizations.push(OptimizationToApply {
|
||||||
bb_with_goto: location.block,
|
bb_with_goto: location.block,
|
||||||
|
@ -525,7 +525,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<ConstantKind<'tcx>> {
|
fn replace_with_const(&mut self, place: Place<'tcx>) -> Option<Const<'tcx>> {
|
||||||
// This will return None if the above `const_prop` invocation only "wrote" a
|
// This will return None if the above `const_prop` invocation only "wrote" a
|
||||||
// type whose creation requires no write. E.g. a generator whose initial state
|
// type whose creation requires no write. E.g. a generator whose initial state
|
||||||
// consists solely of uninitialized memory (so it doesn't capture any locals).
|
// consists solely of uninitialized memory (so it doesn't capture any locals).
|
||||||
@ -541,7 +541,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
let Right(imm) = imm else { return None };
|
let Right(imm) = imm else { return None };
|
||||||
match *imm {
|
match *imm {
|
||||||
Immediate::Scalar(scalar) if scalar.try_to_int().is_ok() => {
|
Immediate::Scalar(scalar) if scalar.try_to_int().is_ok() => {
|
||||||
Some(ConstantKind::from_scalar(self.tcx, scalar, value.layout.ty))
|
Some(Const::from_scalar(self.tcx, scalar, value.layout.ty))
|
||||||
}
|
}
|
||||||
Immediate::ScalarPair(l, r) if l.try_to_int().is_ok() && r.try_to_int().is_ok() => {
|
Immediate::ScalarPair(l, r) if l.try_to_int().is_ok() && r.try_to_int().is_ok() => {
|
||||||
let alloc_id = self
|
let alloc_id = self
|
||||||
@ -551,7 +551,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
})
|
})
|
||||||
.ok()?;
|
.ok()?;
|
||||||
|
|
||||||
Some(ConstantKind::Val(
|
Some(Const::Val(
|
||||||
ConstValue::Indirect { alloc_id, offset: Size::ZERO },
|
ConstValue::Indirect { alloc_id, offset: Size::ZERO },
|
||||||
value.layout.ty,
|
value.layout.ty,
|
||||||
))
|
))
|
||||||
@ -731,7 +731,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
|||||||
if let Some(()) = self.eval_rvalue_with_identities(rvalue, *place) {
|
if let Some(()) = self.eval_rvalue_with_identities(rvalue, *place) {
|
||||||
// If this was already an evaluated constant, keep it.
|
// If this was already an evaluated constant, keep it.
|
||||||
if let Rvalue::Use(Operand::Constant(c)) = rvalue
|
if let Rvalue::Use(Operand::Constant(c)) = rvalue
|
||||||
&& let ConstantKind::Val(..) = c.literal
|
&& let Const::Val(..) = c.const_
|
||||||
{
|
{
|
||||||
trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
|
trace!("skipping replace of Rvalue::Use({:?} because it is already a const", c);
|
||||||
} else if let Some(operand) = self.replace_with_const(*place) {
|
} else if let Some(operand) = self.replace_with_const(*place) {
|
||||||
|
@ -281,7 +281,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the value, if any, of evaluating `c`.
|
/// Returns the value, if any, of evaluating `c`.
|
||||||
fn eval_constant(&mut self, c: &Constant<'tcx>, location: Location) -> Option<OpTy<'tcx>> {
|
fn eval_constant(&mut self, c: &ConstOperand<'tcx>, location: Location) -> Option<OpTy<'tcx>> {
|
||||||
// FIXME we need to revisit this for #67176
|
// FIXME we need to revisit this for #67176
|
||||||
if c.has_param() {
|
if c.has_param() {
|
||||||
return None;
|
return None;
|
||||||
@ -293,7 +293,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
|||||||
// that the `RevealAll` pass has happened and that the body's consts
|
// that the `RevealAll` pass has happened and that the body's consts
|
||||||
// are normalized, so any call to resolve before that needs to be
|
// are normalized, so any call to resolve before that needs to be
|
||||||
// manually normalized.
|
// manually normalized.
|
||||||
let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.literal).ok()?;
|
let val = self.tcx.try_normalize_erasing_regions(self.param_env, c.const_).ok()?;
|
||||||
|
|
||||||
self.use_ecx(location, |this| this.ecx.eval_mir_constant(&val, Some(c.span), None))
|
self.use_ecx(location, |this| this.ecx.eval_mir_constant(&val, Some(c.span), None))
|
||||||
}
|
}
|
||||||
@ -580,7 +580,7 @@ impl<'tcx> Visitor<'tcx> for ConstPropagator<'_, 'tcx> {
|
|||||||
self.super_operand(operand, location);
|
self.super_operand(operand, location);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_constant(&mut self, constant: &Constant<'tcx>, location: Location) {
|
fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, location: Location) {
|
||||||
trace!("visit_constant: {:?}", constant);
|
trace!("visit_constant: {:?}", constant);
|
||||||
self.super_constant(constant, location);
|
self.super_constant(constant, location);
|
||||||
self.eval_constant(constant, location);
|
self.eval_constant(constant, location);
|
||||||
|
@ -206,7 +206,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
|||||||
&& let operand_ty = operand.ty(self.local_decls, self.tcx)
|
&& let operand_ty = operand.ty(self.local_decls, self.tcx)
|
||||||
&& let Some(operand_ty) = operand_ty.builtin_deref(true)
|
&& let Some(operand_ty) = operand_ty.builtin_deref(true)
|
||||||
&& let ty::Array(_, len) = operand_ty.ty.kind()
|
&& let ty::Array(_, len) = operand_ty.ty.kind()
|
||||||
&& let Some(len) = ConstantKind::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env)
|
&& let Some(len) = Const::Ty(*len).try_eval_scalar_int(self.tcx, self.param_env)
|
||||||
{
|
{
|
||||||
state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map());
|
state.insert_value_idx(target_len, FlatSet::Elem(len.into()), self.map());
|
||||||
}
|
}
|
||||||
@ -224,7 +224,7 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
|||||||
Rvalue::Len(place) => {
|
Rvalue::Len(place) => {
|
||||||
let place_ty = place.ty(self.local_decls, self.tcx);
|
let place_ty = place.ty(self.local_decls, self.tcx);
|
||||||
if let ty::Array(_, len) = place_ty.ty.kind() {
|
if let ty::Array(_, len) = place_ty.ty.kind() {
|
||||||
ConstantKind::Ty(*len)
|
Const::Ty(*len)
|
||||||
.try_eval_scalar(self.tcx, self.param_env)
|
.try_eval_scalar(self.tcx, self.param_env)
|
||||||
.map_or(FlatSet::Top, FlatSet::Elem)
|
.map_or(FlatSet::Top, FlatSet::Elem)
|
||||||
} else if let [ProjectionElem::Deref] = place.projection[..] {
|
} else if let [ProjectionElem::Deref] = place.projection[..] {
|
||||||
@ -295,11 +295,11 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
|
|||||||
|
|
||||||
fn handle_constant(
|
fn handle_constant(
|
||||||
&self,
|
&self,
|
||||||
constant: &Constant<'tcx>,
|
constant: &ConstOperand<'tcx>,
|
||||||
_state: &mut State<Self::Value>,
|
_state: &mut State<Self::Value>,
|
||||||
) -> Self::Value {
|
) -> Self::Value {
|
||||||
constant
|
constant
|
||||||
.literal
|
.const_
|
||||||
.try_eval_scalar(self.tcx, self.param_env)
|
.try_eval_scalar(self.tcx, self.param_env)
|
||||||
.map_or(FlatSet::Top, FlatSet::Elem)
|
.map_or(FlatSet::Top, FlatSet::Elem)
|
||||||
}
|
}
|
||||||
@ -360,7 +360,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Operand::Constant(box constant) => {
|
Operand::Constant(box constant) => {
|
||||||
if let Ok(constant) = self.ecx.eval_mir_constant(&constant.literal, None, None) {
|
if let Ok(constant) = self.ecx.eval_mir_constant(&constant.const_, None, None) {
|
||||||
self.assign_constant(state, place, constant, &[]);
|
self.assign_constant(state, place, constant, &[]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -518,10 +518,10 @@ pub(crate) struct Patch<'tcx> {
|
|||||||
/// For a given MIR location, this stores the values of the operands used by that location. In
|
/// For a given MIR location, this stores the values of the operands used by that location. In
|
||||||
/// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
|
/// particular, this is before the effect, such that the operands of `_1 = _1 + _2` are
|
||||||
/// properly captured. (This may become UB soon, but it is currently emitted even by safe code.)
|
/// properly captured. (This may become UB soon, but it is currently emitted even by safe code.)
|
||||||
pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), ConstantKind<'tcx>>,
|
pub(crate) before_effect: FxHashMap<(Location, Place<'tcx>), Const<'tcx>>,
|
||||||
|
|
||||||
/// Stores the assigned values for assignments where the Rvalue is constant.
|
/// Stores the assigned values for assignments where the Rvalue is constant.
|
||||||
pub(crate) assignments: FxHashMap<Location, ConstantKind<'tcx>>,
|
pub(crate) assignments: FxHashMap<Location, Const<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Patch<'tcx> {
|
impl<'tcx> Patch<'tcx> {
|
||||||
@ -529,8 +529,8 @@ impl<'tcx> Patch<'tcx> {
|
|||||||
Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
|
Self { tcx, before_effect: FxHashMap::default(), assignments: FxHashMap::default() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_operand(&self, literal: ConstantKind<'tcx>) -> Operand<'tcx> {
|
fn make_operand(&self, const_: Const<'tcx>) -> Operand<'tcx> {
|
||||||
Operand::Constant(Box::new(Constant { span: DUMMY_SP, user_ty: None, literal }))
|
Operand::Constant(Box::new(ConstOperand { span: DUMMY_SP, user_ty: None, const_ }))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,12 +549,12 @@ impl<'tcx, 'locals> Collector<'tcx, 'locals> {
|
|||||||
place: Place<'tcx>,
|
place: Place<'tcx>,
|
||||||
state: &State<FlatSet<Scalar>>,
|
state: &State<FlatSet<Scalar>>,
|
||||||
map: &Map,
|
map: &Map,
|
||||||
) -> Option<ConstantKind<'tcx>> {
|
) -> Option<Const<'tcx>> {
|
||||||
let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else {
|
let FlatSet::Elem(Scalar::Int(value)) = state.get(place.as_ref(), &map) else {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let ty = place.ty(self.local_decls, self.patch.tcx).ty;
|
let ty = place.ty(self.local_decls, self.patch.tcx).ty;
|
||||||
Some(ConstantKind::Val(ConstValue::Scalar(value.into()), ty))
|
Some(Const::Val(ConstValue::Scalar(value.into()), ty))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ fn rvalue_hash<H: Hasher>(hasher: &mut H, rvalue: &Rvalue<'_>) {
|
|||||||
|
|
||||||
fn operand_hash<H: Hasher>(hasher: &mut H, operand: &Operand<'_>) {
|
fn operand_hash<H: Hasher>(hasher: &mut H, operand: &Operand<'_>) {
|
||||||
match operand {
|
match operand {
|
||||||
Operand::Constant(box Constant { user_ty: _, literal, span: _ }) => literal.hash(hasher),
|
Operand::Constant(box ConstOperand { user_ty: _, const_, span: _ }) => const_.hash(hasher),
|
||||||
x => x.hash(hasher),
|
x => x.hash(hasher),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -179,9 +179,9 @@ fn rvalue_eq<'tcx>(lhs: &Rvalue<'tcx>, rhs: &Rvalue<'tcx>) -> bool {
|
|||||||
fn operand_eq<'tcx>(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool {
|
fn operand_eq<'tcx>(lhs: &Operand<'tcx>, rhs: &Operand<'tcx>) -> bool {
|
||||||
let res = match (lhs, rhs) {
|
let res = match (lhs, rhs) {
|
||||||
(
|
(
|
||||||
Operand::Constant(box Constant { user_ty: _, literal, span: _ }),
|
Operand::Constant(box ConstOperand { user_ty: _, const_, span: _ }),
|
||||||
Operand::Constant(box Constant { user_ty: _, literal: literal2, span: _ }),
|
Operand::Constant(box ConstOperand { user_ty: _, const_: const2, span: _ }),
|
||||||
) => literal == literal2,
|
) => const_ == const2,
|
||||||
(x, y) => x == y,
|
(x, y) => x == y,
|
||||||
};
|
};
|
||||||
debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res);
|
debug!("operand_eq lhs: `{:?}` rhs: `{:?}` result: {:?}", lhs, rhs, res);
|
||||||
|
@ -402,10 +402,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
|
fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
|
||||||
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||||
span,
|
span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::from_bool(self.tcx, val),
|
const_: Const::from_bool(self.tcx, val),
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1189,10 +1189,10 @@ fn insert_panic_block<'tcx>(
|
|||||||
) -> BasicBlock {
|
) -> BasicBlock {
|
||||||
let assert_block = BasicBlock::new(body.basic_blocks.len());
|
let assert_block = BasicBlock::new(body.basic_blocks.len());
|
||||||
let term = TerminatorKind::Assert {
|
let term = TerminatorKind::Assert {
|
||||||
cond: Operand::Constant(Box::new(Constant {
|
cond: Operand::Constant(Box::new(ConstOperand {
|
||||||
span: body.span,
|
span: body.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::from_bool(tcx, false),
|
const_: Const::from_bool(tcx, false),
|
||||||
})),
|
})),
|
||||||
expected: true,
|
expected: true,
|
||||||
msg: Box::new(message),
|
msg: Box::new(message),
|
||||||
|
@ -652,11 +652,11 @@ impl<'tcx> Inliner<'tcx> {
|
|||||||
// `required_consts`, here we may not only have `ConstKind::Unevaluated`
|
// `required_consts`, here we may not only have `ConstKind::Unevaluated`
|
||||||
// because we are calling `subst_and_normalize_erasing_regions`.
|
// because we are calling `subst_and_normalize_erasing_regions`.
|
||||||
caller_body.required_consts.extend(
|
caller_body.required_consts.extend(
|
||||||
callee_body.required_consts.iter().copied().filter(|&ct| match ct.literal {
|
callee_body.required_consts.iter().copied().filter(|&ct| match ct.const_ {
|
||||||
ConstantKind::Ty(_) => {
|
Const::Ty(_) => {
|
||||||
bug!("should never encounter ty::UnevaluatedConst in `required_consts`")
|
bug!("should never encounter ty::UnevaluatedConst in `required_consts`")
|
||||||
}
|
}
|
||||||
ConstantKind::Val(..) | ConstantKind::Unevaluated(..) => true,
|
Const::Val(..) | Const::Unevaluated(..) => true,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -824,7 +824,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
|
TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
|
||||||
let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.literal.ty()));
|
let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder::bind(&f.const_.ty()));
|
||||||
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
|
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
|
||||||
// Don't give intrinsics the extra penalty for calls
|
// Don't give intrinsics the extra penalty for calls
|
||||||
INSTR_COST
|
INSTR_COST
|
||||||
|
@ -104,7 +104,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
|
|||||||
|
|
||||||
fn try_eval_bool(&self, a: &Operand<'_>) -> Option<bool> {
|
fn try_eval_bool(&self, a: &Operand<'_>) -> Option<bool> {
|
||||||
let a = a.constant()?;
|
let a = a.constant()?;
|
||||||
if a.literal.ty().is_bool() { a.literal.try_to_bool() } else { None }
|
if a.const_.ty().is_bool() { a.const_.try_to_bool() } else { None }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Transform "&(*a)" ==> "a".
|
/// Transform "&(*a)" ==> "a".
|
||||||
@ -136,8 +136,8 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let literal = ConstantKind::from_ty_const(len, self.tcx);
|
let const_ = Const::from_ty_const(len, self.tcx);
|
||||||
let constant = Constant { span: source_info.span, literal, user_ty: None };
|
let constant = ConstOperand { span: source_info.span, const_, user_ty: None };
|
||||||
*rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
|
*rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,10 +149,10 @@ impl EnumSizeOpt {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let place = Place::from(size_array_local);
|
let place = Place::from(size_array_local);
|
||||||
let constant_vals = Constant {
|
let constant_vals = ConstOperand {
|
||||||
span,
|
span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::Val(
|
const_: Const::Val(
|
||||||
ConstValue::Indirect { alloc_id, offset: Size::ZERO },
|
ConstValue::Indirect { alloc_id, offset: Size::ZERO },
|
||||||
tmp_ty,
|
tmp_ty,
|
||||||
),
|
),
|
||||||
|
@ -31,9 +31,9 @@ use rustc_hir::intravisit::{self, Visitor};
|
|||||||
use rustc_index::IndexVec;
|
use rustc_index::IndexVec;
|
||||||
use rustc_middle::mir::visit::Visitor as _;
|
use rustc_middle::mir::visit::Visitor as _;
|
||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstQualifs, Constant, LocalDecl,
|
traversal, AnalysisPhase, Body, CallSource, ClearCrossCrate, ConstOperand, ConstQualifs,
|
||||||
MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
|
LocalDecl, MirPass, MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue,
|
||||||
Statement, StatementKind, TerminatorKind, START_BLOCK,
|
SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK,
|
||||||
};
|
};
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
|
||||||
@ -149,14 +149,14 @@ fn remap_mir_for_const_eval_select<'tcx>(
|
|||||||
let terminator = bb.terminator.as_mut().expect("invalid terminator");
|
let terminator = bb.terminator.as_mut().expect("invalid terminator");
|
||||||
match terminator.kind {
|
match terminator.kind {
|
||||||
TerminatorKind::Call {
|
TerminatorKind::Call {
|
||||||
func: Operand::Constant(box Constant { ref literal, .. }),
|
func: Operand::Constant(box ConstOperand { ref const_, .. }),
|
||||||
ref mut args,
|
ref mut args,
|
||||||
destination,
|
destination,
|
||||||
target,
|
target,
|
||||||
unwind,
|
unwind,
|
||||||
fn_span,
|
fn_span,
|
||||||
..
|
..
|
||||||
} if let ty::FnDef(def_id, _) = *literal.ty().kind()
|
} if let ty::FnDef(def_id, _) = *const_.ty().kind()
|
||||||
&& tcx.item_name(def_id) == sym::const_eval_select
|
&& tcx.item_name(def_id) == sym::const_eval_select
|
||||||
&& tcx.is_intrinsic(def_id) =>
|
&& tcx.is_intrinsic(def_id) =>
|
||||||
{
|
{
|
||||||
|
@ -32,10 +32,10 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
|
|||||||
source_info: terminator.source_info,
|
source_info: terminator.source_info,
|
||||||
kind: StatementKind::Assign(Box::new((
|
kind: StatementKind::Assign(Box::new((
|
||||||
*destination,
|
*destination,
|
||||||
Rvalue::Use(Operand::Constant(Box::new(Constant {
|
Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||||
span: terminator.source_info.span,
|
span: terminator.source_info.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::zero_sized(tcx.types.unit),
|
const_: Const::zero_sized(tcx.types.unit),
|
||||||
}))),
|
}))),
|
||||||
))),
|
))),
|
||||||
});
|
});
|
||||||
|
@ -98,10 +98,10 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
|||||||
StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
|
StatementKind::Assign(box (lhs_f, Rvalue::Use(Operand::Constant(f_c)))),
|
||||||
StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
|
StatementKind::Assign(box (lhs_s, Rvalue::Use(Operand::Constant(s_c)))),
|
||||||
) if lhs_f == lhs_s
|
) if lhs_f == lhs_s
|
||||||
&& f_c.literal.ty().is_bool()
|
&& f_c.const_.ty().is_bool()
|
||||||
&& s_c.literal.ty().is_bool()
|
&& s_c.const_.ty().is_bool()
|
||||||
&& f_c.literal.try_eval_bool(tcx, param_env).is_some()
|
&& f_c.const_.try_eval_bool(tcx, param_env).is_some()
|
||||||
&& s_c.literal.try_eval_bool(tcx, param_env).is_some() => {}
|
&& s_c.const_.try_eval_bool(tcx, param_env).is_some() => {}
|
||||||
|
|
||||||
// Otherwise we cannot optimize. Try another block.
|
// Otherwise we cannot optimize. Try another block.
|
||||||
_ => continue 'outer,
|
_ => continue 'outer,
|
||||||
@ -128,8 +128,8 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
|
|||||||
StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))),
|
StatementKind::Assign(box (_, Rvalue::Use(Operand::Constant(s_c)))),
|
||||||
) => {
|
) => {
|
||||||
// From earlier loop we know that we are dealing with bool constants only:
|
// From earlier loop we know that we are dealing with bool constants only:
|
||||||
let f_b = f_c.literal.try_eval_bool(tcx, param_env).unwrap();
|
let f_b = f_c.const_.try_eval_bool(tcx, param_env).unwrap();
|
||||||
let s_b = s_c.literal.try_eval_bool(tcx, param_env).unwrap();
|
let s_b = s_c.const_.try_eval_bool(tcx, param_env).unwrap();
|
||||||
if f_b == s_b {
|
if f_b == s_b {
|
||||||
// Same value in both blocks. Use statement as is.
|
// Same value in both blocks. Use statement as is.
|
||||||
(*f).clone()
|
(*f).clone()
|
||||||
|
@ -90,10 +90,10 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
|
|||||||
&& let [PlaceElem::Deref] = &place.projection[..]
|
&& let [PlaceElem::Deref] = &place.projection[..]
|
||||||
&& let Some(len) = self.slice_lengths[place.local]
|
&& let Some(len) = self.slice_lengths[place.local]
|
||||||
{
|
{
|
||||||
*rvalue = Rvalue::Use(Operand::Constant(Box::new(Constant {
|
*rvalue = Rvalue::Use(Operand::Constant(Box::new(ConstOperand {
|
||||||
span: rustc_span::DUMMY_SP,
|
span: rustc_span::DUMMY_SP,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::from_ty_const(len, self.tcx),
|
const_: Const::from_ty_const(len, self.tcx),
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
self.super_rvalue(rvalue, loc);
|
self.super_rvalue(rvalue, loc);
|
||||||
|
@ -62,12 +62,12 @@ impl<'tcx> Replacer<'_, 'tcx> {
|
|||||||
layout.is_zst()
|
layout.is_zst()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_zst(&self, ty: Ty<'tcx>) -> Constant<'tcx> {
|
fn make_zst(&self, ty: Ty<'tcx>) -> ConstOperand<'tcx> {
|
||||||
debug_assert!(self.known_to_be_zst(ty));
|
debug_assert!(self.known_to_be_zst(ty));
|
||||||
Constant {
|
ConstOperand {
|
||||||
span: rustc_span::DUMMY_SP,
|
span: rustc_span::DUMMY_SP,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::Val(ConstValue::ZeroSized, ty),
|
const_: Const::Val(ConstValue::ZeroSized, ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,27 @@
|
|||||||
use rustc_middle::mir::visit::Visitor;
|
use rustc_middle::mir::visit::Visitor;
|
||||||
use rustc_middle::mir::{Constant, ConstantKind, Location};
|
use rustc_middle::mir::{Const, ConstOperand, Location};
|
||||||
use rustc_middle::ty::ConstKind;
|
use rustc_middle::ty::ConstKind;
|
||||||
|
|
||||||
pub struct RequiredConstsVisitor<'a, 'tcx> {
|
pub struct RequiredConstsVisitor<'a, 'tcx> {
|
||||||
required_consts: &'a mut Vec<Constant<'tcx>>,
|
required_consts: &'a mut Vec<ConstOperand<'tcx>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> {
|
impl<'a, 'tcx> RequiredConstsVisitor<'a, 'tcx> {
|
||||||
pub fn new(required_consts: &'a mut Vec<Constant<'tcx>>) -> Self {
|
pub fn new(required_consts: &'a mut Vec<ConstOperand<'tcx>>) -> Self {
|
||||||
RequiredConstsVisitor { required_consts }
|
RequiredConstsVisitor { required_consts }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
|
impl<'tcx> Visitor<'tcx> for RequiredConstsVisitor<'_, 'tcx> {
|
||||||
fn visit_constant(&mut self, constant: &Constant<'tcx>, _: Location) {
|
fn visit_constant(&mut self, constant: &ConstOperand<'tcx>, _: Location) {
|
||||||
let literal = constant.literal;
|
let const_ = constant.const_;
|
||||||
match literal {
|
match const_ {
|
||||||
ConstantKind::Ty(c) => match c.kind() {
|
Const::Ty(c) => match c.kind() {
|
||||||
ConstKind::Param(_) | ConstKind::Error(_) | ConstKind::Value(_) => {}
|
ConstKind::Param(_) | ConstKind::Error(_) | ConstKind::Value(_) => {}
|
||||||
_ => bug!("only ConstKind::Param/Value should be encountered here, got {:#?}", c),
|
_ => bug!("only ConstKind::Param/Value should be encountered here, got {:#?}", c),
|
||||||
},
|
},
|
||||||
ConstantKind::Unevaluated(..) => self.required_consts.push(*constant),
|
Const::Unevaluated(..) => self.required_consts.push(*constant),
|
||||||
ConstantKind::Val(..) => {}
|
Const::Val(..) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,12 +35,12 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _: Location) {
|
fn visit_constant(&mut self, constant: &mut ConstOperand<'tcx>, _: Location) {
|
||||||
// We have to use `try_normalize_erasing_regions` here, since it's
|
// We have to use `try_normalize_erasing_regions` here, since it's
|
||||||
// possible that we visit impossible-to-satisfy where clauses here,
|
// possible that we visit impossible-to-satisfy where clauses here,
|
||||||
// see #91745
|
// see #91745
|
||||||
if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.literal) {
|
if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.const_) {
|
||||||
constant.literal = c;
|
constant.const_ = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -497,10 +497,10 @@ impl<'tcx> CloneShimBuilder<'tcx> {
|
|||||||
|
|
||||||
// `func == Clone::clone(&ty) -> ty`
|
// `func == Clone::clone(&ty) -> ty`
|
||||||
let func_ty = Ty::new_fn_def(tcx, self.def_id, [ty]);
|
let func_ty = Ty::new_fn_def(tcx, self.def_id, [ty]);
|
||||||
let func = Operand::Constant(Box::new(Constant {
|
let func = Operand::Constant(Box::new(ConstOperand {
|
||||||
span: self.span,
|
span: self.span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::zero_sized(func_ty),
|
const_: Const::zero_sized(func_ty),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let ref_loc = self.make_place(
|
let ref_loc = self.make_place(
|
||||||
@ -764,10 +764,10 @@ fn build_call_shim<'tcx>(
|
|||||||
CallKind::Direct(def_id) => {
|
CallKind::Direct(def_id) => {
|
||||||
let ty = tcx.type_of(def_id).instantiate_identity();
|
let ty = tcx.type_of(def_id).instantiate_identity();
|
||||||
(
|
(
|
||||||
Operand::Constant(Box::new(Constant {
|
Operand::Constant(Box::new(ConstOperand {
|
||||||
span,
|
span,
|
||||||
user_ty: None,
|
user_ty: None,
|
||||||
literal: ConstantKind::zero_sized(ty),
|
const_: Const::zero_sized(ty),
|
||||||
})),
|
})),
|
||||||
rcvr.into_iter().collect::<Vec<_>>(),
|
rcvr.into_iter().collect::<Vec<_>>(),
|
||||||
)
|
)
|
||||||
|
@ -23,7 +23,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
|
|||||||
TerminatorKind::SwitchInt {
|
TerminatorKind::SwitchInt {
|
||||||
discr: Operand::Constant(ref c), ref targets, ..
|
discr: Operand::Constant(ref c), ref targets, ..
|
||||||
} => {
|
} => {
|
||||||
let constant = c.literal.try_eval_bits(tcx, param_env, c.ty());
|
let constant = c.const_.try_eval_bits(tcx, param_env);
|
||||||
if let Some(constant) = constant {
|
if let Some(constant) = constant {
|
||||||
let target = targets.target_for_value(constant);
|
let target = targets.target_for_value(constant);
|
||||||
TerminatorKind::Goto { target }
|
TerminatorKind::Goto { target }
|
||||||
@ -33,7 +33,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
|
|||||||
}
|
}
|
||||||
TerminatorKind::Assert {
|
TerminatorKind::Assert {
|
||||||
target, cond: Operand::Constant(ref c), expected, ..
|
target, cond: Operand::Constant(ref c), expected, ..
|
||||||
} => match c.literal.try_eval_bool(tcx, param_env) {
|
} => match c.const_.try_eval_bool(tcx, param_env) {
|
||||||
Some(v) if v == expected => TerminatorKind::Goto { target },
|
Some(v) if v == expected => TerminatorKind::Goto { target },
|
||||||
_ => continue,
|
_ => continue,
|
||||||
},
|
},
|
||||||
|
@ -206,12 +206,12 @@ fn find_branch_value_info<'tcx>(
|
|||||||
match (left, right) {
|
match (left, right) {
|
||||||
(Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on))
|
(Constant(branch_value), Copy(to_switch_on) | Move(to_switch_on))
|
||||||
| (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => {
|
| (Copy(to_switch_on) | Move(to_switch_on), Constant(branch_value)) => {
|
||||||
let branch_value_ty = branch_value.literal.ty();
|
let branch_value_ty = branch_value.const_.ty();
|
||||||
// we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats
|
// we only want to apply this optimization if we are matching on integrals (and chars), as it is not possible to switch on floats
|
||||||
if !branch_value_ty.is_integral() && !branch_value_ty.is_char() {
|
if !branch_value_ty.is_integral() && !branch_value_ty.is_char() {
|
||||||
return None;
|
return None;
|
||||||
};
|
};
|
||||||
let branch_value_scalar = branch_value.literal.try_to_scalar()?;
|
let branch_value_scalar = branch_value.const_.try_to_scalar()?;
|
||||||
Some((branch_value_scalar, branch_value_ty, *to_switch_on))
|
Some((branch_value_scalar, branch_value_ty, *to_switch_on))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
|
@ -746,20 +746,20 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
|
|||||||
/// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily
|
/// to walk it would attempt to evaluate the `ty::Const` inside, which doesn't necessarily
|
||||||
/// work, as some constants cannot be represented in the type system.
|
/// work, as some constants cannot be represented in the type system.
|
||||||
#[instrument(skip(self), level = "debug")]
|
#[instrument(skip(self), level = "debug")]
|
||||||
fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
|
fn visit_constant(&mut self, constant: &mir::ConstOperand<'tcx>, location: Location) {
|
||||||
let literal = self.monomorphize(constant.literal);
|
let const_ = self.monomorphize(constant.const_);
|
||||||
let param_env = ty::ParamEnv::reveal_all();
|
let param_env = ty::ParamEnv::reveal_all();
|
||||||
let val = match literal.eval(self.tcx, param_env, None) {
|
let val = match const_.eval(self.tcx, param_env, None) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(ErrorHandled::Reported(..)) => return,
|
Err(ErrorHandled::Reported(..)) => return,
|
||||||
Err(ErrorHandled::TooGeneric(..)) => span_bug!(
|
Err(ErrorHandled::TooGeneric(..)) => span_bug!(
|
||||||
self.body.source_info(location).span,
|
self.body.source_info(location).span,
|
||||||
"collection encountered polymorphic constant: {:?}",
|
"collection encountered polymorphic constant: {:?}",
|
||||||
literal
|
const_
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
collect_const_value(self.tcx, val, self.output);
|
collect_const_value(self.tcx, val, self.output);
|
||||||
MirVisitor::visit_ty(self, literal.ty(), TyContext::Location(location));
|
MirVisitor::visit_ty(self, const_.ty(), TyContext::Location(location));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
|
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) {
|
||||||
@ -796,7 +796,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirUsedCollector<'a, 'tcx> {
|
|||||||
for op in operands {
|
for op in operands {
|
||||||
match *op {
|
match *op {
|
||||||
mir::InlineAsmOperand::SymFn { ref value } => {
|
mir::InlineAsmOperand::SymFn { ref value } => {
|
||||||
let fn_ty = self.monomorphize(value.literal.ty());
|
let fn_ty = self.monomorphize(value.const_.ty());
|
||||||
visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output, &[]);
|
visit_fn_use(self.tcx, fn_ty, false, source, &mut self.output, &[]);
|
||||||
}
|
}
|
||||||
mir::InlineAsmOperand::SymStatic { def_id } => {
|
mir::InlineAsmOperand::SymStatic { def_id } => {
|
||||||
|
@ -9,13 +9,13 @@ use rustc_hir::{def::DefKind, def_id::DefId, ConstContext};
|
|||||||
use rustc_middle::mir::{
|
use rustc_middle::mir::{
|
||||||
self,
|
self,
|
||||||
visit::{TyContext, Visitor},
|
visit::{TyContext, Visitor},
|
||||||
Constant, ConstantKind, Local, LocalDecl, Location,
|
Local, LocalDecl, Location,
|
||||||
};
|
};
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self,
|
self,
|
||||||
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor},
|
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor},
|
||||||
Const, GenericArgsRef, Ty, TyCtxt, UnusedGenericParams,
|
GenericArgsRef, Ty, TyCtxt, UnusedGenericParams,
|
||||||
};
|
};
|
||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
@ -261,12 +261,12 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
|||||||
self.super_local_decl(local, local_decl);
|
self.super_local_decl(local, local_decl);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_constant(&mut self, ct: &Constant<'tcx>, location: Location) {
|
fn visit_constant(&mut self, ct: &mir::ConstOperand<'tcx>, location: Location) {
|
||||||
match ct.literal {
|
match ct.const_ {
|
||||||
ConstantKind::Ty(c) => {
|
mir::Const::Ty(c) => {
|
||||||
c.visit_with(self);
|
c.visit_with(self);
|
||||||
}
|
}
|
||||||
ConstantKind::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => {
|
mir::Const::Unevaluated(mir::UnevaluatedConst { def, args: _, promoted }, ty) => {
|
||||||
// Avoid considering `T` unused when constants are of the form:
|
// Avoid considering `T` unused when constants are of the form:
|
||||||
// `<Self as Foo<T>>::foo::promoted[p]`
|
// `<Self as Foo<T>>::foo::promoted[p]`
|
||||||
if let Some(p) = promoted {
|
if let Some(p) = promoted {
|
||||||
@ -280,7 +280,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
|||||||
|
|
||||||
Visitor::visit_ty(self, ty, TyContext::Location(location));
|
Visitor::visit_ty(self, ty, TyContext::Location(location));
|
||||||
}
|
}
|
||||||
ConstantKind::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)),
|
mir::Const::Val(_, ty) => Visitor::visit_ty(self, ty, TyContext::Location(location)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -291,7 +291,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
|
|||||||
|
|
||||||
impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkUsedGenericParams<'a, 'tcx> {
|
impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkUsedGenericParams<'a, 'tcx> {
|
||||||
#[instrument(level = "debug", skip(self))]
|
#[instrument(level = "debug", skip(self))]
|
||||||
fn visit_const(&mut self, c: Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
fn visit_const(&mut self, c: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||||
if !c.has_non_region_param() {
|
if !c.has_non_region_param() {
|
||||||
return ControlFlow::Continue(());
|
return ControlFlow::Continue(());
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,8 @@ use crate::stable_mir::ty::{
|
|||||||
};
|
};
|
||||||
use crate::stable_mir::{self, CompilerError, Context};
|
use crate::stable_mir::{self, CompilerError, Context};
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
|
use rustc_middle::mir;
|
||||||
use rustc_middle::mir::interpret::{alloc_range, AllocId};
|
use rustc_middle::mir::interpret::{alloc_range, AllocId};
|
||||||
use rustc_middle::mir::{self, ConstantKind};
|
|
||||||
use rustc_middle::ty::{self, Ty, TyCtxt, Variance};
|
use rustc_middle::ty::{self, Ty, TyCtxt, Variance};
|
||||||
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
|
||||||
use rustc_span::ErrorGuaranteed;
|
use rustc_span::ErrorGuaranteed;
|
||||||
@ -539,14 +539,14 @@ impl<'tcx> Stable<'tcx> for mir::Operand<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Stable<'tcx> for mir::Constant<'tcx> {
|
impl<'tcx> Stable<'tcx> for mir::ConstOperand<'tcx> {
|
||||||
type T = stable_mir::mir::Constant;
|
type T = stable_mir::mir::Constant;
|
||||||
|
|
||||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
stable_mir::mir::Constant {
|
stable_mir::mir::Constant {
|
||||||
span: self.span.stable(tables),
|
span: self.span.stable(tables),
|
||||||
user_ty: self.user_ty.map(|u| u.as_usize()).or(None),
|
user_ty: self.user_ty.map(|u| u.as_usize()).or(None),
|
||||||
literal: self.literal.stable(tables),
|
literal: self.const_.stable(tables),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1247,13 +1247,13 @@ impl<'tcx> Stable<'tcx> for ty::TraitDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> {
|
impl<'tcx> Stable<'tcx> for rustc_middle::mir::Const<'tcx> {
|
||||||
type T = stable_mir::ty::Const;
|
type T = stable_mir::ty::Const;
|
||||||
|
|
||||||
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
fn stable(&self, tables: &mut Tables<'tcx>) -> Self::T {
|
||||||
match *self {
|
match *self {
|
||||||
ConstantKind::Ty(c) => c.stable(tables),
|
mir::Const::Ty(c) => c.stable(tables),
|
||||||
ConstantKind::Unevaluated(unev_const, ty) => stable_mir::ty::Const {
|
mir::Const::Unevaluated(unev_const, ty) => stable_mir::ty::Const {
|
||||||
literal: stable_mir::ty::ConstantKind::Unevaluated(
|
literal: stable_mir::ty::ConstantKind::Unevaluated(
|
||||||
stable_mir::ty::UnevaluatedConst {
|
stable_mir::ty::UnevaluatedConst {
|
||||||
def: tables.const_def(unev_const.def),
|
def: tables.const_def(unev_const.def),
|
||||||
@ -1263,7 +1263,7 @@ impl<'tcx> Stable<'tcx> for rustc_middle::mir::ConstantKind<'tcx> {
|
|||||||
),
|
),
|
||||||
ty: tables.intern_ty(ty),
|
ty: tables.intern_ty(ty),
|
||||||
},
|
},
|
||||||
ConstantKind::Val(val, ty) => stable_mir::ty::Const {
|
mir::Const::Val(val, ty) => stable_mir::ty::Const {
|
||||||
literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
|
literal: stable_mir::ty::ConstantKind::Allocated(alloc::new_allocation(
|
||||||
ty, val, tables,
|
ty, val, tables,
|
||||||
)),
|
)),
|
||||||
|
@ -118,7 +118,7 @@ fn encode_const<'tcx>(
|
|||||||
// bool value false is encoded as 0 and true as 1.
|
// bool value false is encoded as 0 and true as 1.
|
||||||
match c.ty().kind() {
|
match c.ty().kind() {
|
||||||
ty::Int(ity) => {
|
ty::Int(ity) => {
|
||||||
let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty());
|
let bits = c.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||||
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
let val = Integer::from_int_ty(&tcx, *ity).size().sign_extend(bits) as i128;
|
||||||
if val < 0 {
|
if val < 0 {
|
||||||
s.push('n');
|
s.push('n');
|
||||||
@ -126,7 +126,7 @@ fn encode_const<'tcx>(
|
|||||||
let _ = write!(s, "{val}");
|
let _ = write!(s, "{val}");
|
||||||
}
|
}
|
||||||
ty::Uint(_) => {
|
ty::Uint(_) => {
|
||||||
let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all(), c.ty());
|
let val = c.eval_bits(tcx, ty::ParamEnv::reveal_all());
|
||||||
let _ = write!(s, "{val}");
|
let _ = write!(s, "{val}");
|
||||||
}
|
}
|
||||||
ty::Bool => {
|
ty::Bool => {
|
||||||
|
@ -594,7 +594,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
|
|||||||
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
|
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
|
||||||
self = ty.print(self)?;
|
self = ty.print(self)?;
|
||||||
|
|
||||||
let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ty);
|
let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all());
|
||||||
|
|
||||||
// Negative integer values are mangled using `n` as a "sign prefix".
|
// Negative integer values are mangled using `n` as a "sign prefix".
|
||||||
if let ty::Int(ity) = ty.kind() {
|
if let ty::Int(ity) = ty.kind() {
|
||||||
|
@ -283,7 +283,7 @@ pub(crate) fn print_evaluated_const(
|
|||||||
(_, &ty::Ref(..)) => None,
|
(_, &ty::Ref(..)) => None,
|
||||||
(mir::ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
|
(mir::ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
|
||||||
(mir::ConstValue::Scalar(_), _) => {
|
(mir::ConstValue::Scalar(_), _) => {
|
||||||
let const_ = mir::ConstantKind::from_value(val, ty);
|
let const_ = mir::Const::from_value(val, ty);
|
||||||
Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type))
|
Some(print_const_with_custom_print_scalar(tcx, const_, underscores_and_type))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
@ -319,20 +319,20 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
|
|||||||
|
|
||||||
fn print_const_with_custom_print_scalar<'tcx>(
|
fn print_const_with_custom_print_scalar<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
ct: mir::ConstantKind<'tcx>,
|
ct: mir::Const<'tcx>,
|
||||||
underscores_and_type: bool,
|
underscores_and_type: bool,
|
||||||
) -> String {
|
) -> String {
|
||||||
// Use a slightly different format for integer types which always shows the actual value.
|
// Use a slightly different format for integer types which always shows the actual value.
|
||||||
// For all other types, fallback to the original `pretty_print_const`.
|
// For all other types, fallback to the original `pretty_print_const`.
|
||||||
match (ct, ct.ty().kind()) {
|
match (ct, ct.ty().kind()) {
|
||||||
(mir::ConstantKind::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => {
|
(mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Uint(ui)) => {
|
||||||
if underscores_and_type {
|
if underscores_and_type {
|
||||||
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
|
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
|
||||||
} else {
|
} else {
|
||||||
int.to_string()
|
int.to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(mir::ConstantKind::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => {
|
(mir::Const::Val(mir::ConstValue::Scalar(int), _), ty::Int(i)) => {
|
||||||
let ty = ct.ty();
|
let ty = ct.ty();
|
||||||
let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
|
let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
|
||||||
let data = int.assert_bits(size);
|
let data = int.assert_bits(size);
|
||||||
|
@ -50,7 +50,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
|
|||||||
.tcx
|
.tcx
|
||||||
.const_eval_poly(def_id.to_def_id())
|
.const_eval_poly(def_id.to_def_id())
|
||||||
.ok()
|
.ok()
|
||||||
.map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty));
|
.map(|val| rustc_middle::mir::Const::from_value(val, ty));
|
||||||
if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) {
|
if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) {
|
||||||
if let ty::Adt(adt, _) = ty.kind() {
|
if let ty::Adt(adt, _) = ty.kind() {
|
||||||
if adt.is_enum() {
|
if adt.is_enum() {
|
||||||
|
@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
|
|||||||
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
|
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
|
||||||
None => {
|
None => {
|
||||||
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
let min_val_const = ty.numeric_min_val(cx.tcx)?;
|
||||||
miri_to_const(cx, mir::ConstantKind::from_ty_const(min_val_const, cx.tcx))?
|
miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))?
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let rhs_const = match rhs {
|
let rhs_const = match rhs {
|
||||||
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
|
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
|
||||||
None => {
|
None => {
|
||||||
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
let max_val_const = ty.numeric_max_val(cx.tcx)?;
|
||||||
miri_to_const(cx, mir::ConstantKind::from_ty_const(max_val_const, cx.tcx))?
|
miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))?
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let lhs_val = lhs_const.int_value(cx, ty)?;
|
let lhs_val = lhs_const.int_value(cx, ty)?;
|
||||||
|
@ -21,7 +21,7 @@ use std::iter;
|
|||||||
/// A `LitKind`-like enum to fold constant `Expr`s into.
|
/// A `LitKind`-like enum to fold constant `Expr`s into.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Constant<'tcx> {
|
pub enum Constant<'tcx> {
|
||||||
Adt(rustc_middle::mir::ConstantKind<'tcx>),
|
Adt(rustc_middle::mir::Const<'tcx>),
|
||||||
/// A `String` (e.g., "abc").
|
/// A `String` (e.g., "abc").
|
||||||
Str(String),
|
Str(String),
|
||||||
/// A binary string (e.g., `b"abc"`).
|
/// A binary string (e.g., `b"abc"`).
|
||||||
@ -482,7 +482,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
.tcx
|
.tcx
|
||||||
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
|
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?;
|
.map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
|
||||||
let result = miri_to_const(self.lcx, result)?;
|
let result = miri_to_const(self.lcx, result)?;
|
||||||
self.source = ConstantSource::Constant;
|
self.source = ConstantSource::Constant;
|
||||||
Some(result)
|
Some(result)
|
||||||
@ -655,10 +655,10 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'tcx>) -> Option<Constant<'tcx>> {
|
pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
|
||||||
use rustc_middle::mir::ConstValue;
|
use rustc_middle::mir::ConstValue;
|
||||||
match result {
|
match result {
|
||||||
mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
|
mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
|
||||||
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||||
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
|
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
|
||||||
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
|
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
|
||||||
@ -671,11 +671,11 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t
|
|||||||
ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
|
ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
mir::ConstantKind::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) => {
|
mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) => {
|
||||||
let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
|
let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
|
||||||
String::from_utf8(data.to_owned()).ok().map(Constant::Str)
|
String::from_utf8(data.to_owned()).ok().map(Constant::Str)
|
||||||
}
|
}
|
||||||
mir::ConstantKind::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => {
|
mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => {
|
||||||
let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory();
|
let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory();
|
||||||
match result.ty().kind() {
|
match result.ty().kind() {
|
||||||
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
|
||||||
@ -714,17 +714,17 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::ConstantKind<'t
|
|||||||
fn field_of_struct<'tcx>(
|
fn field_of_struct<'tcx>(
|
||||||
adt_def: ty::AdtDef<'tcx>,
|
adt_def: ty::AdtDef<'tcx>,
|
||||||
lcx: &LateContext<'tcx>,
|
lcx: &LateContext<'tcx>,
|
||||||
result: mir::ConstantKind<'tcx>,
|
result: mir::Const<'tcx>,
|
||||||
field: &Ident,
|
field: &Ident,
|
||||||
) -> Option<mir::ConstantKind<'tcx>> {
|
) -> Option<mir::Const<'tcx>> {
|
||||||
if let mir::ConstantKind::Val(result, ty) = result
|
if let mir::Const::Val(result, ty) = result
|
||||||
&& let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_diagnostics((result, ty))
|
&& let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_diagnostics((result, ty))
|
||||||
&& let Some(dc_variant) = dc.variant
|
&& let Some(dc_variant) = dc.variant
|
||||||
&& let Some(variant) = adt_def.variants().get(dc_variant)
|
&& let Some(variant) = adt_def.variants().get(dc_variant)
|
||||||
&& let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name)
|
&& let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name)
|
||||||
&& let Some(&(val, ty)) = dc.fields.get(field_idx)
|
&& let Some(&(val, ty)) = dc.fields.get(field_idx)
|
||||||
{
|
{
|
||||||
Some(mir::ConstantKind::Val(val, ty))
|
Some(mir::Const::Val(val, ty))
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
None
|
None
|
||||||
|
@ -97,7 +97,7 @@ use rustc_hir::{
|
|||||||
use rustc_lexer::{tokenize, TokenKind};
|
use rustc_lexer::{tokenize, TokenKind};
|
||||||
use rustc_lint::{LateContext, Level, Lint, LintContext};
|
use rustc_lint::{LateContext, Level, Lint, LintContext};
|
||||||
use rustc_middle::hir::place::PlaceBase;
|
use rustc_middle::hir::place::PlaceBase;
|
||||||
use rustc_middle::mir::ConstantKind;
|
use rustc_middle::mir::Const;
|
||||||
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
|
||||||
use rustc_middle::ty::binding::BindingMode;
|
use rustc_middle::ty::binding::BindingMode;
|
||||||
use rustc_middle::ty::fast_reject::SimplifiedType;
|
use rustc_middle::ty::fast_reject::SimplifiedType;
|
||||||
@ -1510,7 +1510,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
|
|||||||
&& let bnd_ty = subst.type_at(0)
|
&& let bnd_ty = subst.type_at(0)
|
||||||
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
|
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
|
||||||
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
|
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
|
||||||
&& let min_const_kind = ConstantKind::from_value(const_val, bnd_ty)
|
&& let min_const_kind = Const::from_value(const_val, bnd_ty)
|
||||||
&& let Some(min_const) = miri_to_const(cx, min_const_kind)
|
&& let Some(min_const) = miri_to_const(cx, min_const_kind)
|
||||||
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
|
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
|
||||||
{
|
{
|
||||||
@ -1526,7 +1526,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
|
|||||||
&& let bnd_ty = subst.type_at(0)
|
&& let bnd_ty = subst.type_at(0)
|
||||||
&& let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
|
&& let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
|
||||||
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
|
&& let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
|
||||||
&& let max_const_kind = ConstantKind::from_value(const_val, bnd_ty)
|
&& let max_const_kind = Const::from_value(const_val, bnd_ty)
|
||||||
&& let Some(max_const) = miri_to_const(cx, max_const_kind)
|
&& let Some(max_const) = miri_to_const(cx, max_const_kind)
|
||||||
&& let Some(end_const) = constant(cx, cx.typeck_results(), end)
|
&& let Some(end_const) = constant(cx, cx.typeck_results(), end)
|
||||||
{
|
{
|
||||||
|
@ -9,9 +9,9 @@ fn outer(_1: u8) -> u8 {
|
|||||||
StorageLive(_2); // scope 0 at $DIR/spans.rs:10:11: 10:13
|
StorageLive(_2); // scope 0 at $DIR/spans.rs:10:11: 10:13
|
||||||
_2 = &_1; // scope 0 at $DIR/spans.rs:10:11: 10:13
|
_2 = &_1; // scope 0 at $DIR/spans.rs:10:11: 10:13
|
||||||
_0 = inner(move _2) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/spans.rs:10:5: 10:14
|
_0 = inner(move _2) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/spans.rs:10:5: 10:14
|
||||||
// mir::Constant
|
// mir::ConstOperand
|
||||||
// + span: $DIR/spans.rs:10:5: 10:10
|
// + span: $DIR/spans.rs:10:5: 10:10
|
||||||
// + literal: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) }
|
// + const_: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) }
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
|
@ -9,9 +9,9 @@ fn outer(_1: u8) -> u8 {
|
|||||||
StorageLive(_2); // scope 0 at $DIR/spans.rs:10:11: 10:13
|
StorageLive(_2); // scope 0 at $DIR/spans.rs:10:11: 10:13
|
||||||
_2 = &_1; // scope 0 at $DIR/spans.rs:10:11: 10:13
|
_2 = &_1; // scope 0 at $DIR/spans.rs:10:11: 10:13
|
||||||
_0 = inner(move _2) -> [return: bb1, unwind continue]; // scope 0 at $DIR/spans.rs:10:5: 10:14
|
_0 = inner(move _2) -> [return: bb1, unwind continue]; // scope 0 at $DIR/spans.rs:10:5: 10:14
|
||||||
// mir::Constant
|
// mir::ConstOperand
|
||||||
// + span: $DIR/spans.rs:10:5: 10:10
|
// + span: $DIR/spans.rs:10:5: 10:10
|
||||||
// + literal: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) }
|
// + const_: Const { ty: for<'a> fn(&'a u8) -> u8 {inner}, val: Value(inner) }
|
||||||
}
|
}
|
||||||
|
|
||||||
bb1: {
|
bb1: {
|
||||||
|
Loading…
Reference in New Issue
Block a user