Skip to content

Commit fa74a9e

Browse files
committed
valtree construction: keep track of which type was valtree-incompatible
1 parent 52f3c71 commit fa74a9e

File tree

11 files changed

+37
-35
lines changed

11 files changed

+37
-35
lines changed

compiler/rustc_codegen_ssa/src/mir/constant.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -37,13 +37,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
3737
pub fn eval_unevaluated_mir_constant_to_valtree(
3838
&self,
3939
constant: &mir::ConstOperand<'tcx>,
40-
) -> Result<Option<ty::ValTree<'tcx>>, ErrorHandled> {
40+
) -> Result<Result<ty::ValTree<'tcx>, Ty<'tcx>>, ErrorHandled> {
4141
let uv = match self.monomorphize(constant.const_) {
4242
mir::Const::Unevaluated(uv, _) => uv.shrink(),
4343
mir::Const::Ty(_, c) => match c.kind() {
4444
// A constant that came from a const generic but was then used as an argument to old-style
4545
// simd_shuffle (passing as argument instead of as a generic param).
46-
rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Some(valtree)),
46+
rustc_type_ir::ConstKind::Value(_, valtree) => return Ok(Ok(valtree)),
4747
other => span_bug!(constant.span, "{other:#?}"),
4848
},
4949
// We should never encounter `Const::Val` unless MIR opts (like const prop) evaluate
@@ -70,6 +70,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
7070
let val = self
7171
.eval_unevaluated_mir_constant_to_valtree(constant)
7272
.ok()
73+
.map(|x| x.ok())
7374
.flatten()
7475
.map(|val| {
7576
let field_ty = ty.builtin_index().unwrap();

compiler/rustc_const_eval/src/const_eval/mod.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@ pub(crate) use valtrees::{eval_to_valtree, valtree_to_const_value};
2727
// We forbid type-level constants that contain more than `VALTREE_MAX_NODES` nodes.
2828
const VALTREE_MAX_NODES: usize = 100000;
2929

30-
pub(crate) enum ValTreeCreationError {
30+
pub(crate) enum ValTreeCreationError<'tcx> {
3131
NodesOverflow,
3232
/// Values of this type, or this particular value, are not supported as valtrees.
33-
NonSupportedType,
33+
NonSupportedType(Ty<'tcx>),
3434
}
35-
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError>;
35+
pub(crate) type ValTreeCreationResult<'tcx> = Result<ty::ValTree<'tcx>, ValTreeCreationError<'tcx>>;
3636

37-
impl From<InterpErrorInfo<'_>> for ValTreeCreationError {
38-
fn from(err: InterpErrorInfo<'_>) -> Self {
37+
impl<'tcx> From<InterpErrorInfo<'tcx>> for ValTreeCreationError<'tcx> {
38+
fn from(err: InterpErrorInfo<'tcx>) -> Self {
3939
ty::tls::with(|tcx| {
4040
bug!(
4141
"Unexpected Undefined Behavior error during valtree construction: {}",

compiler/rustc_const_eval/src/const_eval/valtrees.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -120,21 +120,21 @@ fn const_to_valtree_inner<'tcx>(
120120
// We could allow wide raw pointers where both sides are integers in the future,
121121
// but for now we reject them.
122122
if matches!(val.layout.abi, Abi::ScalarPair(..)) {
123-
return Err(ValTreeCreationError::NonSupportedType);
123+
return Err(ValTreeCreationError::NonSupportedType(ty));
124124
}
125125
let val = val.to_scalar();
126126
// We are in the CTFE machine, so ptr-to-int casts will fail.
127127
// This can only be `Ok` if `val` already is an integer.
128128
let Ok(val) = val.try_to_scalar_int() else {
129-
return Err(ValTreeCreationError::NonSupportedType);
129+
return Err(ValTreeCreationError::NonSupportedType(ty));
130130
};
131131
// It's just a ScalarInt!
132132
Ok(ty::ValTree::Leaf(val))
133133
}
134134

135135
// Technically we could allow function pointers (represented as `ty::Instance`), but this is not guaranteed to
136136
// agree with runtime equality tests.
137-
ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType),
137+
ty::FnPtr(_) => Err(ValTreeCreationError::NonSupportedType(ty)),
138138

139139
ty::Ref(_, _, _) => {
140140
let derefd_place = ecx.deref_pointer(place)?;
@@ -148,15 +148,15 @@ fn const_to_valtree_inner<'tcx>(
148148
// resolving their backing type, even if we can do that at const eval time. We may
149149
// hypothetically be able to allow `dyn StructuralPartialEq` trait objects in the future,
150150
// but it is unclear if this is useful.
151-
ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType),
151+
ty::Dynamic(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
152152

153153
ty::Tuple(elem_tys) => {
154154
branches(ecx, place, elem_tys.len(), None, num_nodes)
155155
}
156156

157157
ty::Adt(def, _) => {
158158
if def.is_union() {
159-
return Err(ValTreeCreationError::NonSupportedType);
159+
return Err(ValTreeCreationError::NonSupportedType(ty));
160160
} else if def.variants().is_empty() {
161161
bug!("uninhabited types should have errored and never gotten converted to valtree")
162162
}
@@ -180,7 +180,7 @@ fn const_to_valtree_inner<'tcx>(
180180
| ty::Closure(..)
181181
| ty::CoroutineClosure(..)
182182
| ty::Coroutine(..)
183-
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType),
183+
| ty::CoroutineWitness(..) => Err(ValTreeCreationError::NonSupportedType(ty)),
184184
}
185185
}
186186

@@ -251,7 +251,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
251251
let valtree_result = const_to_valtree_inner(&ecx, &place, &mut num_nodes);
252252

253253
match valtree_result {
254-
Ok(valtree) => Ok(Some(valtree)),
254+
Ok(valtree) => Ok(Ok(valtree)),
255255
Err(err) => {
256256
let did = cid.instance.def_id();
257257
let global_const_id = cid.display(tcx);
@@ -262,7 +262,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
262262
tcx.dcx().emit_err(MaxNumNodesInConstErr { span, global_const_id });
263263
Err(handled.into())
264264
}
265-
ValTreeCreationError::NonSupportedType => Ok(None),
265+
ValTreeCreationError::NonSupportedType(ty) => Ok(Err(ty)),
266266
}
267267
}
268268
}

compiler/rustc_infer/src/infer/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1427,17 +1427,17 @@ impl<'tcx> InferCtxt<'tcx> {
14271427
span: Span,
14281428
) -> Result<ty::Const<'tcx>, ErrorHandled> {
14291429
match self.const_eval_resolve(param_env, unevaluated, span) {
1430-
Ok(Some(val)) => Ok(ty::Const::new_value(
1430+
Ok(Ok(val)) => Ok(ty::Const::new_value(
14311431
self.tcx,
14321432
val,
14331433
self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
14341434
)),
1435-
Ok(None) => {
1435+
Ok(Err(bad_ty)) => {
14361436
let tcx = self.tcx;
14371437
let def_id = unevaluated.def;
14381438
span_bug!(
14391439
tcx.def_span(def_id),
1440-
"unable to construct a constant value for the unevaluated constant {:?}",
1440+
"unable to construct a valtree for the unevaluated constant {:?}: type {bad_ty} is not valtree-compatible",
14411441
unevaluated
14421442
);
14431443
}

compiler/rustc_middle/src/mir/interpret/error.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,11 @@ TrivialTypeTraversalImpls! { ErrorHandled }
9090
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
9191
pub type EvalStaticInitializerRawResult<'tcx> = Result<ConstAllocation<'tcx>, ErrorHandled>;
9292
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
93-
/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed.
94-
/// This is needed in `thir::pattern::lower_inline_const`.
95-
pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
93+
/// `Ok(Err(ty))` indicates the constant was fine, but the valtree couldn't be constructed
94+
/// because the value containts something of type `ty` that is not valtree-compatible.
95+
/// The caller can then show an appropriate error; the query does not have the
96+
/// necssary context to give good user-facing errors for this case.
97+
pub type EvalToValTreeResult<'tcx> = Result<Result<ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>;
9698

9799
#[cfg(target_pointer_width = "64")]
98100
rustc_data_structures::static_assert_size!(InterpErrorInfo<'_>, 8);

compiler/rustc_middle/src/query/erase.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,10 @@ impl EraseType for Result<mir::ConstValue<'_>, mir::interpret::ErrorHandled> {
157157
type Result = [u8; size_of::<Result<mir::ConstValue<'static>, mir::interpret::ErrorHandled>>()];
158158
}
159159

160-
impl EraseType for Result<Option<ty::ValTree<'_>>, mir::interpret::ErrorHandled> {
161-
type Result =
162-
[u8; size_of::<Result<Option<ty::ValTree<'static>>, mir::interpret::ErrorHandled>>()];
160+
impl EraseType for Result<Result<ty::ValTree<'_>, Ty<'_>>, mir::interpret::ErrorHandled> {
161+
type Result = [u8; size_of::<
162+
Result<Result<ty::ValTree<'static>, Ty<'static>>, mir::interpret::ErrorHandled>,
163+
>()];
163164
}
164165

165166
impl EraseType for Result<&'_ ty::List<Ty<'_>>, ty::util::AlwaysRequiresDrop> {

compiler/rustc_middle/src/ty/consts.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -328,8 +328,7 @@ impl<'tcx> Const<'tcx> {
328328
let (param_env, unevaluated) = unevaluated.prepare_for_eval(tcx, param_env);
329329
// try to resolve e.g. associated constants to their definition on an impl, and then
330330
// evaluate the const.
331-
let Some(c) = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)?
332-
else {
331+
let Ok(c) = tcx.const_eval_resolve_for_typeck(param_env, unevaluated, span)? else {
333332
// This can happen when we run on ill-typed code.
334333
let e = tcx.dcx().span_delayed_bug(
335334
span,

compiler/rustc_mir_build/src/thir/pattern/mod.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
581581
.tcx
582582
.const_eval_global_id_for_typeck(param_env_reveal_all, cid, span)
583583
.map(|val| match val {
584-
Some(valtree) => mir::Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)),
585-
None => mir::Const::Val(
584+
Ok(valtree) => mir::Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)),
585+
Err(_) => mir::Const::Val(
586586
self.tcx
587587
.const_eval_global_id(param_env_reveal_all, cid, span)
588588
.expect("const_eval_global_id_for_typeck should have already failed"),
@@ -682,8 +682,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
682682
// First try using a valtree in order to destructure the constant into a pattern.
683683
// FIXME: replace "try to do a thing, then fall back to another thing"
684684
// but something more principled, like a trait query checking whether this can be turned into a valtree.
685-
if let Ok(Some(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, span)
686-
{
685+
if let Ok(Ok(valtree)) = self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, span) {
687686
let subpattern = self.const_to_pat(
688687
Const::Ty(ty, ty::Const::new_value(self.tcx, valtree, ty)),
689688
id,

compiler/rustc_trait_selection/src/solve/delegate.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,12 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate<
8787
) -> Option<ty::Const<'tcx>> {
8888
use rustc_middle::mir::interpret::ErrorHandled;
8989
match self.const_eval_resolve(param_env, unevaluated, DUMMY_SP) {
90-
Ok(Some(val)) => Some(ty::Const::new_value(
90+
Ok(Ok(val)) => Some(ty::Const::new_value(
9191
self.tcx,
9292
val,
9393
self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args),
9494
)),
95-
Ok(None) | Err(ErrorHandled::TooGeneric(_)) => None,
95+
Ok(Err(_)) | Err(ErrorHandled::TooGeneric(_)) => None,
9696
Err(ErrorHandled::Reported(e, _)) => Some(ty::Const::new_error(self.tcx, e.into())),
9797
}
9898
}

compiler/rustc_trait_selection/src/traits/auto_trait.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -765,8 +765,8 @@ impl<'tcx> AutoTraitFinder<'tcx> {
765765
unevaluated,
766766
obligation.cause.span,
767767
) {
768-
Ok(Some(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))),
769-
Ok(None) => {
768+
Ok(Ok(valtree)) => Ok(ty::Const::new_value(selcx.tcx(),valtree, self.tcx.type_of(unevaluated.def).instantiate(self.tcx, unevaluated.args))),
769+
Ok(Err(_)) => {
770770
let tcx = self.tcx;
771771
let reported =
772772
tcx.dcx().emit_err(UnableToConstructConstantValue {

src/tools/clippy/clippy_lints/src/non_copy_const.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ impl<'tcx> NonCopyConst<'tcx> {
235235

236236
fn is_value_unfrozen_raw(
237237
cx: &LateContext<'tcx>,
238-
result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>,
238+
result: Result<Result<ty::ValTree<'tcx>, Ty<'tcx>>, ErrorHandled>,
239239
ty: Ty<'tcx>,
240240
) -> bool {
241241
result.map_or_else(

0 commit comments

Comments
 (0)