Rollup merge of #138360 - Urgau:fix-fp-expr_or_init, r=wesleywiser

Fix false-positive in `expr_or_init` and in the `invalid_from_utf8` lint

This PR fixes the logic for finding initializer in the `expr_or_init` and `expr_or_init_with_outside_body` functions.

If the binding were to be mutable (`let mut`), the logic wouldn't consider that the initializer expression could have been modified and would return the init expression even-trough multiple subsequent assignments could have been done.

Example:
```rust
let mut a = [99, 108, 130, 105, 112, 112]; // invalid, not UTF-8
loop {
    a = *b"clippy"; // valid
    break;
}
std::str::from_utf8_mut(&mut a); // currently warns, with this PR it doesn't
```

This PR modifies the logic to excludes mutable let bindings.

Found when using `expr_or_init` in https://github.com/rust-lang/rust/pull/119220.

r? compiler
This commit is contained in:
Matthias Krüger 2025-03-12 08:06:50 +01:00 committed by GitHub
commit b849aa9f61
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 58 additions and 64 deletions

View file

@ -6,6 +6,7 @@
use std::cell::Cell;
use std::slice;
use rustc_ast::BindingMode;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync;
use rustc_data_structures::unord::UnordMap;
@ -14,6 +15,7 @@ use rustc_feature::Features;
use rustc_hir::def::Res;
use rustc_hir::def_id::{CrateNum, DefId};
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_hir::{Pat, PatKind};
use rustc_middle::bug;
use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
@ -890,7 +892,12 @@ impl<'tcx> LateContext<'tcx> {
}
&& let Some(init) = match parent_node {
hir::Node::Expr(expr) => Some(expr),
hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
hir::Node::LetStmt(hir::LetStmt {
init,
// Binding is immutable, init cannot be re-assigned
pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
..
}) => *init,
_ => None,
}
{
@ -935,7 +942,12 @@ impl<'tcx> LateContext<'tcx> {
}
&& let Some(init) = match parent_node {
hir::Node::Expr(expr) => Some(expr),
hir::Node::LetStmt(hir::LetStmt { init, .. }) => *init,
hir::Node::LetStmt(hir::LetStmt {
init,
// Binding is immutable, init cannot be re-assigned
pat: Pat { kind: PatKind::Binding(BindingMode::NONE, ..), .. },
..
}) => *init,
hir::Node::Item(item) => match item.kind {
hir::ItemKind::Const(.., body_id) | hir::ItemKind::Static(.., body_id) => {
Some(self.tcx.hir_body(body_id).value)