Auto merge of #96591 - b-naber:transition-to-valtrees-in-type-system, r=lcnr

Use valtrees as the type-system representation for constant values

This is not quite ready yet, there are still some problems with pretty printing and symbol mangling and `deref_const` seems to not work correctly in all cases.

Mainly opening now for a perf-run (which should be good to go, despite the still existing problems).

r? `@oli-obk`

cc `@lcnr` `@RalfJung`
This commit is contained in:
bors 2022-06-14 17:19:38 +00:00
commit 1f34da9ec8
117 changed files with 1614 additions and 1011 deletions

View file

@ -127,7 +127,7 @@ pub(crate) fn codegen_constant<'tcx>(
ConstantKind::Val(val, ty) => return codegen_const_value(fx, val, ty),
};
let const_val = match const_.kind() {
ConstKind::Value(const_val) => const_val,
ConstKind::Value(valtree) => fx.tcx.valtree_to_const_val((const_.ty(), valtree)),
ConstKind::Unevaluated(ty::Unevaluated { def, substs, promoted })
if fx.tcx.is_static(def.did) =>
{
@ -468,9 +468,10 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
) -> Option<ConstValue<'tcx>> {
match operand {
Operand::Constant(const_) => match const_.literal {
ConstantKind::Ty(const_) => {
fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).kind().try_to_value()
}
ConstantKind::Ty(const_) => fx
.monomorphize(const_)
.eval_for_mir(fx.tcx, ParamEnv::reveal_all())
.try_to_value(fx.tcx),
ConstantKind::Val(val, _) => Some(val),
},
// FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored

View file

@ -703,15 +703,19 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
// but we get a deterministic, virtually unique value for the constant.
let hcx = &mut tcx.create_stable_hashing_context();
let mut hasher = StableHasher::new();
hcx.while_hashing_spans(false, |hcx| ct.kind().hash_stable(hcx, &mut hasher));
let ct = ct.eval(tcx, ty::ParamEnv::reveal_all());
hcx.while_hashing_spans(false, |hcx| ct.to_valtree().hash_stable(hcx, &mut hasher));
// Let's only emit 64 bits of the hash value. That should be plenty for
// avoiding collisions and will make the emitted type names shorter.
let hash: u64 = hasher.finish();
// Note: Don't use `StableHashResult` impl of `u64` here directly, since that
// would lead to endianness problems.
let hash: u128 = hasher.finish();
let hash_short = (hash.to_le() as u64).to_le();
if cpp_like_debuginfo(tcx) {
write!(output, "CONST${:x}", hash)
write!(output, "CONST${:x}", hash_short)
} else {
write!(output, "{{CONST#{:x}}}", hash)
write!(output, "{{CONST#{:x}}}", hash_short)
}
}
},

View file

@ -38,7 +38,7 @@ pub fn eval_mir_constant(
self.cx.tcx().sess.span_err(constant.span, "erroneous constant encountered");
err
}),
ty::ConstKind::Value(value) => Ok(value),
ty::ConstKind::Value(val) => Ok(self.cx.tcx().valtree_to_const_val((ct.ty(), val))),
err => span_bug!(
constant.span,
"encountered bad ConstKind after monomorphizing: {:?}",
@ -58,14 +58,14 @@ pub fn simd_shuffle_indices(
constant
.map(|val| {
let field_ty = ty.builtin_index().unwrap();
let c = ty::Const::from_value(bx.tcx(), val, ty);
let c = mir::ConstantKind::from_value(val, ty);
let values: Vec<_> = bx
.tcx()
.destructure_const(ty::ParamEnv::reveal_all().and(c))
.destructure_mir_constant(ty::ParamEnv::reveal_all(), c)
.fields
.iter()
.map(|field| {
if let Some(prim) = field.kind().try_to_scalar() {
if let Some(prim) = field.try_to_scalar() {
let layout = bx.layout_of(field_ty);
let Abi::Scalar(scalar) = layout.abi else {
bug!("from_const: invalid ByVal layout: {:#?}", layout);

View file

@ -140,6 +140,7 @@ pub fn report_as_lint(
///
/// If `lint_root.is_some()` report it as a lint, else report it as a hard error.
/// (Except that for some errors, we ignore all that -- see `must_error` below.)
#[instrument(skip(self, tcx, decorate, lint_root), level = "debug")]
fn struct_generic(
&self,
tcx: TyCtxtAt<'tcx>,
@ -190,6 +191,7 @@ fn struct_generic(
decorate(err);
};
debug!("self.error: {:?}", self.error);
// Special handling for certain errors
match &self.error {
// Don't emit a new diagnostic for these errors

View file

@ -196,7 +196,7 @@ pub(super) fn op_to_const<'tcx>(
}
#[instrument(skip(tcx), level = "debug")]
fn turn_into_const_value<'tcx>(
pub(crate) fn turn_into_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
constant: ConstAlloc<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
@ -222,6 +222,7 @@ fn turn_into_const_value<'tcx>(
const_val
}
#[instrument(skip(tcx), level = "debug")]
pub fn eval_to_const_value_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
@ -256,6 +257,7 @@ pub fn eval_to_const_value_raw_provider<'tcx>(
tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key))
}
#[instrument(skip(tcx), level = "debug")]
pub fn eval_to_allocation_raw_provider<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,

View file

@ -1,12 +1,11 @@
// Not in interpret to make sure we do not use private implementation details
use std::convert::TryFrom;
use rustc_hir::Mutability;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{EvalToValTreeResult, GlobalId};
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
use rustc_target::abi::VariantIdx;
use crate::interpret::{
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MemPlaceMeta,
@ -40,7 +39,7 @@ pub(crate) fn const_caller_location(
}
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
const VALTREE_MAX_NODES: usize = 1000;
const VALTREE_MAX_NODES: usize = 100000;
pub(crate) enum ValTreeCreationError {
NodesOverflow,
@ -56,6 +55,8 @@ pub(crate) fn eval_to_valtree<'tcx>(
cid: GlobalId<'tcx>,
) -> EvalToValTreeResult<'tcx> {
let const_alloc = tcx.eval_to_allocation_raw(param_env.and(cid))?;
// FIXME Need to provide a span to `eval_to_valtree`
let ecx = mk_eval_cx(
tcx, DUMMY_SP, param_env,
// It is absolutely crucial for soundness that
@ -90,40 +91,81 @@ pub(crate) fn eval_to_valtree<'tcx>(
}
}
/// This function should never fail for validated constants. However, it is also invoked from the
/// pretty printer which might attempt to format invalid constants and in that case it might fail.
/// Tries to destructure constants of type Array or Adt into the constants
/// of its fields.
pub(crate) fn try_destructure_const<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
val: ty::Const<'tcx>,
) -> InterpResult<'tcx, mir::DestructuredConst<'tcx>> {
trace!("destructure_const: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
let op = ecx.const_to_op(val, None)?;
// We go to `usize` as we cannot allocate anything bigger anyway.
let (field_count, variant, down) = match val.ty().kind() {
ty::Array(_, len) => (usize::try_from(len.eval_usize(tcx, param_env)).unwrap(), None, op),
// Checks if we have any variants, to avoid downcasting to a non-existing variant (when
// there are no variants `read_discriminant` successfully returns a non-existing variant
// index).
ty::Adt(def, _) if def.variants().is_empty() => throw_ub!(Unreachable),
ty::Adt(def, _) => {
let variant = ecx.read_discriminant(&op)?.1;
let down = ecx.operand_downcast(&op, variant)?;
(def.variant(variant).fields.len(), Some(variant), down)
}
ty::Tuple(substs) => (substs.len(), None, op),
_ => bug!("cannot destructure constant {:?}", val),
};
let fields = (0..field_count)
.map(|i| {
let field_op = ecx.operand_field(&down, i)?;
let val = op_to_const(&ecx, &field_op);
Ok(ty::Const::from_value(tcx, val, field_op.layout.ty))
})
.collect::<InterpResult<'tcx, Vec<_>>>()?;
let fields = tcx.arena.alloc_from_iter(fields);
Ok(mir::DestructuredConst { variant, fields })
const_: ty::Const<'tcx>,
) -> Option<ty::DestructuredConst<'tcx>> {
if let ty::ConstKind::Value(valtree) = const_.kind() {
let branches = match valtree {
ty::ValTree::Branch(b) => b,
_ => return None,
};
let (fields, variant) = match const_.ty().kind() {
ty::Array(inner_ty, _) | ty::Slice(inner_ty) => {
// construct the consts for the elements of the array/slice
let field_consts = branches
.iter()
.map(|b| {
tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(*b), ty: *inner_ty })
})
.collect::<Vec<_>>();
debug!(?field_consts);
(field_consts, None)
}
ty::Adt(def, _) if def.variants().is_empty() => bug!("unreachable"),
ty::Adt(def, substs) => {
let variant_idx = if def.is_enum() {
VariantIdx::from_u32(branches[0].unwrap_leaf().try_to_u32().ok()?)
} else {
VariantIdx::from_u32(0)
};
let fields = &def.variant(variant_idx).fields;
let mut field_consts = Vec::with_capacity(fields.len());
// Note: First element inValTree corresponds to variant of enum
let mut valtree_idx = if def.is_enum() { 1 } else { 0 };
for field in fields {
let field_ty = field.ty(tcx, substs);
let field_valtree = branches[valtree_idx]; // first element of branches is variant
let field_const = tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Value(field_valtree),
ty: field_ty,
});
field_consts.push(field_const);
valtree_idx += 1;
}
debug!(?field_consts);
(field_consts, Some(variant_idx))
}
ty::Tuple(elem_tys) => {
let fields = elem_tys
.iter()
.enumerate()
.map(|(i, elem_ty)| {
let elem_valtree = branches[i];
tcx.mk_const(ty::ConstS {
kind: ty::ConstKind::Value(elem_valtree),
ty: elem_ty,
})
})
.collect::<Vec<_>>();
(fields, None)
}
_ => bug!("cannot destructure constant {:?}", const_),
};
let fields = tcx.arena.alloc_from_iter(fields.into_iter());
Some(ty::DestructuredConst { variant, fields })
} else {
None
}
}
#[instrument(skip(tcx), level = "debug")]
@ -143,8 +185,8 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
throw_ub!(Unreachable)
}
ty::Adt(def, _) => {
let variant = ecx.read_discriminant(&op).unwrap().1;
let down = ecx.operand_downcast(&op, variant).unwrap();
let variant = ecx.read_discriminant(&op)?.1;
let down = ecx.operand_downcast(&op, variant)?;
(def.variants()[variant].fields.len(), Some(variant), down)
}
ty::Tuple(substs) => (substs.len(), None, op),
@ -163,43 +205,6 @@ pub(crate) fn try_destructure_mir_constant<'tcx>(
Ok(mir::DestructuredMirConstant { variant, fields })
}
#[instrument(skip(tcx), level = "debug")]
pub(crate) fn deref_const<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
val: ty::Const<'tcx>,
) -> ty::Const<'tcx> {
trace!("deref_const: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
let op = ecx.const_to_op(val, None).unwrap();
let mplace = ecx.deref_operand(&op).unwrap();
if let Some(alloc_id) = mplace.ptr.provenance {
assert_eq!(
tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().inner().mutability,
Mutability::Not,
"deref_const cannot be used with mutable allocations as \
that could allow pattern matching to observe mutable statics",
);
}
let ty = match mplace.meta {
MemPlaceMeta::None => mplace.layout.ty,
MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace),
// In case of unsized types, figure out the real type behind.
MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() {
ty::Str => bug!("there's no sized equivalent of a `str`"),
ty::Slice(elem_ty) => tcx.mk_array(*elem_ty, scalar.to_machine_usize(&tcx).unwrap()),
_ => bug!(
"type {} should not have metadata, but had {:?}",
mplace.layout.ty,
mplace.meta
),
},
};
tcx.mk_const(ty::ConstS { kind: ty::ConstKind::Value(op_to_const(&ecx, &mplace.into())), ty })
}
#[instrument(skip(tcx), level = "debug")]
pub(crate) fn deref_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>,
@ -213,14 +218,14 @@ pub(crate) fn deref_mir_constant<'tcx>(
assert_eq!(
tcx.get_global_alloc(alloc_id).unwrap().unwrap_memory().0.0.mutability,
Mutability::Not,
"deref_const cannot be used with mutable allocations as \
"deref_mir_constant cannot be used with mutable allocations as \
that could allow pattern matching to observe mutable statics",
);
}
let ty = match mplace.meta {
MemPlaceMeta::None => mplace.layout.ty,
MemPlaceMeta::Poison => bug!("poison metadata in `deref_const`: {:#?}", mplace),
MemPlaceMeta::Poison => bug!("poison metadata in `deref_mir_constant`: {:#?}", mplace),
// In case of unsized types, figure out the real type behind.
MemPlaceMeta::Meta(scalar) => match mplace.layout.ty.kind() {
ty::Str => bug!("there's no sized equivalent of a `str`"),

View file

@ -5,13 +5,11 @@
intern_const_alloc_recursive, ConstValue, ImmTy, Immediate, InternKind, MemPlaceMeta,
MemoryKind, PlaceTy, Scalar, ScalarMaybeUninit,
};
use crate::interpret::{MPlaceTy, Value};
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
use rustc_span::source_map::DUMMY_SP;
use rustc_target::abi::{Align, VariantIdx};
use crate::interpret::MPlaceTy;
use crate::interpret::Value;
use rustc_middle::ty::{self, ScalarInt, Ty, TyCtxt};
#[instrument(skip(ecx), level = "debug")]
fn branches<'tcx>(
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
@ -76,13 +74,13 @@ pub(crate) fn const_to_valtree_inner<'tcx>(
place: &MPlaceTy<'tcx>,
num_nodes: &mut usize,
) -> ValTreeCreationResult<'tcx> {
let ty = place.layout.ty;
debug!("ty kind: {:?}", ty.kind());
if *num_nodes >= VALTREE_MAX_NODES {
return Err(ValTreeCreationError::NodesOverflow);
}
let ty = place.layout.ty;
debug!("ty kind: {:?}", ty.kind());
match ty.kind() {
ty::FnDef(..) => {
*num_nodes += 1;
@ -234,19 +232,15 @@ fn create_pointee_place<'tcx>(
// Get the size of the memory behind the DST
let dst_size = unsized_inner_ty_size.checked_mul(num_elems as u64, &tcx).unwrap();
let ptr = ecx
.allocate_ptr(
size_of_sized_part.checked_add(dst_size, &tcx).unwrap(),
Align::from_bytes(1).unwrap(),
MemoryKind::Stack,
)
.unwrap();
let size = size_of_sized_part.checked_add(dst_size, &tcx).unwrap();
let align = Align::from_bytes(size.bytes().next_power_of_two()).unwrap();
let ptr = ecx.allocate_ptr(size, align, MemoryKind::Stack).unwrap();
debug!(?ptr);
let place = MPlaceTy::from_aligned_ptr_with_meta(
ptr.into(),
layout,
MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)),
MemPlaceMeta::Meta(Scalar::from_machine_usize(num_elems as u64, &tcx)),
);
debug!(?place);
@ -262,7 +256,7 @@ fn create_pointee_place<'tcx>(
#[instrument(skip(tcx), level = "debug")]
pub fn valtree_to_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
ty: Ty<'tcx>,
param_env_ty: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
valtree: ty::ValTree<'tcx>,
) -> ConstValue<'tcx> {
// Basic idea: We directly construct `Scalar` values from trivial `ValTree`s
@ -272,8 +266,8 @@ pub fn valtree_to_const_value<'tcx>(
// create inner `MPlace`s which are filled recursively.
// FIXME Does this need an example?
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, ty::ParamEnv::empty(), false);
let param_env_ty = ty::ParamEnv::empty().and(ty);
let (param_env, ty) = param_env_ty.into_parts();
let mut ecx = mk_eval_cx(tcx, DUMMY_SP, param_env, false);
match ty.kind() {
ty::FnDef(..) => {
@ -336,7 +330,6 @@ pub fn valtree_to_const_value<'tcx>(
}
}
// FIXME Needs a better/correct name
#[instrument(skip(ecx), level = "debug")]
fn valtree_into_mplace<'tcx>(
ecx: &mut CompileTimeEvalContext<'tcx, 'tcx>,
@ -377,7 +370,8 @@ fn valtree_into_mplace<'tcx>(
let imm = match inner_ty.kind() {
ty::Slice(_) | ty::Str => {
let len = valtree.unwrap_branch().len();
let len_scalar = ScalarMaybeUninit::Scalar(Scalar::from_u64(len as u64));
let len_scalar =
ScalarMaybeUninit::Scalar(Scalar::from_machine_usize(len as u64, &tcx));
Immediate::ScalarPair(
ScalarMaybeUninit::from_maybe_pointer((*pointee_place).ptr, &tcx),
@ -448,7 +442,10 @@ fn valtree_into_mplace<'tcx>(
place
.offset(
offset,
MemPlaceMeta::Meta(Scalar::from_u64(num_elems as u64)),
MemPlaceMeta::Meta(Scalar::from_machine_usize(
num_elems as u64,
&tcx,
)),
inner_layout,
&tcx,
)

View file

@ -637,7 +637,11 @@ pub fn const_to_op(
ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => {
span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", c)
}
ty::ConstKind::Value(val) => self.const_val_to_op(val, c.ty(), layout),
ty::ConstKind::Value(valtree) => {
let ty = c.ty();
let const_val = self.tcx.valtree_to_const_val((ty, valtree));
self.const_val_to_op(const_val, ty, layout)
}
}
}

View file

@ -34,6 +34,7 @@
pub mod transform;
pub mod util;
use rustc_middle::ty;
use rustc_middle::ty::query::Providers;
pub fn provide(providers: &mut Providers) {
@ -41,10 +42,7 @@ pub fn provide(providers: &mut Providers) {
providers.eval_to_const_value_raw = const_eval::eval_to_const_value_raw_provider;
providers.eval_to_allocation_raw = const_eval::eval_to_allocation_raw_provider;
providers.const_caller_location = const_eval::const_caller_location;
providers.try_destructure_const = |tcx, param_env_and_val| {
let (param_env, c) = param_env_and_val.into_parts();
const_eval::try_destructure_const(tcx, param_env, c).ok()
};
providers.try_destructure_const = |tcx, val| const_eval::try_destructure_const(tcx, val);
providers.eval_to_valtree = |tcx, param_env_and_value| {
let (param_env, raw) = param_env_and_value.into_parts();
const_eval::eval_to_valtree(tcx, param_env, raw)
@ -53,11 +51,8 @@ pub fn provide(providers: &mut Providers) {
let (param_env, value) = param_env_and_value.into_parts();
const_eval::try_destructure_mir_constant(tcx, param_env, value).ok()
};
providers.valtree_to_const_val =
|tcx, (ty, valtree)| const_eval::valtree_to_const_value(tcx, ty, valtree);
providers.deref_const = |tcx, param_env_and_value| {
let (param_env, value) = param_env_and_value.into_parts();
const_eval::deref_const(tcx, param_env, value)
providers.valtree_to_const_val = |tcx, (ty, valtree)| {
const_eval::valtree_to_const_value(tcx, ty::ParamEnv::empty().and(ty), valtree)
};
providers.deref_mir_constant = |tcx, param_env_and_value| {
let (param_env, value) = param_env_and_value.into_parts();

View file

@ -765,7 +765,7 @@ fn promote_temp(&mut self, temp: Local) -> Local {
let unit = Rvalue::Use(Operand::Constant(Box::new(Constant {
span: statement.source_info.span,
user_ty: None,
literal: ty::Const::zero_sized(self.tcx, self.tcx.types.unit).into(),
literal: ConstantKind::zero_sized(self.tcx.types.unit),
})));
mem::replace(rhs, unit)
},
@ -835,26 +835,25 @@ fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) ->
let mut promoted_operand = |ty, span| {
promoted.span = span;
promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span);
let _const = tcx.mk_const(ty::ConstS {
ty,
kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
def,
substs: InternalSubsts::for_item(tcx, def.did, |param, _| {
if let ty::GenericParamDefKind::Lifetime = param.kind {
tcx.lifetimes.re_erased.into()
} else {
tcx.mk_param_from_def(param)
}
}),
promoted: Some(promoted_id),
}),
});
Operand::Constant(Box::new(Constant {
span,
user_ty: None,
literal: tcx
.mk_const(ty::ConstS {
ty,
kind: ty::ConstKind::Unevaluated(ty::Unevaluated {
def,
substs: InternalSubsts::for_item(tcx, def.did, |param, _| {
if let ty::GenericParamDefKind::Lifetime = param.kind {
tcx.lifetimes.re_erased.into()
} else {
tcx.mk_param_from_def(param)
}
}),
promoted: Some(promoted_id),
}),
})
.into(),
literal: ConstantKind::from_const(_const, tcx),
}))
};
let (blocks, local_decls) = self.source.basic_blocks_and_local_decls_mut();

View file

@ -20,7 +20,7 @@
use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues};
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir::interpret::{ErrorHandled, EvalToConstValueResult};
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
use rustc_middle::traits::select;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
@ -1616,6 +1616,28 @@ pub fn create_next_universe(&self) -> ty::UniverseIndex {
u
}
pub fn try_const_eval_resolve(
&self,
param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::Unevaluated<'tcx>,
ty: Ty<'tcx>,
span: Option<Span>,
) -> Result<ty::Const<'tcx>, ErrorHandled> {
match self.const_eval_resolve(param_env, unevaluated, span) {
Ok(Some(val)) => Ok(ty::Const::from_value(self.tcx, val, ty)),
Ok(None) => {
let tcx = self.tcx;
let def_id = unevaluated.def.did;
span_bug!(
tcx.def_span(def_id),
"unable to construct a constant value for the unevaluated constant {:?}",
unevaluated
);
}
Err(err) => Err(err),
}
}
/// Resolves and evaluates a constant.
///
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
@ -1634,7 +1656,7 @@ pub fn const_eval_resolve(
param_env: ty::ParamEnv<'tcx>,
unevaluated: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
) -> EvalToValTreeResult<'tcx> {
let substs = self.resolve_vars_if_possible(unevaluated.substs);
debug!(?substs);
@ -1658,7 +1680,7 @@ pub fn const_eval_resolve(
// The return value is the evaluated value which doesn't contain any reference to inference
// variables, thus we don't need to substitute back the original values.
self.tcx.const_eval_resolve(param_env_erased, unevaluated, span)
self.tcx.const_eval_resolve_for_typeck(param_env_erased, unevaluated, span)
}
/// `ty_or_const_infer_var_changed` is equivalent to one of these two:

View file

@ -1,4 +1,4 @@
use super::{ErrorHandled, EvalToConstValueResult, GlobalId};
use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId};
use crate::mir;
use crate::ty::fold::TypeFoldable;
@ -11,6 +11,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Evaluates a constant without providing any substitutions. This is useful to evaluate consts
/// that can't take any generic arguments like statics, const items or enum discriminants. If a
/// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
// In some situations def_id will have substitutions within scope, but they aren't allowed
// to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions
@ -22,7 +23,6 @@ pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> {
let param_env = self.param_env(def_id).with_reveal_all_normalized(self);
self.const_eval_global_id(param_env, cid, None)
}
/// Resolves and evaluates a constant.
///
/// The constant can be located on a trait like `<A as B>::C`, in which case the given
@ -59,6 +59,33 @@ pub fn const_eval_resolve(
}
}
#[instrument(level = "debug", skip(self))]
pub fn const_eval_resolve_for_typeck(
self,
param_env: ty::ParamEnv<'tcx>,
ct: ty::Unevaluated<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
// variables. We reject those here since `resolve_opt_const_arg`
// would fail otherwise.
//
// When trying to evaluate constants containing inference variables,
// use `Infcx::const_eval_resolve` instead.
if ct.substs.has_infer_types_or_consts() {
bug!("did not expect inference variables here");
}
match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id_for_typeck(param_env, cid, span)
}
Ok(None) => Err(ErrorHandled::TooGeneric),
Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
}
}
pub fn const_eval_instance(
self,
param_env: ty::ParamEnv<'tcx>,
@ -68,7 +95,8 @@ pub fn const_eval_instance(
self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span)
}
/// Evaluate a constant.
/// Evaluate a constant to a `ConstValue`.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_global_id(
self,
param_env: ty::ParamEnv<'tcx>,
@ -86,6 +114,27 @@ pub fn const_eval_global_id(
}
}
/// Evaluate a constant to a type-level constant.
#[instrument(skip(self), level = "debug")]
pub fn const_eval_global_id_for_typeck(
self,
param_env: ty::ParamEnv<'tcx>,
cid: GlobalId<'tcx>,
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
let param_env = param_env.with_const();
debug!(?param_env);
// Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should
// improve caching of queries.
let inputs = self.erase_regions(param_env.and(cid));
debug!(?inputs);
if let Some(span) = span {
self.at(span).eval_to_valtree(inputs)
} else {
self.eval_to_valtree(inputs)
}
}
/// Evaluate a static's initializer, returning the allocation of the initializer's memory.
#[inline(always)]
pub fn eval_static_initializer(
@ -125,11 +174,8 @@ fn eval_to_allocation(
impl<'tcx> TyCtxt<'tcx> {
/// Destructure a type-level constant ADT or array into its variant index and its field values.
/// Panics if the destructuring fails, use `try_destructure_const` for fallible version.
pub fn destructure_const(
self,
param_env_and_val: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>,
) -> mir::DestructuredConst<'tcx> {
self.try_destructure_const(param_env_and_val).unwrap()
pub fn destructure_const(self, const_: ty::Const<'tcx>) -> ty::DestructuredConst<'tcx> {
self.try_destructure_const(const_).unwrap()
}
/// Destructure a mir constant ADT or array into its variant index and its field values.

View file

@ -111,6 +111,10 @@ pub fn from_u64(i: u64) -> Self {
pub fn from_machine_usize(i: u64, cx: &impl HasDataLayout) -> Self {
ConstValue::Scalar(Scalar::from_machine_usize(i, cx))
}
pub fn zst() -> Self {
Self::Scalar(Scalar::ZST)
}
}
/// A `Scalar` represents an immediate, primitive value existing outside of a

View file

@ -3,7 +3,9 @@
//! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/mir/index.html
use crate::mir::coverage::{CodeRegion, CoverageKind};
use crate::mir::interpret::{ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar};
use crate::mir::interpret::{
AllocRange, ConstAllocation, ConstValue, GlobalAlloc, LitToConstInput, Scalar,
};
use crate::mir::visit::MirVisitable;
use crate::ty::adjustment::PointerCast;
use crate::ty::codec::{TyDecoder, TyEncoder};
@ -2399,7 +2401,7 @@ pub fn function_handle(
Operand::Constant(Box::new(Constant {
span,
user_ty: None,
literal: ConstantKind::Ty(ty::Const::zero_sized(tcx, ty)),
literal: ConstantKind::Val(ConstValue::zst(), ty),
}))
}
@ -2953,22 +2955,9 @@ pub fn ty(&self) -> Ty<'tcx> {
}
}
impl<'tcx> From<ty::Const<'tcx>> for ConstantKind<'tcx> {
#[inline]
fn from(ct: ty::Const<'tcx>) -> Self {
match ct.kind() {
ty::ConstKind::Value(cv) => {
// FIXME Once valtrees are introduced we need to convert those
// into `ConstValue` instances here
Self::Val(cv, ct.ty())
}
_ => Self::Ty(ct),
}
}
}
impl<'tcx> ConstantKind<'tcx> {
/// Returns `None` if the constant is not trivially safe for use in the type system.
#[inline]
pub fn const_for_ty(&self) -> Option<ty::Const<'tcx>> {
match self {
ConstantKind::Ty(c) => Some(*c),
@ -2976,6 +2965,7 @@ pub fn const_for_ty(&self) -> Option<ty::Const<'tcx>> {
}
}
#[inline(always)]
pub fn ty(&self) -> Ty<'tcx> {
match self {
ConstantKind::Ty(c) => c.ty(),
@ -2983,32 +2973,34 @@ pub fn ty(&self) -> Ty<'tcx> {
}
}
pub fn try_val(&self) -> Option<ConstValue<'tcx>> {
#[inline]
pub fn try_to_value(self, tcx: TyCtxt<'tcx>) -> Option<interpret::ConstValue<'tcx>> {
match self {
ConstantKind::Ty(c) => match c.kind() {
ty::ConstKind::Value(v) => Some(v),
ty::ConstKind::Value(valtree) => Some(tcx.valtree_to_const_val((c.ty(), valtree))),
_ => None,
},
ConstantKind::Val(v, _) => Some(*v),
}
}
#[inline]
pub fn try_to_value(self) -> Option<interpret::ConstValue<'tcx>> {
match self {
ConstantKind::Ty(c) => c.kind().try_to_value(),
ConstantKind::Val(val, _) => Some(val),
}
}
#[inline]
pub fn try_to_scalar(self) -> Option<Scalar> {
self.try_to_value()?.try_to_scalar()
match self {
ConstantKind::Ty(c) => match c.kind() {
ty::ConstKind::Value(valtree) => match valtree {
ty::ValTree::Leaf(scalar_int) => Some(Scalar::Int(scalar_int)),
ty::ValTree::Branch(_) => None,
},
_ => None,
},
ConstantKind::Val(val, _) => val.try_to_scalar(),
}
}
#[inline]
pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
Some(self.try_to_value()?.try_to_scalar()?.assert_int())
Some(self.try_to_scalar()?.assert_int())
}
#[inline]
@ -3025,9 +3017,7 @@ pub fn try_to_bool(self) -> Option<bool> {
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
match self {
Self::Ty(c) => {
// FIXME Need to use a different evaluation function that directly returns a `ConstValue`
// if evaluation succeeds and does not create a ValTree first
if let Some(val) = c.kind().try_eval(tcx, param_env) {
if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) {
match val {
Ok(val) => Self::Val(val, c.ty()),
Err(_) => Self::Ty(tcx.const_error(self.ty())),
@ -3081,6 +3071,11 @@ pub fn try_eval_usize(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -
}
}
#[inline]
pub fn from_value(val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
Self::Val(val, ty)
}
pub fn from_bits(
tcx: TyCtxt<'tcx>,
bits: u128,
@ -3097,11 +3092,13 @@ pub fn from_bits(
Self::Val(cv, param_env_ty.value)
}
#[inline]
pub fn from_bool(tcx: TyCtxt<'tcx>, v: bool) -> Self {
let cv = ConstValue::from_bool(v);
Self::Val(cv, tcx.types.bool)
}
#[inline]
pub fn zero_sized(ty: Ty<'tcx>) -> Self {
let cv = ConstValue::Scalar(Scalar::ZST);
Self::Val(cv, ty)
@ -3112,6 +3109,12 @@ pub fn from_usize(tcx: TyCtxt<'tcx>, n: u64) -> Self {
Self::from_bits(tcx, n as u128, ty::ParamEnv::empty().and(ty))
}
#[inline]
pub fn from_scalar(_tcx: TyCtxt<'tcx>, s: Scalar, ty: Ty<'tcx>) -> Self {
let val = ConstValue::Scalar(s);
Self::Val(val, ty)
}
/// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
/// converted to a constant, everything else becomes `Unevaluated`.
pub fn from_anon_const(
@ -3199,8 +3202,10 @@ fn from_opt_const_arg_anon_const(
}
_ => expr,
};
debug!("expr.kind: {:?}", expr.kind);
let ty = tcx.type_of(def.def_id_for_type_of());
debug!(?ty);
// FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
// does not provide the parents generics to anonymous constants. We still allow generic const
@ -3224,6 +3229,7 @@ fn from_opt_const_arg_anon_const(
kind: ty::ConstKind::Param(ty::ParamConst::new(index, name)),
ty,
});
debug!(?ty_const);
return Self::Ty(ty_const);
}
@ -3253,8 +3259,12 @@ fn from_opt_const_arg_anon_const(
debug!(?span, ?param_env);
match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
Ok(val) => Self::Val(val, ty),
Ok(val) => {
debug!("evaluated const value: {:?}", val);
Self::Val(val, ty)
}
Err(_) => {
debug!("error encountered during evaluation");
// Error was handled in `const_eval_resolve`. Here we just create a
// new unevaluated const and error hard later in codegen
let ty_const = tcx.mk_const(ty::ConstS {
@ -3265,11 +3275,22 @@ fn from_opt_const_arg_anon_const(
}),
ty,
});
debug!(?ty_const);
Self::Ty(ty_const)
}
}
}
pub fn from_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self {
match c.kind() {
ty::ConstKind::Value(valtree) => {
let const_val = tcx.valtree_to_const_val((c.ty(), valtree));
Self::Val(const_val, c.ty())
}
_ => Self::Ty(c),
}
}
}
/// A collection of projections into user types.
@ -3485,20 +3506,183 @@ fn pretty_print_const<'tcx>(
})
}
fn pretty_print_byte_str(fmt: &mut Formatter<'_>, byte_str: &[u8]) -> fmt::Result {
fmt.write_str("b\"")?;
for &c in byte_str {
for e in std::ascii::escape_default(c) {
fmt.write_char(e as char)?;
}
}
fmt.write_str("\"")?;
Ok(())
}
fn comma_sep<'tcx>(fmt: &mut Formatter<'_>, elems: Vec<ConstantKind<'tcx>>) -> fmt::Result {
let mut first = true;
for elem in elems {
if !first {
fmt.write_str(", ")?;
}
fmt.write_str(&format!("{}", elem))?;
first = false;
}
Ok(())
}
// FIXME: Move that into `mir/pretty.rs`.
fn pretty_print_const_value<'tcx>(
val: interpret::ConstValue<'tcx>,
ct: ConstValue<'tcx>,
ty: Ty<'tcx>,
fmt: &mut Formatter<'_>,
print_types: bool,
print_ty: bool,
) -> fmt::Result {
use crate::ty::print::PrettyPrinter;
ty::tls::with(|tcx| {
let val = tcx.lift(val).unwrap();
let ct = tcx.lift(ct).unwrap();
let ty = tcx.lift(ty).unwrap();
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
cx.print_alloc_ids = true;
let cx = cx.pretty_print_const_value(val, ty, print_types)?;
fmt.write_str(&cx.into_buffer())?;
if tcx.sess.verbose() {
fmt.write_str(&format!("ConstValue({:?}: {})", ct, ty))?;
return Ok(());
}
let u8_type = tcx.types.u8;
match (ct, ty.kind()) {
// Byte/string slices, printed as (byte) string literals.
(ConstValue::Slice { data, start, end }, ty::Ref(_, inner, _)) => {
match inner.kind() {
ty::Slice(t) => {
if *t == u8_type {
// The `inspect` here is okay since we checked the bounds, and there are
// no relocations (we have an active slice reference here). We don't use
// this result to affect interpreter execution.
let byte_str = data
.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
pretty_print_byte_str(fmt, byte_str)?;
return Ok(());
}
}
ty::Str => {
// The `inspect` here is okay since we checked the bounds, and there are no
// relocations (we have an active `str` reference here). We don't use this
// result to affect interpreter execution.
let slice = data
.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
fmt.write_str(&format!("{:?}", String::from_utf8_lossy(slice)))?;
return Ok(());
}
_ => {}
}
}
(ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
let n = n.kind().try_to_bits(tcx.data_layout.pointer_size).unwrap();
// cast is ok because we already checked for pointer size (32 or 64 bit) above
let range = AllocRange { start: offset, size: Size::from_bytes(n) };
let byte_str = alloc.inner().get_bytes(&tcx, range).unwrap();
fmt.write_str("*")?;
pretty_print_byte_str(fmt, byte_str)?;
return Ok(());
}
// Aggregates, printed as array/tuple/struct/variant construction syntax.
//
// NB: the `has_param_types_or_consts` check ensures that we can use
// the `destructure_const` query with an empty `ty::ParamEnv` without
// introducing ICEs (e.g. via `layout_of`) from missing bounds.
// E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
// to be able to destructure the tuple into `(0u8, *mut T)
//
// FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
// correct `ty::ParamEnv` to allow printing *all* constant values.
(_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
let ct = tcx.lift(ct).unwrap();
let ty = tcx.lift(ty).unwrap();
if let Some(contents) = tcx.try_destructure_mir_constant(
ty::ParamEnv::reveal_all().and(ConstantKind::Val(ct, ty)),
) {
let fields = contents.fields.iter().copied().collect::<Vec<_>>();
match *ty.kind() {
ty::Array(..) => {
fmt.write_str("[")?;
comma_sep(fmt, fields)?;
fmt.write_str("]")?;
}
ty::Tuple(..) => {
fmt.write_str("(")?;
comma_sep(fmt, fields)?;
if contents.fields.len() == 1 {
fmt.write_str(",")?;
}
fmt.write_str(")")?;
}
ty::Adt(def, _) if def.variants().is_empty() => {
fmt.write_str(&format!("{{unreachable(): {}}}", ty))?;
}
ty::Adt(def, substs) => {
let variant_idx = contents
.variant
.expect("destructed mir constant of adt without variant idx");
let variant_def = &def.variant(variant_idx);
let substs = tcx.lift(substs).unwrap();
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
cx.print_alloc_ids = true;
let cx = cx.print_value_path(variant_def.def_id, substs)?;
fmt.write_str(&cx.into_buffer())?;
match variant_def.ctor_kind {
CtorKind::Const => {}
CtorKind::Fn => {
fmt.write_str("(")?;
comma_sep(fmt, fields)?;
fmt.write_str(")")?;
}
CtorKind::Fictive => {
fmt.write_str(" {{ ")?;
let mut first = true;
for (field_def, field) in iter::zip(&variant_def.fields, fields)
{
if !first {
fmt.write_str(", ")?;
}
fmt.write_str(&format!("{}: {}", field_def.name, field))?;
first = false;
}
fmt.write_str(" }}")?;
}
}
}
_ => unreachable!(),
}
return Ok(());
} else {
// Fall back to debug pretty printing for invalid constants.
fmt.write_str(&format!("{:?}", ct))?;
if print_ty {
fmt.write_str(&format!(": {}", ty))?;
}
return Ok(());
};
}
(ConstValue::Scalar(scalar), _) => {
let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS);
cx.print_alloc_ids = true;
let ty = tcx.lift(ty).unwrap();
cx = cx.pretty_print_const_scalar(scalar, ty, print_ty)?;
fmt.write_str(&cx.into_buffer())?;
return Ok(());
}
// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
// their fields instead of just dumping the memory.
_ => {}
}
// fallback
fmt.write_str(&format!("{:?}", ct))?;
if print_ty {
fmt.write_str(&format!(": {}", ty))?;
}
Ok(())
})
}

View file

@ -454,7 +454,12 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) {
ConstValue::ByRef { .. } => format!("ByRef(..)"),
};
let kind = match literal {
let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree {
ty::ValTree::Leaf(leaf) => format!("ValTree::Leaf({:?})", leaf),
ty::ValTree::Branch(_) => format!("ValTree::Branch(..)"),
};
let val = match literal {
ConstantKind::Ty(ct) => match ct.kind() {
ty::ConstKind::Param(p) => format!("Param({})", p),
ty::ConstKind::Unevaluated(uv) => format!(
@ -463,7 +468,7 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) {
uv.substs,
uv.promoted,
),
ty::ConstKind::Value(val) => format!("Value({})", fmt_val(&val)),
ty::ConstKind::Value(val) => format!("Value({})", fmt_valtree(&val)),
ty::ConstKind::Error(_) => "Error".to_string(),
// These variants shouldn't exist in the MIR.
ty::ConstKind::Placeholder(_)
@ -479,7 +484,7 @@ fn visit_constant(&mut self, constant: &Constant<'tcx>, _location: Location) {
// This reflects what `Const` looked liked before `val` was renamed
// as `kind`. We print it like this to avoid having to update
// expected output in a lot of tests.
self.push(&format!("+ literal: Const {{ ty: {}, val: {} }}", literal.ty(), kind));
self.push(&format!("+ literal: Const {{ ty: {}, val: {} }}", literal.ty(), val));
}
}
@ -665,7 +670,8 @@ fn alloc_ids_from_alloc(
) -> impl DoubleEndedIterator<Item = AllocId> + '_ {
alloc.inner().relocations().values().map(|id| *id)
}
fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
fn alloc_ids_from_const_val(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> + '_ {
match val {
ConstValue::Scalar(interpret::Scalar::Ptr(ptr, _)) => {
Either::Left(Either::Left(std::iter::once(ptr.provenance)))
@ -681,17 +687,11 @@ fn alloc_ids_from_const(val: ConstValue<'_>) -> impl Iterator<Item = AllocId> +
struct CollectAllocIds(BTreeSet<AllocId>);
impl<'tcx> Visitor<'tcx> for CollectAllocIds {
fn visit_const(&mut self, c: ty::Const<'tcx>, _loc: Location) {
if let ty::ConstKind::Value(val) = c.kind() {
self.0.extend(alloc_ids_from_const(val));
}
}
fn visit_constant(&mut self, c: &Constant<'tcx>, loc: Location) {
match c.literal {
ConstantKind::Ty(c) => self.visit_const(c, loc),
ConstantKind::Val(val, _) => {
self.0.extend(alloc_ids_from_const(val));
self.0.extend(alloc_ids_from_const_val(val));
}
}
}

View file

@ -1,6 +1,6 @@
//! Values computed by queries that use MIR.
use crate::mir::{self, Body, Promoted};
use crate::mir::{Body, ConstantKind, Promoted};
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
use rustc_data_structures::stable_map::FxHashMap;
use rustc_data_structures::vec_map::VecMap;
@ -427,7 +427,7 @@ pub struct DestructuredConst<'tcx> {
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredMirConstant<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [mir::ConstantKind<'tcx>],
pub fields: &'tcx [ConstantKind<'tcx>],
}
/// Coverage information summarized from a MIR if instrumented for source code coverage (see

View file

@ -1,3 +1,4 @@
use crate::mir;
use crate::mir::interpret::Scalar;
use crate::ty::{self, Ty, TyCtxt};
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
@ -676,7 +677,7 @@ pub fn fmt_successor_labels(&self) -> Vec<Cow<'static, str>> {
.values
.iter()
.map(|&u| {
ty::Const::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
mir::ConstantKind::from_scalar(tcx, Scalar::from_uint(u, size), switch_ty)
.to_string()
.into()
})

View file

@ -967,36 +967,26 @@
query eval_to_valtree(
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>
) -> EvalToValTreeResult<'tcx> {
desc { "evaluate type-level constant" }
remap_env_constness
desc { "evaluating type-level constant" }
}
/// Converts a type level constant value into `ConstValue`
query valtree_to_const_val(key: (Ty<'tcx>, ty::ValTree<'tcx>)) -> ConstValue<'tcx> {
desc { "convert type-level constant value to mir constant value"}
desc { "converting type-level constant value to mir constant value"}
}
/// Destructure a constant ADT or array into its variant index and its
/// field values or return `None` if constant is invalid.
///
/// Use infallible `TyCtxt::destructure_const` when you know that constant is valid.
query try_destructure_const(key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>) -> Option<mir::DestructuredConst<'tcx>> {
desc { "destructure type level constant"}
query try_destructure_const(key: ty::Const<'tcx>) -> Option<ty::DestructuredConst<'tcx>> {
desc { "destructuring type level constant"}
}
/// Tries to destructure an `mir::ConstantKind` ADT or array into its variant index
/// and its field values.
query try_destructure_mir_constant(key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>) -> Option<mir::DestructuredMirConstant<'tcx>> {
desc { "destructure mir constant"}
remap_env_constness
}
/// Dereference a constant reference or raw pointer and turn the result into a constant
/// again.
query deref_const(
key: ty::ParamEnvAnd<'tcx, ty::Const<'tcx>>
) -> ty::Const<'tcx> {
desc { "deref constant" }
desc { "destructuring mir constant"}
remap_env_constness
}
@ -1005,7 +995,7 @@
query deref_mir_constant(
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> mir::ConstantKind<'tcx> {
desc { "deref constant" }
desc { "dereferencing mir constant" }
remap_env_constness
}

View file

@ -5,7 +5,6 @@
//! its name suggest, is to provide an abstraction boundary for creating
//! interned Chalk types.
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::{self, AdtDef, TyCtxt};
use rustc_hir::def_id::DefId;
@ -62,7 +61,7 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> {
type InternedType = Box<chalk_ir::TyData<Self>>;
type InternedLifetime = Box<chalk_ir::LifetimeData<Self>>;
type InternedConst = Box<chalk_ir::ConstData<Self>>;
type InternedConcreteConst = ConstValue<'tcx>;
type InternedConcreteConst = ty::ValTree<'tcx>;
type InternedGenericArg = Box<chalk_ir::GenericArgData<Self>>;
type InternedGoal = Box<chalk_ir::GoalData<Self>>;
type InternedGoals = Vec<chalk_ir::Goal<Self>>;

View file

@ -1,5 +1,5 @@
use crate::mir::interpret::ConstValue;
use crate::mir::interpret::{LitToConstInput, Scalar};
use crate::mir::interpret::LitToConstInput;
use crate::mir::ConstantKind;
use crate::ty::{
self, InlineConstSubsts, InlineConstSubstsParts, InternalSubsts, ParamEnv, ParamEnvAnd, Ty,
TyCtxt, TypeFoldable,
@ -195,14 +195,21 @@ pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
/// Interns the given value as a constant.
#[inline]
pub fn from_value(tcx: TyCtxt<'tcx>, val: ConstValue<'tcx>, ty: Ty<'tcx>) -> Self {
pub fn from_value(tcx: TyCtxt<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> Self {
tcx.mk_const(ConstS { kind: ConstKind::Value(val), ty })
}
#[inline]
/// Interns the given scalar as a constant.
pub fn from_scalar(tcx: TyCtxt<'tcx>, val: Scalar, ty: Ty<'tcx>) -> Self {
Self::from_value(tcx, ConstValue::Scalar(val), ty)
/// Panics if self.kind != ty::ConstKind::Value
pub fn to_valtree(self) -> ty::ValTree<'tcx> {
match self.kind() {
ty::ConstKind::Value(valtree) => valtree,
_ => bug!("expected ConstKind::Value"),
}
}
pub fn from_scalar_int(tcx: TyCtxt<'tcx>, i: ScalarInt, ty: Ty<'tcx>) -> Self {
let valtree = ty::ValTree::from_scalar_int(i);
Self::from_value(tcx, valtree, ty)
}
#[inline]
@ -212,13 +219,14 @@ pub fn from_bits(tcx: TyCtxt<'tcx>, bits: u128, ty: ParamEnvAnd<'tcx, Ty<'tcx>>)
.layout_of(ty)
.unwrap_or_else(|e| panic!("could not compute layout for {:?}: {:?}", ty, e))
.size;
Self::from_scalar(tcx, Scalar::from_uint(bits, size), ty.value)
Self::from_scalar_int(tcx, ScalarInt::try_from_uint(bits, size).unwrap(), ty.value)
}
#[inline]
/// Creates an interned zst constant.
pub fn zero_sized(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Self {
Self::from_scalar(tcx, Scalar::ZST, ty)
let valtree = ty::ValTree::zst();
Self::from_value(tcx, valtree, ty)
}
#[inline]
@ -263,16 +271,31 @@ pub fn try_eval_usize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Opt
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
/// unevaluated constant.
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Const<'tcx> {
if let Some(val) = self.kind().try_eval(tcx, param_env) {
if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) {
match val {
Ok(val) => Const::from_value(tcx, val, self.ty()),
Err(ErrorGuaranteed { .. }) => tcx.const_error(self.ty()),
}
} else {
// Either the constant isn't evaluatable or ValTree creation failed.
self
}
}
#[inline]
/// Tries to evaluate the constant if it is `Unevaluated` and creates a ConstValue if the
/// evaluation succeeds. If it doesn't succeed, returns the unevaluated constant.
pub fn eval_for_mir(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> ConstantKind<'tcx> {
if let Some(val) = self.kind().try_eval_for_mir(tcx, param_env) {
match val {
Ok(const_val) => ConstantKind::from_value(const_val, self.ty()),
Err(ErrorGuaranteed { .. }) => ConstantKind::Ty(tcx.const_error(self.ty())),
}
} else {
ConstantKind::Ty(self)
}
}
#[inline]
/// 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 {

View file

@ -63,7 +63,7 @@ pub enum ConstKind<'tcx> {
Unevaluated(Unevaluated<'tcx>),
/// Used to hold computed value.
Value(ConstValue<'tcx>),
Value(ty::ValTree<'tcx>),
/// A placeholder for a const which could not be computed; this is
/// propagated to avoid useless error messages.
@ -75,7 +75,7 @@ pub enum ConstKind<'tcx> {
impl<'tcx> ConstKind<'tcx> {
#[inline]
pub fn try_to_value(self) -> Option<ConstValue<'tcx>> {
pub fn try_to_value(self) -> Option<ty::ValTree<'tcx>> {
if let ConstKind::Value(val) = self { Some(val) } else { None }
}
@ -86,7 +86,7 @@ pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
#[inline]
pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
Some(self.try_to_value()?.try_to_scalar()?.assert_int())
self.try_to_value()?.try_to_scalar_int()
}
#[inline]
@ -115,23 +115,65 @@ pub enum InferConst<'tcx> {
Fresh(u32),
}
enum EvalMode {
Typeck,
Mir,
}
enum EvalResult<'tcx> {
ValTree(ty::ValTree<'tcx>),
ConstVal(ConstValue<'tcx>),
}
impl<'tcx> ConstKind<'tcx> {
#[inline]
/// Tries to evaluate the constant if it is `Unevaluated`. If that doesn't succeed, return the
/// unevaluated constant.
pub fn eval(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
self.try_eval(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
self.try_eval_for_typeck(tcx, param_env).and_then(Result::ok).map_or(self, ConstKind::Value)
}
#[inline]
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
/// return `None`.
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
pub fn try_eval(
pub fn try_eval_for_mir(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<Result<ConstValue<'tcx>, ErrorGuaranteed>> {
match self.try_eval_inner(tcx, param_env, EvalMode::Mir) {
Some(Ok(EvalResult::ValTree(_))) => unreachable!(),
Some(Ok(EvalResult::ConstVal(v))) => Some(Ok(v)),
Some(Err(e)) => Some(Err(e)),
None => None,
}
}
#[inline]
/// Tries to evaluate the constant if it is `Unevaluated`. If that isn't possible or necessary
/// return `None`.
// FIXME(@lcnr): Completely rework the evaluation/normalization system for `ty::Const` once valtrees are merged.
pub fn try_eval_for_typeck(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
) -> Option<Result<ty::ValTree<'tcx>, ErrorGuaranteed>> {
match self.try_eval_inner(tcx, param_env, EvalMode::Typeck) {
Some(Ok(EvalResult::ValTree(v))) => Some(Ok(v)),
Some(Ok(EvalResult::ConstVal(_))) => unreachable!(),
Some(Err(e)) => Some(Err(e)),
None => None,
}
}
#[inline]
fn try_eval_inner(
self,
tcx: TyCtxt<'tcx>,
param_env: ParamEnv<'tcx>,
eval_mode: EvalMode,
) -> Option<Result<EvalResult<'tcx>, ErrorGuaranteed>> {
if let ConstKind::Unevaluated(unevaluated) = self {
use crate::mir::interpret::ErrorHandled;
@ -166,14 +208,29 @@ pub fn try_eval(
let (param_env, unevaluated) = param_env_and.into_parts();
// try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const.
match tcx.const_eval_resolve(param_env, unevaluated, None) {
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
// and we use the original type, so nothing from `substs`
// (which may be identity substs, see above),
// can leak through `val` into the const we return.
Ok(val) => Some(Ok(val)),
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
Err(ErrorHandled::Reported(e)) => Some(Err(e)),
match eval_mode {
EvalMode::Typeck => {
match tcx.const_eval_resolve_for_typeck(param_env, unevaluated, None) {
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
// and we use the original type, so nothing from `substs`
// (which may be identity substs, see above),
// can leak through `val` into the const we return.
Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
Err(ErrorHandled::Reported(e)) => Some(Err(e)),
}
}
EvalMode::Mir => {
match tcx.const_eval_resolve(param_env, unevaluated, None) {
// NOTE(eddyb) `val` contains no lifetimes/types/consts,
// and we use the original type, so nothing from `substs`
// (which may be identity substs, see above),
// can leak through `val` into the const we return.
Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
Err(ErrorHandled::TooGeneric | ErrorHandled::Linted) => None,
Err(ErrorHandled::Reported(e)) => Some(Err(e)),
}
}
}
} else {
None

View file

@ -1,4 +1,6 @@
use super::ScalarInt;
use crate::mir::interpret::{AllocId, Scalar};
use crate::ty::{self, Ty, TyCtxt};
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
@ -50,4 +52,61 @@ pub fn unwrap_branch(self) -> &'tcx [Self] {
_ => bug!("expected branch, got {:?}", self),
}
}
pub fn from_raw_bytes<'a>(tcx: TyCtxt<'tcx>, bytes: &'a [u8]) -> Self {
let branches = bytes.iter().map(|b| Self::Leaf(ScalarInt::from(*b)));
let interned = tcx.arena.alloc_from_iter(branches);
Self::Branch(interned)
}
pub fn from_scalar_int(i: ScalarInt) -> Self {
Self::Leaf(i)
}
pub fn try_to_scalar(self) -> Option<Scalar<AllocId>> {
self.try_to_scalar_int().map(Scalar::Int)
}
pub fn try_to_scalar_int(self) -> Option<ScalarInt> {
match self {
Self::Leaf(s) => Some(s),
Self::Branch(_) => None,
}
}
pub fn try_to_machine_usize(self, tcx: TyCtxt<'tcx>) -> Option<u64> {
self.try_to_scalar_int().map(|s| s.try_to_machine_usize(tcx).ok()).flatten()
}
/// Get the values inside the ValTree as a slice of bytes. This only works for
/// constants with types &str and &[u8].
pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> {
match ty.kind() {
ty::Ref(_, inner_ty, _) => match inner_ty.kind() {
ty::Str => {
let leafs = self
.unwrap_branch()
.into_iter()
.map(|v| v.unwrap_leaf().try_to_u8().unwrap())
.collect::<Vec<_>>();
return Some(tcx.arena.alloc_from_iter(leafs.into_iter()));
}
ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {
let leafs = self
.unwrap_branch()
.into_iter()
.map(|v| v.unwrap_leaf().try_to_u8().unwrap())
.collect::<Vec<_>>();
return Some(tcx.arena.alloc_from_iter(leafs.into_iter()));
}
_ => {}
},
_ => {}
}
None
}
}

View file

@ -8,7 +8,7 @@
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
use crate::middle::resolve_lifetime;
use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
use crate::mir::interpret::{self, Allocation, ConstAllocation};
use crate::mir::{
Body, BorrowCheckResult, Field, Local, Place, PlaceElem, ProjectionKind, Promoted,
};
@ -991,7 +991,7 @@ fn new(interners: &CtxtInterners<'tcx>, types: &CommonTypes<'tcx>) -> CommonCons
CommonConsts {
unit: mk_const(ty::ConstS {
kind: ty::ConstKind::Value(ConstValue::Scalar(Scalar::ZST)),
kind: ty::ConstKind::Value(ty::ValTree::zst()),
ty: types.unit,
}),
}

View file

@ -369,7 +369,6 @@ pub fn resolve(
}
// This should be kept up to date with `resolve`.
#[instrument(level = "debug", skip(tcx))]
pub fn resolve_opt_const_arg(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,

View file

@ -42,7 +42,7 @@
use rustc_session::cstore::CrateStoreDyn;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::Span;
use rustc_target::abi::Align;
use rustc_target::abi::{Align, VariantIdx};
pub use subst::*;
pub use vtable::*;
@ -2161,22 +2161,28 @@ pub fn expect_variant_res(self, res: Res) -> &'tcx VariantDef {
}
/// Returns the possibly-auto-generated MIR of a `(DefId, Subst)` pair.
#[instrument(skip(self), level = "debug")]
pub fn instance_mir(self, instance: ty::InstanceDef<'tcx>) -> &'tcx Body<'tcx> {
match instance {
ty::InstanceDef::Item(def) => match self.def_kind(def.did) {
DefKind::Const
| DefKind::Static(..)
| DefKind::AssocConst
| DefKind::Ctor(..)
| DefKind::AnonConst
| DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
// If the caller wants `mir_for_ctfe` of a function they should not be using
// `instance_mir`, so we'll assume const fn also wants the optimized version.
_ => {
assert_eq!(def.const_param_did, None);
self.optimized_mir(def.did)
ty::InstanceDef::Item(def) => {
debug!("calling def_kind on def: {:?}", def);
let def_kind = self.def_kind(def.did);
debug!("returned from def_kind: {:?}", def_kind);
match def_kind {
DefKind::Const
| DefKind::Static(..)
| DefKind::AssocConst
| DefKind::Ctor(..)
| DefKind::AnonConst
| DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
// If the caller wants `mir_for_ctfe` of a function they should not be using
// `instance_mir`, so we'll assume const fn also wants the optimized version.
_ => {
assert_eq!(def.const_param_did, None);
self.optimized_mir(def.did)
}
}
},
}
ty::InstanceDef::VtableShim(..)
| ty::InstanceDef::ReifyShim(..)
| ty::InstanceDef::Intrinsic(..)
@ -2447,3 +2453,10 @@ pub struct FoundRelationships {
/// _>::AssocType = ?T`
pub output: bool,
}
/// The constituent parts of a type level constant of kind ADT or array.
#[derive(Copy, Clone, Debug, HashStable)]
pub struct DestructuredConst<'tcx> {
pub variant: Option<VariantIdx>,
pub fields: &'tcx [ty::Const<'tcx>],
}

View file

@ -302,6 +302,7 @@ fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
impl<'tcx, P: Printer<'tcx>> Print<'tcx, P> for Ty<'tcx> {
type Output = P::Type;
type Error = P::Error;
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
cx.print_type(*self)
}

View file

@ -1,4 +1,4 @@
use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Provenance, Scalar};
use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst};
use crate::ty::{
self, ConstInt, DefIdTree, ParamConst, ScalarInt, Term, Ty, TyCtxt, TypeFoldable,
@ -1224,7 +1224,7 @@ macro_rules! print_underscore {
}
ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)),
ty::ConstKind::Value(value) => {
return self.pretty_print_const_value(value, ct.ty(), print_ty);
return self.pretty_print_const_valtree(value, ct.ty(), print_ty);
}
ty::ConstKind::Bound(debruijn, bound_var) => {
@ -1262,7 +1262,7 @@ fn pretty_print_const_scalar_ptr(
ty::Ref(_, inner, _) => {
if let ty::Array(elem, len) = inner.kind() {
if let ty::Uint(ty::UintTy::U8) = elem.kind() {
if let ty::ConstKind::Value(ConstValue::Scalar(int)) = len.kind() {
if let ty::ConstKind::Value(ty::ValTree::Leaf(int)) = len.kind() {
match self.tcx().get_global_alloc(alloc_id) {
Some(GlobalAlloc::Memory(alloc)) => {
let len = int.assert_bits(self.tcx().data_layout.pointer_size);
@ -1408,85 +1408,62 @@ fn pretty_print_byte_str(mut self, byte_str: &'tcx [u8]) -> Result<Self::Const,
Ok(self)
}
fn pretty_print_const_value(
fn pretty_print_const_valtree(
mut self,
ct: ConstValue<'tcx>,
valtree: ty::ValTree<'tcx>,
ty: Ty<'tcx>,
print_ty: bool,
) -> Result<Self::Const, Self::Error> {
define_scoped_cx!(self);
if self.tcx().sess.verbose() {
p!(write("ConstValue({:?}: ", ct), print(ty), ")");
p!(write("ValTree({:?}: ", valtree), print(ty), ")");
return Ok(self);
}
let u8_type = self.tcx().types.u8;
match (ct, ty.kind()) {
// Byte/string slices, printed as (byte) string literals.
(ConstValue::Slice { data, start, end }, ty::Ref(_, inner, _)) => {
match inner.kind() {
ty::Slice(t) => {
if *t == u8_type {
// The `inspect` here is okay since we checked the bounds, and there are
// no relocations (we have an active slice reference here). We don't use
// this result to affect interpreter execution.
let byte_str = data
.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
return self.pretty_print_byte_str(byte_str);
}
}
ty::Str => {
// The `inspect` here is okay since we checked the bounds, and there are no
// relocations (we have an active `str` reference here). We don't use this
// result to affect interpreter execution.
let slice = data
.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
p!(write("{:?}", String::from_utf8_lossy(slice)));
return Ok(self);
}
_ => {}
match (valtree, ty.kind()) {
(ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() {
ty::Slice(t) if *t == u8_type => {
let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
bug!(
"expected to convert valtree {:?} to raw bytes for type {:?}",
valtree,
t
)
});
return self.pretty_print_byte_str(bytes);
}
}
(ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => {
let n = n.kind().try_to_bits(self.tcx().data_layout.pointer_size).unwrap();
// cast is ok because we already checked for pointer size (32 or 64 bit) above
let range = AllocRange { start: offset, size: Size::from_bytes(n) };
let byte_str = alloc.inner().get_bytes(&self.tcx(), range).unwrap();
ty::Str => {
let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
bug!("expected to convert valtree to raw bytes for type {:?}", ty)
});
p!(write("{:?}", String::from_utf8_lossy(bytes)));
return Ok(self);
}
_ => {}
},
(ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => {
let bytes = valtree.try_to_raw_bytes(self.tcx(), *t).unwrap_or_else(|| {
bug!("expected to convert valtree to raw bytes for type {:?}", t)
});
p!("*");
p!(pretty_print_byte_str(byte_str));
p!(pretty_print_byte_str(bytes));
return Ok(self);
}
// Aggregates, printed as array/tuple/struct/variant construction syntax.
//
// NB: the `has_param_types_or_consts` check ensures that we can use
// the `destructure_const` query with an empty `ty::ParamEnv` without
// introducing ICEs (e.g. via `layout_of`) from missing bounds.
// E.g. `transmute([0usize; 2]): (u8, *mut T)` needs to know `T: Sized`
// to be able to destructure the tuple into `(0u8, *mut T)
//
// FIXME(eddyb) for `--emit=mir`/`-Z dump-mir`, we should provide the
// correct `ty::ParamEnv` to allow printing *all* constant values.
(_, ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) if !ty.has_param_types_or_consts() => {
(ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => {
let Some(contents) = self.tcx().try_destructure_const(
ty::ParamEnv::reveal_all()
.and(self.tcx().mk_const(ty::ConstS { kind: ty::ConstKind::Value(ct), ty })),
ty::Const::from_value(self.tcx(), valtree, ty)
) else {
// Fall back to debug pretty printing for invalid constants.
p!(write("{:?}", ct));
p!(write("{:?}", valtree));
if print_ty {
p!(": ", print(ty));
}
return Ok(self);
};
let fields = contents.fields.iter().copied();
match *ty.kind() {
ty::Array(..) => {
p!("[", comma_sep(fields), "]");
@ -1513,7 +1490,6 @@ fn pretty_print_const_value(
contents.variant.expect("destructed const of adt without variant idx");
let variant_def = &def.variant(variant_idx);
p!(print_value_path(variant_def.def_id, substs));
match variant_def.ctor_kind {
CtorKind::Const => {}
CtorKind::Fn => {
@ -1535,21 +1511,22 @@ fn pretty_print_const_value(
}
_ => unreachable!(),
}
return Ok(self);
}
(ConstValue::Scalar(scalar), _) => {
return self.pretty_print_const_scalar(scalar, ty, print_ty);
(ty::ValTree::Leaf(leaf), _) => {
return self.pretty_print_const_scalar_int(leaf, ty, print_ty);
}
// FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading
// their fields instead of just dumping the memory.
_ => {}
}
// fallback
p!(write("{:?}", ct));
if valtree == ty::ValTree::zst() {
p!(write("<ZST>"));
} else {
p!(write("{:?}", valtree));
}
if print_ty {
p!(": ", print(ty));
}
@ -2296,7 +2273,6 @@ pub fn pretty_wrap_binder<T, C: Fn(&T, Self) -> Result<Self, fmt::Error>>(
Ok(inner)
}
#[instrument(skip(self), level = "debug")]
fn prepare_late_bound_region_info<T>(&mut self, value: &ty::Binder<'tcx, T>)
where
T: TypeFoldable<'tcx>,
@ -2309,7 +2285,6 @@ struct LateBoundRegionNameCollector<'a, 'tcx> {
impl<'tcx> ty::fold::TypeVisitor<'tcx> for LateBoundRegionNameCollector<'_, 'tcx> {
type BreakTy = ();
#[instrument(skip(self), level = "trace")]
fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
trace!("address: {:p}", r.0.0);
if let ty::ReLateBound(_, ty::BoundRegion { kind: ty::BrNamed(_, name), .. }) = *r {
@ -2326,7 +2301,6 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
// We collect types in order to prevent really large types from compiling for
// a really long time. See issue #83150 for why this is necessary.
#[instrument(skip(self), level = "trace")]
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
let not_previously_inserted = self.type_collector.insert(ty);
if not_previously_inserted {
@ -2353,6 +2327,7 @@ impl<'tcx, T, P: PrettyPrinter<'tcx>> Print<'tcx, P> for ty::Binder<'tcx, T>
{
type Output = P;
type Error = P::Error;
fn print(&self, cx: P) -> Result<Self::Output, Self::Error> {
cx.in_binder(self)
}

View file

@ -4,7 +4,6 @@
//! types or regions but can be other things. Examples of type relations are
//! subtyping, type equality, etc.
use crate::mir::interpret::{get_slice_bytes, ConstValue, GlobalAlloc, Scalar};
use crate::ty::error::{ExpectedFound, TypeError};
use crate::ty::subst::{GenericArg, GenericArgKind, Subst, SubstsRef};
use crate::ty::{self, ImplSubject, Term, Ty, TyCtxt, TypeFoldable};
@ -613,9 +612,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
(ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index,
(ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => {
check_const_value_eq(relation, a_val, b_val, a, b)?
}
(ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
(ty::ConstKind::Unevaluated(au), ty::ConstKind::Unevaluated(bu))
if tcx.features().generic_const_exprs =>
@ -649,66 +646,6 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
if is_match { Ok(a) } else { Err(TypeError::ConstMismatch(expected_found(relation, a, b))) }
}
fn check_const_value_eq<'tcx, R: TypeRelation<'tcx>>(
relation: &mut R,
a_val: ConstValue<'tcx>,
b_val: ConstValue<'tcx>,
// FIXME(oli-obk): these arguments should go away with valtrees
a: ty::Const<'tcx>,
b: ty::Const<'tcx>,
// FIXME(oli-obk): this should just be `bool` with valtrees
) -> RelateResult<'tcx, bool> {
let tcx = relation.tcx();
Ok(match (a_val, b_val) {
(ConstValue::Scalar(Scalar::Int(a_val)), ConstValue::Scalar(Scalar::Int(b_val))) => {
a_val == b_val
}
(
ConstValue::Scalar(Scalar::Ptr(a_val, _a_size)),
ConstValue::Scalar(Scalar::Ptr(b_val, _b_size)),
) => {
a_val == b_val
|| match (tcx.global_alloc(a_val.provenance), tcx.global_alloc(b_val.provenance)) {
(GlobalAlloc::Function(a_instance), GlobalAlloc::Function(b_instance)) => {
a_instance == b_instance
}
_ => false,
}
}
(ConstValue::Slice { .. }, ConstValue::Slice { .. }) => {
get_slice_bytes(&tcx, a_val) == get_slice_bytes(&tcx, b_val)
}
(ConstValue::ByRef { alloc: alloc_a, .. }, ConstValue::ByRef { alloc: alloc_b, .. })
if a.ty().is_ref() || b.ty().is_ref() =>
{
if a.ty().is_ref() && b.ty().is_ref() {
alloc_a == alloc_b
} else {
false
}
}
(ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => {
let a_destructured = tcx.destructure_const(relation.param_env().and(a));
let b_destructured = tcx.destructure_const(relation.param_env().and(b));
// Both the variant and each field have to be equal.
if a_destructured.variant == b_destructured.variant {
for (a_field, b_field) in iter::zip(a_destructured.fields, b_destructured.fields) {
relation.consts(*a_field, *b_field)?;
}
true
} else {
false
}
}
_ => false,
})
}
impl<'tcx> Relate<'tcx> for &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>> {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,

View file

@ -1,12 +1,16 @@
//! See docs in build/expr/mod.rs
use crate::build::{lit_to_mir_constant, Builder};
use crate::build::{parse_float_into_constval, Builder};
use rustc_ast as ast;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
use rustc_middle::mir::interpret::{
Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt};
use rustc_target::abi::Size;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Compile `expr`, yielding a compile-time constant. Assumes that
@ -84,3 +88,54 @@ pub(crate) fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> {
}
}
}
#[instrument(skip(tcx, lit_input))]
pub(crate) fn lit_to_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
) -> Result<ConstantKind<'tcx>, LitToConstError> {
let LitToConstInput { lit, ty, neg } = lit_input;
let trunc = |n| {
let param_ty = ty::ParamEnv::reveal_all().and(ty);
let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
let result = width.truncate(n);
trace!("trunc result: {}", result);
Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
};
let value = match (lit, &ty.kind()) {
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
let s = s.as_str();
let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: s.len() }
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
if matches!(inner_ty.kind(), ty::Slice(_)) =>
{
let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: data.len() }
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
}
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
}
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
parse_float_into_constval(*n, *fty, neg).ok_or(LitToConstError::Reported)?
}
(ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
(ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
(ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
_ => return Err(LitToConstError::TypeError),
};
Ok(ConstantKind::Val(value, ty))
}

View file

@ -1,9 +1,10 @@
use crate::build;
pub(crate) use crate::build::expr::as_constant::lit_to_mir_constant;
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::scope::DropKind;
use crate::thir::constant::parse_float;
use crate::thir::pattern::pat_from_hir;
use rustc_ast as ast;
use rustc_apfloat::ieee::{Double, Single};
use rustc_apfloat::Float;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
@ -14,15 +15,15 @@
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::middle::region;
use rustc_middle::mir::interpret::Allocation;
use rustc_middle::mir::interpret::{ConstValue, LitToConstError, LitToConstInput, Scalar};
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::*;
use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, LocalVarId, PatKind, Thir};
use rustc_middle::ty::subst::Subst;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults};
use rustc_span::symbol::sym;
use rustc_span::Span;
use rustc_target::abi::Size;
use rustc_span::Symbol;
use rustc_target::spec::abi::Abi;
use super::lints;
@ -266,57 +267,6 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_
})
}
#[instrument(skip(tcx, lit_input))]
pub(crate) fn lit_to_mir_constant<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
) -> Result<ConstantKind<'tcx>, LitToConstError> {
let LitToConstInput { lit, ty, neg } = lit_input;
let trunc = |n| {
let param_ty = ty::ParamEnv::reveal_all().and(ty);
let width = tcx.layout_of(param_ty).map_err(|_| LitToConstError::Reported)?.size;
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
let result = width.truncate(n);
trace!("trunc result: {}", result);
Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
};
let value = match (lit, &ty.kind()) {
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
let s = s.as_str();
let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: s.len() }
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
if matches!(inner_ty.kind(), ty::Slice(_)) =>
{
let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: data.len() }
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
}
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
}
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)?
}
(ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
(ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
(ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
_ => return Err(LitToConstError::TypeError),
};
Ok(ConstantKind::Val(value, ty))
}
///////////////////////////////////////////////////////////////////////////
// BuildMir -- walks a crate, looking for fn items and methods to build MIR from
@ -1137,6 +1087,70 @@ fn get_unit_temp(&mut self) -> Place<'tcx> {
}
}
fn parse_float_into_constval<'tcx>(
num: Symbol,
float_ty: ty::FloatTy,
neg: bool,
) -> Option<ConstValue<'tcx>> {
parse_float_into_scalar(num, float_ty, neg).map(ConstValue::Scalar)
}
pub(crate) fn parse_float_into_scalar(
num: Symbol,
float_ty: ty::FloatTy,
neg: bool,
) -> Option<Scalar> {
let num = num.as_str();
match float_ty {
ty::FloatTy::F32 => {
let Ok(rust_f) = num.parse::<f32>() else { return None };
let mut f = num.parse::<Single>().unwrap_or_else(|e| {
panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
});
assert!(
u128::from(rust_f.to_bits()) == f.to_bits(),
"apfloat::ieee::Single gave different result for `{}`: \
{}({:#x}) vs Rust's {}({:#x})",
rust_f,
f,
f.to_bits(),
Single::from_bits(rust_f.to_bits().into()),
rust_f.to_bits()
);
if neg {
f = -f;
}
Some(Scalar::from_f32(f))
}
ty::FloatTy::F64 => {
let Ok(rust_f) = num.parse::<f64>() else { return None };
let mut f = num.parse::<Double>().unwrap_or_else(|e| {
panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
});
assert!(
u128::from(rust_f.to_bits()) == f.to_bits(),
"apfloat::ieee::Double gave different result for `{}`: \
{}({:#x}) vs Rust's {}({:#x})",
rust_f,
f,
f.to_bits(),
Double::from_bits(rust_f.to_bits().into()),
rust_f.to_bits()
);
if neg {
f = -f;
}
Some(Scalar::from_f64(f))
}
}
}
///////////////////////////////////////////////////////////////////////////
// Builder methods are broken up into modules, depending on what kind
// of thing is being lowered. Note that they use the `unpack` macro

View file

@ -1,13 +1,7 @@
use rustc_apfloat::Float;
use rustc_ast as ast;
use rustc_middle::mir::interpret::{
Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::ty::{self, ParamEnv, TyCtxt};
use rustc_span::symbol::Symbol;
use rustc_target::abi::Size;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
use rustc_middle::ty::{self, ParamEnv, ScalarInt, TyCtxt};
// FIXME Once valtrees are available, get rid of this function and the query
pub(crate) fn lit_to_const<'tcx>(
tcx: TyCtxt<'tcx>,
lit_input: LitToConstInput<'tcx>,
@ -20,94 +14,39 @@ pub(crate) fn lit_to_const<'tcx>(
trace!("trunc {} with size {} and shift {}", n, width.bits(), 128 - width.bits());
let result = width.truncate(n);
trace!("trunc result: {}", result);
Ok(ConstValue::Scalar(Scalar::from_uint(result, width)))
Ok(ScalarInt::try_from_uint(result, width)
.unwrap_or_else(|| bug!("expected to create ScalarInt from uint {:?}", result)))
};
let lit = match (lit, &ty.kind()) {
let valtree = match (lit, &ty.kind()) {
(ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => {
let s = s.as_str();
let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes());
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: s.len() }
let str_bytes = s.as_str().as_bytes();
ty::ValTree::from_raw_bytes(tcx, str_bytes)
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _))
if matches!(inner_ty.kind(), ty::Slice(_)) =>
{
let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
let allocation = tcx.intern_const_alloc(allocation);
ConstValue::Slice { data: allocation, start: 0, end: data.len() }
let bytes = data as &[u8];
ty::ValTree::from_raw_bytes(tcx, bytes)
}
(ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => {
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
let bytes = data as &[u8];
ty::ValTree::from_raw_bytes(tcx, bytes)
}
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
ty::ValTree::from_scalar_int((*n).into())
}
(ast::LitKind::Int(n, _), ty::Uint(_)) | (ast::LitKind::Int(n, _), ty::Int(_)) => {
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?
let scalar_int =
trunc(if neg { (*n as i128).overflowing_neg().0 as u128 } else { *n })?;
ty::ValTree::from_scalar_int(scalar_int)
}
(ast::LitKind::Float(n, _), ty::Float(fty)) => {
parse_float(*n, *fty, neg).ok_or(LitToConstError::Reported)?
}
(ast::LitKind::Bool(b), ty::Bool) => ConstValue::Scalar(Scalar::from_bool(*b)),
(ast::LitKind::Char(c), ty::Char) => ConstValue::Scalar(Scalar::from_char(*c)),
(ast::LitKind::Bool(b), ty::Bool) => ty::ValTree::from_scalar_int((*b).into()),
(ast::LitKind::Char(c), ty::Char) => ty::ValTree::from_scalar_int((*c).into()),
(ast::LitKind::Err(_), _) => return Err(LitToConstError::Reported),
_ => return Err(LitToConstError::TypeError),
};
Ok(ty::Const::from_value(tcx, lit, ty))
}
// FIXME move this to rustc_mir_build::build
pub(crate) fn parse_float<'tcx>(
num: Symbol,
fty: ty::FloatTy,
neg: bool,
) -> Option<ConstValue<'tcx>> {
let num = num.as_str();
use rustc_apfloat::ieee::{Double, Single};
let scalar = match fty {
ty::FloatTy::F32 => {
let Ok(rust_f) = num.parse::<f32>() else { return None };
let mut f = num.parse::<Single>().unwrap_or_else(|e| {
panic!("apfloat::ieee::Single failed to parse `{}`: {:?}", num, e)
});
assert!(
u128::from(rust_f.to_bits()) == f.to_bits(),
"apfloat::ieee::Single gave different result for `{}`: \
{}({:#x}) vs Rust's {}({:#x})",
rust_f,
f,
f.to_bits(),
Single::from_bits(rust_f.to_bits().into()),
rust_f.to_bits()
);
if neg {
f = -f;
}
Scalar::from_f32(f)
}
ty::FloatTy::F64 => {
let Ok(rust_f) = num.parse::<f64>() else { return None };
let mut f = num.parse::<Double>().unwrap_or_else(|e| {
panic!("apfloat::ieee::Double failed to parse `{}`: {:?}", num, e)
});
assert!(
u128::from(rust_f.to_bits()) == f.to_bits(),
"apfloat::ieee::Double gave different result for `{}`: \
{}({:#x}) vs Rust's {}({:#x})",
rust_f,
f,
f.to_bits(),
Double::from_bits(rust_f.to_bits().into()),
rust_f.to_bits()
);
if neg {
f = -f;
}
Scalar::from_f64(f)
}
};
Some(ConstValue::Scalar(scalar))
Ok(ty::Const::from_value(tcx, valtree, ty))
}

View file

@ -371,6 +371,7 @@ fn recur(
}
ty::Adt(adt_def, substs) if adt_def.is_enum() => {
let destructured = tcx.destructure_mir_constant(param_env, cv);
PatKind::Variant {
adt_def: *adt_def,
substs,
@ -502,7 +503,7 @@ fn recur(
// deref pattern.
_ => {
if !pointee_ty.is_sized(tcx.at(span), param_env) {
// `tcx.deref_const()` below will ICE with an unsized type
// `tcx.deref_mir_constant()` below will ICE with an unsized type
// (except slices, which are handled in a separate arm above).
let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
if self.include_lint_checks {

View file

@ -185,11 +185,11 @@ fn normalize_range_pattern_ends(
}
(Some(PatKind::Constant { value: lo }), None) => {
let hi = ty.numeric_max_val(self.tcx)?;
Some((*lo, hi.into()))
Some((*lo, mir::ConstantKind::from_const(hi, self.tcx)))
}
(None, Some(PatKind::Constant { value: hi })) => {
let lo = ty.numeric_min_val(self.tcx)?;
Some((lo.into(), *hi))
Some((mir::ConstantKind::from_const(lo, self.tcx), *hi))
}
_ => None,
}
@ -798,11 +798,12 @@ pub(crate) fn compare_const_vals<'tcx>(
if let ty::Str = ty.kind() && let (
Some(a_val @ ConstValue::Slice { .. }),
Some(b_val @ ConstValue::Slice { .. }),
) = (a.try_val(), b.try_val())
) = (a.try_to_value(tcx), b.try_to_value(tcx))
{
let a_bytes = get_slice_bytes(&tcx, a_val);
let b_bytes = get_slice_bytes(&tcx, b_val);
return from_bool(a_bytes == b_bytes);
}
fallback()
}

View file

@ -1032,7 +1032,7 @@ fn constant_usize(&self, val: u16) -> Operand<'tcx> {
Operand::Constant(Box::new(Constant {
span: self.source_info.span,
user_ty: None,
literal: ty::Const::from_usize(self.tcx(), val.into()).into(),
literal: ConstantKind::from_usize(self.tcx(), val.into()),
}))
}

View file

@ -19,7 +19,7 @@ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.opts.debugging_opts.unsound_mir_opts && sess.mir_opt_level() > 0
}
fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("running ConstDebugInfo on {:?}", body.source);
for (local, constant) in find_optimization_oportunities(body) {

View file

@ -67,6 +67,7 @@ fn is_enabled(&self, _sess: &rustc_session::Session) -> bool {
true
}
#[instrument(skip(self, tcx), level = "debug")]
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
// will be evaluated by miri and produce its errors there
if body.source.promoted.is_some() {
@ -687,7 +688,7 @@ fn operand_from_scalar(&self, scalar: Scalar, ty: Ty<'tcx>, span: Span) -> Opera
Operand::Constant(Box::new(Constant {
span,
user_ty: None,
literal: ty::Const::from_scalar(self.tcx, scalar, ty).into(),
literal: ConstantKind::from_scalar(self.tcx, scalar, ty),
}))
}
@ -765,20 +766,12 @@ fn replace_with_const(
if let Some(Some(alloc)) = alloc {
// Assign entire constant in a single statement.
// We can't use aggregates, as we run after the aggregate-lowering `MirPhase`.
let const_val = ConstValue::ByRef { alloc, offset: Size::ZERO };
let literal = ConstantKind::Val(const_val, ty);
*rval = Rvalue::Use(Operand::Constant(Box::new(Constant {
span: source_info.span,
user_ty: None,
literal: self
.ecx
.tcx
.mk_const(ty::ConstS {
ty,
kind: ty::ConstKind::Value(ConstValue::ByRef {
alloc,
offset: Size::ZERO,
}),
})
.into(),
literal,
})));
}
}

View file

@ -470,7 +470,7 @@ fn constant_bool(&self, span: Span, val: bool) -> Rvalue<'tcx> {
Rvalue::Use(Operand::Constant(Box::new(Constant {
span,
user_ty: None,
literal: ty::Const::from_bool(self.tcx, val).into(),
literal: ConstantKind::from_bool(self.tcx, val),
})))
}

View file

@ -991,7 +991,7 @@ fn insert_panic_block<'tcx>(
cond: Operand::Constant(Box::new(Constant {
span: body.span,
user_ty: None,
literal: ty::Const::from_bool(tcx, false).into(),
literal: ConstantKind::from_bool(tcx, false),
})),
expected: true,
msg: message,

View file

@ -3,8 +3,8 @@
use crate::MirPass;
use rustc_hir::Mutability;
use rustc_middle::mir::{
BinOp, Body, Constant, LocalDecls, Operand, Place, ProjectionElem, Rvalue, SourceInfo,
Statement, StatementKind, Terminator, TerminatorKind, UnOp,
BinOp, Body, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem, Rvalue,
SourceInfo, Statement, StatementKind, Terminator, TerminatorKind, UnOp,
};
use rustc_middle::ty::{self, TyCtxt};
@ -129,8 +129,8 @@ fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
return;
}
let constant =
Constant { span: source_info.span, literal: len.into(), user_ty: None };
let literal = ConstantKind::from_const(len, self.tcx);
let constant = Constant { span: source_info.span, literal, user_ty: None };
*rvalue = Rvalue::Use(Operand::Constant(Box::new(constant)));
}
}

View file

@ -531,8 +531,10 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
None => {}
Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other),
}
debug!("about to call mir_drops_elaborated...");
let mut body =
tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
debug!("body: {:#?}", body);
run_optimization_passes(tcx, &mut body);
debug_assert!(!body.has_free_regions(), "Free regions in optimized MIR");

View file

@ -34,7 +34,7 @@ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
Rvalue::Use(Operand::Constant(Box::new(Constant {
span: terminator.source_info.span,
user_ty: None,
literal: ty::Const::zero_sized(tcx, tcx.types.unit).into(),
literal: ConstantKind::zero_sized(tcx.types.unit),
}))),
))),
});

View file

@ -15,7 +15,7 @@ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.panic_strategy() != PanicStrategy::Abort
}
fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
debug!("remove_noop_landing_pads({:?})", body);
self.remove_nop_landing_pads(body)
}
@ -81,6 +81,8 @@ fn is_nop_landing_pad(
}
fn remove_nop_landing_pads(&self, body: &mut Body<'_>) {
debug!("body: {:#?}", body);
// make sure there's a single resume block
let resume_block = {
let patch = MirPatch::new(body);

View file

@ -430,7 +430,7 @@ fn make_clone_call(
let func = Operand::Constant(Box::new(Constant {
span: self.span,
user_ty: None,
literal: ty::Const::zero_sized(tcx, func_ty).into(),
literal: ConstantKind::zero_sized(func_ty),
}));
let ref_loc = self.make_place(
@ -630,7 +630,7 @@ fn build_call_shim<'tcx>(
Operand::Constant(Box::new(Constant {
span,
user_ty: None,
literal: ty::Const::zero_sized(tcx, ty).into(),
literal: ConstantKind::zero_sized(ty),
})),
rcvr.into_iter().collect::<Vec<_>>(),
)

View file

@ -323,6 +323,7 @@ pub fn iter_accesses<F>(&self, mut f: F)
}
}
#[instrument(skip(tcx, mode), level = "debug")]
pub fn collect_crate_mono_items(
tcx: TyCtxt<'_>,
mode: MonoItemCollectionMode,
@ -362,6 +363,7 @@ pub fn collect_crate_mono_items(
// Find all non-generic items by walking the HIR. These items serve as roots to
// start monomorphizing from.
#[instrument(skip(tcx, mode), level = "debug")]
fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<'_>> {
debug!("collecting roots");
let mut roots = MonoItems { compute_inlining: false, tcx, items: Vec::new() };
@ -400,6 +402,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
/// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
/// post-monorphization error is encountered during a collection step.
#[instrument(skip(tcx, visited, recursion_depths, recursion_limit, inlining_map), level = "debug")]
fn collect_items_rec<'tcx>(
tcx: TyCtxt<'tcx>,
starting_point: Spanned<MonoItem<'tcx>>,
@ -752,13 +755,15 @@ fn visit_rvalue(&mut self, rvalue: &mir::Rvalue<'tcx>, location: Location) {
/// This does not walk the constant, as it has been handled entirely here and trying
/// 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.
#[instrument(skip(self), level = "debug")]
fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location) {
let literal = self.monomorphize(constant.literal);
let val = match literal {
mir::ConstantKind::Val(val, _) => val,
mir::ConstantKind::Ty(ct) => match ct.kind() {
ty::ConstKind::Value(val) => val,
ty::ConstKind::Value(val) => self.tcx.valtree_to_const_val((ct.ty(), val)),
ty::ConstKind::Unevaluated(ct) => {
debug!(?ct);
let param_env = ty::ParamEnv::reveal_all();
match self.tcx.const_eval_resolve(param_env, ct, None) {
// The `monomorphize` call should have evaluated that constant already.
@ -778,6 +783,7 @@ fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: Location)
self.visit_ty(literal.ty(), TyContext::Location(location));
}
#[instrument(skip(self), level = "debug")]
fn visit_const(&mut self, constant: ty::Const<'tcx>, location: Location) {
debug!("visiting const {:?} @ {:?}", constant, location);
@ -785,7 +791,10 @@ fn visit_const(&mut self, constant: ty::Const<'tcx>, location: Location) {
let param_env = ty::ParamEnv::reveal_all();
match substituted_constant.kind() {
ty::ConstKind::Value(val) => collect_const_value(self.tcx, val, self.output),
ty::ConstKind::Value(val) => {
let const_val = self.tcx.valtree_to_const_val((constant.ty(), val));
collect_const_value(self.tcx, const_val, self.output)
}
ty::ConstKind::Unevaluated(unevaluated) => {
match self.tcx.const_eval_resolve(param_env, unevaluated, None) {
// The `monomorphize` call should have evaluated that constant already.
@ -1120,6 +1129,7 @@ fn find_vtable_types_for_unsizing<'tcx>(
}
}
#[instrument(skip(tcx), level = "debug")]
fn create_fn_mono_item<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
@ -1133,7 +1143,10 @@ fn create_fn_mono_item<'tcx>(
crate::util::dump_closure_profile(tcx, instance);
}
respan(source, MonoItem::Fn(instance.polymorphize(tcx)))
let respanned = respan(source, MonoItem::Fn(instance.polymorphize(tcx)));
debug!(?respanned);
respanned
}
/// Creates a `MonoItem` for each method that is referenced by the vtable for
@ -1275,6 +1288,7 @@ fn is_root(&self, def_id: LocalDefId) -> bool {
/// If `def_id` represents a root, pushes it onto the list of
/// outputs. (Note that all roots must be monomorphic.)
#[instrument(skip(self), level = "debug")]
fn push_if_root(&mut self, def_id: LocalDefId) {
if self.is_root(def_id) {
debug!("RootCollector::push_if_root: found root def_id={:?}", def_id);
@ -1415,17 +1429,17 @@ fn collect_miri<'tcx>(tcx: TyCtxt<'tcx>, alloc_id: AllocId, output: &mut MonoIte
}
/// Scans the MIR in order to find function calls, closures, and drop-glue.
#[instrument(skip(tcx, output), level = "debug")]
fn collect_neighbours<'tcx>(
tcx: TyCtxt<'tcx>,
instance: Instance<'tcx>,
output: &mut MonoItems<'tcx>,
) {
debug!("collect_neighbours: {:?}", instance.def_id());
let body = tcx.instance_mir(instance.def);
MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body);
}
#[instrument(skip(tcx, output), level = "debug")]
fn collect_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
value: ConstValue<'tcx>,

View file

@ -1,7 +1,6 @@
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir::def_id::CrateNum;
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::mir::interpret::{ConstValue, Scalar};
use rustc_middle::ty::print::{PrettyPrinter, Print, Printer};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind};
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, TypeFoldable};
@ -30,6 +29,7 @@ pub(super) fn mangle<'tcx>(
match key.disambiguated_data.data {
DefPathData::TypeNs(_) | DefPathData::ValueNs(_) => {
instance_ty = tcx.type_of(ty_def_id);
debug!(?instance_ty);
break;
}
_ => {
@ -261,10 +261,7 @@ fn print_dyn_existential(
fn print_const(self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error> {
// only print integers
match (ct.kind(), ct.ty().kind()) {
(
ty::ConstKind::Value(ConstValue::Scalar(Scalar::Int(scalar))),
ty::Int(_) | ty::Uint(_),
) => {
(ty::ConstKind::Value(ty::ValTree::Leaf(scalar)), ty::Int(_) | ty::Uint(_)) => {
// The `pretty_print_const` formatting depends on -Zverbose
// flag, so we cannot reuse it here.
let signed = matches!(ct.ty().kind(), ty::Int(_));

View file

@ -5,7 +5,6 @@
use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::print::{Print, Printer};
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst};
@ -604,16 +603,18 @@ fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error
if let Some(&i) = self.consts.get(&ct) {
return self.print_backref(i);
}
let start = self.out.len();
let ty = ct.ty();
match ct.ty().kind() {
match ty.kind() {
ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Char => {
self = ct.ty().print(self)?;
self = ty.print(self)?;
let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ct.ty());
let mut bits = ct.eval_bits(self.tcx, ty::ParamEnv::reveal_all(), ty);
// Negative integer values are mangled using `n` as a "sign prefix".
if let ty::Int(ity) = ct.ty().kind() {
if let ty::Int(ity) = ty.kind() {
let val =
Integer::from_int_ty(&self.tcx, *ity).size().sign_extend(bits) as i128;
if val < 0 {
@ -625,46 +626,57 @@ fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error
let _ = write!(self.out, "{:x}_", bits);
}
// HACK(eddyb) because `ty::Const` only supports sized values (for now),
// we can't use `deref_const` + supporting `str`, we have to specially
// handle `&str` and include both `&` ("R") and `str` ("e") prefixes.
ty::Ref(_, ty, hir::Mutability::Not) if *ty == self.tcx.types.str_ => {
self.push("R");
match ct.kind() {
ty::ConstKind::Value(ConstValue::Slice { data, start, end }) => {
// NOTE(eddyb) the following comment was kept from `ty::print::pretty`:
// The `inspect` here is okay since we checked the bounds, and there are no
// relocations (we have an active `str` reference here). We don't use this
// result to affect interpreter execution.
let slice = data
.inner()
.inspect_with_uninit_and_ptr_outside_interpreter(start..end);
let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
self.push("e");
// FIXME(eddyb) use a specialized hex-encoding loop.
for byte in s.bytes() {
let _ = write!(self.out, "{:02x}", byte);
}
self.push("_");
}
_ => {
bug!("symbol_names: unsupported `&str` constant: {:?}", ct);
}
}
}
ty::Ref(_, _, mutbl) => {
// FIXME(valtrees): Remove the special case for `str`
// here and fully support unsized constants.
ty::Ref(_, inner_ty, mutbl) => {
self.push(match mutbl {
hir::Mutability::Not => "R",
hir::Mutability::Mut => "Q",
});
self = self.tcx.deref_const(ty::ParamEnv::reveal_all().and(ct)).print(self)?;
match inner_ty.kind() {
ty::Str if *mutbl == hir::Mutability::Not => {
match ct.kind() {
ty::ConstKind::Value(valtree) => {
let slice =
valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| {
bug!(
"expected to get raw bytes from valtree {:?} for type {:}",
valtree, ty
)
});
let s = std::str::from_utf8(slice).expect("non utf8 str from miri");
self.push("e");
// FIXME(eddyb) use a specialized hex-encoding loop.
for byte in s.bytes() {
let _ = write!(self.out, "{:02x}", byte);
}
self.push("_");
}
_ => {
bug!("symbol_names: unsupported `&str` constant: {:?}", ct);
}
}
}
_ => {
let pointee_ty = ct
.ty()
.builtin_deref(true)
.expect("tried to dereference on non-ptr type")
.ty;
let dereferenced_const =
self.tcx.mk_const(ty::ConstS { kind: ct.kind(), ty: pointee_ty });
self = dereferenced_const.print(self)?;
}
}
}
ty::Array(..) | ty::Tuple(..) | ty::Adt(..) => {
let contents = self.tcx.destructure_const(ty::ParamEnv::reveal_all().and(ct));
ty::Array(..) | ty::Tuple(..) | ty::Adt(..) | ty::Slice(_) => {
let contents = self.tcx.destructure_const(ct);
let fields = contents.fields.iter().copied();
let print_field_list = |mut this: Self| {
@ -676,7 +688,7 @@ fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error
};
match *ct.ty().kind() {
ty::Array(..) => {
ty::Array(..) | ty::Slice(_) => {
self.push("A");
self = print_field_list(self)?;
}
@ -723,7 +735,6 @@ fn print_const(mut self, ct: ty::Const<'tcx>) -> Result<Self::Const, Self::Error
_ => unreachable!(),
}
}
_ => {
bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty(), ct);
}

View file

@ -6,6 +6,7 @@
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::InferCtxt;
use crate::traits::project::ProjectAndUnifyResult;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::{Region, RegionVid, Term};
@ -834,7 +835,16 @@ fn evaluate_nested_obligations(
unevaluated,
Some(obligation.cause.span),
) {
Ok(val) => Ok(ty::Const::from_value(select.tcx(), val, c.ty())),
Ok(Some(valtree)) => {
Ok(ty::Const::from_value(select.tcx(), valtree, c.ty()))
}
Ok(None) => {
let tcx = self.tcx;
let def_id = unevaluated.def.did;
let reported = tcx.sess.struct_span_err(tcx.def_span(def_id), &format!("unable to construct a constant value for the unevaluated constant {:?}", unevaluated)).emit();
Err(ErrorHandled::Reported(reported))
}
Err(err) => Err(err),
}
} else {

View file

@ -13,9 +13,7 @@
use rustc_index::vec::IndexVec;
use rustc_infer::infer::InferCtxt;
use rustc_middle::mir;
use rustc_middle::mir::interpret::{
ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
};
use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput};
use rustc_middle::thir;
use rustc_middle::thir::abstract_const::{self, Node, NodeId, NotConstEvaluatable};
use rustc_middle::ty::subst::{Subst, SubstsRef};
@ -449,9 +447,8 @@ fn recurse_build(&mut self, node: thir::ExprId) -> Result<NodeId, ErrorGuarantee
self.nodes.push(Node::Leaf(constant))
}
&ExprKind::NonHirLiteral { lit , user_ty: _} => {
// FIXME Construct a Valtree from this ScalarInt when introducing Valtrees
let const_value = ConstValue::Scalar(Scalar::Int(lit));
self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, const_value, node.ty)))
let val = ty::ValTree::from_scalar_int(lit);
self.nodes.push(Node::Leaf(ty::Const::from_value(self.tcx, val, node.ty)))
}
&ExprKind::NamedConst { def_id, substs, user_ty: _ } => {
let uneval = ty::Unevaluated::new(ty::WithOptConstParam::unknown(def_id), substs);

View file

@ -594,22 +594,24 @@ fn process_changed_obligations(
let mut evaluate = |c: Const<'tcx>| {
if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
match self.selcx.infcx().const_eval_resolve(
match self.selcx.infcx().try_const_eval_resolve(
obligation.param_env,
unevaluated,
c.ty(),
Some(obligation.cause.span),
) {
Ok(val) => Ok(Const::from_value(self.selcx.tcx(), val, c.ty())),
Err(ErrorHandled::TooGeneric) => {
stalled_on.extend(
unevaluated
.substs
.iter()
.filter_map(TyOrConstInferVar::maybe_from_generic_arg),
);
Err(ErrorHandled::TooGeneric)
}
Err(err) => Err(err),
Ok(val) => Ok(val),
Err(e) => match e {
ErrorHandled::TooGeneric => {
stalled_on.extend(
unevaluated.substs.iter().filter_map(
TyOrConstInferVar::maybe_from_generic_arg,
),
);
Err(ErrorHandled::TooGeneric)
}
_ => Err(e),
},
}
} else {
Ok(c)

View file

@ -618,11 +618,14 @@ fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
}
}
#[instrument(skip(self), level = "debug")]
fn fold_const(&mut self, constant: ty::Const<'tcx>) -> ty::Const<'tcx> {
if self.selcx.tcx().lazy_normalization() || !self.eager_inference_replacement {
constant
} else {
let constant = constant.super_fold_with(self);
debug!(?constant);
debug!("self.param_env: {:?}", self.param_env);
constant.eval(self.selcx.tcx(), self.param_env)
}
}

View file

@ -100,7 +100,7 @@ fn normalize<T>(&self, value: T) -> Result<Normalized<'tcx, T>, NoSolution>
}
}
/// Visitor to find the maximum escaping bound var
// Visitor to find the maximum escaping bound var
struct MaxEscapingBoundVarVisitor {
// The index which would count as escaping
outer_index: ty::DebruijnIndex,
@ -336,12 +336,15 @@ fn try_fold_mir_const(
) -> Result<mir::ConstantKind<'tcx>, Self::Error> {
Ok(match constant {
mir::ConstantKind::Ty(c) => {
let const_folded = c.try_fold_with(self)?;
let const_folded = c.try_super_fold_with(self)?;
match const_folded.kind() {
ty::ConstKind::Value(cv) => {
// FIXME With Valtrees we need to convert `cv: ValTree`
// to a `ConstValue` here.
mir::ConstantKind::Val(cv, const_folded.ty())
ty::ConstKind::Value(valtree) => {
let tcx = self.infcx.tcx;
let ty = const_folded.ty();
let const_val = tcx.valtree_to_const_val((ty, valtree));
debug!(?ty, ?valtree, ?const_val);
mir::ConstantKind::Val(const_val, ty)
}
_ => mir::ConstantKind::Ty(const_folded),
}

View file

@ -636,13 +636,15 @@ fn evaluate_predicate_recursively<'o>(
let evaluate = |c: ty::Const<'tcx>| {
if let ty::ConstKind::Unevaluated(unevaluated) = c.kind() {
self.infcx
.const_eval_resolve(
obligation.param_env,
unevaluated,
Some(obligation.cause.span),
)
.map(|val| ty::Const::from_value(self.tcx(), val, c.ty()))
match self.infcx.try_const_eval_resolve(
obligation.param_env,
unevaluated,
c.ty(),
Some(obligation.cause.span),
) {
Ok(val) => Ok(val),
Err(e) => Err(e),
}
} else {
Ok(c)
}

View file

@ -25,7 +25,6 @@ pub(crate) fn provide(p: &mut Providers) {
};
}
#[instrument(level = "debug", skip(tcx))]
fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<'tcx> + PartialEq + Copy>(
tcx: TyCtxt<'tcx>,
goal: ParamEnvAnd<'tcx, T>,

View file

@ -112,7 +112,6 @@ fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
}
}
#[instrument(level = "debug", skip(tcx))]
fn resolve_instance<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>,
@ -141,7 +140,6 @@ fn resolve_instance_of_const_arg<'tcx>(
)
}
#[instrument(level = "debug", skip(tcx))]
fn inner_resolve_instance<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>,

View file

@ -15,6 +15,7 @@
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::mir;
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
@ -270,7 +271,7 @@ pub(crate) fn print_evaluated_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option<St
(_, &ty::Ref(..)) => None,
(ConstValue::Scalar(_), &ty::Adt(_, _)) => None,
(ConstValue::Scalar(_), _) => {
let const_ = ty::Const::from_value(tcx, val, ty);
let const_ = mir::ConstantKind::from_value(val, ty);
Some(print_const_with_custom_print_scalar(tcx, const_))
}
_ => None,
@ -304,19 +305,18 @@ fn format_integer_with_underscore_sep(num: &str) -> String {
.collect()
}
fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: ty::Const<'_>) -> String {
fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: mir::ConstantKind<'_>) -> String {
// 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`.
match (ct.kind(), ct.ty().kind()) {
(ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Uint(ui)) => {
match (ct, ct.ty().kind()) {
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Uint(ui)) => {
format!("{}{}", format_integer_with_underscore_sep(&int.to_string()), ui.name_str())
}
(ty::ConstKind::Value(ConstValue::Scalar(int)), ty::Int(i)) => {
(mir::ConstantKind::Val(ConstValue::Scalar(int), _), ty::Int(i)) => {
let ty = tcx.lift(ct.ty()).unwrap();
let size = tcx.layout_of(ty::ParamEnv::empty().and(ty)).unwrap().size;
let data = int.assert_bits(size);
let sign_extended_data = size.sign_extend(data) as i128;
format!(
"{}{}",
format_integer_with_underscore_sep(&sign_extended_data.to_string()),

View file

@ -37,7 +37,7 @@
// Const generic parameter
// gdb-command:info functions -q function_names::const_generic_fn.*
// gdb-check:[...]static fn function_names::const_generic_fn_bool<false>();
// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#3fcd7c34c1555be6}>();
// gdb-check:[...]static fn function_names::const_generic_fn_non_int<{CONST#6348c650c7b26618}>();
// gdb-check:[...]static fn function_names::const_generic_fn_signed_int<-7>();
// gdb-check:[...]static fn function_names::const_generic_fn_unsigned_int<14>();
@ -76,7 +76,7 @@
// Const generic parameter
// cdb-command:x a!function_names::const_generic_fn*
// cdb-check:[...] a!function_names::const_generic_fn_bool<false> (void)
// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$3fcd7c34c1555be6> (void)
// cdb-check:[...] a!function_names::const_generic_fn_non_int<CONST$6348c650c7b26618> (void)
// cdb-check:[...] a!function_names::const_generic_fn_unsigned_int<14> (void)
// cdb-check:[...] a!function_names::const_generic_fn_signed_int<-7> (void)

View file

@ -14,7 +14,7 @@ impl Tr for str {
type Arr = [u8; 8];
#[cfg(cfail)]
type Arr = [u8; Self::C];
//[cfail]~^ ERROR cycle detected when simplifying constant
//[cfail]~^ ERROR cycle detected when evaluating type-level constant
}
fn main() {}

View file

@ -21,41 +21,41 @@ fn main() -> () {
}
alloc1 (static: FOO, size: 8, align: 4) {
alloc28 03 00 00 00 ....
alloc22 03 00 00 00 ....
}
alloc28 (size: 48, align: 4) {
0x00 00 00 00 00 __ __ __ __ alloc13 00 00 00 00 ........
0x10 00 00 00 00 __ __ __ __ alloc18 02 00 00 00 ........
0x20 01 00 00 00 2a 00 00 00 alloc26 03 00 00 00 ....*.......
alloc22 (size: 48, align: 4) {
0x00 00 00 00 00 __ __ __ __ alloc9 00 00 00 00 ........
0x10 00 00 00 00 __ __ __ __ alloc14 02 00 00 00 ........
0x20 01 00 00 00 2a 00 00 00 alloc20 03 00 00 00 ....*.......
}
alloc13 (size: 0, align: 4) {}
alloc9 (size: 0, align: 4) {}
alloc18 (size: 8, align: 4) {
alloc16 alloc17
alloc14 (size: 8, align: 4) {
alloc12 alloc13
}
alloc16 (size: 1, align: 1) {
alloc12 (size: 1, align: 1) {
05 .
}
alloc17 (size: 1, align: 1) {
alloc13 (size: 1, align: 1) {
06 .
}
alloc26 (size: 12, align: 4) {
a22+0x3 alloc23 a25+0x2
alloc20 (size: 12, align: 4) {
a17+0x3 alloc18 a19+0x2
}
alloc22 (size: 4, align: 1) {
alloc17 (size: 4, align: 1) {
2a 45 15 6f *E.o
}
alloc23 (size: 1, align: 1) {
alloc18 (size: 1, align: 1) {
2a *
}
alloc25 (size: 4, align: 1) {
alloc19 (size: 4, align: 1) {
2a 45 15 6f *E.o
}

View file

@ -21,44 +21,44 @@ fn main() -> () {
}
alloc1 (static: FOO, size: 16, align: 8) {
alloc28 03 00 00 00 00 00 00 00 ........
alloc22 03 00 00 00 00 00 00 00 ........
}
alloc28 (size: 72, align: 8) {
0x00 00 00 00 00 __ __ __ __ alloc13 ....
alloc22 (size: 72, align: 8) {
0x00 00 00 00 00 __ __ __ __ alloc9 ....
0x10 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ ............
0x20 alloc18 02 00 00 00 00 00 00 00 ........
0x30 01 00 00 00 2a 00 00 00 alloc26 ....*...
0x20 alloc14 02 00 00 00 00 00 00 00 ........
0x30 01 00 00 00 2a 00 00 00 alloc20 ....*...
0x40 03 00 00 00 00 00 00 00 ........
}
alloc13 (size: 0, align: 8) {}
alloc9 (size: 0, align: 8) {}
alloc18 (size: 16, align: 8) {
alloc16 alloc17
alloc14 (size: 16, align: 8) {
alloc12 alloc13
}
alloc16 (size: 1, align: 1) {
alloc12 (size: 1, align: 1) {
05 .
}
alloc17 (size: 1, align: 1) {
alloc13 (size: 1, align: 1) {
06 .
}
alloc26 (size: 24, align: 8) {
0x00 alloc22+0x3 alloc23
0x10 alloc25+0x2
alloc20 (size: 24, align: 8) {
0x00 alloc17+0x3 alloc18
0x10 alloc19+0x2
}
alloc22 (size: 4, align: 1) {
alloc17 (size: 4, align: 1) {
2a 45 15 6f *E.o
}
alloc23 (size: 1, align: 1) {
alloc18 (size: 1, align: 1) {
2a *
}
alloc25 (size: 4, align: 1) {
alloc19 (size: 4, align: 1) {
2a 45 15 6f *E.o
}

View file

@ -36,7 +36,7 @@
+ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ StorageLive(_8); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ _8 = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: NonNull::<u32> { pointer: {0x4 as *const u32} }, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ _8 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
// mir::Constant
- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
- // + user_ty: UserType(1)
@ -46,7 +46,7 @@
- bb2: {
+ // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef(..)) }
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
+ Deinit((*_7)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ ((*_7).0: alloc::raw_vec::RawVec<u32>) = move _8; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ ((*_7).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL

View file

@ -36,7 +36,7 @@
+ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ _7 = &mut (*_5); // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43
+ StorageLive(_8); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ _8 = const alloc::raw_vec::RawVec::<u32> { ptr: Unique::<u32> { pointer: NonNull::<u32> { pointer: {0x4 as *const u32} }, _marker: PhantomData::<u32> }, cap: 0_usize, alloc: std::alloc::Global }; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ _8 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
// mir::Constant
- // + span: $DIR/inline-into-box-place.rs:8:33: 8:41
- // + user_ty: UserType(1)
@ -46,7 +46,7 @@
- bb2: {
+ // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ // + user_ty: UserType(0)
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Value(ByRef(..)) }
+ // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) }
+ Deinit((*_7)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ ((*_7).0: alloc::raw_vec::RawVec<u32>) = move _8; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL
+ ((*_7).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL

View file

@ -23,7 +23,7 @@
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
let mut _1: [usize; Const { ty: usize, kind: Value(Scalar(0x00000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x00000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:16: 18:17
let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18
let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18
@ -63,7 +63,7 @@ fn main() -> () {
FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
_7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
}
bb2: {

View file

@ -23,7 +23,7 @@
|
fn main() -> () {
let mut _0: (); // return place in scope 0 at $DIR/region-subtyping-basic.rs:16:11: 16:11
let mut _1: [usize; Const { ty: usize, kind: Value(Scalar(0x0000000000000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
let mut _1: [usize; Const { ty: usize, kind: Value(Leaf(0x0000000000000003)) }]; // in scope 0 at $DIR/region-subtyping-basic.rs:17:9: 17:14
let _3: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:16: 18:17
let mut _4: usize; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18
let mut _5: bool; // in scope 0 at $DIR/region-subtyping-basic.rs:18:14: 18:18
@ -63,7 +63,7 @@ fn main() -> () {
FakeRead(ForLet(None), _6); // bb1[4]: scope 2 at $DIR/region-subtyping-basic.rs:19:9: 19:10
StorageLive(_7); // bb1[5]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
_7 = const ConstValue(Scalar(0x01): bool); // bb1[6]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
switchInt(move _7) -> [Const(Value(Scalar(0x00)): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
switchInt(move _7) -> [ConstValue(Scalar(0x00): bool): bb4, otherwise: bb2]; // bb1[7]: scope 3 at $DIR/region-subtyping-basic.rs:20:8: 20:12
}
bb2: {

View file

@ -1,9 +1,9 @@
// build-fail
//~^ ERROR cycle detected when normalizing `<() as Tr>::A` [E0391]
// Cyclic assoc. const defaults don't error unless *used*
trait Tr {
const A: u8 = Self::B;
//~^ cycle detected when const-evaluating + checking `Tr::A`
const B: u8 = Self::A;
}

View file

@ -1,42 +1,20 @@
error[E0391]: cycle detected when normalizing `<() as Tr>::A`
|
note: ...which requires simplifying constant for the type system `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:6:5
error[E0391]: cycle detected when const-evaluating + checking `Tr::A`
--> $DIR/defaults-cyclic-fail.rs:5:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:6:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Tr::A`...
--> $DIR/defaults-cyclic-fail.rs:6:5
|
LL | const A: u8 = Self::B;
| ^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `<() as Tr>::B`...
note: ...which requires simplifying constant for the type system `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
|
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
|
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Tr::B`...
--> $DIR/defaults-cyclic-fail.rs:8:5
|
LL | const B: u8 = Self::A;
| ^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires normalizing `<() as Tr>::A`, completing the cycle
= note: ...which again requires const-evaluating + checking `Tr::A`, completing the cycle
note: cycle used when const-evaluating + checking `main::promoted[1]`
--> $DIR/defaults-cyclic-fail.rs:14:1
--> $DIR/defaults-cyclic-fail.rs:16:16
|
LL | fn main() {
| ^^^^^^^^^
LL | assert_eq!(<() as Tr>::A, 0);
| ^^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -1,16 +1,10 @@
error[E0391]: cycle detected when elaborating drops for `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:22
|
LL | const BAR: u32 = IMPL_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^
|
= note: ...which requires normalizing `IMPL_REF_BAR`...
note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`...
note: ...which requires const-evaluating + checking `IMPL_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
@ -20,17 +14,6 @@ note: ...which requires const-evaluating + checking `IMPL_REF_BAR`...
|
LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
|
LL | const BAR: u32 = IMPL_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
|
LL | const BAR: u32 = IMPL_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-impl.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5
|

View file

@ -1,16 +1,10 @@
error[E0391]: cycle detected when elaborating drops for `FooDefault::BAR`
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:22
|
LL | const BAR: u32 = DEFAULT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^^^
|
= note: ...which requires normalizing `DEFAULT_REF_BAR`...
note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`...
note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
@ -20,17 +14,6 @@ note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`...
|
LL | const DEFAULT_REF_BAR: u32 = <GlobalDefaultRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `<GlobalDefaultRef as FooDefault>::BAR`...
note: ...which requires simplifying constant for the type system `FooDefault::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
|
LL | const BAR: u32 = DEFAULT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `FooDefault::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
|
LL | const BAR: u32 = DEFAULT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `FooDefault::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5
|

View file

@ -1,16 +1,10 @@
error[E0391]: cycle detected when elaborating drops for `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:22
|
LL | const BAR: u32 = TRAIT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| ^^^^^^^^^^^^^
|
= note: ...which requires normalizing `TRAIT_REF_BAR`...
note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1
|
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`...
note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1
|
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
@ -20,17 +14,6 @@ note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`...
|
LL | const TRAIT_REF_BAR: u32 = <GlobalTraitRef>::BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `<GlobalTraitRef as Foo>::BAR`...
note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
|
LL | const BAR: u32 = TRAIT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
|
LL | const BAR: u32 = TRAIT_REF_BAR;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `<impl at $DIR/issue-24949-assoc-const-static-recursion-trait.rs:11:1: 13:2>::BAR`...
--> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5
|

View file

@ -2,6 +2,8 @@
// The `panic!()` below is important to trigger the fixed ICE.
const _CONST: &[u8] = &f(&[], |_| {});
//~^ ERROR any use of this value
//~| WARNING this was previously
const fn f<F>(_: &[u8], _: F) -> &[u8]
where

View file

@ -1,5 +1,5 @@
error[E0080]: evaluation of constant value failed
--> $DIR/issue-81899.rs:10:5
--> $DIR/issue-81899.rs:12:5
|
LL | const _CONST: &[u8] = &f(&[], |_| {});
| -------------- inside `_CONST` at $DIR/issue-81899.rs:4:24
@ -7,11 +7,23 @@ LL | const _CONST: &[u8] = &f(&[], |_| {});
LL | panic!()
| ^^^^^^^^
| |
| the evaluated program panicked at 'explicit panic', $DIR/issue-81899.rs:10:5
| the evaluated program panicked at 'explicit panic', $DIR/issue-81899.rs:12:5
| inside `f::<[closure@$DIR/issue-81899.rs:4:31: 4:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
|
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
error: any use of this value will cause an error
--> $DIR/issue-81899.rs:4:23
|
LL | const _CONST: &[u8] = &f(&[], |_| {});
| ----------------------^^^^^^^^^^^^^^^-
| |
| referenced constant has errors
|
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0080`.

View file

@ -1,6 +1,8 @@
// Regression test related to issue 88434
const _CONST: &() = &f(&|_| {});
//~^ ERROR any use of this value
//~| WARNING this was previously
const fn f<F>(_: &F)
where

View file

@ -1,5 +1,5 @@
error[E0080]: evaluation of constant value failed
--> $DIR/issue-88434-minimal-example.rs:9:5
--> $DIR/issue-88434-minimal-example.rs:11:5
|
LL | const _CONST: &() = &f(&|_| {});
| ---------- inside `_CONST` at $DIR/issue-88434-minimal-example.rs:3:22
@ -7,11 +7,23 @@ LL | const _CONST: &() = &f(&|_| {});
LL | panic!()
| ^^^^^^^^
| |
| the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:9:5
| the evaluated program panicked at 'explicit panic', $DIR/issue-88434-minimal-example.rs:11:5
| inside `f::<[closure@$DIR/issue-88434-minimal-example.rs:3:25: 3:31]>` at $SRC_DIR/std/src/panic.rs:LL:COL
|
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
error: any use of this value will cause an error
--> $DIR/issue-88434-minimal-example.rs:3:21
|
LL | const _CONST: &() = &f(&|_| {});
| --------------------^^^^^^^^^^^-
| |
| referenced constant has errors
|
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0080`.

View file

@ -1,6 +1,8 @@
// Regression test for issue 88434
const _CONST: &[u8] = &f(&[], |_| {});
//~^ ERROR any use of this value will cause an error
//~| WARNING this was previously
const fn f<F>(_: &[u8], _: F) -> &[u8]
where

View file

@ -1,5 +1,5 @@
error[E0080]: evaluation of constant value failed
--> $DIR/issue-88434-removal-index-should-be-less.rs:9:5
--> $DIR/issue-88434-removal-index-should-be-less.rs:11:5
|
LL | const _CONST: &[u8] = &f(&[], |_| {});
| -------------- inside `_CONST` at $DIR/issue-88434-removal-index-should-be-less.rs:3:24
@ -7,11 +7,23 @@ LL | const _CONST: &[u8] = &f(&[], |_| {});
LL | panic!()
| ^^^^^^^^
| |
| the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:9:5
| the evaluated program panicked at 'explicit panic', $DIR/issue-88434-removal-index-should-be-less.rs:11:5
| inside `f::<[closure@$DIR/issue-88434-removal-index-should-be-less.rs:3:31: 3:37]>` at $SRC_DIR/std/src/panic.rs:LL:COL
|
= note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to previous error
error: any use of this value will cause an error
--> $DIR/issue-88434-removal-index-should-be-less.rs:3:23
|
LL | const _CONST: &[u8] = &f(&[], |_| {});
| ----------------------^^^^^^^^^^^^^^^-
| |
| referenced constant has errors
|
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: aborting due to 2 previous errors
For more information about this error, try `rustc --explain E0080`.

View file

@ -2,7 +2,7 @@ error[E0308]: mismatched types
--> $DIR/different_generic_args_array.rs:9:9
|
LL | x = Const::<{ [4] }> {};
| ^^^^^^^^^^^^^^^^^^^ expected `3_usize`, found `4_usize`
| ^^^^^^^^^^^^^^^^^^^ expected `[3_usize]`, found `[4_usize]`
|
= note: expected struct `Const<[3_usize]>`
found struct `Const<[4_usize]>`

View file

@ -10,7 +10,11 @@ note: ...which requires checking if `TensorDimension` fulfills its obligations..
LL | trait TensorDimension {
| ^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires resolving instance `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>::DIM`, completing the cycle
= note: cycle used when normalizing `<LazyUpdim<T, { T::DIM }, DIM> as TensorDimension>::DIM`
note: cycle used when checking if `TensorDimension` fulfills its obligations
--> $DIR/issue-83765.rs:4:1
|
LL | trait TensorDimension {
| ^^^^^^^^^^^^^^^^^^^^^
error: aborting due to previous error

View file

@ -4,7 +4,7 @@ error[E0080]: evaluation of constant value failed
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| memory access failed: alloc7 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
| memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
::: $DIR/out_of_bounds_read.rs:12:33
@ -18,7 +18,7 @@ error[E0080]: evaluation of constant value failed
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| memory access failed: alloc7 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
| memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL
@ -37,7 +37,7 @@ error[E0080]: evaluation of constant value failed
LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| memory access failed: alloc7 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
| memory access failed: alloc5 has size 4, so pointer to 4 bytes starting at offset 4 is out-of-bounds
| inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL
|
::: $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL

View file

@ -1,5 +1,4 @@
// compile-flags: -Ztreat-err-as-bug=2
//~^ ERROR 1:1: 1:1: ty::ConstKind::Error constructed but no error reported
// build-fail
// failure-status: 101
// rustc-env:RUST_BACKTRACE=1
@ -23,5 +22,7 @@
fn main() {
let x: &'static i32 = &X;
//~^ ERROR evaluation of constant value failed
//~| ERROR erroneous constant used
//~| WARNING this was previously accepted by the compiler
println!("x={}", x);
}

View file

@ -1,5 +1,5 @@
warning: any use of this value will cause an error
--> $DIR/const-eval-query-stack.rs:20:16
--> $DIR/const-eval-query-stack.rs:19:16
|
LL | const X: i32 = 1 / 0;
| ---------------^^^^^-
@ -7,7 +7,7 @@ LL | const X: i32 = 1 / 0;
| attempt to divide `1_i32` by zero
|
note: the lint level is defined here
--> $DIR/const-eval-query-stack.rs:19:8
--> $DIR/const-eval-query-stack.rs:18:8
|
LL | #[warn(const_err)]
| ^^^^^^^^^
@ -15,13 +15,23 @@ LL | #[warn(const_err)]
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error[E0080]: evaluation of constant value failed
--> $DIR/const-eval-query-stack.rs:24:28
--> $DIR/const-eval-query-stack.rs:23:28
|
LL | let x: &'static i32 = &X;
| ^ referenced constant has errors
error: erroneous constant used
--> $DIR/const-eval-query-stack.rs:23:27
|
LL | let x: &'static i32 = &X;
| ^^ referenced constant has errors
|
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
query stack during panic:
#0 [try_normalize_mir_const_after_erasing_regions] normalizing `main::promoted[1]`
#1 [mir_drops_elaborated_and_const_checked] elaborating drops for `main`
#2 [optimized_mir] optimizing MIR for `main`
#3 [collect_and_partition_mono_items] collect_and_partition_mono_items
#0 [mir_drops_elaborated_and_const_checked] elaborating drops for `main`
#1 [optimized_mir] optimizing MIR for `main`
#2 [collect_and_partition_mono_items] collect_and_partition_mono_items
end of query stack

View file

@ -149,8 +149,19 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
╾─allocN─╼ │ ╾──╼
}
error: any use of this value will cause an error
--> $DIR/ub-wide-ptr.rs:87:40
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
| ---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
| referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:93:1
--> $DIR/ub-wide-ptr.rs:95:1
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean
@ -160,8 +171,19 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3
╾allocN─╼ │ ╾──╼
}
error: any use of this value will cause an error
--> $DIR/ub-wide-ptr.rs:95:42
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
| referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:96:1
--> $DIR/ub-wide-ptr.rs:100:1
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean
@ -171,8 +193,19 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran
╾allocN─╼ │ ╾──╼
}
error: any use of this value will cause an error
--> $DIR/ub-wide-ptr.rs:100:42
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
| referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:103:1
--> $DIR/ub-wide-ptr.rs:109:1
|
LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
LL | |
@ -187,7 +220,7 @@ LL | | };
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:111:1
--> $DIR/ub-wide-ptr.rs:117:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
@ -198,7 +231,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:114:1
--> $DIR/ub-wide-ptr.rs:120:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
@ -209,7 +242,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:117:1
--> $DIR/ub-wide-ptr.rs:123:1
|
LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer
@ -220,7 +253,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:119:1
--> $DIR/ub-wide-ptr.rs:125:1
|
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer
@ -231,7 +264,7 @@ LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:121:1
--> $DIR/ub-wide-ptr.rs:127:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
@ -242,7 +275,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:123:1
--> $DIR/ub-wide-ptr.rs:129:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
@ -253,7 +286,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:125:1
--> $DIR/ub-wide-ptr.rs:131:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function)
@ -264,7 +297,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:129:1
--> $DIR/ub-wide-ptr.rs:135:1
|
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
@ -275,7 +308,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:133:1
--> $DIR/ub-wide-ptr.rs:139:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer
@ -286,7 +319,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:135:1
--> $DIR/ub-wide-ptr.rs:141:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable
@ -297,17 +330,17 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm
}
error[E0080]: could not evaluate static initializer
--> $DIR/ub-wide-ptr.rs:141:5
--> $DIR/ub-wide-ptr.rs:147:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer
error[E0080]: could not evaluate static initializer
--> $DIR/ub-wide-ptr.rs:145:5
--> $DIR/ub-wide-ptr.rs:151:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 12 bytes starting at offset N is out-of-bounds
error: aborting due to 29 previous errors
error: aborting due to 32 previous errors
For more information about this error, try `rustc --explain E0080`.

View file

@ -149,8 +149,19 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
╾───────allocN───────╼ │ ╾──────╼
}
error: any use of this value will cause an error
--> $DIR/ub-wide-ptr.rs:87:40
|
LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
| ---------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
| referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:93:1
--> $DIR/ub-wide-ptr.rs:95:1
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.0: encountered 0x03, but expected a boolean
@ -160,8 +171,19 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3
╾──────allocN───────╼ │ ╾──────╼
}
error: any use of this value will cause an error
--> $DIR/ub-wide-ptr.rs:95:42
|
LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
| -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
| referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:96:1
--> $DIR/ub-wide-ptr.rs:100:1
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.1[0]: encountered 0x03, but expected a boolean
@ -171,8 +193,19 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran
╾──────allocN───────╼ │ ╾──────╼
}
error: any use of this value will cause an error
--> $DIR/ub-wide-ptr.rs:100:42
|
LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
| -----------------------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
| |
| referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:103:1
--> $DIR/ub-wide-ptr.rs:109:1
|
LL | / const RAW_SLICE_LENGTH_UNINIT: *const [u8] = unsafe {
LL | |
@ -187,7 +220,7 @@ LL | | };
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:111:1
--> $DIR/ub-wide-ptr.rs:117:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
@ -198,7 +231,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:114:1
--> $DIR/ub-wide-ptr.rs:120:1
|
LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered too small vtable
@ -209,7 +242,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:117:1
--> $DIR/ub-wide-ptr.rs:123:1
|
LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered dangling vtable pointer in wide pointer
@ -220,7 +253,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:119:1
--> $DIR/ub-wide-ptr.rs:125:1
|
LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92u8, &[0u8; 128])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered unaligned vtable pointer in wide pointer
@ -231,7 +264,7 @@ LL | const TRAIT_OBJ_UNALIGNED_VTABLE: &dyn Trait = unsafe { mem::transmute((&92
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:121:1
--> $DIR/ub-wide-ptr.rs:127:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92u8, &[0usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
@ -242,7 +275,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NULL: &dyn Trait = unsafe { mem::transmute((&92
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:123:1
--> $DIR/ub-wide-ptr.rs:129:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u8, &[1usize; 8])) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (not pointing to a function)
@ -253,7 +286,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_INT: &dyn Trait = unsafe { mem::transmute((&92u
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:125:1
--> $DIR/ub-wide-ptr.rs:131:1
|
LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .0: encountered invalid drop function pointer in vtable (not pointing to a function)
@ -264,7 +297,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:129:1
--> $DIR/ub-wide-ptr.rs:135:1
|
LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .<deref>.<dyn-downcast>: encountered 0x03, but expected a boolean
@ -275,7 +308,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_,
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:133:1
--> $DIR/ub-wide-ptr.rs:139:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer
@ -286,7 +319,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute
}
error[E0080]: it is undefined behavior to use this value
--> $DIR/ub-wide-ptr.rs:135:1
--> $DIR/ub-wide-ptr.rs:141:1
|
LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered too small vtable
@ -297,17 +330,17 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm
}
error[E0080]: could not evaluate static initializer
--> $DIR/ub-wide-ptr.rs:141:5
--> $DIR/ub-wide-ptr.rs:147:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, 0usize))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer
error[E0080]: could not evaluate static initializer
--> $DIR/ub-wide-ptr.rs:145:5
--> $DIR/ub-wide-ptr.rs:151:5
|
LL | mem::transmute::<_, &dyn Trait>((&92u8, &3u64))
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: allocN has size N, so pointer to 24 bytes starting at offset N is out-of-bounds
error: aborting due to 29 previous errors
error: aborting due to 32 previous errors
For more information about this error, try `rustc --explain E0080`.

View file

@ -86,15 +86,21 @@ impl Trait for bool {}
// bad data *inside* the slice
const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }];
//~^ ERROR it is undefined behavior to use this value
//~| ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
// good MySliceBool
const MYSLICE_GOOD: &MySliceBool = &MySlice(true, [false]);
// bad: sized field is not okay
const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]);
//~^ ERROR it is undefined behavior to use this value
//~| ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
// bad: unsized part is not okay
const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]);
//~^ ERROR it is undefined behavior to use this value
//~| ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
// # raw slice
const RAW_SLICE_VALID: *const [u8] = unsafe { mem::transmute((&42u8, 1usize)) }; // ok

View file

@ -28,14 +28,22 @@ fn f32() {
const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
//~^ ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
//~^ ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
// LLVM does not guarantee that loads and stores of NaNs preserve their exact bit pattern.
// In practice, this seems to only cause a problem on x86, since the most widely used calling
// convention mandates that floating point values are returned on the x87 FPU stack. See #73328.
if !cfg!(target_arch = "x86") {
const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
//~^ ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
//~^ ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
}
}
@ -47,12 +55,20 @@ fn f64() {
const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
//~^ ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
//~^ ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
// See comment above.
if !cfg!(target_arch = "x86") {
const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
//~^ ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
//~^ ERROR any use of this value will cause an error
//~| WARNING this was previously accepted
}
}

View file

@ -56,6 +56,55 @@ LL | const MASKED_NAN2: u32 = f32::NAN.to_bits() ^ 0x0055_5555;
|
= note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: any use of this value will cause an error
--> $DIR/const-float-bits-reject-conv.rs:30:34
|
LL | const _: () = assert!($a);
| --------------------------
...
LL | const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
| ^^^^^^^^^^^ referenced constant has errors
|
= note: `#[deny(const_err)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: any use of this value will cause an error
--> $DIR/const-float-bits-reject-conv.rs:33:34
|
LL | const _: () = assert!($a);
| --------------------------
...
LL | const_assert!(f32::from_bits(MASKED_NAN1).is_nan());
| ^^^^^^^^^^^ referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: any use of this value will cause an error
--> $DIR/const-float-bits-reject-conv.rs:41:38
|
LL | const _: () = assert!($a == $b);
| --------------------------------
...
LL | const_assert!(f32::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
| ^^^^^^^^^^^ referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: any use of this value will cause an error
--> $DIR/const-float-bits-reject-conv.rs:44:38
|
LL | const _: () = assert!($a == $b);
| --------------------------------
...
LL | const_assert!(f32::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
| ^^^^^^^^^^^ referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error[E0080]: evaluation of constant value failed
--> $SRC_DIR/core/src/num/f64.rs:LL:COL
|
@ -78,10 +127,10 @@ LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
LL | called_in_const.call_once(arg)
| ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64}, [closure@core::f64::<impl f64>::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
::: $DIR/const-float-bits-reject-conv.rs:46:30
::: $DIR/const-float-bits-reject-conv.rs:54:30
|
LL | const MASKED_NAN1: u64 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA;
| ------------------ inside `f64::MASKED_NAN1` at $DIR/const-float-bits-reject-conv.rs:46:30
| ------------------ inside `f64::MASKED_NAN1` at $DIR/const-float-bits-reject-conv.rs:54:30
|
= note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
@ -107,13 +156,61 @@ LL | extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
LL | called_in_const.call_once(arg)
| ------------------------------ inside `const_eval_select::<(f64,), fn(f64) -> u64 {core::f64::<impl f64>::to_bits::ct_f64_to_u64}, [closure@core::f64::<impl f64>::to_bits::{closure#0}], u64>` at $SRC_DIR/core/src/intrinsics.rs:LL:COL
|
::: $DIR/const-float-bits-reject-conv.rs:47:30
::: $DIR/const-float-bits-reject-conv.rs:55:30
|
LL | const MASKED_NAN2: u64 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555;
| ------------------ inside `f64::MASKED_NAN2` at $DIR/const-float-bits-reject-conv.rs:47:30
| ------------------ inside `f64::MASKED_NAN2` at $DIR/const-float-bits-reject-conv.rs:55:30
|
= note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info)
error: aborting due to 4 previous errors
error: any use of this value will cause an error
--> $DIR/const-float-bits-reject-conv.rs:57:34
|
LL | const _: () = assert!($a);
| --------------------------
...
LL | const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
| ^^^^^^^^^^^ referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: any use of this value will cause an error
--> $DIR/const-float-bits-reject-conv.rs:60:34
|
LL | const _: () = assert!($a);
| --------------------------
...
LL | const_assert!(f64::from_bits(MASKED_NAN1).is_nan());
| ^^^^^^^^^^^ referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: any use of this value will cause an error
--> $DIR/const-float-bits-reject-conv.rs:66:38
|
LL | const _: () = assert!($a == $b);
| --------------------------------
...
LL | const_assert!(f64::from_bits(MASKED_NAN1).to_bits(), MASKED_NAN1);
| ^^^^^^^^^^^ referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: any use of this value will cause an error
--> $DIR/const-float-bits-reject-conv.rs:69:38
|
LL | const _: () = assert!($a == $b);
| --------------------------------
...
LL | const_assert!(f64::from_bits(MASKED_NAN2).to_bits(), MASKED_NAN2);
| ^^^^^^^^^^^ referenced constant has errors
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #71800 <https://github.com/rust-lang/rust/issues/71800>
error: aborting due to 12 previous errors
For more information about this error, try `rustc --explain E0080`.

View file

@ -6,6 +6,7 @@
//~| ERROR mismatched types
//~| expected `usize`, found `bool`
const ARR: [i32; X] = [99; 34];
//~^ ERROR evaluation of constant value failed
const X1: usize = 42 || 39;
//~^ ERROR mismatched types
@ -15,6 +16,7 @@
//~| ERROR mismatched types
//~| expected `usize`, found `bool`
const ARR1: [i32; X1] = [99; 47];
//~^ ERROR evaluation of constant value failed
const X2: usize = -42 || -39;
//~^ ERROR mismatched types
@ -24,6 +26,7 @@
//~| ERROR mismatched types
//~| expected `usize`, found `bool`
const ARR2: [i32; X2] = [99; 18446744073709551607];
//~^ ERROR evaluation of constant value failed
const X3: usize = -42 && -39;
//~^ ERROR mismatched types
@ -33,36 +36,43 @@
//~| ERROR mismatched types
//~| expected `usize`, found `bool`
const ARR3: [i32; X3] = [99; 6];
//~^ ERROR evaluation of constant value failed
const Y: usize = 42.0 == 42.0;
//~^ ERROR mismatched types
//~| expected `usize`, found `bool`
const ARRR: [i32; Y] = [99; 1];
//~^ ERROR evaluation of constant value failed
const Y1: usize = 42.0 >= 42.0;
//~^ ERROR mismatched types
//~| expected `usize`, found `bool`
const ARRR1: [i32; Y1] = [99; 1];
//~^ ERROR evaluation of constant value failed
const Y2: usize = 42.0 <= 42.0;
//~^ ERROR mismatched types
//~| expected `usize`, found `bool`
const ARRR2: [i32; Y2] = [99; 1];
//~^ ERROR evaluation of constant value failed
const Y3: usize = 42.0 > 42.0;
//~^ ERROR mismatched types
//~| expected `usize`, found `bool`
const ARRR3: [i32; Y3] = [99; 0];
//~^ ERROR evaluation of constant value failed
const Y4: usize = 42.0 < 42.0;
//~^ ERROR mismatched types
//~| expected `usize`, found `bool`
const ARRR4: [i32; Y4] = [99; 0];
//~^ ERROR evaluation of constant value failed
const Y5: usize = 42.0 != 42.0;
//~^ ERROR mismatched types
//~| expected `usize`, found `bool`
const ARRR5: [i32; Y5] = [99; 0];
//~^ ERROR evaluation of constant value failed
fn main() {
let _ = ARR;

View file

@ -16,96 +16,157 @@ error[E0308]: mismatched types
LL | const X: usize = 42 && 39;
| ^^^^^^^^ expected `usize`, found `bool`
error[E0080]: evaluation of constant value failed
--> $DIR/const-integer-bool-ops.rs:8:18
|
LL | const ARR: [i32; X] = [99; 34];
| ^ referenced constant has errors
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:10:19
--> $DIR/const-integer-bool-ops.rs:11:19
|
LL | const X1: usize = 42 || 39;
| ^^ expected `bool`, found integer
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:10:25
--> $DIR/const-integer-bool-ops.rs:11:25
|
LL | const X1: usize = 42 || 39;
| ^^ expected `bool`, found integer
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:10:19
--> $DIR/const-integer-bool-ops.rs:11:19
|
LL | const X1: usize = 42 || 39;
| ^^^^^^^^ expected `usize`, found `bool`
error[E0080]: evaluation of constant value failed
--> $DIR/const-integer-bool-ops.rs:18:19
|
LL | const ARR1: [i32; X1] = [99; 47];
| ^^ referenced constant has errors
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:19:19
--> $DIR/const-integer-bool-ops.rs:21:19
|
LL | const X2: usize = -42 || -39;
| ^^^ expected `bool`, found integer
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:19:26
--> $DIR/const-integer-bool-ops.rs:21:26
|
LL | const X2: usize = -42 || -39;
| ^^^ expected `bool`, found integer
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:19:19
--> $DIR/const-integer-bool-ops.rs:21:19
|
LL | const X2: usize = -42 || -39;
| ^^^^^^^^^^ expected `usize`, found `bool`
error[E0308]: mismatched types
error[E0080]: evaluation of constant value failed
--> $DIR/const-integer-bool-ops.rs:28:19
|
LL | const ARR2: [i32; X2] = [99; 18446744073709551607];
| ^^ referenced constant has errors
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:31:19
|
LL | const X3: usize = -42 && -39;
| ^^^ expected `bool`, found integer
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:28:26
--> $DIR/const-integer-bool-ops.rs:31:26
|
LL | const X3: usize = -42 && -39;
| ^^^ expected `bool`, found integer
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:28:19
--> $DIR/const-integer-bool-ops.rs:31:19
|
LL | const X3: usize = -42 && -39;
| ^^^^^^^^^^ expected `usize`, found `bool`
error[E0080]: evaluation of constant value failed
--> $DIR/const-integer-bool-ops.rs:38:19
|
LL | const ARR3: [i32; X3] = [99; 6];
| ^^ referenced constant has errors
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:37:18
--> $DIR/const-integer-bool-ops.rs:41:18
|
LL | const Y: usize = 42.0 == 42.0;
| ^^^^^^^^^^^^ expected `usize`, found `bool`
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:42:19
error[E0080]: evaluation of constant value failed
--> $DIR/const-integer-bool-ops.rs:44:19
|
LL | const Y1: usize = 42.0 >= 42.0;
| ^^^^^^^^^^^^ expected `usize`, found `bool`
LL | const ARRR: [i32; Y] = [99; 1];
| ^ referenced constant has errors
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:47:19
|
LL | const Y1: usize = 42.0 >= 42.0;
| ^^^^^^^^^^^^ expected `usize`, found `bool`
error[E0080]: evaluation of constant value failed
--> $DIR/const-integer-bool-ops.rs:50:20
|
LL | const ARRR1: [i32; Y1] = [99; 1];
| ^^ referenced constant has errors
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:53:19
|
LL | const Y2: usize = 42.0 <= 42.0;
| ^^^^^^^^^^^^ expected `usize`, found `bool`
error[E0080]: evaluation of constant value failed
--> $DIR/const-integer-bool-ops.rs:56:20
|
LL | const ARRR2: [i32; Y2] = [99; 1];
| ^^ referenced constant has errors
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:52:19
--> $DIR/const-integer-bool-ops.rs:59:19
|
LL | const Y3: usize = 42.0 > 42.0;
| ^^^^^^^^^^^ expected `usize`, found `bool`
error[E0080]: evaluation of constant value failed
--> $DIR/const-integer-bool-ops.rs:62:20
|
LL | const ARRR3: [i32; Y3] = [99; 0];
| ^^ referenced constant has errors
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:57:19
--> $DIR/const-integer-bool-ops.rs:65:19
|
LL | const Y4: usize = 42.0 < 42.0;
| ^^^^^^^^^^^ expected `usize`, found `bool`
error[E0080]: evaluation of constant value failed
--> $DIR/const-integer-bool-ops.rs:68:20
|
LL | const ARRR4: [i32; Y4] = [99; 0];
| ^^ referenced constant has errors
error[E0308]: mismatched types
--> $DIR/const-integer-bool-ops.rs:62:19
--> $DIR/const-integer-bool-ops.rs:71:19
|
LL | const Y5: usize = 42.0 != 42.0;
| ^^^^^^^^^^^^ expected `usize`, found `bool`
error: aborting due to 18 previous errors
error[E0080]: evaluation of constant value failed
--> $DIR/const-integer-bool-ops.rs:74:20
|
LL | const ARRR5: [i32; Y5] = [99; 0];
| ^^ referenced constant has errors
For more information about this error, try `rustc --explain E0308`.
error: aborting due to 28 previous errors
Some errors have detailed explanations: E0080, E0308.
For more information about an error, try `rustc --explain E0080`.

View file

@ -19,7 +19,13 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
LL | const S: &'static mut str = &mut " hello ";
| ^^^^^^^^^^^^^^ cannot borrow as mutable
error: aborting due to 3 previous errors
error[E0080]: evaluation of constant value failed
--> $DIR/issue-76510.rs:11:70
|
LL | let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3));
| ^ referenced constant has errors
Some errors have detailed explanations: E0596, E0658, E0764.
For more information about an error, try `rustc --explain E0596`.
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0080, E0596, E0658, E0764.
For more information about an error, try `rustc --explain E0080`.

View file

@ -19,7 +19,13 @@ error[E0596]: cannot borrow data in a `&` reference as mutable
LL | const S: &'static mut str = &mut " hello ";
| ^^^^^^^^^^^^^^ cannot borrow as mutable
error: aborting due to 3 previous errors
error[E0080]: evaluation of constant value failed
--> $DIR/issue-76510.rs:11:70
|
LL | let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3));
| ^ referenced constant has errors
Some errors have detailed explanations: E0596, E0658, E0764.
For more information about an error, try `rustc --explain E0596`.
error: aborting due to 4 previous errors
Some errors have detailed explanations: E0080, E0596, E0658, E0764.
For more information about an error, try `rustc --explain E0080`.

View file

@ -9,6 +9,7 @@
const fn trigger() -> [(); unsafe {
let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3));
//~^ ERROR evaluation of constant value failed
0
}] {
[(); 0]

View file

@ -1,10 +1,10 @@
error[E0391]: cycle detected when simplifying constant for the type system `Foo::bytes::{constant#0}`
error[E0391]: cycle detected when evaluating type-level constant
--> $DIR/const-size_of-cycle.rs:4:17
|
LL | bytes: [u8; std::mem::size_of::<Foo>()]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`...
note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
--> $DIR/const-size_of-cycle.rs:4:17
|
LL | bytes: [u8; std::mem::size_of::<Foo>()]
@ -17,7 +17,7 @@ LL | bytes: [u8; std::mem::size_of::<Foo>()]
= note: ...which requires computing layout of `Foo`...
= note: ...which requires computing layout of `[u8; _]`...
= note: ...which requires normalizing `[u8; _]`...
= note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle
= note: ...which again requires evaluating type-level constant, completing the cycle
note: cycle used when checking that `Foo` is well-formed
--> $DIR/const-size_of-cycle.rs:3:1
|

View file

@ -4,6 +4,7 @@
//~^ ERROR mismatched types
//~| expected tuple, found `usize`
const ARR: [i32; TUP.0] = [];
//~^ ERROR evaluation of constant value failed
fn main() {
}

View file

@ -11,6 +11,13 @@ help: use a trailing comma to create a tuple with one element
LL | const TUP: (usize,) = (5usize << 64,);
| + ++
error: aborting due to previous error
error[E0080]: evaluation of constant value failed
--> $DIR/const-tup-index-span.rs:6:18
|
LL | const ARR: [i32; TUP.0] = [];
| ^^^ referenced constant has errors
For more information about this error, try `rustc --explain E0308`.
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0080, E0308.
For more information about an error, try `rustc --explain E0080`.

View file

@ -6,7 +6,7 @@ LL | fn main() {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 4, align: 4) {
╾─alloc8──╼ │ ╾──╼
╾─alloc7──╼ │ ╾──╼
}
error: erroneous constant used

View file

@ -6,7 +6,7 @@ LL | fn main() {
|
= note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior.
= note: the raw bytes of the constant (size: 8, align: 8) {
╾───────alloc8────────╼ │ ╾──────╼
╾───────alloc7────────╼ │ ╾──────╼
}
error: erroneous constant used

View file

@ -1,48 +1,20 @@
error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}`
error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{constant#0}`
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
|
note: ...which requires simplifying constant for the type system `Foo::B::{constant#0}`...
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`...
--> $DIR/issue-36163.rs:4:9
|
LL | B = A,
| ^
= note: ...which requires normalizing `A`...
note: ...which requires simplifying constant for the type system `A`...
--> $DIR/issue-36163.rs:1:1
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `A`...
--> $DIR/issue-36163.rs:1:1
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `A`...
--> $DIR/issue-36163.rs:1:1
|
LL | const A: isize = Foo::B as isize;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which requires normalizing `A`...
= note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/issue-36163.rs:1:1
= note: ...which again requires const-evaluating + checking `Foo::B::{constant#0}`, completing the cycle
note: cycle used when simplifying constant for the type system `Foo::B::{constant#0}`
--> $DIR/issue-36163.rs:4:9
|
LL | / const A: isize = Foo::B as isize;
LL | |
LL | | enum Foo {
LL | | B = A,
LL | | }
LL | |
LL | | fn main() {}
| |____________^
LL | B = A,
| ^
error: aborting due to previous error

View file

@ -4,7 +4,7 @@
struct Foo {
bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
//~^ ERROR cycle detected when simplifying constant for the type system
//~^ ERROR cycle detected when evaluating type-level constant
x: usize,
}

View file

@ -1,10 +1,10 @@
error[E0391]: cycle detected when simplifying constant for the type system `Foo::bytes::{constant#0}`
error[E0391]: cycle detected when evaluating type-level constant
--> $DIR/issue-44415.rs:6:17
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
| ^^^^^^
|
note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`...
note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`...
--> $DIR/issue-44415.rs:6:17
|
LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
@ -17,7 +17,7 @@ LL | bytes: [u8; unsafe { intrinsics::size_of::<Foo>() }],
= note: ...which requires computing layout of `Foo`...
= note: ...which requires computing layout of `[u8; _]`...
= note: ...which requires normalizing `[u8; _]`...
= note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle
= note: ...which again requires evaluating type-level constant, completing the cycle
note: cycle used when checking that `Foo` is well-formed
--> $DIR/issue-44415.rs:5:1
|

View file

@ -1,21 +1,10 @@
error[E0391]: cycle detected when normalizing `FOO`
|
note: ...which requires simplifying constant for the type system `FOO`...
error[E0391]: cycle detected when const-evaluating + checking `FOO`
--> $DIR/issue-17252.rs:1:1
|
LL | const FOO: usize = FOO;
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires simplifying constant for the type system `FOO`...
--> $DIR/issue-17252.rs:1:1
|
LL | const FOO: usize = FOO;
| ^^^^^^^^^^^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `FOO`...
--> $DIR/issue-17252.rs:1:1
|
LL | const FOO: usize = FOO;
| ^^^^^^^^^^^^^^^^^^^^^^^
= note: ...which again requires normalizing `FOO`, completing the cycle
= note: ...which immediately requires const-evaluating + checking `FOO` again
note: cycle used when const-evaluating + checking `main::{constant#0}`
--> $DIR/issue-17252.rs:4:18
|

View file

@ -1,26 +1,15 @@
error[E0391]: cycle detected when simplifying constant for the type system `X::A::{constant#0}`
error[E0391]: cycle detected when const-evaluating + checking `X::A::{constant#0}`
--> $DIR/issue-23302-1.rs:4:9
|
LL | A = X::A as isize,
| ^^^^^^^^^^^^^
|
note: ...which requires simplifying constant for the type system `X::A::{constant#0}`...
= note: ...which immediately requires const-evaluating + checking `X::A::{constant#0}` again
note: cycle used when simplifying constant for the type system `X::A::{constant#0}`
--> $DIR/issue-23302-1.rs:4:9
|
LL | A = X::A as isize,
| ^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `X::A::{constant#0}`...
--> $DIR/issue-23302-1.rs:4:9
|
LL | A = X::A as isize,
| ^^^^^^^^^^^^^
= note: ...which requires normalizing `X::A as isize`...
= note: ...which again requires simplifying constant for the type system `X::A::{constant#0}`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/issue-23302-1.rs:3:1
|
LL | enum X {
| ^^^^^^
error: aborting due to previous error

View file

@ -1,26 +1,15 @@
error[E0391]: cycle detected when simplifying constant for the type system `Y::A::{constant#0}`
error[E0391]: cycle detected when const-evaluating + checking `Y::A::{constant#0}`
--> $DIR/issue-23302-2.rs:4:9
|
LL | A = Y::B as isize,
| ^^^^^^^^^^^^^
|
note: ...which requires simplifying constant for the type system `Y::A::{constant#0}`...
= note: ...which immediately requires const-evaluating + checking `Y::A::{constant#0}` again
note: cycle used when simplifying constant for the type system `Y::A::{constant#0}`
--> $DIR/issue-23302-2.rs:4:9
|
LL | A = Y::B as isize,
| ^^^^^^^^^^^^^
note: ...which requires const-evaluating + checking `Y::A::{constant#0}`...
--> $DIR/issue-23302-2.rs:4:9
|
LL | A = Y::B as isize,
| ^^^^^^^^^^^^^
= note: ...which requires normalizing `Y::B as isize`...
= note: ...which again requires simplifying constant for the type system `Y::A::{constant#0}`, completing the cycle
note: cycle used when collecting item types in top-level module
--> $DIR/issue-23302-2.rs:3:1
|
LL | enum Y {
| ^^^^^^
error: aborting due to previous error

Some files were not shown because too many files have changed in this diff Show more