Skip to content

Commit 8742025

Browse files
committed
Diagnose liveness on MIR.
1 parent 75b3a5b commit 8742025

File tree

88 files changed

+2543
-2718
lines changed

Some content is hidden

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

88 files changed

+2543
-2718
lines changed

compiler/rustc_interface/src/passes.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
10961096
tcx.ensure_ok().check_transmutes(def_id);
10971097
}
10981098
tcx.ensure_ok().has_ffi_unwind_calls(def_id);
1099+
tcx.ensure_ok().check_liveness(def_id);
10991100

11001101
// If we need to codegen, ensure that we emit all errors from
11011102
// `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
@@ -894,7 +894,7 @@ pub enum BindingForm<'tcx> {
894894
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
895895
ImplicitSelf(ImplicitSelfKind),
896896
/// Reference used in a guard expression to ensure immutability.
897-
RefForGuard,
897+
RefForGuard(Local),
898898
}
899899

900900
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
@@ -917,7 +917,7 @@ mod binding_form_impl {
917917
match self {
918918
Var(binding) => binding.hash_stable(hcx, hasher),
919919
ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
920-
RefForGuard => (),
920+
RefForGuard(local) => local.hash_stable(hcx, hasher),
921921
}
922922
}
923923
}
@@ -1129,7 +1129,7 @@ impl<'tcx> LocalDecl<'tcx> {
11291129
/// expression that is used to access said variable for the guard of the
11301130
/// match arm.
11311131
pub fn is_ref_for_guard(&self) -> bool {
1132-
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
1132+
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard(_)))
11331133
}
11341134

11351135
/// 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
@@ -1195,8 +1195,10 @@ rustc_queries! {
11951195
desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) }
11961196
}
11971197

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

12021204
/// 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::query::Key;
@@ -158,6 +158,114 @@ pub(crate) struct FnItemRef {
158158
pub ident: Ident,
159159
}
160160

161+
#[derive(LintDiagnostic)]
162+
#[diag(mir_transform_unused_capture_maybe_capture_ref)]
163+
#[help]
164+
pub(crate) struct UnusedCaptureMaybeCaptureRef {
165+
pub name: Symbol,
166+
}
167+
168+
#[derive(LintDiagnostic)]
169+
#[diag(mir_transform_unused_var_assigned_only)]
170+
#[note]
171+
pub(crate) struct UnusedVarAssignedOnly {
172+
pub name: Symbol,
173+
}
174+
175+
#[derive(LintDiagnostic)]
176+
#[diag(mir_transform_unused_assign)]
177+
pub(crate) struct UnusedAssign {
178+
pub name: Symbol,
179+
#[subdiagnostic]
180+
pub suggestion: Option<UnusedAssignSuggestion>,
181+
#[help]
182+
pub help: bool,
183+
}
184+
185+
#[derive(Subdiagnostic)]
186+
#[multipart_suggestion(mir_transform_unused_assign_suggestion, applicability = "maybe-incorrect")]
187+
pub(crate) struct UnusedAssignSuggestion {
188+
pub pre: &'static str,
189+
#[suggestion_part(code = "{pre}mut ")]
190+
pub ty_span: Option<Span>,
191+
#[suggestion_part(code = "")]
192+
pub ty_ref_span: Span,
193+
#[suggestion_part(code = "*")]
194+
pub pre_lhs_span: Span,
195+
#[suggestion_part(code = "")]
196+
pub rhs_borrow_span: Span,
197+
}
198+
199+
#[derive(LintDiagnostic)]
200+
#[diag(mir_transform_unused_assign_passed)]
201+
#[help]
202+
pub(crate) struct UnusedAssignPassed {
203+
pub name: Symbol,
204+
}
205+
206+
#[derive(LintDiagnostic)]
207+
#[diag(mir_transform_unused_variable)]
208+
pub(crate) struct UnusedVariable {
209+
pub name: Symbol,
210+
#[subdiagnostic]
211+
pub string_interp: Vec<UnusedVariableStringInterp>,
212+
#[subdiagnostic]
213+
pub sugg: UnusedVariableSugg,
214+
}
215+
216+
#[derive(Subdiagnostic)]
217+
pub(crate) enum UnusedVariableSugg {
218+
#[multipart_suggestion(
219+
mir_transform_unused_variable_try_ignore,
220+
applicability = "machine-applicable"
221+
)]
222+
TryIgnore {
223+
#[suggestion_part(code = "{name}: _")]
224+
shorthands: Vec<Span>,
225+
#[suggestion_part(code = "_")]
226+
non_shorthands: Vec<Span>,
227+
name: Symbol,
228+
},
229+
230+
#[multipart_suggestion(
231+
mir_transform_unused_var_underscore,
232+
applicability = "machine-applicable"
233+
)]
234+
TryPrefix {
235+
#[suggestion_part(code = "_{name}")]
236+
spans: Vec<Span>,
237+
name: Symbol,
238+
},
239+
240+
#[help(mir_transform_unused_variable_args_in_macro)]
241+
NoSugg {
242+
#[primary_span]
243+
span: Span,
244+
name: Symbol,
245+
},
246+
}
247+
248+
pub(crate) struct UnusedVariableStringInterp {
249+
pub lit: Span,
250+
}
251+
252+
impl Subdiagnostic for UnusedVariableStringInterp {
253+
fn add_to_diag<G: EmissionGuarantee>(self, diag: &mut Diag<'_, G>) {
254+
diag.span_label(
255+
self.lit,
256+
crate::fluent_generated::mir_transform_maybe_string_interpolation,
257+
);
258+
diag.multipart_suggestion(
259+
crate::fluent_generated::mir_transform_string_interpolation_only_works,
260+
vec![
261+
(self.lit.shrink_to_lo(), String::from("format!(")),
262+
(self.lit.shrink_to_hi(), String::from(")")),
263+
],
264+
Applicability::MachineApplicable,
265+
);
266+
}
267+
}
268+
161269
pub(crate) struct MustNotSupend<'a, 'tcx> {
162270
pub tcx: TyCtxt<'tcx>,
163271
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
@@ -51,6 +51,7 @@ mod errors;
5151
mod ffi_unwind_calls;
5252
mod lint;
5353
mod lint_tail_expr_drop_order;
54+
mod liveness;
5455
mod patch;
5556
mod shim;
5657
mod ssa;
@@ -216,6 +217,7 @@ pub fn provide(providers: &mut Providers) {
216217
mir_for_ctfe,
217218
mir_coroutine_witnesses: coroutine::mir_coroutine_witnesses,
218219
optimized_mir,
220+
check_liveness: liveness::check_liveness,
219221
is_mir_available,
220222
is_ctfe_mir_available: is_mir_available,
221223
mir_callgraph_cyclic: inline::cycle::mir_callgraph_cyclic,
@@ -513,6 +515,8 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
513515
}
514516
}
515517

518+
tcx.ensure_done().check_liveness(def);
519+
516520
let (body, _) = tcx.mir_promoted(def);
517521
let mut body = body.steal();
518522

0 commit comments

Comments
 (0)