Validate before reporting interning errors.
validation produces much higher quality errors and already handles most of the cases
This commit is contained in:
parent
8b2a4f8b43
commit
77fe9f0a72
18 changed files with 253 additions and 513 deletions
|
@ -10,20 +10,21 @@ use rustc_middle::traits::Reveal;
|
|||
use rustc_middle::ty::layout::LayoutOf;
|
||||
use rustc_middle::ty::print::with_no_trimmed_paths;
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::{self, Abi};
|
||||
|
||||
use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter};
|
||||
use crate::const_eval::CheckAlignment;
|
||||
use crate::errors;
|
||||
use crate::errors::ConstEvalError;
|
||||
use crate::interpret::eval_nullary_intrinsic;
|
||||
use crate::errors::{self, DanglingPtrInFinal};
|
||||
use crate::interpret::{
|
||||
create_static_alloc, intern_const_alloc_recursive, CtfeValidationMode, GlobalId, Immediate,
|
||||
InternKind, InterpCx, InterpError, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking,
|
||||
StackPopCleanup,
|
||||
};
|
||||
use crate::interpret::{eval_nullary_intrinsic, InternResult};
|
||||
use crate::CTRL_C_RECEIVED;
|
||||
|
||||
// Returns a pointer to where the result lives
|
||||
|
@ -89,11 +90,33 @@ fn eval_body_using_ecx<'mir, 'tcx, R: InterpretationResult<'tcx>>(
|
|||
}
|
||||
|
||||
// Intern the result
|
||||
intern_const_alloc_recursive(ecx, intern_kind, &ret)?;
|
||||
let intern_result = intern_const_alloc_recursive(ecx, intern_kind, &ret);
|
||||
|
||||
// Since evaluation had no errors, validate the resulting constant.
|
||||
const_validate_mplace(&ecx, &ret, cid)?;
|
||||
|
||||
// Only report this after validation, as validaiton produces much better diagnostics.
|
||||
// FIXME: ensure validation always reports this and stop making interning care about it.
|
||||
|
||||
if let Err(InternResult { found_bad_mutable_pointer, found_dangling_pointer }) = intern_result {
|
||||
if found_dangling_pointer {
|
||||
return Err(ecx
|
||||
.tcx
|
||||
.dcx()
|
||||
.emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })
|
||||
.into());
|
||||
} else if found_bad_mutable_pointer {
|
||||
// only report mutable pointers if there were no dangling pointers
|
||||
let err_diag = errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind };
|
||||
ecx.tcx.emit_node_span_lint(
|
||||
lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
|
||||
ecx.best_lint_scope(),
|
||||
err_diag.span,
|
||||
err_diag,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Ok(R::make_result(ret, ecx))
|
||||
}
|
||||
|
||||
|
|
|
@ -16,19 +16,17 @@
|
|||
use hir::def::DefKind;
|
||||
use rustc_ast::Mutability;
|
||||
use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
|
||||
use rustc_errors::ErrorGuaranteed;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
|
||||
use rustc_middle::mir::interpret::{ConstAllocation, CtfeProvenance, InterpResult};
|
||||
use rustc_middle::query::TyCtxtAt;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_session::lint;
|
||||
use rustc_span::def_id::LocalDefId;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::{AllocId, Allocation, InterpCx, MPlaceTy, Machine, MemoryKind, PlaceTy};
|
||||
use crate::const_eval;
|
||||
use crate::errors::{DanglingPtrInFinal, MutablePtrInFinal, NestedStaticInThreadLocal};
|
||||
use crate::errors::NestedStaticInThreadLocal;
|
||||
|
||||
pub trait CompileTimeMachine<'mir, 'tcx: 'mir, T> = Machine<
|
||||
'mir,
|
||||
|
@ -134,6 +132,19 @@ pub enum InternKind {
|
|||
Promoted,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct InternResult {
|
||||
pub found_bad_mutable_pointer: bool,
|
||||
pub found_dangling_pointer: bool,
|
||||
}
|
||||
|
||||
impl InternResult {
|
||||
fn has_errors(&self) -> bool {
|
||||
let Self { found_bad_mutable_pointer, found_dangling_pointer } = *self;
|
||||
found_bad_mutable_pointer || found_dangling_pointer
|
||||
}
|
||||
}
|
||||
|
||||
/// Intern `ret` and everything it references.
|
||||
///
|
||||
/// This *cannot raise an interpreter error*. Doing so is left to validation, which
|
||||
|
@ -149,7 +160,7 @@ pub fn intern_const_alloc_recursive<
|
|||
ecx: &mut InterpCx<'mir, 'tcx, M>,
|
||||
intern_kind: InternKind,
|
||||
ret: &MPlaceTy<'tcx>,
|
||||
) -> Result<(), ErrorGuaranteed> {
|
||||
) -> Result<(), InternResult> {
|
||||
// We are interning recursively, and for mutability we are distinguishing the "root" allocation
|
||||
// that we are starting in, and all other allocations that we are encountering recursively.
|
||||
let (base_mutability, inner_mutability, is_static) = match intern_kind {
|
||||
|
@ -201,7 +212,7 @@ pub fn intern_const_alloc_recursive<
|
|||
// Whether we encountered a bad mutable pointer.
|
||||
// We want to first report "dangling" and then "mutable", so we need to delay reporting these
|
||||
// errors.
|
||||
let mut found_bad_mutable_pointer = false;
|
||||
let mut result = InternResult::default();
|
||||
|
||||
// Keep interning as long as there are things to intern.
|
||||
// We show errors if there are dangling pointers, or mutable pointers in immutable contexts
|
||||
|
@ -251,7 +262,7 @@ pub fn intern_const_alloc_recursive<
|
|||
// on the promotion analysis not screwing up to ensure that it is sound to intern
|
||||
// promoteds as immutable.
|
||||
trace!("found bad mutable pointer");
|
||||
found_bad_mutable_pointer = true;
|
||||
result.found_bad_mutable_pointer = true;
|
||||
}
|
||||
if ecx.tcx.try_get_global_alloc(alloc_id).is_some() {
|
||||
// Already interned.
|
||||
|
@ -269,21 +280,15 @@ pub fn intern_const_alloc_recursive<
|
|||
// pointers before deciding which allocations can be made immutable; but for now we are
|
||||
// okay with losing some potential for immutability here. This can anyway only affect
|
||||
// `static mut`.
|
||||
todo.extend(intern_shallow(ecx, alloc_id, inner_mutability).map_err(|()| {
|
||||
ecx.tcx.dcx().emit_err(DanglingPtrInFinal { span: ecx.tcx.span, kind: intern_kind })
|
||||
})?);
|
||||
match intern_shallow(ecx, alloc_id, inner_mutability) {
|
||||
Ok(nested) => todo.extend(nested),
|
||||
Err(()) => {
|
||||
ecx.tcx.dcx().delayed_bug("found dangling pointer during const interning");
|
||||
result.found_dangling_pointer = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if found_bad_mutable_pointer {
|
||||
let err_diag = MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind };
|
||||
ecx.tcx.emit_node_span_lint(
|
||||
lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE,
|
||||
ecx.best_lint_scope(),
|
||||
err_diag.span,
|
||||
err_diag,
|
||||
)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
if result.has_errors() { Err(result) } else { Ok(()) }
|
||||
}
|
||||
|
||||
/// Intern `ret`. This function assumes that `ret` references no other allocation.
|
||||
|
|
|
@ -23,6 +23,7 @@ pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in
|
|||
pub use self::eval_context::{format_interp_error, Frame, FrameInfo, InterpCx, StackPopCleanup};
|
||||
pub use self::intern::{
|
||||
intern_const_alloc_for_constprop, intern_const_alloc_recursive, HasStaticRootDefId, InternKind,
|
||||
InternResult,
|
||||
};
|
||||
pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump};
|
||||
pub use self::memory::{AllocKind, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue