summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_middle/src/mir/interpret
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_middle/src/mir/interpret')
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs91
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs19
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs18
-rw-r--r--compiler/rustc_middle/src/mir/interpret/value.rs134
5 files changed, 113 insertions, 151 deletions
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index e6ef5a41e..bc464aca5 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -1,8 +1,9 @@
-use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
+use super::{AllocId, AllocRange, Pointer, Scalar};
-use crate::mir::interpret::ConstValue;
+use crate::error;
+use crate::mir::{ConstAlloc, ConstValue};
use crate::query::TyCtxtAt;
-use crate::ty::{layout, tls, Ty, ValTree};
+use crate::ty::{layout, tls, Ty, TyCtxt, ValTree};
use rustc_data_structures::sync::Lock;
use rustc_errors::{
@@ -11,7 +12,7 @@ use rustc_errors::{
};
use rustc_macros::HashStable;
use rustc_session::CtfeBacktrace;
-use rustc_span::def_id::DefId;
+use rustc_span::{def_id::DefId, Span, DUMMY_SP};
use rustc_target::abi::{call, Align, Size, VariantIdx, WrappingRange};
use std::borrow::Cow;
@@ -21,16 +22,51 @@ use std::{any::Any, backtrace::Backtrace, fmt};
pub enum ErrorHandled {
/// Already reported an error for this evaluation, and the compilation is
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
- Reported(ReportedErrorInfo),
+ Reported(ReportedErrorInfo, Span),
/// Don't emit an error, the evaluation failed because the MIR was generic
/// and the args didn't fully monomorphize it.
- TooGeneric,
+ TooGeneric(Span),
}
impl From<ErrorGuaranteed> for ErrorHandled {
#[inline]
fn from(error: ErrorGuaranteed) -> ErrorHandled {
- ErrorHandled::Reported(error.into())
+ ErrorHandled::Reported(error.into(), DUMMY_SP)
+ }
+}
+
+impl ErrorHandled {
+ pub fn with_span(self, span: Span) -> Self {
+ match self {
+ ErrorHandled::Reported(err, _span) => ErrorHandled::Reported(err, span),
+ ErrorHandled::TooGeneric(_span) => ErrorHandled::TooGeneric(span),
+ }
+ }
+
+ pub fn emit_err(&self, tcx: TyCtxt<'_>) -> ErrorGuaranteed {
+ match self {
+ &ErrorHandled::Reported(err, span) => {
+ if !err.is_tainted_by_errors && !span.is_dummy() {
+ tcx.sess.emit_err(error::ErroneousConstant { span });
+ }
+ err.error
+ }
+ &ErrorHandled::TooGeneric(span) => tcx.sess.delay_span_bug(
+ span,
+ "encountered TooGeneric error when monomorphic data was expected",
+ ),
+ }
+ }
+
+ pub fn emit_note(&self, tcx: TyCtxt<'_>) {
+ match self {
+ &ErrorHandled::Reported(err, span) => {
+ if !err.is_tainted_by_errors && !span.is_dummy() {
+ tcx.sess.emit_note(error::ErroneousConstant { span });
+ }
+ }
+ &ErrorHandled::TooGeneric(_) => {}
+ }
}
}
@@ -45,12 +81,6 @@ impl ReportedErrorInfo {
pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
ReportedErrorInfo { is_tainted_by_errors: true, error }
}
-
- /// Returns true if evaluation failed because MIR was tainted by errors.
- #[inline]
- pub fn is_tainted_by_errors(self) -> bool {
- self.is_tainted_by_errors
- }
}
impl From<ErrorGuaranteed> for ReportedErrorInfo {
@@ -67,10 +97,12 @@ impl Into<ErrorGuaranteed> for ReportedErrorInfo {
}
}
-TrivialTypeTraversalAndLiftImpls! { ErrorHandled }
+TrivialTypeTraversalImpls! { ErrorHandled }
pub type EvalToAllocationRawResult<'tcx> = Result<ConstAlloc<'tcx>, ErrorHandled>;
pub type EvalToConstValueResult<'tcx> = Result<ConstValue<'tcx>, ErrorHandled>;
+/// `Ok(None)` indicates the constant was fine, but the valtree couldn't be constructed.
+/// This is needed in `thir::pattern::lower_inline_const`.
pub type EvalToValTreeResult<'tcx> = Result<Option<ValTree<'tcx>>, ErrorHandled>;
pub fn struct_error<'tcx>(
@@ -160,6 +192,16 @@ impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
}
}
+impl From<ErrorHandled> for InterpErrorInfo<'_> {
+ fn from(err: ErrorHandled) -> Self {
+ InterpError::InvalidProgram(match err {
+ ErrorHandled::Reported(r, _span) => InvalidProgramInfo::AlreadyReported(r),
+ ErrorHandled::TooGeneric(_span) => InvalidProgramInfo::TooGeneric,
+ })
+ .into()
+ }
+}
+
impl<'tcx> From<InterpError<'tcx>> for InterpErrorInfo<'tcx> {
fn from(kind: InterpError<'tcx>) -> Self {
InterpErrorInfo(Box::new(InterpErrorInfoInner {
@@ -255,9 +297,16 @@ impl_into_diagnostic_arg_through_debug! {
/// Error information for when the program caused Undefined Behavior.
#[derive(Debug)]
-pub enum UndefinedBehaviorInfo<'a> {
+pub enum UndefinedBehaviorInfo<'tcx> {
/// Free-form case. Only for errors that are never caught! Used by miri
Ub(String),
+ // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
+ // dispatched
+ /// A custom (free-form) fluent-translated error, created by `err_ub_custom!`.
+ Custom(crate::error::CustomSubdiagnostic<'tcx>),
+ /// Validation error.
+ ValidationError(ValidationErrorInfo<'tcx>),
+
/// Unreachable code was executed.
Unreachable,
/// A slice/array index projection went out-of-bounds.
@@ -319,12 +368,10 @@ pub enum UndefinedBehaviorInfo<'a> {
UninhabitedEnumVariantWritten(VariantIdx),
/// An uninhabited enum variant is projected.
UninhabitedEnumVariantRead(VariantIdx),
- /// Validation error.
- ValidationError(ValidationErrorInfo<'a>),
- // FIXME(fee1-dead) these should all be actual variants of the enum instead of dynamically
- // dispatched
- /// A custom (free-form) error, created by `err_ub_custom!`.
- Custom(crate::error::CustomSubdiagnostic<'a>),
+ /// ABI-incompatible argument types.
+ AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
+ /// ABI-incompatible return types.
+ AbiMismatchReturn { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
}
#[derive(Debug, Clone, Copy)]
@@ -415,6 +462,8 @@ pub enum UnsupportedOpInfo {
/// Free-form case. Only for errors that are never caught!
// FIXME still use translatable diagnostics
Unsupported(String),
+ /// Unsized local variables.
+ UnsizedLocal,
//
// The variants below are only reachable from CTFE/const prop, miri will never emit them.
//
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 3543158bf..d21f82f04 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -149,7 +149,7 @@ pub use self::error::{
UnsupportedOpInfo, ValidationErrorInfo, ValidationErrorKind,
};
-pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar};
+pub use self::value::Scalar;
pub use self::allocation::{
alloc_range, AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation,
@@ -162,7 +162,7 @@ pub use self::pointer::{Pointer, PointerArithmetic, Provenance};
/// - A constant
/// - A static
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, TyEncodable, TyDecodable)]
-#[derive(HashStable, Lift, TypeFoldable, TypeVisitable)]
+#[derive(HashStable, TypeFoldable, TypeVisitable)]
pub struct GlobalId<'tcx> {
/// For a constant or static, the `Instance` of the item itself.
/// For a promoted global, the `Instance` of the function they belong to.
@@ -389,7 +389,7 @@ impl<'s> AllocDecodingSession<'s> {
trace!("creating fn alloc ID");
let instance = ty::Instance::decode(decoder);
trace!("decoded fn alloc instance: {:?}", instance);
- let alloc_id = decoder.interner().create_fn_alloc(instance);
+ let alloc_id = decoder.interner().reserve_and_set_fn_alloc(instance);
alloc_id
}
AllocDiscriminant::VTable => {
@@ -399,7 +399,8 @@ impl<'s> AllocDecodingSession<'s> {
let poly_trait_ref =
<Option<ty::PolyExistentialTraitRef<'_>> as Decodable<D>>::decode(decoder);
trace!("decoded vtable alloc instance: {ty:?}, {poly_trait_ref:?}");
- let alloc_id = decoder.interner().create_vtable_alloc(ty, poly_trait_ref);
+ let alloc_id =
+ decoder.interner().reserve_and_set_vtable_alloc(ty, poly_trait_ref);
alloc_id
}
AllocDiscriminant::Static => {
@@ -407,7 +408,7 @@ impl<'s> AllocDecodingSession<'s> {
trace!("creating extern static alloc ID");
let did = <DefId as Decodable<D>>::decode(decoder);
trace!("decoded static def-ID: {:?}", did);
- let alloc_id = decoder.interner().create_static_alloc(did);
+ let alloc_id = decoder.interner().reserve_and_set_static_alloc(did);
alloc_id
}
}
@@ -544,13 +545,13 @@ impl<'tcx> TyCtxt<'tcx> {
/// Generates an `AllocId` for a static or return a cached one in case this function has been
/// called on the same static before.
- pub fn create_static_alloc(self, static_id: DefId) -> AllocId {
+ pub fn reserve_and_set_static_alloc(self, static_id: DefId) -> AllocId {
self.reserve_and_set_dedup(GlobalAlloc::Static(static_id))
}
/// Generates an `AllocId` for a function. Depending on the function type,
/// this might get deduplicated or assigned a new ID each time.
- pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
+ pub fn reserve_and_set_fn_alloc(self, instance: Instance<'tcx>) -> AllocId {
// Functions cannot be identified by pointers, as asm-equal functions can get deduplicated
// by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be
// duplicated across crates.
@@ -575,7 +576,7 @@ impl<'tcx> TyCtxt<'tcx> {
}
/// Generates an `AllocId` for a (symbolic, not-reified) vtable. Will get deduplicated.
- pub fn create_vtable_alloc(
+ pub fn reserve_and_set_vtable_alloc(
self,
ty: Ty<'tcx>,
poly_trait_ref: Option<ty::PolyExistentialTraitRef<'tcx>>,
@@ -588,7 +589,7 @@ impl<'tcx> TyCtxt<'tcx> {
/// Statics with identical content will still point to the same `Allocation`, i.e.,
/// their data will be deduplicated through `Allocation` interning -- but they
/// are different places in memory and as such need different IDs.
- pub fn create_memory_alloc(self, mem: ConstAllocation<'tcx>) -> AllocId {
+ pub fn reserve_and_set_memory_alloc(self, mem: ConstAllocation<'tcx>) -> AllocId {
let id = self.reserve_alloc_id();
self.set_alloc_id_memory(id, mem);
id
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 65d049193..1c9ce1cb1 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -103,7 +103,7 @@ impl<T: HasDataLayout> PointerArithmetic for T {}
/// mostly opaque; the `Machine` trait extends it with some more operations that also have access to
/// some global state.
/// The `Debug` rendering is used to display bare provenance, and for the default impl of `fmt`.
-pub trait Provenance: Copy + fmt::Debug {
+pub trait Provenance: Copy + fmt::Debug + 'static {
/// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address.
/// - If `false`, the offset *must* be relative. This means the bytes representing a pointer are
/// different from what the Abstract Machine prescribes, so the interpreter must prevent any
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index fc659ce18..fbf6403ea 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -61,8 +61,10 @@ impl<'tcx> TyCtxt<'tcx> {
let cid = GlobalId { instance, promoted: ct.promoted };
self.const_eval_global_id(param_env, cid, span)
}
- Ok(None) => Err(ErrorHandled::TooGeneric),
- Err(err) => Err(ErrorHandled::Reported(err.into())),
+ // For errors during resolution, we deliberately do not point at the usage site of the constant,
+ // since for these errors the place the constant is used shouldn't matter.
+ Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
+ Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
}
}
@@ -117,8 +119,10 @@ impl<'tcx> TyCtxt<'tcx> {
}
})
}
- Ok(None) => Err(ErrorHandled::TooGeneric),
- Err(err) => Err(ErrorHandled::Reported(err.into())),
+ // For errors during resolution, we deliberately do not point at the usage site of the constant,
+ // since for these errors the place the constant is used shouldn't matter.
+ Ok(None) => Err(ErrorHandled::TooGeneric(DUMMY_SP)),
+ Err(err) => Err(ErrorHandled::Reported(err.into(), DUMMY_SP)),
}
}
@@ -143,7 +147,8 @@ impl<'tcx> TyCtxt<'tcx> {
// improve caching of queries.
let inputs = self.erase_regions(param_env.and(cid));
if let Some(span) = span {
- self.at(span).eval_to_const_value_raw(inputs)
+ // The query doesn't know where it is being invoked, so we need to fix the span.
+ self.at(span).eval_to_const_value_raw(inputs).map_err(|e| e.with_span(span))
} else {
self.eval_to_const_value_raw(inputs)
}
@@ -162,7 +167,8 @@ impl<'tcx> TyCtxt<'tcx> {
let inputs = self.erase_regions(param_env.and(cid));
debug!(?inputs);
if let Some(span) = span {
- self.at(span).eval_to_valtree(inputs)
+ // The query doesn't know where it is being invoked, so we need to fix the span.
+ self.at(span).eval_to_valtree(inputs).map_err(|e| e.with_span(span))
} else {
self.eval_to_valtree(inputs)
}
diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs
index 5345a6588..0d548f886 100644
--- a/compiler/rustc_middle/src/mir/interpret/value.rs
+++ b/compiler/rustc_middle/src/mir/interpret/value.rs
@@ -9,102 +9,9 @@ use rustc_apfloat::{
use rustc_macros::HashStable;
use rustc_target::abi::{HasDataLayout, Size};
-use crate::ty::{ParamEnv, ScalarInt, Ty, TyCtxt};
+use crate::ty::ScalarInt;
-use super::{
- AllocId, AllocRange, ConstAllocation, InterpResult, Pointer, PointerArithmetic, Provenance,
- ScalarSizeMismatch,
-};
-
-/// Represents the result of const evaluation via the `eval_to_allocation` query.
-#[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)]
-pub struct ConstAlloc<'tcx> {
- /// The value lives here, at offset 0, and that allocation definitely is an `AllocKind::Memory`
- /// (so you can use `AllocMap::unwrap_memory`).
- pub alloc_id: AllocId,
- pub ty: Ty<'tcx>,
-}
-
-/// Represents a constant value in Rust. `Scalar` and `Slice` are optimizations for
-/// array length computations, enum discriminants and the pattern matching logic.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, Hash)]
-#[derive(HashStable, Lift)]
-pub enum ConstValue<'tcx> {
- /// Used only for types with `layout::abi::Scalar` ABI.
- ///
- /// Not using the enum `Value` to encode that this must not be `Uninit`.
- Scalar(Scalar),
-
- /// Only used for ZSTs.
- ZeroSized,
-
- /// Used only for `&[u8]` and `&str`
- Slice { data: ConstAllocation<'tcx>, start: usize, end: usize },
-
- /// A value not represented/representable by `Scalar` or `Slice`
- ByRef {
- /// The backing memory of the value, may contain more memory than needed for just the value
- /// in order to share `ConstAllocation`s between values
- alloc: ConstAllocation<'tcx>,
- /// Offset into `alloc`
- offset: Size,
- },
-}
-
-#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-static_assert_size!(ConstValue<'_>, 32);
-
-impl<'tcx> ConstValue<'tcx> {
- #[inline]
- pub fn try_to_scalar(&self) -> Option<Scalar<AllocId>> {
- match *self {
- ConstValue::ByRef { .. } | ConstValue::Slice { .. } | ConstValue::ZeroSized => None,
- ConstValue::Scalar(val) => Some(val),
- }
- }
-
- pub fn try_to_scalar_int(&self) -> Option<ScalarInt> {
- self.try_to_scalar()?.try_to_int().ok()
- }
-
- pub fn try_to_bits(&self, size: Size) -> Option<u128> {
- self.try_to_scalar_int()?.to_bits(size).ok()
- }
-
- pub fn try_to_bool(&self) -> Option<bool> {
- self.try_to_scalar_int()?.try_into().ok()
- }
-
- pub fn try_to_target_usize(&self, tcx: TyCtxt<'tcx>) -> Option<u64> {
- self.try_to_scalar_int()?.try_to_target_usize(tcx).ok()
- }
-
- pub fn try_to_bits_for_ty(
- &self,
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- ty: Ty<'tcx>,
- ) -> Option<u128> {
- let size = tcx.layout_of(param_env.with_reveal_all_normalized(tcx).and(ty)).ok()?.size;
- self.try_to_bits(size)
- }
-
- pub fn from_bool(b: bool) -> Self {
- ConstValue::Scalar(Scalar::from_bool(b))
- }
-
- pub fn from_u64(i: u64) -> Self {
- ConstValue::Scalar(Scalar::from_u64(i))
- }
-
- pub fn from_u128(i: u128) -> Self {
- ConstValue::Scalar(Scalar::from_u128(i))
- }
-
- pub fn from_target_usize(i: u64, cx: &impl HasDataLayout) -> Self {
- ConstValue::Scalar(Scalar::from_target_usize(i, cx))
- }
-}
+use super::{AllocId, InterpResult, Pointer, PointerArithmetic, Provenance, ScalarSizeMismatch};
/// A `Scalar` represents an immediate, primitive value existing outside of a
/// `memory::Allocation`. It is in many ways like a small chunk of an `Allocation`, up to 16 bytes in
@@ -267,6 +174,16 @@ impl<Prov> Scalar<Prov> {
}
#[inline]
+ pub fn from_i8(i: i8) -> Self {
+ Self::from_int(i, Size::from_bits(8))
+ }
+
+ #[inline]
+ pub fn from_i16(i: i16) -> Self {
+ Self::from_int(i, Size::from_bits(16))
+ }
+
+ #[inline]
pub fn from_i32(i: i32) -> Self {
Self::from_int(i, Size::from_bits(32))
}
@@ -494,29 +411,18 @@ impl<'tcx, Prov: Provenance> Scalar<Prov> {
}
#[inline]
- pub fn to_f32(self) -> InterpResult<'tcx, Single> {
- // Going through `u32` to check size and truncation.
- Ok(Single::from_bits(self.to_u32()?.into()))
+ pub fn to_float<F: Float>(self) -> InterpResult<'tcx, F> {
+ // Going through `to_uint` to check size and truncation.
+ Ok(F::from_bits(self.to_uint(Size::from_bits(F::BITS))?))
}
#[inline]
- pub fn to_f64(self) -> InterpResult<'tcx, Double> {
- // Going through `u64` to check size and truncation.
- Ok(Double::from_bits(self.to_u64()?.into()))
+ pub fn to_f32(self) -> InterpResult<'tcx, Single> {
+ self.to_float()
}
-}
-/// Gets the bytes of a constant slice value.
-pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> &'tcx [u8] {
- if let ConstValue::Slice { data, start, end } = val {
- let len = end - start;
- data.inner()
- .get_bytes_strip_provenance(
- cx,
- AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) },
- )
- .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err))
- } else {
- bug!("expected const slice, but found another const value");
+ #[inline]
+ pub fn to_f64(self) -> InterpResult<'tcx, Double> {
+ self.to_float()
}
}