Skip to content

Commit 50ba7f2

Browse files
Auto merge of #142390 - cjgillot:mir-liveness, r=<try>
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. <!-- homu-ignore:start --> <!-- If this PR is related to an unstable feature or an otherwise tracked effort, please link to the relevant tracking issue here. If you don't know of a related tracking issue or there are none, feel free to ignore this. This PR will get automatically assigned to a reviewer. In case you would like a specific user to review your work, you can assign it to them by using r? <reviewer name> --> <!-- homu-ignore:end -->
2 parents 573a015 + 1d8df21 commit 50ba7f2

File tree

104 files changed

+2637
-2627
lines changed

Some content is hidden

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

104 files changed

+2637
-2627
lines changed

compiler/rustc_borrowck/src/diagnostics/move_errors.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
140140
// whether or not the right-hand side is a place expression
141141
if let LocalInfo::User(BindingForm::Var(VarBindingForm {
142142
opt_match_place: Some((opt_match_place, match_span)),
143-
binding_mode: _,
144-
opt_ty_info: _,
145-
pat_span: _,
143+
..
146144
})) = *local_decl.local_info()
147145
{
148146
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
@@ -307,8 +307,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
307307
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
308308
binding_mode: BindingMode(ByRef::No, Mutability::Not),
309309
opt_ty_info: Some(sp),
310-
opt_match_place: _,
311-
pat_span: _,
310+
..
312311
})) => {
313312
if suggest {
314313
err.span_note(sp, "the binding is already a mutable borrow");
@@ -738,6 +737,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
738737
opt_ty_info: _,
739738
opt_match_place: _,
740739
pat_span,
740+
introductions: _,
741741
})) => pat_span,
742742
_ => local_decl.source_info.span,
743743
};

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: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,8 @@ pub struct VarBindingForm<'tcx> {
926926
pub opt_match_place: Option<(Option<Place<'tcx>>, Span)>,
927927
/// The span of the pattern in which this variable was bound.
928928
pub pat_span: Span,
929+
/// For each introduction place, record here the span and whether this was a shorthand pattern.
930+
pub introductions: Vec<(Span, /* is_shorthand */ bool)>,
929931
}
930932

931933
#[derive(Clone, Debug, TyEncodable, TyDecodable)]
@@ -935,7 +937,7 @@ pub enum BindingForm<'tcx> {
935937
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
936938
ImplicitSelf(ImplicitSelfKind),
937939
/// Reference used in a guard expression to ensure immutability.
938-
RefForGuard,
940+
RefForGuard(Local),
939941
}
940942

941943
mod binding_form_impl {
@@ -950,7 +952,7 @@ mod binding_form_impl {
950952
match self {
951953
Var(binding) => binding.hash_stable(hcx, hasher),
952954
ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
953-
RefForGuard => (),
955+
RefForGuard(local) => local.hash_stable(hcx, hasher),
954956
}
955957
}
956958
}
@@ -1131,12 +1133,8 @@ impl<'tcx> LocalDecl<'tcx> {
11311133
matches!(
11321134
self.local_info(),
11331135
LocalInfo::User(
1134-
BindingForm::Var(VarBindingForm {
1135-
binding_mode: BindingMode(ByRef::No, _),
1136-
opt_ty_info: _,
1137-
opt_match_place: _,
1138-
pat_span: _,
1139-
}) | BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
1136+
BindingForm::Var(VarBindingForm { binding_mode: BindingMode(ByRef::No, _), .. })
1137+
| BindingForm::ImplicitSelf(ImplicitSelfKind::Imm),
11401138
)
11411139
)
11421140
}
@@ -1148,12 +1146,8 @@ impl<'tcx> LocalDecl<'tcx> {
11481146
matches!(
11491147
self.local_info(),
11501148
LocalInfo::User(
1151-
BindingForm::Var(VarBindingForm {
1152-
binding_mode: BindingMode(ByRef::No, _),
1153-
opt_ty_info: _,
1154-
opt_match_place: _,
1155-
pat_span: _,
1156-
}) | BindingForm::ImplicitSelf(_),
1149+
BindingForm::Var(VarBindingForm { binding_mode: BindingMode(ByRef::No, _), .. })
1150+
| BindingForm::ImplicitSelf(_),
11571151
)
11581152
)
11591153
}
@@ -1169,7 +1163,7 @@ impl<'tcx> LocalDecl<'tcx> {
11691163
/// expression that is used to access said variable for the guard of the
11701164
/// match arm.
11711165
pub fn is_ref_for_guard(&self) -> bool {
1172-
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
1166+
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard(_)))
11731167
}
11741168

11751169
/// 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
@@ -1127,8 +1127,10 @@ rustc_queries! {
11271127
desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) }
11281128
}
11291129

1130-
query check_liveness(key: LocalDefId) {
1131-
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key) }
1130+
query check_liveness(key: LocalDefId) -> &'tcx rustc_index::bit_set::DenseBitSet<abi::FieldIdx> {
1131+
arena_cache
1132+
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key.to_def_id()) }
1133+
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
11321134
}
11331135

11341136
/// Return the live symbols in the crate for dead code check.

compiler/rustc_middle/src/thir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,7 @@ pub enum PatKind<'tcx> {
777777
/// (The same binding can occur multiple times in different branches of
778778
/// an or-pattern, but only one of them will be primary.)
779779
is_primary: bool,
780+
is_shorthand: bool,
780781
},
781782

782783
/// `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
@@ -346,6 +346,11 @@ mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
346346
mir_build_union_pattern = cannot use unions in constant patterns
347347
.label = can't use a `union` here
348348
349+
mir_build_unreachable_due_to_uninhabited = unreachable {$descr}
350+
.label = unreachable {$descr}
351+
.label_orig = any code following this expression is unreachable
352+
.note = this expression has type `{$ty}`, which is uninhabited
353+
349354
mir_build_unreachable_making_this_unreachable = collectively making this unreachable
350355
351356
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: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
204204
block,
205205
node,
206206
span,
207+
false,
207208
OutsideGuard,
208209
ScheduleDrops::Yes,
209210
);
@@ -296,6 +297,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
296297
block,
297298
node,
298299
span,
300+
false,
299301
OutsideGuard,
300302
ScheduleDrops::Yes,
301303
);

compiler/rustc_mir_build/src/builder/expr/into.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -269,18 +269,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
269269
args,
270270
unwind: UnwindAction::Continue,
271271
destination,
272-
// The presence or absence of a return edge affects control-flow sensitive
273-
// MIR checks and ultimately whether code is accepted or not. We can only
274-
// omit the return edge if a return type is visibly uninhabited to a module
275-
// that makes the call.
276-
target: expr
277-
.ty
278-
.is_inhabited_from(
279-
this.tcx,
280-
this.parent_module,
281-
this.infcx.typing_env(this.param_env),
282-
)
283-
.then_some(success),
272+
target: Some(success),
284273
call_source: if from_hir_call {
285274
CallSource::Normal
286275
} else {

compiler/rustc_mir_build/src/builder/matches/match_pair.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ impl<'tcx> MatchPairTree<'tcx> {
160160
None
161161
}
162162

163-
PatKind::Binding { mode, var, ref subpattern, .. } => {
163+
PatKind::Binding { mode, var, is_shorthand, ref subpattern, .. } => {
164164
// In order to please the borrow checker, when lowering a pattern
165165
// like `x @ subpat` we must establish any bindings in `subpat`
166166
// before establishing the binding for `x`.
@@ -199,6 +199,7 @@ impl<'tcx> MatchPairTree<'tcx> {
199199
source,
200200
var_id: var,
201201
binding_mode: mode,
202+
is_shorthand,
202203
});
203204
}
204205

compiler/rustc_mir_build/src/builder/matches/mod.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
600600
block,
601601
var,
602602
irrefutable_pat.span,
603+
false,
603604
OutsideGuard,
604605
ScheduleDrops::Yes,
605606
);
@@ -629,6 +630,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
629630
block,
630631
var,
631632
irrefutable_pat.span,
633+
false,
632634
OutsideGuard,
633635
ScheduleDrops::Yes,
634636
);
@@ -761,6 +763,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
761763
pattern,
762764
&ProjectedUserTypesNode::None,
763765
&mut |this, name, mode, var, span, ty, user_tys| {
766+
let saved_scope = this.source_scope;
767+
this.set_correct_source_scope_for_arg(var.0, saved_scope, span);
764768
let vis_scope = *visibility_scope
765769
.get_or_insert_with(|| this.new_source_scope(scope_span, LintLevel::Inherited));
766770
let source_info = SourceInfo { span, scope: this.source_scope };
@@ -778,6 +782,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
778782
opt_match_place.map(|(x, y)| (x.cloned(), y)),
779783
pattern.span,
780784
);
785+
this.source_scope = saved_scope;
781786
},
782787
);
783788
if let Some(guard_expr) = guard {
@@ -821,6 +826,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
821826
block: BasicBlock,
822827
var: LocalVarId,
823828
span: Span,
829+
is_shorthand: bool,
824830
for_guard: ForGuard,
825831
schedule_drop: ScheduleDrops,
826832
) -> Place<'tcx> {
@@ -834,6 +840,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
834840
{
835841
self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
836842
}
843+
let local_info = self.local_decls[local_id].local_info.as_mut().unwrap_crate_local();
844+
if let LocalInfo::User(BindingForm::Var(var_info)) = &mut **local_info {
845+
var_info.introductions.push((span, is_shorthand));
846+
}
837847
Place::from(local_id)
838848
}
839849

@@ -1230,6 +1240,7 @@ struct Binding<'tcx> {
12301240
source: Place<'tcx>,
12311241
var_id: LocalVarId,
12321242
binding_mode: BindingMode,
1243+
is_shorthand: bool,
12331244
}
12341245

12351246
/// Indicates that the type of `source` must be a subtype of the
@@ -2693,6 +2704,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
26932704
block,
26942705
binding.var_id,
26952706
binding.span,
2707+
binding.is_shorthand,
26962708
RefWithinGuard,
26972709
schedule_drops,
26982710
);
@@ -2709,6 +2721,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
27092721
block,
27102722
binding.var_id,
27112723
binding.span,
2724+
binding.is_shorthand,
27122725
OutsideGuard,
27132726
schedule_drops,
27142727
);
@@ -2748,6 +2761,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
27482761
block,
27492762
binding.var_id,
27502763
binding.span,
2764+
binding.is_shorthand,
27512765
OutsideGuard,
27522766
schedule_drops,
27532767
),
@@ -2801,6 +2815,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
28012815
opt_ty_info: None,
28022816
opt_match_place,
28032817
pat_span,
2818+
introductions: Vec::new(),
28042819
},
28052820
)))),
28062821
};
@@ -2823,7 +2838,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
28232838
user_ty: None,
28242839
source_info,
28252840
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(
2826-
BindingForm::RefForGuard,
2841+
BindingForm::RefForGuard(for_arm_body),
28272842
))),
28282843
});
28292844
if self.should_emit_debug_info_for_binding(name, var_id) {

0 commit comments

Comments
 (0)