Skip to content

Commit 47baa0a

Browse files
committed
Diagnose liveness on MIR.
1 parent 4aba0a5 commit 47baa0a

File tree

86 files changed

+2419
-2542
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+2419
-2542
lines changed

compiler/rustc_interface/src/passes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,6 +1085,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
10851085
tcx.ensure_ok().check_transmutes(def_id);
10861086
}
10871087
tcx.ensure_ok().has_ffi_unwind_calls(def_id);
1088+
tcx.ensure_ok().check_liveness(def_id);
10881089

10891090
// If we need to codegen, ensure that we emit all errors from
10901091
// `mir_drops_elaborated_and_const_checked` now, to avoid discovering

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -896,7 +896,7 @@ pub enum BindingForm<'tcx> {
896896
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
897897
ImplicitSelf(ImplicitSelfKind),
898898
/// Reference used in a guard expression to ensure immutability.
899-
RefForGuard,
899+
RefForGuard(Local),
900900
}
901901

902902
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -919,7 +919,7 @@ mod binding_form_impl {
919919
match self {
920920
Var(binding) => binding.hash_stable(hcx, hasher),
921921
ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
922-
RefForGuard => (),
922+
RefForGuard(local) => local.hash_stable(hcx, hasher),
923923
}
924924
}
925925
}
@@ -1131,7 +1131,7 @@ impl<'tcx> LocalDecl<'tcx> {
11311131
/// expression that is used to access said variable for the guard of the
11321132
/// match arm.
11331133
pub fn is_ref_for_guard(&self) -> bool {
1134-
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
1134+
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard(_)))
11351135
}
11361136

11371137
/// Returns `Some` if this is a reference to a static item that is used to

compiler/rustc_middle/src/mir/statement.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@ impl<'tcx> PlaceTy<'tcx> {
237237
impl<V, T> ProjectionElem<V, T> {
238238
/// Returns `true` if the target of this projection may refer to a different region of memory
239239
/// than the base.
240-
fn is_indirect(&self) -> bool {
240+
pub fn is_indirect(&self) -> bool {
241241
match self {
242242
Self::Deref => true,
243243

compiler/rustc_middle/src/query/mod.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,8 +1193,10 @@ rustc_queries! {
11931193
desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) }
11941194
}
11951195

1196-
query check_liveness(key: LocalDefId) {
1197-
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key) }
1196+
query check_liveness(key: LocalDefId) -> &'tcx rustc_index::bit_set::DenseBitSet<abi::FieldIdx> {
1197+
arena_cache
1198+
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key.to_def_id()) }
1199+
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
11981200
}
11991201

12001202
/// Return the live symbols in the crate for dead code check.

compiler/rustc_middle/src/ty/closure.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,11 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc
327327
)
328328
}
329329
},
330+
HirProjectionKind::UnwrapUnsafeBinder => {
331+
curr_string = format!("unwrap_binder!({curr_string})");
332+
}
333+
// Just change the type to the hidden type, so we can actually project.
334+
HirProjectionKind::OpaqueCast => {}
330335
proj => bug!("{:?} unexpected because it isn't captured", proj),
331336
}
332337
}

compiler/rustc_mir_build/src/builder/matches/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2864,7 +2864,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
28642864
user_ty: None,
28652865
source_info,
28662866
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(
2867-
BindingForm::RefForGuard,
2867+
BindingForm::RefForGuard(for_arm_body),
28682868
))),
28692869
});
28702870
if self.should_emit_debug_info_for_binding(name, var_id) {

compiler/rustc_mir_build/src/builder/mod.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,11 +69,6 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
6969
}
7070
};
7171

72-
// Checking liveness after building the THIR ensures there were no typeck errors.
73-
//
74-
// maybe move the check to a MIR pass?
75-
tcx.ensure_ok().check_liveness(def);
76-
7772
// Don't steal here, instead steal in unsafeck. This is so that
7873
// pattern inline constants can be evaluated as part of building the
7974
// THIR of the parent function without a cycle.

compiler/rustc_mir_transform/messages.ftl

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,16 @@ mir_transform_force_inline_attr =
3434
mir_transform_force_inline_justification =
3535
`{$callee}` is required to be inlined to: {$sym}
3636
37+
mir_transform_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
38+
3739
mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
3840
.label = the value is held across this suspend point
3941
.note = {$reason}
4042
.help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
4143
mir_transform_operation_will_panic = this operation will panic at runtime
4244
45+
mir_transform_string_interpolation_only_works = string interpolation only works in `format!` invocations
46+
4347
mir_transform_tail_expr_drop_order = relative drop order changing in Rust 2024
4448
.temporaries = in Rust 2024, this temporary value will be dropped first
4549
.observers = in Rust 2024, this local variable or temporary value will be dropped second
@@ -77,3 +81,26 @@ mir_transform_unconditional_recursion = function cannot return without recursing
7781
mir_transform_unconditional_recursion_call_site_label = recursive call site
7882
7983
mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored
84+
85+
mir_transform_unused_assign = value assigned to `{$name}` is never read
86+
.help = maybe it is overwritten before being read?
87+
88+
mir_transform_unused_assign_passed = value passed to `{$name}` is never read
89+
.help = maybe it is overwritten before being read?
90+
91+
mir_transform_unused_assign_suggestion =
92+
you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
93+
94+
mir_transform_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read
95+
.help = did you mean to capture by reference instead?
96+
97+
mir_transform_unused_var_assigned_only = variable `{$name}` is assigned to, but never used
98+
.note = consider using `_{$name}` instead
99+
100+
mir_transform_unused_var_underscore = if this is intentional, prefix it with an underscore
101+
102+
mir_transform_unused_variable = unused variable: `{$name}`
103+
104+
mir_transform_unused_variable_args_in_macro = `{$name}` is captured in macro and introduced a unused variable
105+
106+
mir_transform_unused_variable_try_ignore = try ignoring the field

compiler/rustc_mir_transform/src/errors.rs

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use rustc_errors::codes::*;
2-
use rustc_errors::{Diag, LintDiagnostic};
2+
use rustc_errors::{Applicability, Diag, EmissionGuarantee, LintDiagnostic, Subdiagnostic};
33
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
44
use rustc_middle::mir::AssertKind;
55
use rustc_middle::ty::TyCtxt;
@@ -117,6 +117,114 @@ pub(crate) struct FnItemRef {
117117
pub ident: Ident,
118118
}
119119

120+
#[derive(LintDiagnostic)]
121+
#[diag(mir_transform_unused_capture_maybe_capture_ref)]
122+
#[help]
123+
pub(crate) struct UnusedCaptureMaybeCaptureRef {
124+
pub name: String,
125+
}
126+
127+
#[derive(LintDiagnostic)]
128+
#[diag(mir_transform_unused_var_assigned_only)]
129+
#[note]
130+
pub(crate) struct UnusedVarAssignedOnly {
131+
pub name: String,
132+
}
133+
134+
#[derive(LintDiagnostic)]
135+
#[diag(mir_transform_unused_assign)]
136+
pub(crate) struct UnusedAssign {
137+
pub name: String,
138+
#[subdiagnostic]
139+
pub suggestion: Option<UnusedAssignSuggestion>,
140+
#[help]
141+
pub help: bool,
142+
}
143+
144+
#[derive(Subdiagnostic)]
145+
#[multipart_suggestion(mir_transform_unused_assign_suggestion, applicability = "maybe-incorrect")]
146+
pub(crate) struct UnusedAssignSuggestion {
147+
pub pre: &'static str,
148+
#[suggestion_part(code = "{pre}mut ")]
149+
pub ty_span: Option<Span>,
150+
#[suggestion_part(code = "")]
151+
pub ty_ref_span: Span,
152+
#[suggestion_part(code = "*")]
153+
pub pre_lhs_span: Span,
154+
#[suggestion_part(code = "")]
155+
pub rhs_borrow_span: Span,
156+
}
157+
158+
#[derive(LintDiagnostic)]
159+
#[diag(mir_transform_unused_assign_passed)]
160+
#[help]
161+
pub(crate) struct UnusedAssignPassed {
162+
pub name: String,
163+
}
164+
165+
#[derive(LintDiagnostic)]
166+
#[diag(mir_transform_unused_variable)]
167+
pub(crate) struct UnusedVariable {
168+
pub name: String,
169+
#[subdiagnostic]
170+
pub string_interp: Vec<UnusedVariableStringInterp>,
171+
#[subdiagnostic]
172+
pub sugg: UnusedVariableSugg,
173+
}
174+
175+
#[derive(Subdiagnostic)]
176+
pub(crate) enum UnusedVariableSugg {
177+
#[multipart_suggestion(
178+
mir_transform_unused_variable_try_ignore,
179+
applicability = "machine-applicable"
180+
)]
181+
TryIgnore {
182+
#[suggestion_part(code = "{name}: _")]
183+
shorthands: Vec<Span>,
184+
#[suggestion_part(code = "_")]
185+
non_shorthands: Vec<Span>,
186+
name: String,
187+
},
188+
189+
#[multipart_suggestion(
190+
mir_transform_unused_var_underscore,
191+
applicability = "machine-applicable"
192+
)]
193+
TryPrefix {
194+
#[suggestion_part(code = "_{name}")]
195+
spans: Vec<Span>,
196+
name: String,
197+
},
198+
199+
#[help(mir_transform_unused_variable_args_in_macro)]
200+
NoSugg {
201+
#[primary_span]
202+
span: Span,
203+
name: String,
204+
},
205+
}
206+
207+
pub(crate) struct UnusedVariableStringInterp {
208+
pub lit: Span,
209+
}
210+
211+
impl Subdiagnostic for UnusedVariableStringInterp {
212+
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
213+
diag.span_label(
214+
self.lit,
215+
crate::fluent_generated::mir_transform_maybe_string_interpolation,
216+
);
217+
diag.multipart_suggestion(
218+
crate::fluent_generated::mir_transform_string_interpolation_only_works,
219+
vec![
220+
(self.lit.shrink_to_lo(), String::from("format!(")),
221+
(self.lit.shrink_to_hi(), String::from(")")),
222+
],
223+
Applicability::MachineApplicable,
224+
);
225+
}
226+
}
227+
120228
pub(crate) struct MustNotSupend<'a, 'tcx> {
121229
pub tcx: TyCtxt<'tcx>,
122230
pub yield_sp: Span,

compiler/rustc_mir_transform/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ mod errors;
5050
mod ffi_unwind_calls;
5151
mod lint;
5252
mod lint_tail_expr_drop_order;
53+
mod liveness;
5354
mod patch;
5455
mod shim;
5556
mod ssa;
@@ -214,6 +215,7 @@ pub fn provide(providers: &mut Providers) {
214215
mir_for_ctfe,
215216
mir_coroutine_witnesses: coroutine::mir_coroutine_witnesses,
216217
optimized_mir,
218+
check_liveness: liveness::check_liveness,
217219
is_mir_available,
218220
is_ctfe_mir_available: is_mir_available,
219221
mir_callgraph_cyclic: inline::cycle::mir_callgraph_cyclic,
@@ -508,6 +510,8 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
508510
}
509511
}
510512

513+
tcx.ensure_done().check_liveness(def);
514+
511515
let (body, _) = tcx.mir_promoted(def);
512516
let mut body = body.steal();
513517

0 commit comments

Comments
 (0)