summary refs log tree commit diff
path: root/compiler/rustc_const_eval/src
diff options
context:
space:
mode:
authorTomasz Miąsko <tomasz.miasko@gmail.com>2022-02-15 13:58:34 +0100
committerTomasz Miąsko <tomasz.miasko@gmail.com>2022-02-16 00:38:59 +0100
commit92d20c4aaddea9507f8ad37fe37c551219153bbf (patch)
tree12922a3d4bbc15f867ab89b344c994e62ab704da /compiler/rustc_const_eval/src
parentbfb2856f271fcb647b3cad1b88b29ec97bbab2a3 (diff)
downloadrust-92d20c4aaddea9507f8ad37fe37c551219153bbf.tar.gz
rust-92d20c4aaddea9507f8ad37fe37c551219153bbf.zip
Support pretty printing of invalid constants
Make it possible to pretty print invalid constants by introducing a
fallible variant of `destructure_const` and falling back to debug
formatting when it fails.
Diffstat (limited to 'compiler/rustc_const_eval/src')
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs38
-rw-r--r--compiler/rustc_const_eval/src/lib.rs4
2 files changed, 20 insertions, 22 deletions
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index eaa333fd8a9..ba1d5f45bbb 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -11,7 +11,8 @@ use rustc_middle::{
 use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
 
 use crate::interpret::{
-    intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MPlaceTy, MemPlaceMeta, Scalar,
+    intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy,
+    MemPlaceMeta, Scalar,
 };
 
 mod error;
@@ -132,42 +133,39 @@ fn const_to_valtree_inner<'tcx>(
     }
 }
 
-/// This function uses `unwrap` copiously, because an already validated constant
-/// must have valid fields and can thus never fail outside of compiler bugs. However, it is
-/// invoked from the pretty printer, where it can receive enums with no variants and e.g.
-/// `read_discriminant` needs to be able to handle that.
-pub(crate) fn destructure_const<'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.
+pub(crate) fn try_destructure_const<'tcx>(
     tcx: TyCtxt<'tcx>,
     param_env: ty::ParamEnv<'tcx>,
     val: ty::Const<'tcx>,
-) -> mir::DestructuredConst<'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).unwrap();
+    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),
-        ty::Adt(def, _) if def.variants.is_empty() => {
-            return mir::DestructuredConst { variant: None, fields: &[] };
-        }
         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),
         _ => bug!("cannot destructure constant {:?}", val),
     };
 
-    let fields_iter = (0..field_count).map(|i| {
-        let field_op = ecx.operand_field(&down, i).unwrap();
-        let val = op_to_const(&ecx, &field_op);
-        ty::Const::from_value(tcx, val, field_op.layout.ty)
-    });
-    let fields = tcx.arena.alloc_from_iter(fields_iter);
+    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);
 
-    mir::DestructuredConst { variant, fields }
+    Ok(mir::DestructuredConst { variant, fields })
 }
 
 pub(crate) fn deref_const<'tcx>(
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 838484876c7..77d312f5851 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -41,9 +41,9 @@ 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.destructure_const = |tcx, param_env_and_value| {
+    providers.try_destructure_const = |tcx, param_env_and_value| {
         let (param_env, value) = param_env_and_value.into_parts();
-        const_eval::destructure_const(tcx, param_env, value)
+        const_eval::try_destructure_const(tcx, param_env, value).ok()
     };
     providers.const_to_valtree = |tcx, param_env_and_value| {
         let (param_env, raw) = param_env_and_value.into_parts();