Skip to content

Commit 92f923c

Browse files
committed
Auto merge of #142390 - cjgillot:mir-liveness, r=davidtwco
Perform unused assignment and unused variables lints on MIR. Rebase of #101500 Fixes #51003. The first commit moves detection of uninhabited types from the current liveness pass to MIR building. In order to keep the same level of diagnostics, I had to instrument MIR a little more: - keep for which original local a guard local is created; - store in the `VarBindingForm` the list of introducer places and whether this was a shorthand pattern. I am not very proud of the handling of self-assignments. The proposed scheme is in two parts: first detect probable self-assignments, by pattern matching on MIR, and second treat them specially during dataflow analysis. I welcome ideas. Please review carefully the changes in tests. There are many small changes to behaviour, and I'm not sure all of them are desirable.
2 parents 5d1b897 + 7a6aa32 commit 92f923c

File tree

115 files changed

+2934
-2728
lines changed

Some content is hidden

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

115 files changed

+2934
-2728
lines changed

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
139139
// whether or not the right-hand side is a place expression
140140
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
141141
opt_match_place: Some((opt_match_place, match_span)),
142-
binding_mode: _,
143-
opt_ty_info: _,
144-
pat_span: _,
142+
..
145143
})) = *local_decl.local_info()
146144
{
147145
let stmt_source_info = self.body.source_info(location);

compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,8 +336,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
336336
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
337337
binding_mode: BindingMode(ByRef::No, Mutability::Not),
338338
opt_ty_info: Some(sp),
339-
opt_match_place: _,
340-
pat_span: _,
339+
..
341340
})) => {
342341
if suggest {
343342
err.span_note(sp, "the binding is already a mutable borrow");
@@ -751,6 +750,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
751750
opt_ty_info: _,
752751
opt_match_place: _,
753752
pat_span,
753+
introductions: _,
754754
})) => pat_span,
755755
_ => local_decl.source_info.span,
756756
};

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: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -882,6 +882,9 @@ pub struct VarBindingForm<'tcx> {
882882
pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
883883
/// The span of the pattern in which this variable was bound.
884884
pub pat_span: Span,
885+
/// A binding can be introduced multiple times, with or patterns:
886+
/// `Foo::A { x } | Foo::B { z: x }`. This stores information for each of those introductions.
887+
pub introductions: Vec<VarBindingIntroduction>,
885888
}
886889

887890
#[derive(Clone, Debug, TyEncodable, TyDecodable)]
@@ -891,7 +894,15 @@ pub enum BindingForm<'tcx> {
891894
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
892895
ImplicitSelf(ImplicitSelfKind),
893896
/// Reference used in a guard expression to ensure immutability.
894-
RefForGuard,
897+
RefForGuard(Local),
898+
}
899+
900+
#[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable)]
901+
pub struct VarBindingIntroduction {
902+
/// Where this additional introduction happened.
903+
pub span: Span,
904+
/// Is that introduction a shorthand struct pattern, i.e. `Foo { x }`.
905+
pub is_shorthand: bool,
895906
}
896907

897908
mod binding_form_impl {
@@ -906,7 +917,7 @@ mod binding_form_impl {
906917
match self {
907918
Var(binding) => binding.hash_stable(hcx, hasher),
908919
ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
909-
RefForGuard => (),
920+
RefForGuard(local) => local.hash_stable(hcx, hasher),
910921
}
911922
}
912923
}
@@ -1088,12 +1099,8 @@ impl<'tcx> LocalDecl<'tcx> {
10881099
matches!(
10891100
self.local_info(),
10901101
LocalInfo::User(
1091-
BindingForm::Var(VarBindingForm {
1092-
binding_mode: BindingMode(ByRef::No, _),
1093-
opt_ty_info: _,
1094-
opt_match_place: _,
1095-
pat_span: _,
1096-
}) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
1102+
BindingForm::Var(VarBindingForm { binding_mode: BindingMode(ByRef::No, _), .. })
1103+
| BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
10971104
)
10981105
)
10991106
}
@@ -1105,12 +1112,8 @@ impl<'tcx> LocalDecl<'tcx> {
11051112
matches!(
11061113
self.local_info(),
11071114
LocalInfo::User(
1108-
BindingForm::Var(VarBindingForm {
1109-
binding_mode: BindingMode(ByRef::No, _),
1110-
opt_ty_info: _,
1111-
opt_match_place: _,
1112-
pat_span: _,
1113-
}) | BindingForm::ImplicitSelf(_),
1115+
BindingForm::Var(VarBindingForm { binding_mode: BindingMode(ByRef::No, _), .. })
1116+
| BindingForm::ImplicitSelf(_),
11141117
)
11151118
)
11161119
}
@@ -1126,7 +1129,7 @@ impl<'tcx> LocalDecl<'tcx> {
11261129
/// expression that is used to access said variable for the guard of the
11271130
/// match arm.
11281131
pub fn is_ref_for_guard(&self) -> bool {
1129-
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
1132+
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard(_)))
11301133
}
11311134

11321135
/// 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/thir.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,8 @@ pub enum PatKind<'tcx> {
798798
/// (The same binding can occur multiple times in different branches of
799799
/// an or-pattern, but only one of them will be primary.)
800800
is_primary: bool,
801+
/// Is this binding a shorthand struct pattern, i.e. `Foo { a }`?
802+
is_shorthand: bool,
801803
},
802804

803805
/// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with

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/messages.ftl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,11 @@ mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
383383
mir_build_union_pattern = cannot use unions in constant patterns
384384
.label = can't use a `union` here
385385
386+
mir_build_unreachable_due_to_uninhabited = unreachable {$descr}
387+
.label = unreachable {$descr}
388+
.label_orig = any code following this expression is unreachable
389+
.note = this expression has type `{$ty}`, which is uninhabited
390+
386391
mir_build_unreachable_making_this_unreachable = collectively making this unreachable
387392
388393
mir_build_unreachable_making_this_unreachable_n_more = ...and {$covered_by_many_n_more_count} other patterns collectively make this unreachable

compiler/rustc_mir_build/src/builder/block.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
286286
block,
287287
node,
288288
span,
289+
false,
289290
OutsideGuard,
290291
ScheduleDrops::Yes,
291292
);

0 commit comments

Comments
 (0)