Skip to content

Commit 2696805

Browse files
committed
Fix false-positive in expr_or_init and invalid_from_utf8 lints
1 parent 07292cc commit 2696805

File tree

2 files changed

+79
-2
lines changed

2 files changed

+79
-2
lines changed

compiler/rustc_lint/src/context.rs

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
//! overview of how lints are implemented.
55
66
use std::cell::Cell;
7+
use std::ops::ControlFlow;
78
use std::slice;
89

10+
use rustc_ast::BindingMode;
911
use rustc_data_structures::fx::FxIndexMap;
1012
use rustc_data_structures::sync;
1113
use rustc_data_structures::unord::UnordMap;
@@ -14,6 +16,8 @@ use rustc_feature::Features;
1416
use rustc_hir::def::Res;
1517
use rustc_hir::def_id::{CrateNum, DefId};
1618
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
19+
use rustc_hir::intravisit::Visitor;
20+
use rustc_hir::{HirId, Pat, PatKind};
1721
use rustc_middle::bug;
1822
use rustc_middle::middle::privacy::EffectiveVisibilities;
1923
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
@@ -890,7 +894,18 @@ impl<'tcx> LateContext<'tcx> {
890894
}
891895
&& let Some(init) = match parent_node {
892896
hir::Node::Expr(expr) => Some(expr),
893-
hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
897+
hir::Node::LetStmt(hir::LetStmt {
898+
init,
899+
// Bindigng is immutable, init cannot be re-assigned
900+
pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
901+
..
902+
}) => *init,
903+
hir::Node::LetStmt(hir::LetStmt {
904+
init,
905+
// Bindigng is mutable, init can be re-assigned to, if it is bail-out
906+
pat: Pat { kind: PatKind::Binding(BindingMode::MUT, binding_id, ..), .. },
907+
..
908+
}) if !ReassignBindingFinder::is_binding_reassigned(self, *binding_id) => *init,
894909
_ => None,
895910
}
896911
{
@@ -935,7 +950,18 @@ impl<'tcx> LateContext<'tcx> {
935950
}
936951
&& let Some(init) = match parent_node {
937952
hir::Node::Expr(expr) => Some(expr),
938-
hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
953+
hir::Node::LetStmt(hir::LetStmt {
954+
init,
955+
// Bindigng is immutable, init cannot be re-assigned
956+
pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
957+
..
958+
}) => *init,
959+
hir::Node::LetStmt(hir::LetStmt {
960+
init,
961+
// Bindigng is mutable, init can be re-assigned to, if it is bail-out
962+
pat: Pat { kind: PatKind::Binding(BindingMode::MUT, binding_id, ..), .. },
963+
..
964+
}) if !ReassignBindingFinder::is_binding_reassigned(self, *binding_id) => *init,
939965
hir::Node::Item(item) => match item.kind {
940966
hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
941967
Some(self.tcx.hir_body(body_id).value)
@@ -980,3 +1006,40 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LateContext<'tcx> {
9801006
err
9811007
}
9821008
}
1009+
1010+
struct ReassignBindingFinder<'a, 'tcx> {
1011+
cx: &'a LateContext<'tcx>,
1012+
binding_id: HirId,
1013+
}
1014+
1015+
impl<'a, 'tcx> ReassignBindingFinder<'a, 'tcx> {
1016+
fn is_binding_reassigned(cx: &'a LateContext<'tcx>, binding_id: HirId) -> bool {
1017+
if let Some(enclosing_scope_id) = cx.tcx.hir_get_enclosing_scope(binding_id)
1018+
&& let hir::Node::Block(block) = cx.tcx.hir_node(enclosing_scope_id)
1019+
{
1020+
let mut finder = ReassignBindingFinder { cx, binding_id };
1021+
finder.visit_block(block).is_break()
1022+
} else {
1023+
false
1024+
}
1025+
}
1026+
}
1027+
1028+
impl<'tcx> Visitor<'tcx> for ReassignBindingFinder<'_, 'tcx> {
1029+
type Result = ControlFlow<()>;
1030+
type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
1031+
1032+
fn visit_path(&mut self, path: &hir::Path<'tcx>, hir_id: HirId) -> Self::Result {
1033+
if let Res::Local(id) = path.res {
1034+
if self.binding_id == id && self.cx.tcx.hir_is_lhs(hir_id) {
1035+
return ControlFlow::Break(());
1036+
}
1037+
}
1038+
1039+
ControlFlow::Continue(())
1040+
}
1041+
1042+
fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
1043+
self.cx.tcx
1044+
}
1045+
}

tests/ui/lint/invalid_from_utf8.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,20 @@ pub fn from_utf8_with_indirections() {
164164
//~^ WARN calls to `std::str::from_utf8`
165165
str::from_utf8(INVALID_4);
166166
//~^ WARN calls to `str::from_utf8`
167+
168+
let mut a = [99, 108, 130, 105, 112, 112, 121]; // invalid
169+
loop {
170+
a = [99, 108, 130, 105, 112, 112, 121]; // still invalid, but too complex
171+
break;
172+
}
173+
std::str::from_utf8_mut(&mut a);
174+
175+
let mut a = [99, 108, 130, 105, 112, 112]; // invalid
176+
loop {
177+
a = *b"clippy"; // valid
178+
break;
179+
}
180+
std::str::from_utf8_mut(&mut a);
167181
}
168182

169183
fn main() {}

0 commit comments

Comments
 (0)