Print out destructor
This commit is contained in:
parent
ac91805f31
commit
864cca80b0
11 changed files with 425 additions and 186 deletions
|
@ -24,6 +24,7 @@ rustc_span = { path = "../rustc_span" }
|
|||
rustc_target = { path = "../rustc_target" }
|
||||
rustc_trait_selection = { path = "../rustc_trait_selection" }
|
||||
rustc_type_ir = { path = "../rustc_type_ir" }
|
||||
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
|
||||
tracing = "0.1"
|
||||
unicode-security = "0.1.0"
|
||||
# tidy-alphabetical-end
|
||||
|
|
|
@ -333,6 +333,11 @@ lint_identifier_uncommon_codepoints = identifier contains {$codepoints_len ->
|
|||
*[other] {" "}{$identifier_type}
|
||||
} Unicode general security profile
|
||||
|
||||
lint_if_let_dtor = {$dtor_kind ->
|
||||
[dyn] value may invoke a custom destructor because it contains a trait object
|
||||
*[concrete] value invokes this custom destructor
|
||||
}
|
||||
|
||||
lint_if_let_rescope = `if let` assigns a shorter lifetime since Edition 2024
|
||||
.label = this value has a significant drop implementation which may observe a major change in drop order and requires your discretion
|
||||
.help = the value is now dropped here in Edition 2024
|
||||
|
|
|
@ -7,13 +7,17 @@ use rustc_errors::{
|
|||
Applicability, Diag, EmissionGuarantee, SubdiagMessageOp, Subdiagnostic, SuggestionStyle,
|
||||
};
|
||||
use rustc_hir::{self as hir, HirIdSet};
|
||||
use rustc_macros::LintDiagnostic;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use rustc_macros::{LintDiagnostic, Subdiagnostic};
|
||||
use rustc_middle::ty::adjustment::Adjust;
|
||||
use rustc_middle::ty::significant_drop_order::{
|
||||
extract_component_with_significant_dtor, ty_dtor_span,
|
||||
};
|
||||
use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
use rustc_session::lint::{FutureIncompatibilityReason, LintId};
|
||||
use rustc_session::{declare_lint, impl_lint_pass};
|
||||
use rustc_span::Span;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::{DUMMY_SP, Span};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{LateContext, LateLintPass};
|
||||
|
||||
|
@ -130,6 +134,7 @@ impl IfLetRescope {
|
|||
hir::ExprKind::If(_cond, _conseq, Some(alt)) => alt.span.shrink_to_hi(),
|
||||
_ => return,
|
||||
};
|
||||
let mut seen_dyn = false;
|
||||
let mut add_bracket_to_match_head = match_head_needs_bracket(tcx, expr);
|
||||
let mut significant_droppers = vec![];
|
||||
let mut lifetime_ends = vec![];
|
||||
|
@ -137,6 +142,7 @@ impl IfLetRescope {
|
|||
let mut alt_heads = vec![];
|
||||
let mut match_heads = vec![];
|
||||
let mut consequent_heads = vec![];
|
||||
let mut destructors = vec![];
|
||||
let mut first_if_to_lint = None;
|
||||
let mut first_if_to_rewrite = false;
|
||||
let mut empty_alt = false;
|
||||
|
@ -160,11 +166,25 @@ impl IfLetRescope {
|
|||
let before_conseq = conseq.span.shrink_to_lo();
|
||||
let lifetime_end = source_map.end_point(conseq.span);
|
||||
|
||||
if let ControlFlow::Break(significant_dropper) =
|
||||
if let ControlFlow::Break((drop_span, drop_tys)) =
|
||||
(FindSignificantDropper { cx }).check_if_let_scrutinee(init)
|
||||
{
|
||||
destructors.extend(drop_tys.into_iter().filter_map(|ty| {
|
||||
if let Some(span) = ty_dtor_span(tcx, ty) {
|
||||
Some(DestructorLabel { span, dtor_kind: "concrete" })
|
||||
} else if matches!(ty.kind(), ty::Dynamic(..)) {
|
||||
if seen_dyn {
|
||||
None
|
||||
} else {
|
||||
seen_dyn = true;
|
||||
Some(DestructorLabel { span: DUMMY_SP, dtor_kind: "dyn" })
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}));
|
||||
first_if_to_lint = first_if_to_lint.or_else(|| Some((span, expr.hir_id)));
|
||||
significant_droppers.push(significant_dropper);
|
||||
significant_droppers.push(drop_span);
|
||||
lifetime_ends.push(lifetime_end);
|
||||
if ty_ascription.is_some()
|
||||
|| !expr.span.can_be_used_for_suggestions()
|
||||
|
@ -227,6 +247,7 @@ impl IfLetRescope {
|
|||
hir_id,
|
||||
span,
|
||||
IfLetRescopeLint {
|
||||
destructors,
|
||||
significant_droppers,
|
||||
lifetime_ends,
|
||||
rewrite: first_if_to_rewrite.then_some(IfLetRescopeRewrite {
|
||||
|
@ -288,6 +309,8 @@ impl<'tcx> LateLintPass<'tcx> for IfLetRescope {
|
|||
#[derive(LintDiagnostic)]
|
||||
#[diag(lint_if_let_rescope)]
|
||||
struct IfLetRescopeLint {
|
||||
#[subdiagnostic]
|
||||
destructors: Vec<DestructorLabel>,
|
||||
#[label]
|
||||
significant_droppers: Vec<Span>,
|
||||
#[help]
|
||||
|
@ -347,6 +370,14 @@ impl Subdiagnostic for IfLetRescopeRewrite {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Subdiagnostic)]
|
||||
#[note(lint_if_let_dtor)]
|
||||
struct DestructorLabel {
|
||||
#[primary_span]
|
||||
span: Span,
|
||||
dtor_kind: &'static str,
|
||||
}
|
||||
|
||||
struct AltHead(Span);
|
||||
|
||||
struct ConsequentRewrite {
|
||||
|
@ -374,7 +405,10 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
|
|||
/// of the scrutinee itself, and also recurses into the expression to find any ref
|
||||
/// exprs (or autoref) which would promote temporaries that would be scoped to the
|
||||
/// end of this `if`.
|
||||
fn check_if_let_scrutinee(&mut self, init: &'tcx hir::Expr<'tcx>) -> ControlFlow<Span> {
|
||||
fn check_if_let_scrutinee(
|
||||
&mut self,
|
||||
init: &'tcx hir::Expr<'tcx>,
|
||||
) -> ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)> {
|
||||
self.check_promoted_temp_with_drop(init)?;
|
||||
self.visit_expr(init)
|
||||
}
|
||||
|
@ -385,28 +419,35 @@ impl<'tcx> FindSignificantDropper<'_, 'tcx> {
|
|||
/// An expression is a promoted temporary if it has an addr taken (i.e. `&expr` or autoref)
|
||||
/// or is the scrutinee of the `if let`, *and* the expression is not a place
|
||||
/// expr, and it has a significant drop.
|
||||
fn check_promoted_temp_with_drop(&self, expr: &'tcx hir::Expr<'tcx>) -> ControlFlow<Span> {
|
||||
if !expr.is_place_expr(|base| {
|
||||
fn check_promoted_temp_with_drop(
|
||||
&self,
|
||||
expr: &'tcx hir::Expr<'tcx>,
|
||||
) -> ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)> {
|
||||
if expr.is_place_expr(|base| {
|
||||
self.cx
|
||||
.typeck_results()
|
||||
.adjustments()
|
||||
.get(base.hir_id)
|
||||
.is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
|
||||
}) && self
|
||||
.cx
|
||||
.typeck_results()
|
||||
.expr_ty(expr)
|
||||
.has_significant_drop(self.cx.tcx, self.cx.typing_env())
|
||||
{
|
||||
ControlFlow::Break(expr.span)
|
||||
} else {
|
||||
ControlFlow::Continue(())
|
||||
}) {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
let drop_tys = extract_component_with_significant_dtor(
|
||||
self.cx.tcx,
|
||||
self.cx.typing_env(),
|
||||
self.cx.typeck_results().expr_ty(expr),
|
||||
);
|
||||
if drop_tys.is_empty() {
|
||||
return ControlFlow::Continue(());
|
||||
}
|
||||
|
||||
ControlFlow::Break((expr.span, drop_tys))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for FindSignificantDropper<'_, 'tcx> {
|
||||
type Result = ControlFlow<Span>;
|
||||
type Result = ControlFlow<(Span, SmallVec<[Ty<'tcx>; 4]>)>;
|
||||
|
||||
fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) -> Self::Result {
|
||||
// Blocks introduce temporary terminating scope for all of its
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue