From faa5b3f7de0db76e41bcf5c54c401d7651e69c58 Mon Sep 17 00:00:00 2001 From: Urgau Date: Sun, 9 Mar 2025 18:49:59 +0100 Subject: [PATCH] Fix false-positive in `expr_or_init` and in the `invalid_from_utf8` lint --- compiler/rustc_lint/src/context.rs | 16 ++++++- tests/ui/lint/invalid_from_utf8.rs | 41 +++++++++++----- tests/ui/lint/invalid_from_utf8.stderr | 65 ++++++-------------------- 3 files changed, 58 insertions(+), 64 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index cd4106ebf83af..017ae943e9161 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -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) diff --git a/tests/ui/lint/invalid_from_utf8.rs b/tests/ui/lint/invalid_from_utf8.rs index 87a906761c075..cbc1d8e90459d 100644 --- a/tests/ui/lint/invalid_from_utf8.rs +++ b/tests/ui/lint/invalid_from_utf8.rs @@ -128,18 +128,21 @@ pub fn from_utf8() { } pub fn from_utf8_with_indirections() { - let mut a = [99, 108, 130, 105, 112, 112, 121]; - std::str::from_utf8_mut(&mut a); - //~^ WARN calls to `std::str::from_utf8_mut` - str::from_utf8_mut(&mut a); - //~^ WARN calls to `str::from_utf8_mut` - let mut b = &mut a; - let mut c = b; - std::str::from_utf8_mut(c); - //~^ WARN calls to `std::str::from_utf8_mut` - str::from_utf8_mut(c); - //~^ WARN calls to `str::from_utf8_mut` - let mut c = &[99, 108, 130, 105, 112, 112, 121]; + // NOTE: We used to lint on the patterns below, but due to the + // binding being mutable it could be changed between the + // declaration and the call and that would have created a + // false-positive, so until we can reliably avoid those false + // postive we don't lint on them. Example of FP below. + // + // let mut a = [99, 108, 130, 105, 112, 112, 121]; + // std::str::from_utf8_mut(&mut a); + // str::from_utf8_mut(&mut a); + // let mut b = &mut a; + // let mut c = b; + // std::str::from_utf8_mut(c); + // str::from_utf8_mut(c); + + let c = &[99, 108, 130, 105, 112, 112, 121]; std::str::from_utf8(c); //~^ WARN calls to `std::str::from_utf8` str::from_utf8(c); @@ -164,6 +167,20 @@ pub fn from_utf8_with_indirections() { //~^ WARN calls to `std::str::from_utf8` str::from_utf8(INVALID_4); //~^ WARN calls to `str::from_utf8` + + let mut a = [99, 108, 130, 105, 112, 112, 121]; // invalid + loop { + a = [99, 108, 130, 105, 112, 112, 121]; // still invalid, but too complex + break; + } + std::str::from_utf8_mut(&mut a); + + let mut a = [99, 108, 130, 105, 112, 112]; // invalid + loop { + a = *b"clippy"; // valid + break; + } + std::str::from_utf8_mut(&mut a); } fn main() {} diff --git a/tests/ui/lint/invalid_from_utf8.stderr b/tests/ui/lint/invalid_from_utf8.stderr index 3cd4d227fc276..26bee5c403862 100644 --- a/tests/ui/lint/invalid_from_utf8.stderr +++ b/tests/ui/lint/invalid_from_utf8.stderr @@ -202,60 +202,25 @@ LL | str::from_utf8(concat_bytes!(b"cl", b"\x82ippy")); | | | the literal was valid UTF-8 up to the 2 bytes -warning: calls to `std::str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:132:5 - | -LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; - | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes -LL | std::str::from_utf8_mut(&mut a); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: calls to `str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:134:5 - | -LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; - | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes -... -LL | str::from_utf8_mut(&mut a); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: calls to `std::str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:138:5 - | -LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; - | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes -... -LL | std::str::from_utf8_mut(c); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - -warning: calls to `str::from_utf8_mut` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:140:5 - | -LL | let mut a = [99, 108, 130, 105, 112, 112, 121]; - | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes -... -LL | str::from_utf8_mut(c); - | ^^^^^^^^^^^^^^^^^^^^^ - warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:143:5 + --> $DIR/invalid_from_utf8.rs:146:5 | -LL | let mut c = &[99, 108, 130, 105, 112, 112, 121]; - | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | let c = &[99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes LL | std::str::from_utf8(c); | ^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:145:5 + --> $DIR/invalid_from_utf8.rs:148:5 | -LL | let mut c = &[99, 108, 130, 105, 112, 112, 121]; - | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes +LL | let c = &[99, 108, 130, 105, 112, 112, 121]; + | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes ... LL | str::from_utf8(c); | ^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:148:5 + --> $DIR/invalid_from_utf8.rs:151:5 | LL | const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -263,7 +228,7 @@ LL | std::str::from_utf8(&INVALID_1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:150:5 + --> $DIR/invalid_from_utf8.rs:153:5 | LL | const INVALID_1: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -272,7 +237,7 @@ LL | str::from_utf8(&INVALID_1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:153:5 + --> $DIR/invalid_from_utf8.rs:156:5 | LL | static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -280,7 +245,7 @@ LL | std::str::from_utf8(&INVALID_2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:155:5 + --> $DIR/invalid_from_utf8.rs:158:5 | LL | static INVALID_2: [u8; 7] = [99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -289,7 +254,7 @@ LL | str::from_utf8(&INVALID_2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:158:5 + --> $DIR/invalid_from_utf8.rs:161:5 | LL | const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -297,7 +262,7 @@ LL | std::str::from_utf8(INVALID_3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:160:5 + --> $DIR/invalid_from_utf8.rs:163:5 | LL | const INVALID_3: &'static [u8; 7] = &[99, 108, 130, 105, 112, 112, 121]; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -306,7 +271,7 @@ LL | str::from_utf8(INVALID_3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `std::str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:163:5 + --> $DIR/invalid_from_utf8.rs:166:5 | LL | const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] }; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -314,7 +279,7 @@ LL | std::str::from_utf8(INVALID_4); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: calls to `str::from_utf8` with an invalid literal always return an error - --> $DIR/invalid_from_utf8.rs:165:5 + --> $DIR/invalid_from_utf8.rs:168:5 | LL | const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 121] }; | ---------------------------------- the literal was valid UTF-8 up to the 2 bytes @@ -322,5 +287,5 @@ LL | const INVALID_4: &'static [u8; 7] = { &[99, 108, 130, 105, 112, 112, 12 LL | str::from_utf8(INVALID_4); | ^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: 38 warnings emitted +warning: 34 warnings emitted