valtree construction: keep track of which type was valtree-incompatible

This commit is contained in:
Ralf Jung 2024-07-13 16:13:55 +02:00
parent 52f3c71c8d
commit fa74a9e6aa
11 changed files with 37 additions and 35 deletions

View file

@ -27,15 +27,15 @@ pub(crate) use valtrees::{eval_to_valtree, valtree_to_const_value};
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
const VALTREE_MAX_NODES: usize = 100000;
pub(crate) enum ValTreeCreationError {
pub(crate) enum ValTreeCreationError<'tcx> {
NodesOverflow,
/// Values of this type, or this particular value, are not supported as valtrees.
NonSupportedType,
NonSupportedType(Ty<'tcx>),
}
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError<'tcx>>;
impl From<InterpErrorInfo<'_>> for ValTreeCreationError {
fn from(err: InterpErrorInfo<'_>) -> Self {
impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> {
fn from(err: InterpErrorInfo<'tcx>) -> Self {
ty::tls::with(|tcx| {
bug!(
"Unexpected Undefined Behavior error during valtree construction: {}",

View file

@ -120,13 +120,13 @@ fn const_to_valtree_inner<'tcx>(
// We could allow wide raw pointers where both sides are integers in the future,
// but for now we reject them.
if matches!(val.layout.abi, Abi::ScalarPair(..)) {
return Err(ValTreeCreationError::NonSupportedType);
return Err(ValTreeCreationError::NonSupportedType(ty));
}
let val = val.to_scalar();
// We are in the CTFE machine, so ptr-to-int casts will fail.
// This can only be `Ok` if `val` already is an integer.
let Ok(val) = val.try_to_scalar_int() else {
return Err(ValTreeCreationError::NonSupportedType);
return Err(ValTreeCreationError::NonSupportedType(ty));
};
// It's just a ScalarInt!
Ok(ty::ValTree::Leaf(val))
@ -134,7 +134,7 @@ fn const_to_valtree_inner<'tcx>(
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
// agree with runtime equality tests.
ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType),
ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType(ty)),
ty::Ref(_, _, _) => {
let derefd_place = ecx.deref_pointer(place)?;
@ -148,7 +148,7 @@ fn const_to_valtree_inner<'tcx>(
// resolving their backing type, even if we can do that at const eval time. We may
// hypothetically be able to allow `dyn StructuralPartialEq` trait objects in the future,
// but it is unclear if this is useful.
ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),
ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
ty::Tuple(elem_tys) => {
branches(ecx, place, elem_tys.len(), None, num_nodes)
@ -156,7 +156,7 @@ fn const_to_valtree_inner<'tcx>(
ty::Adt(def, _) => {
if def.is_union() {
return Err(ValTreeCreationError::NonSupportedType);
return Err(ValTreeCreationError::NonSupportedType(ty));
} else if def.variants().is_empty() {
bug!("uninhabited types should have errored and never gotten converted to valtree")
}
@ -180,7 +180,7 @@ fn const_to_valtree_inner<'tcx>(
| ty::Closure(..)
| ty::CoroutineClosure(..)
| ty::Coroutine(..)
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType),
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
}
}
@ -251,7 +251,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
match valtree_result {
Ok(valtree) => Ok(Some(valtree)),
Ok(valtree) => Ok(Ok(valtree)),
Err(err) => {
let did = cid.instance.def_id();
let global_const_id = cid.display(tcx);
@ -262,7 +262,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
Err(handled.into())
}
ValTreeCreationError::NonSupportedType => Ok(None),
ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)),
}
}
}