-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Check for live drops in constants after drop elaboration #71824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
cecfa43
d73674e
a77f046
f5370fa
a43e486
21ddf4d
9e2ee32
2dcf7db
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,119 @@ | ||||||||||||||||||
use rustc_hir::def_id::LocalDefId; | ||||||||||||||||||
use rustc_middle::mir::visit::Visitor; | ||||||||||||||||||
use rustc_middle::mir::{self, BasicBlock, Location}; | ||||||||||||||||||
use rustc_middle::ty::TyCtxt; | ||||||||||||||||||
use rustc_span::Span; | ||||||||||||||||||
|
||||||||||||||||||
use super::ops; | ||||||||||||||||||
use super::qualifs::{NeedsDrop, Qualif}; | ||||||||||||||||||
use super::validation::Qualifs; | ||||||||||||||||||
use super::ConstCx; | ||||||||||||||||||
|
||||||||||||||||||
/// Returns `true` if we should use the more precise live drop checker that runs after drop | ||||||||||||||||||
/// elaboration. | ||||||||||||||||||
pub fn checking_enabled(tcx: TyCtxt<'tcx>) -> bool { | ||||||||||||||||||
tcx.features().const_precise_live_drops | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
/// Look for live drops in a const context. | ||||||||||||||||||
/// | ||||||||||||||||||
/// This is separate from the rest of the const checking logic because it must run after drop | ||||||||||||||||||
/// elaboration. | ||||||||||||||||||
pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body<'tcx>) { | ||||||||||||||||||
let const_kind = tcx.hir().body_const_context(def_id); | ||||||||||||||||||
if const_kind.is_none() { | ||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
if !checking_enabled(tcx) { | ||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
let ccx = ConstCx { | ||||||||||||||||||
body, | ||||||||||||||||||
tcx, | ||||||||||||||||||
def_id: def_id.to_def_id(), | ||||||||||||||||||
const_kind, | ||||||||||||||||||
param_env: tcx.param_env(def_id), | ||||||||||||||||||
}; | ||||||||||||||||||
|
||||||||||||||||||
let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() }; | ||||||||||||||||||
|
||||||||||||||||||
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 std::ops::Deref for CheckLiveDrops<'mir, 'tcx> { | ||||||||||||||||||
type Target = ConstCx<'mir, 'tcx>; | ||||||||||||||||||
|
||||||||||||||||||
fn deref(&self) -> &Self::Target { | ||||||||||||||||||
&self.ccx | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
impl CheckLiveDrops<'mir, 'tcx> { | ||||||||||||||||||
fn check_live_drop(&self, span: Span) { | ||||||||||||||||||
ops::non_const(self.ccx, ops::LiveDrop, span); | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
impl Visitor<'tcx> for CheckLiveDrops<'mir, 'tcx> { | ||||||||||||||||||
fn visit_basic_block_data(&mut self, bb: BasicBlock, block: &mir::BasicBlockData<'tcx>) { | ||||||||||||||||||
trace!("visit_basic_block_data: bb={:?} is_cleanup={:?}", bb, block.is_cleanup); | ||||||||||||||||||
|
||||||||||||||||||
// Ignore drop terminators in cleanup blocks. | ||||||||||||||||||
if block.is_cleanup { | ||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
self.super_basic_block_data(bb, block); | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { | ||||||||||||||||||
trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); | ||||||||||||||||||
|
||||||||||||||||||
match &terminator.kind { | ||||||||||||||||||
mir::TerminatorKind::Drop { location: dropped_place, .. } => { | ||||||||||||||||||
let dropped_ty = dropped_place.ty(self.body, self.tcx).ty; | ||||||||||||||||||
if !NeedsDrop::in_any_value_of_ty(self.ccx, dropped_ty) { | ||||||||||||||||||
return; | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @oli-obk Is this even reachable? I'd think we don't keep There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is indeed not reachable. |
||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
if dropped_place.is_indirect() { | ||||||||||||||||||
self.check_live_drop(terminator.source_info.span); | ||||||||||||||||||
return; | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
if self.qualifs.needs_drop(self.ccx, dropped_place.local, location) { | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here, this looks like it second-guessing drop elaboration which already determined that this drop is indeed necessary. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This one is reachable. I'm not sure yet why, but I am guessing the reason is that Of course such a change would insta-stabilize the feature gate from this PR without any reasonable way to avoid said stabilization. So I'm tempted to stabilize the feature but leave a FIXME on this function to merge its qualif checks into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The alternative would be to ignore qualifs here, and just follow what drop elaboration does. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we do keep following the qualifs to get an edge in precision over drop elaboration (maybe we have to, for backwards compat), we should add a test case for a program where the qualifs are more precise than drop elaboration is (i.e. a program that would get rejected if we just always called There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rust/src/test/ui/consts/drop_none.rs Lines 3 to 10 in a985d8e
Is this what you're looking for? We do have to keep this for back-compat, see #57734 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I forgot to post that here: the follow-up to this discussion is at #83351. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, you already found an equivalent one. |
||||||||||||||||||
// Use the span where the dropped local was declared for the error. | ||||||||||||||||||
let span = self.body.local_decls[dropped_place.local].source_info.span; | ||||||||||||||||||
self.check_live_drop(span); | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
|
||||||||||||||||||
mir::TerminatorKind::DropAndReplace { .. } => span_bug!( | ||||||||||||||||||
terminator.source_info.span, | ||||||||||||||||||
"`DropAndReplace` should be removed by drop elaboration", | ||||||||||||||||||
), | ||||||||||||||||||
|
||||||||||||||||||
mir::TerminatorKind::Abort | ||||||||||||||||||
| mir::TerminatorKind::Call { .. } | ||||||||||||||||||
| mir::TerminatorKind::Assert { .. } | ||||||||||||||||||
| mir::TerminatorKind::FalseEdge { .. } | ||||||||||||||||||
| mir::TerminatorKind::FalseUnwind { .. } | ||||||||||||||||||
| mir::TerminatorKind::GeneratorDrop | ||||||||||||||||||
| mir::TerminatorKind::Goto { .. } | ||||||||||||||||||
| mir::TerminatorKind::InlineAsm { .. } | ||||||||||||||||||
| mir::TerminatorKind::Resume | ||||||||||||||||||
| mir::TerminatorKind::Return | ||||||||||||||||||
| mir::TerminatorKind::SwitchInt { .. } | ||||||||||||||||||
| mir::TerminatorKind::Unreachable | ||||||||||||||||||
| mir::TerminatorKind::Yield { .. } => {} | ||||||||||||||||||
} | ||||||||||||||||||
} | ||||||||||||||||||
} |
Uh oh!
There was an error while loading. Please reload this page.