Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Diagnose liveness on MIR.
  • Loading branch information
cjgillot committed Apr 7, 2024
commit 26902d6545798455d024bbd6d6175e7b48cb9c8e
1 change: 1 addition & 0 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -749,6 +749,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
sess.time("MIR_effect_checking", || {
for def_id in tcx.hir().body_owners() {
tcx.ensure().has_ffi_unwind_calls(def_id);
tcx.ensure().check_liveness(def_id);

// If we need to codegen, ensure that we emit all errors from
// `mir_drops_elaborated_and_const_checked` now, to avoid discovering
Expand Down
6 changes: 3 additions & 3 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1010,7 +1010,7 @@ pub enum BindingForm<'tcx> {
/// Binding for a `self`/`&self`/`&mut self` binding where the type is implicit.
ImplicitSelf(ImplicitSelfKind),
/// Reference used in a guard expression to ensure immutability.
RefForGuard,
RefForGuard(Local),
}

TrivialTypeTraversalImpls! { BindingForm<'tcx> }
Expand All @@ -1027,7 +1027,7 @@ mod binding_form_impl {
match self {
Var(binding) => binding.hash_stable(hcx, hasher),
ImplicitSelf(kind) => kind.hash_stable(hcx, hasher),
RefForGuard => (),
RefForGuard(local) => local.hash_stable(hcx, hasher),
}
}
}
Expand Down Expand Up @@ -1242,7 +1242,7 @@ impl<'tcx> LocalDecl<'tcx> {
/// expression that is used to access said variable for the guard of the
/// match arm.
pub fn is_ref_for_guard(&self) -> bool {
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard))
matches!(self.local_info(), LocalInfo::User(BindingForm::RefForGuard(_)))
}

/// Returns `Some` if this is a reference to a static item that is used to
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/mir/statement.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl<'tcx> StatementKind<'tcx> {
impl<V, T> ProjectionElem<V, T> {
/// Returns `true` if the target of this projection may refer to a different region of memory
/// than the base.
fn is_indirect(&self) -> bool {
pub fn is_indirect(&self) -> bool {
match self {
Self::Deref => true,

Expand Down
6 changes: 4 additions & 2 deletions compiler/rustc_middle/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -943,8 +943,10 @@ rustc_queries! {
desc { |tcx| "checking privacy in {}", describe_as_module(key.to_local_def_id(), tcx) }
}

query check_liveness(key: LocalDefId) {
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key) }
query check_liveness(key: LocalDefId) -> &'tcx rustc_index::bit_set::BitSet<abi::FieldIdx> {
arena_cache
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key.to_def_id()) }
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
}

/// Return the live symbols in the crate for dead code check.
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/ty/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,8 @@ pub fn place_to_string_for_capture<'tcx>(tcx: TyCtxt<'tcx>, place: &HirPlace<'tc
)
}
},
// Just change the type to the hidden type, so we can actually project.
HirProjectionKind::OpaqueCast => {}
proj => bug!("{:?} unexpected because it isn't captured", proj),
}
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2479,7 +2479,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
user_ty: None,
source_info,
local_info: ClearCrossCrate::Set(Box::new(LocalInfo::User(
BindingForm::RefForGuard,
BindingForm::RefForGuard(for_arm_body),
))),
});
self.var_debug_info.push(VarDebugInfo {
Expand Down
6 changes: 0 additions & 6 deletions compiler/rustc_mir_build/src/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,6 @@ pub(crate) fn mir_build<'tcx>(tcx: TyCtxtAt<'tcx>, def: LocalDefId) -> Body<'tcx
thir::BodyTy::Const(ty) => construct_const(tcx, def, thir, expr, ty),
};

// this must run before MIR dump, because
// "not all control paths return a value" is reported here.
//
// maybe move the check to a MIR pass?
tcx.ensure().check_liveness(def);

// Don't steal here, instead steal in unsafeck. This is so that
// pattern inline constants can be evaluated as part of building the
// THIR of the parent function without a cycle.
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_dataflow/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@ pub use self::drop_flag_effects::{
drop_flag_effects_for_function_entry, drop_flag_effects_for_location,
move_path_children_matching, on_all_children_bits, on_lookup_result_bits,
};
use self::framework::SwitchIntEdgeEffects;
pub use self::framework::{
fmt, graphviz, lattice, visit_results, Analysis, AnalysisDomain, Backward, Direction, Engine,
Forward, GenKill, GenKillAnalysis, JoinSemiLattice, MaybeReachable, Results, ResultsCursor,
ResultsVisitable, ResultsVisitor, SwitchIntEdgeEffects,
ResultsVisitable, ResultsVisitor,
};
use self::move_paths::MoveData;

Expand Down
24 changes: 24 additions & 0 deletions compiler/rustc_mir_transform/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,37 @@ mir_transform_ffi_unwind_call = call to {$foreign ->
mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
.suggestion = cast `{$ident}` to obtain a function pointer

mir_transform_maybe_string_interpolation = you might have meant to use string interpolation in this string literal

mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
.label = the value is held across this suspend point
.note = {$reason}
.help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
mir_transform_operation_will_panic = this operation will panic at runtime

mir_transform_string_interpolation_only_works = string interpolation only works in `format!` invocations

mir_transform_unaligned_packed_ref = reference to packed field is unaligned
.note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
.note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
.help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)

mir_transform_unused_assign = value assigned to `{$name}` is never read
.help = maybe it is overwritten before being read?

mir_transform_unused_assign_passed = value passed to `{$name}` is never read
.help = maybe it is overwritten before being read?

mir_transform_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read
.help = did you mean to capture by reference instead?

mir_transform_unused_var_assigned_only = variable `{$name}` is assigned to, but never used
.note = consider using `_{$name}` instead

mir_transform_unused_var_underscore = if this is intentional, prefix it with an underscore

mir_transform_unused_variable = unused variable: `{$name}`

mir_transform_unused_variable_args_in_macro = `{$name}` is captured in macro and introduced a unused variable

mir_transform_unused_variable_try_ignore = try ignoring the field
100 changes: 99 additions & 1 deletion compiler/rustc_mir_transform/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use rustc_errors::{codes::*, Diag, DiagMessage, LintDiagnostic};
use rustc_errors::{
codes::*, Applicability, Diag, DiagMessage, EmissionGuarantee, LintDiagnostic,
SubdiagMessageOp, Subdiagnostic,
};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
use rustc_middle::mir::AssertKind;
use rustc_middle::ty::TyCtxt;
Expand Down Expand Up @@ -91,6 +94,101 @@ pub(crate) struct FnItemRef {
pub ident: String,
}

#[derive(LintDiagnostic)]
#[diag(mir_transform_unused_capture_maybe_capture_ref)]
#[help]
pub(crate) struct UnusedCaptureMaybeCaptureRef {
pub name: String,
}

#[derive(LintDiagnostic)]
#[diag(mir_transform_unused_var_assigned_only)]
#[note]
pub(crate) struct UnusedVarAssignedOnly {
pub name: String,
}

#[derive(LintDiagnostic)]
#[diag(mir_transform_unused_assign)]
#[help]
pub(crate) struct UnusedAssign {
pub name: String,
}

#[derive(LintDiagnostic)]
#[diag(mir_transform_unused_assign_passed)]
#[help]
pub(crate) struct UnusedAssignPassed {
pub name: String,
}

#[derive(LintDiagnostic)]
#[diag(mir_transform_unused_variable)]
pub(crate) struct UnusedVariable {
pub name: String,
#[subdiagnostic]
pub string_interp: Vec<UnusedVariableStringInterp>,
#[subdiagnostic]
pub sugg: UnusedVariableSugg,
}

#[derive(Subdiagnostic)]
pub(crate) enum UnusedVariableSugg {
#[multipart_suggestion(
mir_transform_unused_variable_try_ignore,
applicability = "machine-applicable"
)]
TryIgnore {
#[suggestion_part(code = "{name}: _")]
shorthands: Vec<Span>,
#[suggestion_part(code = "_")]
non_shorthands: Vec<Span>,
name: String,
},

#[multipart_suggestion(
mir_transform_unused_var_underscore,
applicability = "machine-applicable"
)]
TryPrefix {
#[suggestion_part(code = "_{name}")]
spans: Vec<Span>,
name: String,
},

#[help(mir_transform_unused_variable_args_in_macro)]
NoSugg {
#[primary_span]
span: Span,
name: String,
},
}

pub(crate) struct UnusedVariableStringInterp {
pub lit: Span,
}

impl Subdiagnostic for UnusedVariableStringInterp {
fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
self,
diag: &mut Diag<'_, G>,
_: F,
) {
diag.span_label(
self.lit,
crate::fluent_generated::mir_transform_maybe_string_interpolation,
);
diag.multipart_suggestion(
crate::fluent_generated::mir_transform_string_interpolation_only_works,
vec![
(self.lit.shrink_to_lo(), String::from("format!(")),
(self.lit.shrink_to_hi(), String::from(")")),
],
Applicability::MachineApplicable,
);
}
}

pub(crate) struct MustNotSupend<'tcx, 'a> {
pub tcx: TyCtxt<'tcx>,
pub yield_sp: Span,
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_mir_transform/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ mod jump_threading;
mod known_panics_lint;
mod large_enums;
mod lint;
mod liveness;
mod lower_intrinsics;
mod lower_slice_len;
mod match_branches;
Expand Down Expand Up @@ -112,6 +113,7 @@ mod sroa;
mod unreachable_enum_branching;
mod unreachable_prop;

use liveness::check_liveness;
use rustc_const_eval::transform::check_consts::{self, ConstCx};
use rustc_const_eval::transform::validate;
use rustc_mir_dataflow::rustc_peek;
Expand All @@ -132,6 +134,7 @@ pub fn provide(providers: &mut Providers) {
mir_for_ctfe,
mir_coroutine_witnesses: coroutine::mir_coroutine_witnesses,
optimized_mir,
check_liveness,
is_mir_available,
is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did),
mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable,
Expand Down Expand Up @@ -400,6 +403,8 @@ fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &
}
}

tcx.ensure_with_value().check_liveness(def);

let (body, _) = tcx.mir_promoted(def);
let mut body = body.steal();
if let Some(error_reported) = mir_borrowck.tainted_by_errors {
Expand Down
Loading