diff options
Diffstat (limited to 'compiler/rustc_middle/src/mir/interpret')
5 files changed, 95 insertions, 23 deletions
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs index dcb56a175..d4dd56a42 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs @@ -5,7 +5,9 @@ use std::hash; use std::iter; use std::ops::Range; +use rustc_serialize::{Decodable, Encodable}; use rustc_target::abi::Size; +use rustc_type_ir::{TyDecoder, TyEncoder}; use super::AllocRange; @@ -182,11 +184,39 @@ impl InitMask { /// The actual materialized blocks of the bitmask, when we can't keep the `InitMask` lazy. // Note: for performance reasons when interning, some of the fields can be partially // hashed. (see the `Hash` impl below for more details), so the impl is not derived. -#[derive(Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, HashStable)] +#[derive(Clone, Debug, Eq, PartialEq, HashStable)] struct InitMaskMaterialized { blocks: Vec<Block>, } +// `Block` is a `u64`, but it is a bitmask not a numeric value. If we were to just derive +// Encodable and Decodable we would apply varint encoding to the bitmasks, which is slower +// and also produces more output when the high bits of each `u64` are occupied. +// Note: There is probably a remaining optimization for masks that do not use an entire +// `Block`. +impl<E: TyEncoder> Encodable<E> for InitMaskMaterialized { + fn encode(&self, encoder: &mut E) { + encoder.emit_usize(self.blocks.len()); + for block in &self.blocks { + encoder.emit_raw_bytes(&block.to_le_bytes()); + } + } +} + +// This implementation is deliberately not derived, see the matching `Encodable` impl. +impl<D: TyDecoder> Decodable<D> for InitMaskMaterialized { + fn decode(decoder: &mut D) -> Self { + let num_blocks = decoder.read_usize(); + let mut blocks = Vec::with_capacity(num_blocks); + for _ in 0..num_blocks { + let bytes = decoder.read_raw_bytes(8); + let block = u64::from_le_bytes(bytes.try_into().unwrap()); + blocks.push(block); + } + InitMaskMaterialized { blocks } + } +} + // Const allocations are only hashed for interning. However, they can be large, making the hashing // expensive especially since it uses `FxHash`: it's better suited to short keys, not potentially // big buffers like the allocation's init mask. We can partially hash some fields when they're diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index c5137cf06..055d8e9a3 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,8 @@ use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; -use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree}; +use crate::query::TyCtxtAt; +use crate::ty::{layout, tls, Ty, ValTree}; use rustc_data_structures::sync::Lock; use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; @@ -15,15 +16,49 @@ 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(ErrorGuaranteed), + Reported(ReportedErrorInfo), /// Don't emit an error, the evaluation failed because the MIR was generic /// and the substs didn't fully monomorphize it. TooGeneric, } impl From<ErrorGuaranteed> for ErrorHandled { - fn from(err: ErrorGuaranteed) -> ErrorHandled { - ErrorHandled::Reported(err) + #[inline] + fn from(error: ErrorGuaranteed) -> ErrorHandled { + ErrorHandled::Reported(error.into()) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub struct ReportedErrorInfo { + error: ErrorGuaranteed, + is_tainted_by_errors: bool, +} + +impl ReportedErrorInfo { + #[inline] + 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 { + #[inline] + fn from(error: ErrorGuaranteed) -> ReportedErrorInfo { + ReportedErrorInfo { is_tainted_by_errors: false, error } + } +} + +impl Into<ErrorGuaranteed> for ReportedErrorInfo { + #[inline] + fn into(self) -> ErrorGuaranteed { + self.error } } @@ -89,7 +124,7 @@ fn print_backtrace(backtrace: &Backtrace) { impl From<ErrorGuaranteed> for InterpErrorInfo<'_> { fn from(err: ErrorGuaranteed) -> Self { - InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into() + InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into() } } @@ -125,7 +160,7 @@ pub enum InvalidProgramInfo<'tcx> { /// Resolution can fail if we are in a too generic context. TooGeneric, /// Abort in case errors are already reported. - AlreadyReported(ErrorGuaranteed), + AlreadyReported(ReportedErrorInfo), /// An error occurred during layout computation. Layout(layout::LayoutError<'tcx>), /// An error occurred during FnAbi computation: the passed --target lacks FFI support @@ -134,6 +169,9 @@ pub enum InvalidProgramInfo<'tcx> { FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError), /// SizeOf of unsized type was requested. SizeOfUnsizedType(Ty<'tcx>), + /// An unsized local was accessed without having been initialized. + /// This is not meaningful as we can't even have backing memory for such locals. + UninitUnsizedLocal, } impl fmt::Display for InvalidProgramInfo<'_> { @@ -141,7 +179,7 @@ impl fmt::Display for InvalidProgramInfo<'_> { use InvalidProgramInfo::*; match self { TooGeneric => write!(f, "encountered overly generic constant"), - AlreadyReported(ErrorGuaranteed { .. }) => { + AlreadyReported(_) => { write!( f, "an error has already been reported elsewhere (this should not usually be printed)" @@ -150,6 +188,7 @@ impl fmt::Display for InvalidProgramInfo<'_> { Layout(ref err) => write!(f, "{err}"), FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"), SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"), + UninitUnsizedLocal => write!(f, "unsized local is used while uninitialized"), } } } diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 1f8b650e3..3620385fa 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -120,8 +120,8 @@ use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, - MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, - UninitBytesAccess, UnsupportedOpInfo, + MachineStopType, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, + UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, }; pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar}; @@ -227,7 +227,9 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>( // References to statics doesn't need to know about their allocations, // just about its `DefId`. AllocDiscriminant::Static.encode(encoder); - did.encode(encoder); + // Cannot use `did.encode(encoder)` because of a bug around + // specializations and method calls. + Encodable::<E>::encode(&did, encoder); } } } diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs index 60927eed8..65d049193 100644 --- a/compiler/rustc_middle/src/mir/interpret/pointer.rs +++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs @@ -102,7 +102,7 @@ impl<T: HasDataLayout> PointerArithmetic for T {} /// This trait abstracts over the kind of provenance that is associated with a `Pointer`. It is /// 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 distplay bare provenance, and for the default impl of `fmt`. +/// The `Debug` rendering is used to display bare provenance, and for the default impl of `fmt`. pub trait Provenance: Copy + fmt::Debug { /// 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 diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index 856d821a5..f53dc8cb0 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,9 +1,10 @@ use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; use crate::mir; +use crate::query::{TyCtxtAt, TyCtxtEnsure}; use crate::ty::subst::InternalSubsts; use crate::ty::visit::TypeVisitableExt; -use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt}; +use crate::ty::{self, TyCtxt}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_session::lint; @@ -42,7 +43,7 @@ impl<'tcx> TyCtxt<'tcx> { span: Option<Span>, ) -> EvalToConstValueResult<'tcx> { // Cannot resolve `Unevaluated` constants that contain inference - // variables. We reject those here since `resolve_opt_const_arg` + // variables. We reject those here since `resolve` // would fail otherwise. // // When trying to evaluate constants containing inference variables, @@ -51,7 +52,7 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::resolve_opt_const_arg( + match ty::Instance::resolve( self, param_env, // FIXME: maybe have a separate version for resolving mir::UnevaluatedConst? ct.def, ct.substs, @@ -61,7 +62,7 @@ impl<'tcx> TyCtxt<'tcx> { self.const_eval_global_id(param_env, cid, span) } Ok(None) => Err(ErrorHandled::TooGeneric), - Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), + Err(err) => Err(ErrorHandled::Reported(err.into())), } } @@ -73,7 +74,7 @@ impl<'tcx> TyCtxt<'tcx> { span: Option<Span>, ) -> EvalToValTreeResult<'tcx> { // Cannot resolve `Unevaluated` constants that contain inference - // variables. We reject those here since `resolve_opt_const_arg` + // variables. We reject those here since `resolve` // would fail otherwise. // // When trying to evaluate constants containing inference variables, @@ -82,7 +83,7 @@ impl<'tcx> TyCtxt<'tcx> { bug!("did not expect inference variables here"); } - match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) { + match ty::Instance::resolve(self, param_env, ct.def, ct.substs) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted: None }; self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| { @@ -94,14 +95,14 @@ impl<'tcx> TyCtxt<'tcx> { // used generic parameters is a bug of evaluation, so checking for it // here does feel somewhat sensible. if !self.features().generic_const_exprs && ct.substs.has_non_region_param() { - assert!(matches!(self.def_kind(ct.def.did), DefKind::AnonConst)); - let mir_body = self.mir_for_ctfe_opt_const_arg(ct.def); + assert!(matches!(self.def_kind(ct.def), DefKind::AnonConst)); + let mir_body = self.mir_for_ctfe(ct.def); if mir_body.is_polymorphic { - let Some(local_def_id) = ct.def.did.as_local() else { return }; + let Some(local_def_id) = ct.def.as_local() else { return }; self.struct_span_lint_hir( lint::builtin::CONST_EVALUATABLE_UNCHECKED, self.hir().local_def_id_to_hir_id(local_def_id), - self.def_span(ct.def.did), + self.def_span(ct.def), "cannot use constants which depend on generic parameters in types", |err| err, ) @@ -110,7 +111,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } Ok(None) => Err(ErrorHandled::TooGeneric), - Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), + Err(err) => Err(ErrorHandled::Reported(err.into())), } } |