]> git.lizzy.rs Git - rust.git/blobdiff - src/librustc_mir/interpret/validity.rs
Auto merge of #69614 - estebank:ice-age, r=davidtwco
[rust.git] / src / librustc_mir / interpret / validity.rs
index e90a598567779bc8c527c2439f9be9a061d085db..4f99bfe8a852af7ca2806c6853381fd8a609d828 100644 (file)
@@ -67,11 +67,12 @@ pub enum PathElem {
     Field(Symbol),
     Variant(Symbol),
     GeneratorState(VariantIdx),
-    ClosureVar(Symbol),
+    CapturedVar(Symbol),
     ArrayElem(usize),
     TupleElem(usize),
     Deref,
-    Tag,
+    EnumTag,
+    GeneratorTag,
     DynDowncast,
 }
 
@@ -109,9 +110,11 @@ fn write_path(out: &mut String, path: &Vec<PathElem>) {
     for elem in path.iter() {
         match elem {
             Field(name) => write!(out, ".{}", name),
-            Variant(name) => write!(out, ".<downcast-variant({})>", name),
+            EnumTag => write!(out, ".<enum-tag>"),
+            Variant(name) => write!(out, ".<enum-variant({})>", name),
+            GeneratorTag => write!(out, ".<generator-tag>"),
             GeneratorState(idx) => write!(out, ".<generator-state({})>", idx.index()),
-            ClosureVar(name) => write!(out, ".<closure-var({})>", name),
+            CapturedVar(name) => write!(out, ".<captured-var({})>", name),
             TupleElem(idx) => write!(out, ".{}", idx),
             ArrayElem(idx) => write!(out, "[{}]", idx),
             // `.<deref>` does not match Rust syntax, but it is more readable for long paths -- and
@@ -119,7 +122,6 @@ fn write_path(out: &mut String, path: &Vec<PathElem>) {
             // even use the usual syntax because we are just showing the projections,
             // not the root.
             Deref => write!(out, ".<deref>"),
-            Tag => write!(out, ".<enum-tag>"),
             DynDowncast => write!(out, ".<dyn-downcast>"),
         }
         .unwrap()
@@ -142,16 +144,16 @@ fn wrapping_range_contains(r: &RangeInclusive<u128>, test: u128) -> bool {
 // "expected something <in the given range>" makes sense.
 fn wrapping_range_format(r: &RangeInclusive<u128>, max_hi: u128) -> String {
     let (lo, hi) = r.clone().into_inner();
-    debug_assert!(hi <= max_hi);
+    assert!(hi <= max_hi);
     if lo > hi {
         format!("less or equal to {}, or greater or equal to {}", hi, lo)
     } else if lo == hi {
         format!("equal to {}", lo)
     } else if lo == 0 {
-        debug_assert!(hi < max_hi, "should not be printing if the range covers everything");
+        assert!(hi < max_hi, "should not be printing if the range covers everything");
         format!("less or equal to {}", hi)
     } else if hi == max_hi {
-        debug_assert!(lo > 0, "should not be printing if the range covers everything");
+        assert!(lo > 0, "should not be printing if the range covers everything");
         format!("greater or equal to {}", lo)
     } else {
         format!("in the range {:?}", r)
@@ -170,6 +172,21 @@ struct ValidityVisitor<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> {
 
 impl<'rt, 'mir, 'tcx, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, 'tcx, M> {
     fn aggregate_field_path_elem(&mut self, layout: TyLayout<'tcx>, field: usize) -> PathElem {
+        // First, check if we are projecting to a variant.
+        match layout.variants {
+            layout::Variants::Multiple { discr_index, .. } => {
+                if discr_index == field {
+                    return match layout.ty.kind {
+                        ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag,
+                        ty::Generator(..) => PathElem::GeneratorTag,
+                        _ => bug!("non-variant type {:?}", layout.ty),
+                    };
+                }
+            }
+            layout::Variants::Single { .. } => {}
+        }
+
+        // Now we know we are projecting to a field, so figure out which one.
         match layout.ty.kind {
             // generators and closures.
             ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => {
@@ -190,7 +207,7 @@ fn aggregate_field_path_elem(&mut self, layout: TyLayout<'tcx>, field: usize) ->
                     }
                 }
 
-                PathElem::ClosureVar(name.unwrap_or_else(|| {
+                PathElem::CapturedVar(name.unwrap_or_else(|| {
                     // Fall back to showing the field index.
                     sym::integer(field)
                 }))
@@ -207,10 +224,7 @@ fn aggregate_field_path_elem(&mut self, layout: TyLayout<'tcx>, field: usize) ->
                         // Inside a variant
                         PathElem::Field(def.variants[index].fields[field].ident.name)
                     }
-                    layout::Variants::Multiple { discr_index, .. } => {
-                        assert_eq!(discr_index, field);
-                        PathElem::Tag
-                    }
+                    layout::Variants::Multiple { .. } => bug!("we handled variants above"),
                 }
             }
 
@@ -308,16 +322,17 @@ fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<
             ty::Float(_) | ty::Int(_) | ty::Uint(_) => {
                 // NOTE: Keep this in sync with the array optimization for int/float
                 // types below!
-                let size = value.layout.size;
                 let value = value.to_scalar_or_undef();
                 if self.ref_tracking_for_consts.is_some() {
                     // Integers/floats in CTFE: Must be scalar bits, pointers are dangerous
-                    try_validation!(
-                        value.to_bits(size),
-                        value,
-                        self.path,
-                        "initialized plain (non-pointer) bytes"
-                    );
+                    let is_bits = value.not_undef().map_or(false, |v| v.is_bits());
+                    if !is_bits {
+                        throw_validation_failure!(
+                            value,
+                            self.path,
+                            "initialized plain (non-pointer) bytes"
+                        )
+                    }
                 } else {
                     // At run-time, for now, we accept *anything* for these types, including
                     // undef. We should fix that, but let's start low.
@@ -362,12 +377,12 @@ fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<
                         );
                         match err.kind {
                             err_unsup!(InvalidNullPointerUsage) => {
-                                throw_validation_failure!("NULL reference", self.path)
+                                throw_validation_failure!("NULL reference", self.path)
                             }
                             err_unsup!(AlignmentCheckFailed { required, has }) => {
                                 throw_validation_failure!(
                                     format_args!(
-                                        "unaligned reference \
+                                        "an unaligned reference \
                                          (required {} byte alignment but found {})",
                                         required.bytes(),
                                         has.bytes()
@@ -376,11 +391,11 @@ fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<
                                 )
                             }
                             err_unsup!(ReadBytesAsPointer) => throw_validation_failure!(
-                                "dangling reference (created from integer)",
+                                "dangling reference (created from integer)",
                                 self.path
                             ),
                             _ => throw_validation_failure!(
-                                "dangling reference (not entirely in bounds)",
+                                "dangling reference (not entirely in bounds)",
                                 self.path
                             ),
                         }
@@ -441,13 +456,14 @@ fn visit_primitive(&mut self, value: OpTy<'tcx, M::PointerTag>) -> InterpResult<
     fn visit_scalar(
         &mut self,
         op: OpTy<'tcx, M::PointerTag>,
-        layout: &layout::Scalar,
+        scalar_layout: &layout::Scalar,
     ) -> InterpResult<'tcx> {
         let value = self.ecx.read_scalar(op)?;
+        let valid_range = &scalar_layout.valid_range;
+        let (lo, hi) = valid_range.clone().into_inner();
         // Determine the allowed range
-        let (lo, hi) = layout.valid_range.clone().into_inner();
         // `max_hi` is as big as the size fits
-        let max_hi = u128::max_value() >> (128 - op.layout.size.bits());
+        let max_hi = u128::MAX >> (128 - op.layout.size.bits());
         assert!(hi <= max_hi);
         // We could also write `(hi + 1) % (max_hi + 1) == lo` but `max_hi + 1` overflows for `u128`
         if (lo == 0 && hi == max_hi) || (hi + 1 == lo) {
@@ -459,7 +475,7 @@ fn visit_scalar(
             value.not_undef(),
             value,
             self.path,
-            format_args!("something {}", wrapping_range_format(&layout.valid_range, max_hi),)
+            format_args!("something {}", wrapping_range_format(valid_range, max_hi),)
         );
         let bits = match value.to_bits_or_ptr(op.layout.size, self.ecx) {
             Err(ptr) => {
@@ -471,7 +487,7 @@ fn visit_scalar(
                             self.path,
                             format_args!(
                                 "something that cannot possibly fail to be {}",
-                                wrapping_range_format(&layout.valid_range, max_hi)
+                                wrapping_range_format(valid_range, max_hi)
                             )
                         )
                     }
@@ -484,7 +500,7 @@ fn visit_scalar(
                         self.path,
                         format_args!(
                             "something that cannot possibly fail to be {}",
-                            wrapping_range_format(&layout.valid_range, max_hi)
+                            wrapping_range_format(valid_range, max_hi)
                         )
                     )
                 }
@@ -492,13 +508,13 @@ fn visit_scalar(
             Ok(data) => data,
         };
         // Now compare. This is slightly subtle because this is a special "wrap-around" range.
-        if wrapping_range_contains(&layout.valid_range, bits) {
+        if wrapping_range_contains(&valid_range, bits) {
             Ok(())
         } else {
             throw_validation_failure!(
                 bits,
                 self.path,
-                format_args!("something {}", wrapping_range_format(&layout.valid_range, max_hi))
+                format_args!("something {}", wrapping_range_format(valid_range, max_hi))
             )
         }
     }
@@ -594,7 +610,8 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
 
         // *After* all of this, check the ABI.  We need to check the ABI to handle
         // types like `NonNull` where the `Scalar` info is more restrictive than what
-        // the fields say. But in most cases, this will just propagate what the fields say,
+        // the fields say (`rustc_layout_scalar_valid_range_start`).
+        // But in most cases, this will just propagate what the fields say,
         // and then we want the error to point at the field -- so, first recurse,
         // then check ABI.
         //
@@ -603,11 +620,18 @@ fn visit_value(&mut self, op: OpTy<'tcx, M::PointerTag>) -> InterpResult<'tcx> {
         // MyNewtype and then the scalar in there).
         match op.layout.abi {
             layout::Abi::Uninhabited => unreachable!(), // checked above
-            layout::Abi::Scalar(ref layout) => {
-                self.visit_scalar(op, layout)?;
+            layout::Abi::Scalar(ref scalar_layout) => {
+                self.visit_scalar(op, scalar_layout)?;
+            }
+            layout::Abi::ScalarPair { .. } | layout::Abi::Vector { .. } => {
+                // These have fields that we already visited above, so we already checked
+                // all their scalar-level restrictions.
+                // There is also no equivalent to `rustc_layout_scalar_valid_range_start`
+                // that would make skipping them here an issue.
+            }
+            layout::Abi::Aggregate { .. } => {
+                // Nothing to do.
             }
-            // FIXME: Should we do something for ScalarPair? Vector?
-            _ => {}
         }
 
         Ok(())