Skip to content

Commit ddd5cf7

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 91ee6a4 + a6d630c commit ddd5cf7

File tree

111 files changed

+2781
-2628
lines changed

Some content is hidden

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

111 files changed

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

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

899910
mod binding_form_impl {
@@ -908,7 +919,7 @@ mod binding_form_impl {
908919
match self {
909920
Var(binding) => binding.hash_stable(hcx, hasher),
910921
ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
911-
RefForGuard => (),
922+
RefForGuard(local) => local.hash_stable(hcx, hasher),
912923
}
913924
}
914925
}
@@ -1090,12 +1101,8 @@ impl<'tcx> LocalDecl<'tcx> {
10901101
matches!(
10911102
self.local_info(),
10921103
LocalInfo::User(
1093-
BindingForm::Var(VarBindingForm {
1094-
binding_mode: BindingMode(ByRef::No, _),
1095-
opt_ty_info: _,
1096-
opt_match_place: _,
1097-
pat_span: _,
1098-
}) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
1104+
BindingForm::Var(VarBindingForm { binding_mode: BindingMode(ByRef::No, _), .. })
1105+
| BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
10991106
)
11001107
)
11011108
}
@@ -1107,12 +1114,8 @@ impl<'tcx> LocalDecl<'tcx> {
11071114
matches!(
11081115
self.local_info(),
11091116
LocalInfo::User(
1110-
BindingForm::Var(VarBindingForm {
1111-
binding_mode: BindingMode(ByRef::No, _),
1112-
opt_ty_info: _,
1113-
opt_match_place: _,
1114-
pat_span: _,
1115-
}) | BindingForm::ImplicitSelf(_),
1117+
BindingForm::Var(VarBindingForm { binding_mode: BindingMode(ByRef::No, _), .. })
1118+
| BindingForm::ImplicitSelf(_),
11161119
)
11171120
)
11181121
}
@@ -1128,7 +1131,7 @@ impl<'tcx> LocalDecl<'tcx> {
11281131
/// expression that is used to access said variable for the guard of the
11291132
/// match arm.
11301133
pub fn is_ref_for_guard(&self) -> bool {
1131-
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
1134+
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard(_)))
11321135
}
11331136

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