1
Fork 0

Deduplicate checking drop terminator

This commit is contained in:
Michael Goulet 2024-11-19 17:18:54 +00:00
parent 2088260852
commit af0d566e76
12 changed files with 69 additions and 107 deletions

View file

@ -324,14 +324,6 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
}
}
/// Emits an error at the given `span` if an expression cannot be evaluated in the current
/// context. This is meant for use in a post-const-checker pass such as the const precise
/// live drops lint.
pub fn check_op_spanned_post<O: NonConstOp<'tcx>>(mut self, op: O, span: Span) {
self.check_op_spanned(op, span);
assert!(self.secondary_errors.is_empty());
}
fn check_static(&mut self, def_id: DefId, span: Span) {
if self.tcx.is_thread_local_static(def_id) {
self.tcx.dcx().span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef`");
@ -429,6 +421,43 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
true
}
pub fn check_drop_terminator(
&mut self,
dropped_place: Place<'tcx>,
location: Location,
terminator_span: Span,
) {
let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
let needs_drop = if let Some(local) = dropped_place.as_local() {
self.qualifs.needs_drop(self.ccx, local, location)
} else {
qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
};
// If this type doesn't need a drop at all, then there's nothing to enforce.
if !needs_drop {
return;
}
let mut err_span = self.span;
let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
// Use the span where the local was declared as the span of the drop error.
err_span = self.body.local_decls[local].source_info.span;
self.qualifs.needs_non_const_drop(self.ccx, local, location)
} else {
qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
};
self.check_op_spanned(
ops::LiveDrop {
dropped_at: terminator_span,
dropped_ty: ty_of_dropped_place,
needs_non_const_drop,
},
err_span,
);
}
}
impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
@ -874,35 +903,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
return;
}
let mut err_span = self.span;
let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
let needs_drop = if let Some(local) = dropped_place.as_local() {
self.qualifs.needs_drop(self.ccx, local, location)
} else {
qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
};
// If this type doesn't need a drop at all, then there's nothing to enforce.
if !needs_drop {
return;
}
let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
// Use the span where the local was declared as the span of the drop error.
err_span = self.body.local_decls[local].source_info.span;
self.qualifs.needs_non_const_drop(self.ccx, local, location)
} else {
qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
};
self.check_op_spanned(
ops::LiveDrop {
dropped_at: Some(terminator.source_info.span),
dropped_ty: ty_of_dropped_place,
needs_non_const_drop,
},
err_span,
);
self.check_drop_terminator(*dropped_place, location, terminator.source_info.span);
}
TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm),

View file

@ -459,7 +459,7 @@ impl<'tcx> NonConstOp<'tcx> for InlineAsm {
#[derive(Debug)]
pub(crate) struct LiveDrop<'tcx> {
pub dropped_at: Option<Span>,
pub dropped_at: Span,
pub dropped_ty: Ty<'tcx>,
pub needs_non_const_drop: bool,
}

View file

@ -5,11 +5,7 @@ use rustc_span::symbol::sym;
use tracing::trace;
use super::ConstCx;
use super::check::Qualifs;
use super::ops::{self};
use super::qualifs::{NeedsNonConstDrop, Qualif};
use crate::check_consts::check::Checker;
use crate::check_consts::qualifs::NeedsDrop;
use crate::check_consts::rustc_allow_const_fn_unstable;
/// Returns `true` if we should use the more precise live drop checker that runs after drop
@ -46,23 +42,16 @@ pub fn check_live_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>) {
return;
}
let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() };
// I know it's not great to be creating a new const checker, but I'd
// rather use it so we can deduplicate the error emitting logic that
// it contains.
let mut visitor = CheckLiveDrops { checker: Checker::new(&ccx) };
visitor.visit_body(body);
}
struct CheckLiveDrops<'mir, 'tcx> {
ccx: &'mir ConstCx<'mir, 'tcx>,
qualifs: Qualifs<'mir, 'tcx>,
}
// So we can access `body` and `tcx`.
impl<'mir, 'tcx> std::ops::Deref for CheckLiveDrops<'mir, 'tcx> {
type Target = ConstCx<'mir, 'tcx>;
fn deref(&self) -> &Self::Target {
self.ccx
}
checker: Checker<'mir, 'tcx>,
}
impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
@ -82,38 +71,10 @@ impl<'tcx> Visitor<'tcx> for CheckLiveDrops<'_, 'tcx> {
match &terminator.kind {
mir::TerminatorKind::Drop { place: dropped_place, .. } => {
let ty_of_dropped_place = dropped_place.ty(self.body, self.tcx).ty;
let needs_drop = if let Some(local) = dropped_place.as_local() {
self.qualifs.needs_drop(self.ccx, local, location)
} else {
NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
};
// If this type doesn't need a drop at all, then there's nothing to enforce.
if !needs_drop {
return;
}
let mut err_span = terminator.source_info.span;
let needs_non_const_drop = if let Some(local) = dropped_place.as_local() {
// Use the span where the local was declared as the span of the drop error.
err_span = self.body.local_decls[local].source_info.span;
self.qualifs.needs_non_const_drop(self.ccx, local, location)
} else {
NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
};
// I know it's not great to be creating a new const checker, but I'd
// rather use it so we can deduplicate the error emitting logic that
// it contains.
Checker::new(self.ccx).check_op_spanned_post(
ops::LiveDrop {
dropped_at: Some(terminator.source_info.span),
dropped_ty: ty_of_dropped_place,
needs_non_const_drop,
},
err_span,
self.checker.check_drop_terminator(
*dropped_place,
location,
terminator.source_info.span,
);
}

View file

@ -306,11 +306,10 @@ where
return false;
}
// This is currently unconditionally true for all qualifs, since we do
// not recurse into the pointer of a deref projection, but that may change
// in the future. If that changes, each qualif should be required to
// specify whether it operates structurally for deref projections, just like
// we do for `Qualif::is_structural_in_adt`.
// `Deref` currently unconditionally "qualifies" if `in_any_value_of_ty` returns true,
// i.e., we treat all qualifs as non-structural for deref projections. Generally,
// we can say very little about `*ptr` even if we know that `ptr` satisfies all
// sorts of properties.
if matches!(elem, ProjectionElem::Deref) {
// We have to assume that this qualifies.
return true;

View file

@ -411,7 +411,7 @@ pub struct LiveDrop<'tcx> {
pub kind: ConstContext,
pub dropped_ty: Ty<'tcx>,
#[label(const_eval_dropped_at_label)]
pub dropped_at: Option<Span>,
pub dropped_at: Span,
}
#[derive(Diagnostic)]