1
Fork 0

Auto merge of #115748 - RalfJung:post-mono, r=oli-obk

move required_consts check to general post-mono-check function

This factors some code that is common between the interpreter and the codegen backends into shared helper functions. Also as a side-effect the interpreter now uses the same `eval` functions as everyone else to get the evaluated MIR constants.

Also this is in preparation for another post-mono check that will be needed for (the current hackfix for) https://github.com/rust-lang/rust/issues/115709: ensuring that all locals are dynamically sized.

I didn't expect this to change diagnostics, but it's just cycle errors that change.

r? `@oli-obk`
This commit is contained in:
bors 2023-09-18 19:41:21 +00:00
commit cebb9cfd4f
76 changed files with 385 additions and 361 deletions

View file

@ -52,6 +52,8 @@ middle_drop_check_overflow =
overflow while adding drop-check rules for {$ty}
.note = overflowed on {$overflow_ty}
middle_erroneous_constant = erroneous constant encountered
middle_layout_references_error =
the type has an unknown layout

View file

@ -144,5 +144,12 @@ pub struct UnsupportedFnAbi {
pub abi: &'static str,
}
#[derive(Diagnostic)]
#[diag(middle_erroneous_constant)]
pub struct ErroneousConstant {
#[primary_span]
pub span: Span,
}
/// Used by `rustc_const_eval`
pub use crate::fluent_generated::middle_adjust_for_foreign_abi_error;

View file

@ -1,8 +1,9 @@
use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
use crate::error;
use crate::mir::interpret::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 {
@ -162,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 {

View file

@ -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)
}

View file

@ -565,6 +565,34 @@ impl<'tcx> Body<'tcx> {
pub fn is_custom_mir(&self) -> bool {
self.injection_phase.is_some()
}
/// *Must* be called once the full substitution for this body is known, to ensure that the body
/// is indeed fit for code generation or consumption more generally.
///
/// Sadly there's no nice way to represent an "arbitrary normalizer", so we take one for
/// constants specifically. (`Option<GenericArgsRef>` could be used for that, but the fact
/// that `Instance::args_for_mir_body` is private and instead instance exposes normalization
/// functions makes it seem like exposing the generic args is not the intended strategy.)
///
/// Also sadly, CTFE doesn't even know whether it runs on MIR that is already polymorphic or still monomorphic,
/// so we cannot just immediately ICE on TooGeneric.
///
/// Returns Ok(()) if everything went fine, and `Err` if a problem occurred and got reported.
pub fn post_mono_checks(
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
normalize_const: impl Fn(ConstantKind<'tcx>) -> Result<ConstantKind<'tcx>, ErrorHandled>,
) -> Result<(), ErrorHandled> {
// For now, the only thing we have to check is is to ensure that all the constants used in
// the body successfully evaluate.
for &const_ in &self.required_consts {
let c = normalize_const(const_.literal)?;
c.eval(tcx, param_env, Some(const_.span))?;
}
Ok(())
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, TyEncodable, TyDecodable, HashStable)]
@ -2397,10 +2425,10 @@ impl<'tcx> ConstantKind<'tcx> {
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Self {
match self.eval(tcx, param_env, None) {
Ok(val) => Self::Val(val, self.ty()),
Err(ErrorHandled::Reported(guar)) => {
Err(ErrorHandled::Reported(guar, _span)) => {
Self::Ty(ty::Const::new_error(tcx, guar.into(), self.ty()))
}
Err(ErrorHandled::TooGeneric) => self,
Err(ErrorHandled::TooGeneric(_span)) => self,
}
}

View file

@ -478,8 +478,8 @@ impl<'tcx> AdtDef<'tcx> {
}
Err(err) => {
let msg = match err {
ErrorHandled::Reported(_) => "enum discriminant evaluation failed",
ErrorHandled::TooGeneric => "enum discriminant depends on generics",
ErrorHandled::Reported(..) => "enum discriminant evaluation failed",
ErrorHandled::TooGeneric(..) => "enum discriminant depends on generics",
};
tcx.sess.delay_span_bug(tcx.def_span(expr_did), msg);
None

View file

@ -300,7 +300,7 @@ impl<'tcx> Const<'tcx> {
| ConstKind::Infer(_)
| ConstKind::Bound(_, _)
| ConstKind::Placeholder(_)
| ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric),
| ConstKind::Expr(_) => Err(ErrorHandled::TooGeneric(span.unwrap_or(DUMMY_SP))),
}
}
@ -309,8 +309,8 @@ impl<'tcx> Const<'tcx> {
pub fn normalize(self, tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>) -> Self {
match self.eval(tcx, param_env, None) {
Ok(val) => Self::new_value(tcx, val, self.ty()),
Err(ErrorHandled::Reported(r)) => Self::new_error(tcx, r.into(), self.ty()),
Err(ErrorHandled::TooGeneric) => self,
Err(ErrorHandled::Reported(r, _span)) => Self::new_error(tcx, r.into(), self.ty()),
Err(ErrorHandled::TooGeneric(_span)) => self,
}
}