diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
commit | c23a457e72abe608715ac76f076f47dc42af07a5 (patch) | |
tree | 2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /compiler/rustc_middle/src/mir/interpret | |
parent | Releasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip |
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_middle/src/mir/interpret')
-rw-r--r-- | compiler/rustc_middle/src/mir/interpret/error.rs | 91 | ||||
-rw-r--r-- | compiler/rustc_middle/src/mir/interpret/mod.rs | 19 | ||||
-rw-r--r-- | compiler/rustc_middle/src/mir/interpret/pointer.rs | 2 | ||||
-rw-r--r-- | compiler/rustc_middle/src/mir/interpret/queries.rs | 18 | ||||
-rw-r--r-- | compiler/rustc_middle/src/mir/interpret/value.rs | 134 |
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() } } |