Skip to content

Commit cfb54c3

Browse files
committed
Diagnose liveness on MIR.
1 parent 5cffaa2 commit cfb54c3

File tree

87 files changed

+2419
-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

+2419
-2541
lines changed

compiler/rustc_interface/src/passes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
10661066
tcx.ensure_ok().mir_borrowck(def_id)
10671067
}
10681068
tcx.ensure_ok().has_ffi_unwind_calls(def_id);
1069+
tcx.ensure_ok().check_liveness(def_id);
10691070

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

944944
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -961,7 +961,7 @@ mod binding_form_impl {
961961
match self {
962962
Var(binding) => binding.hash_stable(hcx, hasher),
963963
ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
964-
RefForGuard => (),
964+
RefForGuard(local) => local.hash_stable(hcx, hasher),
965965
}
966966
}
967967
}
@@ -1172,7 +1172,7 @@ impl<'tcx> LocalDecl<'tcx> {
11721172
/// expression that is used to access said variable for the guard of the
11731173
/// match arm.
11741174
pub fn is_ref_for_guard(&self) -> bool {
1175-
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
1175+
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard(_)))
11761176
}
11771177

11781178
/// 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
@@ -1184,8 +1184,10 @@ rustc_queries! {
11841184
desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) }
11851185
}
11861186

1187-
query check_liveness(key: LocalDefId) {
1188-
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key) }
1187+
query check_liveness(key: LocalDefId) -> &'tcx rustc_index::bit_set::DenseBitSet<abi::FieldIdx> {
1188+
arena_cache
1189+
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key.to_def_id()) }
1190+
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
11891191
}
11901192

11911193
/// 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)