Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 32 additions & 73 deletions compiler/rustc_const_eval/src/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,91 +49,33 @@ pub(crate) struct Qualifs<'mir, 'tcx> {
}

impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
/// Returns `true` if `local` is `NeedsDrop` at the given `Location`.
///
/// Only updates the cursor if absolutely necessary
pub(crate) fn needs_drop(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
location: Location,
) -> bool {
let ty = ccx.body.local_decls[local].ty;
// Peeking into opaque types causes cycles if the current function declares said opaque
// type. Thus we avoid short circuiting on the type and instead run the more expensive
// analysis that looks at the actual usage within this function
if !ty.has_opaque_types() && !NeedsDrop::in_any_value_of_ty(ccx, ty) {
return false;
}

let needs_drop = self.needs_drop.get_or_insert_with(|| {
let ConstCx { tcx, body, .. } = *ccx;

FlowSensitiveAnalysis::new(NeedsDrop, ccx)
.iterate_to_fixpoint(tcx, body, None)
.into_results_cursor(body)
});

needs_drop.seek_before_primary_effect(location);
needs_drop.get().contains(local)
}

/// Returns `true` if `local` is `NeedsNonConstDrop` at the given `Location`.
///
/// Only updates the cursor if absolutely necessary
pub(crate) fn needs_non_const_drop(
&mut self,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
location: Location,
) -> bool {
let ty = ccx.body.local_decls[local].ty;
// Peeking into opaque types causes cycles if the current function declares said opaque
// type. Thus we avoid short circuiting on the type and instead run the more expensive
// analysis that looks at the actual usage within this function
if !ty.has_opaque_types() && !NeedsNonConstDrop::in_any_value_of_ty(ccx, ty) {
return false;
}

let needs_non_const_drop = self.needs_non_const_drop.get_or_insert_with(|| {
let ConstCx { tcx, body, .. } = *ccx;

FlowSensitiveAnalysis::new(NeedsNonConstDrop, ccx)
.iterate_to_fixpoint(tcx, body, None)
.into_results_cursor(body)
});

needs_non_const_drop.seek_before_primary_effect(location);
needs_non_const_drop.get().contains(local)
}

/// Returns `true` if `local` is `HasMutInterior` at the given `Location`.
/// Does `Q` hold for the `local` at the given `Location`?
///
/// Only updates the cursor if absolutely necessary.
fn has_mut_interior(
&mut self,
fn in_local<Q: Qualif>(
qualif_results: &mut Option<QualifResults<'mir, 'tcx, Q>>,
ccx: &'mir ConstCx<'mir, 'tcx>,
local: Local,
location: Location,
) -> bool {
let ty = ccx.body.local_decls[local].ty;
// Peeking into opaque types causes cycles if the current function declares said opaque
// type. Thus we avoid short circuiting on the type and instead run the more expensive
// analysis that looks at the actual usage within this function
if !ty.has_opaque_types() && !HasMutInterior::in_any_value_of_ty(ccx, ty) {
// analysis that looks at the actual usage within this function.
if !ty.has_opaque_types() && !Q::in_any_value_of_ty(ccx, ty) {
return false;
}

let has_mut_interior = self.has_mut_interior.get_or_insert_with(|| {
let qualif_results = qualif_results.get_or_insert_with(|| {
let ConstCx { tcx, body, .. } = *ccx;

FlowSensitiveAnalysis::new(HasMutInterior, ccx)
FlowSensitiveAnalysis::new(ccx)
.iterate_to_fixpoint(tcx, body, None)
.into_results_cursor(body)
});

has_mut_interior.seek_before_primary_effect(location);
has_mut_interior.get().contains(local)
qualif_results.seek_before_primary_effect(location);
qualif_results.get().contains(local)
}

fn in_return_place(
Expand Down Expand Up @@ -161,9 +103,19 @@ impl<'mir, 'tcx> Qualifs<'mir, 'tcx> {
let return_loc = ccx.body.terminator_loc(return_block);

ConstQualifs {
needs_drop: self.needs_drop(ccx, RETURN_PLACE, return_loc),
needs_non_const_drop: self.needs_non_const_drop(ccx, RETURN_PLACE, return_loc),
has_mut_interior: self.has_mut_interior(ccx, RETURN_PLACE, return_loc),
needs_drop: Self::in_local(&mut self.needs_drop, ccx, RETURN_PLACE, return_loc),
needs_non_const_drop: Self::in_local(
&mut self.needs_non_const_drop,
ccx,
RETURN_PLACE,
return_loc,
),
has_mut_interior: Self::in_local(
&mut self.has_mut_interior,
ccx,
RETURN_PLACE,
return_loc,
),
tainted_by_errors,
}
}
Expand Down Expand Up @@ -435,7 +387,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
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)
Qualifs::in_local(&mut self.qualifs.needs_drop, self.ccx, local, location)
} else {
qualifs::NeedsDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
};
Expand All @@ -448,7 +400,7 @@ impl<'mir, 'tcx> Checker<'mir, 'tcx> {
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)
Qualifs::in_local(&mut self.qualifs.needs_non_const_drop, self.ccx, local, location)
} else {
qualifs::NeedsNonConstDrop::in_any_value_of_ty(self.ccx, ty_of_dropped_place)
};
Expand Down Expand Up @@ -602,7 +554,14 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
| Rvalue::RawPtr(RawPtrKind::Const, place) => {
let borrowed_place_has_mut_interior = qualifs::in_place::<HasMutInterior, _>(
self.ccx,
&mut |local| self.qualifs.has_mut_interior(self.ccx, local, location),
&mut |local| {
Qualifs::in_local(
&mut self.qualifs.has_mut_interior,
self.ccx,
local,
location,
)
},
place.as_ref(),
);

Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_const_eval/src/check_consts/qualifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,10 @@ pub trait Qualif {
const ANALYSIS_NAME: &'static str;

/// Whether this `Qualif` is cleared when a local is moved from.
const IS_CLEARED_ON_MOVE: bool = false;
const IS_CLEARED_ON_MOVE: bool;

/// Whether this `Qualif` might be evaluated after the promotion and can encounter a promoted.
const ALLOW_PROMOTED: bool = false;
const ALLOW_PROMOTED: bool;

/// Extracts the field of `ConstQualifs` that corresponds to this `Qualif`.
fn in_qualifs(qualifs: &ConstQualifs) -> bool;
Expand Down Expand Up @@ -79,6 +79,8 @@ pub struct HasMutInterior;

impl Qualif for HasMutInterior {
const ANALYSIS_NAME: &'static str = "flow_has_mut_interior";
const IS_CLEARED_ON_MOVE: bool = false;
const ALLOW_PROMOTED: bool = false;

fn in_qualifs(qualifs: &ConstQualifs) -> bool {
qualifs.has_mut_interior
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_const_eval/src/check_consts/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,7 @@ impl<'mir, 'tcx, Q> FlowSensitiveAnalysis<'mir, 'tcx, Q>
where
Q: Qualif,
{
pub(super) fn new(_: Q, ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
pub(super) fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self {
FlowSensitiveAnalysis { ccx, _qualif: PhantomData }
}

Expand Down Expand Up @@ -309,7 +309,7 @@ impl<C> DebugWithContext<C> for State {

if self.borrow != old.borrow {
f.write_str("borrow: ")?;
self.qualif.fmt_diff_with(&old.borrow, ctxt, f)?;
self.borrow.fmt_diff_with(&old.borrow, ctxt, f)?;
f.write_str("\n")?;
}

Expand Down
Loading