Skip to content

Commit 48d9c95

Browse files
committed
Diagnose liveness on MIR.
1 parent 64a0a1c commit 48d9c95

File tree

87 files changed

+2427
-2541
lines changed

Some content is hidden

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

87 files changed

+2427
-2541
lines changed

compiler/rustc_interface/src/passes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -990,6 +990,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
990990
tcx.ensure_ok().mir_borrowck(def_id)
991991
}
992992
tcx.ensure_ok().has_ffi_unwind_calls(def_id);
993+
tcx.ensure_ok().check_liveness(def_id);
993994

994995
// If we need to codegen, ensure that we emit all errors from
995996
// `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
@@ -937,7 +937,7 @@ pub enum BindingForm<'tcx> {
937937
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
938938
ImplicitSelf(ImplicitSelfKind),
939939
/// Reference used in a guard expression to ensure immutability.
940-
RefForGuard,
940+
RefForGuard(Local),
941941
}
942942

943943
mod binding_form_impl {
@@ -952,7 +952,7 @@ mod binding_form_impl {
952952
match self {
953953
Var(binding) => binding.hash_stable(hcx, hasher),
954954
ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
955-
RefForGuard => (),
955+
RefForGuard(local) => local.hash_stable(hcx, hasher),
956956
}
957957
}
958958
}
@@ -1163,7 +1163,7 @@ impl<'tcx> LocalDecl<'tcx> {
11631163
/// expression that is used to access said variable for the guard of the
11641164
/// match arm.
11651165
pub fn is_ref_for_guard(&self) -> bool {
1166-
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
1166+
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard(_)))
11671167
}
11681168

11691169
/// 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
@@ -228,7 +228,7 @@ impl<'tcx> PlaceTy<'tcx> {
228228
impl<V, T> ProjectionElem<V, T> {
229229
/// Returns `true` if the target of this projection may refer to a different region of memory
230230
/// than the base.
231-
fn is_indirect(&self) -> bool {
231+
pub fn is_indirect(&self) -> bool {
232232
match self {
233233
Self::Deref => true,
234234

compiler/rustc_middle/src/query/mod.rs

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

1122-
query check_liveness(key: LocalDefId) {
1123-
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key) }
1122+
query check_liveness(key: LocalDefId) -> &'tcx rustc_index::bit_set::DenseBitSet<abi::FieldIdx> {
1123+
arena_cache
1124+
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key.to_def_id()) }
1125+
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
11241126
}
11251127

11261128
/// 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
@@ -2838,7 +2838,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
28382838
user_ty: None,
28392839
source_info,
28402840
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(
2841-
BindingForm::RefForGuard,
2841+
BindingForm::RefForGuard(for_arm_body),
28422842
))),
28432843
});
28442844
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
@@ -68,11 +68,6 @@ pub fn build_mir<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Body<'tcx> {
6868
}
6969
};
7070

71-
// Checking liveness after building the THIR ensures there were no typeck errors.
72-
//
73-
// maybe move the check to a MIR pass?
74-
tcx.ensure_ok().check_liveness(def);
75-
7671
// Don't steal here, instead steal in unsafeck. This is so that
7772
// pattern inline constants can be evaluated as part of building the
7873
// 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
@@ -36,12 +36,16 @@ mir_transform_force_inline_attr =
3636
mir_transform_force_inline_justification =
3737
`{$callee}` is required to be inlined to: {$sym}
3838
39+
mir_transform_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
40+
3941
mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
4042
.label = the value is held across this suspend point
4143
.note = {$reason}
4244
.help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
4345
mir_transform_operation_will_panic = this operation will panic at runtime
4446
47+
mir_transform_string_interpolation_only_works = string interpolation only works in `format!` invocations
48+
4549
mir_transform_tail_expr_drop_order = relative drop order changing in Rust 2024
4650
.temporaries = in Rust 2024, this temporary value will be dropped first
4751
.observers = in Rust 2024, this local variable or temporary value will be dropped second
@@ -79,3 +83,26 @@ mir_transform_unconditional_recursion = function cannot return without recursing
7983
mir_transform_unconditional_recursion_call_site_label = recursive call site
8084
8185
mir_transform_unknown_pass_name = MIR pass `{$name}` is unknown and will be ignored
86+
87+
mir_transform_unused_assign = value assigned to `{$name}` is never read
88+
.help = maybe it is overwritten before being read?
89+
90+
mir_transform_unused_assign_passed = value passed to `{$name}` is never read
91+
.help = maybe it is overwritten before being read?
92+
93+
mir_transform_unused_assign_suggestion =
94+
you might have meant to mutate the pointed at value being passed in, instead of changing the reference in the local binding
95+
96+
mir_transform_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read
97+
.help = did you mean to capture by reference instead?
98+
99+
mir_transform_unused_var_assigned_only = variable `{$name}` is assigned to, but never used
100+
.note = consider using `_{$name}` instead
101+
102+
mir_transform_unused_var_underscore = if this is intentional, prefix it with an underscore
103+
104+
mir_transform_unused_variable = unused variable: `{$name}`
105+
106+
mir_transform_unused_variable_args_in_macro = `{$name}` is captured in macro and introduced a unused variable
107+
108+
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;
@@ -125,6 +125,114 @@ pub(crate) struct MCDCExceedsTestVectorLimit {
125125
pub(crate) max_num_test_vectors: usize,
126126
}
127127

128+
#[derive(LintDiagnostic)]
129+
#[diag(mir_transform_unused_capture_maybe_capture_ref)]
130+
#[help]
131+
pub(crate) struct UnusedCaptureMaybeCaptureRef {
132+
pub name: String,
133+
}
134+
135+
#[derive(LintDiagnostic)]
136+
#[diag(mir_transform_unused_var_assigned_only)]
137+
#[note]
138+
pub(crate) struct UnusedVarAssignedOnly {
139+
pub name: String,
140+
}
141+
142+
#[derive(LintDiagnostic)]
143+
#[diag(mir_transform_unused_assign)]
144+
pub(crate) struct UnusedAssign {
145+
pub name: String,
146+
#[subdiagnostic]
147+
pub suggestion: Option<UnusedAssignSuggestion>,
148+
#[help]
149+
pub help: bool,
150+
}
151+
152+
#[derive(Subdiagnostic)]
153+
#[multipart_suggestion(mir_transform_unused_assign_suggestion, applicability = "maybe-incorrect")]
154+
pub(crate) struct UnusedAssignSuggestion {
155+
pub pre: &'static str,
156+
#[suggestion_part(code = "{pre}mut ")]
157+
pub ty_span: Option<Span>,
158+
#[suggestion_part(code = "")]
159+
pub ty_ref_span: Span,
160+
#[suggestion_part(code = "*")]
161+
pub pre_lhs_span: Span,
162+
#[suggestion_part(code = "")]
163+
pub rhs_borrow_span: Span,
164+
}
165+
166+
#[derive(LintDiagnostic)]
167+
#[diag(mir_transform_unused_assign_passed)]
168+
#[help]
169+
pub(crate) struct UnusedAssignPassed {
170+
pub name: String,
171+
}
172+
173+
#[derive(LintDiagnostic)]
174+
#[diag(mir_transform_unused_variable)]
175+
pub(crate) struct UnusedVariable {
176+
pub name: String,
177+
#[subdiagnostic]
178+
pub string_interp: Vec<UnusedVariableStringInterp>,
179+
#[subdiagnostic]
180+
pub sugg: UnusedVariableSugg,
181+
}
182+
183+
#[derive(Subdiagnostic)]
184+
pub(crate) enum UnusedVariableSugg {
185+
#[multipart_suggestion(
186+
mir_transform_unused_variable_try_ignore,
187+
applicability = "machine-applicable"
188+
)]
189+
TryIgnore {
190+
#[suggestion_part(code = "{name}: _")]
191+
shorthands: Vec<Span>,
192+
#[suggestion_part(code = "_")]
193+
non_shorthands: Vec<Span>,
194+
name: String,
195+
},
196+
197+
#[multipart_suggestion(
198+
mir_transform_unused_var_underscore,
199+
applicability = "machine-applicable"
200+
)]
201+
TryPrefix {
202+
#[suggestion_part(code = "_{name}")]
203+
spans: Vec<Span>,
204+
name: String,
205+
},
206+
207+
#[help(mir_transform_unused_variable_args_in_macro)]
208+
NoSugg {
209+
#[primary_span]
210+
span: Span,
211+
name: String,
212+
},
213+
}
214+
215+
pub(crate) struct UnusedVariableStringInterp {
216+
pub lit: Span,
217+
}
218+
219+
impl Subdiagnostic for UnusedVariableStringInterp {
220+
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
221+
diag.span_label(
222+
self.lit,
223+
crate::fluent_generated::mir_transform_maybe_string_interpolation,
224+
);
225+
diag.multipart_suggestion(
226+
crate::fluent_generated::mir_transform_string_interpolation_only_works,
227+
vec![
228+
(self.lit.shrink_to_lo(), String::from("format!(")),
229+
(self.lit.shrink_to_hi(), String::from(")")),
230+
],
231+
Applicability::MachineApplicable,
232+
);
233+
}
234+
}
235+
128236
pub(crate) struct MustNotSupend<'a, 'tcx> {
129237
pub tcx: TyCtxt<'tcx>,
130238
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;
@@ -213,6 +214,7 @@ pub fn provide(providers: &mut Providers) {
213214
mir_for_ctfe,
214215
mir_coroutine_witnesses: coroutine::mir_coroutine_witnesses,
215216
optimized_mir,
217+
check_liveness: liveness::check_liveness,
216218
is_mir_available,
217219
is_ctfe_mir_available: is_mir_available,
218220
mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable,
@@ -507,6 +509,8 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
507509
}
508510
}
509511

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

0 commit comments

Comments
 (0)