Merge remote-tracking branch 'upstream/master' into rustup

This commit is contained in:
Philipp Krones 2024-11-14 18:27:35 +01:00
commit c166ee1fc8
No known key found for this signature in database
GPG key ID: 1CA0DF2AF59D68A5
101 changed files with 1201 additions and 308 deletions

View file

@ -1,6 +1,7 @@
//@aux-build:paths.rs
#![deny(clippy::internal)]
#![feature(rustc_private)]
#![allow(clippy::unnecessary_map_or)]
extern crate clippy_utils;
extern crate paths;

View file

@ -1,6 +1,7 @@
//@aux-build:paths.rs
#![deny(clippy::internal)]
#![feature(rustc_private)]
#![allow(clippy::unnecessary_map_or)]
extern crate clippy_utils;
extern crate paths;

View file

@ -1,5 +1,5 @@
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:36:13
--> tests/ui-internal/unnecessary_def_path.rs:37:13
|
LL | let _ = match_type(cx, ty, &OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
@ -12,61 +12,61 @@ LL | #![deny(clippy::internal)]
= note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]`
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:37:13
--> tests/ui-internal/unnecessary_def_path.rs:38:13
|
LL | let _ = match_type(cx, ty, RESULT);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:38:13
--> tests/ui-internal/unnecessary_def_path.rs:39:13
|
LL | let _ = match_type(cx, ty, &["core", "result", "Result"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:42:13
--> tests/ui-internal/unnecessary_def_path.rs:43:13
|
LL | let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Rc)`
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:44:13
--> tests/ui-internal/unnecessary_def_path.rs:45:13
|
LL | let _ = match_type(cx, ty, &paths::OPTION);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:45:13
--> tests/ui-internal/unnecessary_def_path.rs:46:13
|
LL | let _ = match_type(cx, ty, paths::RESULT);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
error: use of a def path to a `LangItem`
--> tests/ui-internal/unnecessary_def_path.rs:47:13
--> tests/ui-internal/unnecessary_def_path.rs:48:13
|
LL | let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_lang_item(cx, ty, LangItem::OwnedBox)`
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:48:13
--> tests/ui-internal/unnecessary_def_path.rs:49:13
|
LL | let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit)`
error: use of a def path to a `LangItem`
--> tests/ui-internal/unnecessary_def_path.rs:50:13
--> tests/ui-internal/unnecessary_def_path.rs:51:13
|
LL | let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did)`
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:51:13
--> tests/ui-internal/unnecessary_def_path.rs:52:13
|
LL | let _ = match_def_path(cx, did, &["core", "option", "Option"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.is_diagnostic_item(sym::Option, did)`
error: use of a def path to a `LangItem`
--> tests/ui-internal/unnecessary_def_path.rs:52:13
--> tests/ui-internal/unnecessary_def_path.rs:53:13
|
LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did)`
@ -74,25 +74,25 @@ LL | let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
= help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:54:13
--> tests/ui-internal/unnecessary_def_path.rs:55:13
|
LL | let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_trait_method(cx, expr, sym::AsRef)`
error: use of a def path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path.rs:56:13
--> tests/ui-internal/unnecessary_def_path.rs:57:13
|
LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_path_diagnostic_item(cx, expr, sym::Option)`
error: use of a def path to a `LangItem`
--> tests/ui-internal/unnecessary_def_path.rs:57:13
--> tests/ui-internal/unnecessary_def_path.rs:58:13
|
LL | let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().get(LangItem::IteratorNext) == Some(id))`
error: use of a def path to a `LangItem`
--> tests/ui-internal/unnecessary_def_path.rs:58:13
--> tests/ui-internal/unnecessary_def_path.rs:59:13
|
LL | let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome)`

View file

@ -19,8 +19,8 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
error: hardcoded path to a diagnostic item
--> tests/ui-internal/unnecessary_def_path_hardcoded_path.rs:12:43
|
LL | const OPS_MOD: [&str; 5] = ["core", "ops"];
| ^^^^^^^^^^^^^^^
LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= help: convert all references to use `sym::deref_method`

View file

@ -15,5 +15,9 @@ const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt");
const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt");
//~^ large_include_file
#[doc = include_str!("too_big.txt")] //~ large_include_file
#[doc = include_str!("too_big.txt")]
//~^ large_include_file
// Should not lint!
// Regression test for <https://github.com/rust-lang/rust-clippy/issues/13670>.
#[doc = include_str!("empty.txt")]
fn main() {}

View file

@ -1,4 +1,5 @@
#![warn(clippy::case_sensitive_file_extension_comparisons)]
#![allow(clippy::unnecessary_map_or)]
use std::string::String;

View file

@ -1,4 +1,5 @@
#![warn(clippy::case_sensitive_file_extension_comparisons)]
#![allow(clippy::unnecessary_map_or)]
use std::string::String;

View file

@ -1,5 +1,5 @@
error: case-sensitive file extension comparison
--> tests/ui/case_sensitive_file_extension_comparisons.rs:13:5
--> tests/ui/case_sensitive_file_extension_comparisons.rs:14:5
|
LL | filename.ends_with(".rs")
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -15,7 +15,7 @@ LL + .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
|
error: case-sensitive file extension comparison
--> tests/ui/case_sensitive_file_extension_comparisons.rs:18:13
--> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13
|
LL | let _ = String::new().ends_with(".ext12");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -29,7 +29,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
|
error: case-sensitive file extension comparison
--> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13
--> tests/ui/case_sensitive_file_extension_comparisons.rs:20:13
|
LL | let _ = "str".ends_with(".ext12");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -43,7 +43,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
|
error: case-sensitive file extension comparison
--> tests/ui/case_sensitive_file_extension_comparisons.rs:23:17
--> tests/ui/case_sensitive_file_extension_comparisons.rs:24:17
|
LL | let _ = "str".ends_with(".ext12");
| ^^^^^^^^^^^^^^^^^^^^^^^^^
@ -57,7 +57,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
|
error: case-sensitive file extension comparison
--> tests/ui/case_sensitive_file_extension_comparisons.rs:30:13
--> tests/ui/case_sensitive_file_extension_comparisons.rs:31:13
|
LL | let _ = String::new().ends_with(".EXT12");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@ -71,7 +71,7 @@ LL ~ .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
|
error: case-sensitive file extension comparison
--> tests/ui/case_sensitive_file_extension_comparisons.rs:31:13
--> tests/ui/case_sensitive_file_extension_comparisons.rs:32:13
|
LL | let _ = "str".ends_with(".EXT12");
| ^^^^^^^^^^^^^^^^^^^^^^^^^

View file

@ -6,7 +6,6 @@
)]
#![warn(clippy::expl_impl_clone_on_copy)]
#[derive(Copy)]
struct Qux;

View file

@ -1,5 +1,5 @@
error: you are implementing `Clone` explicitly on a `Copy` type
--> tests/ui/derive.rs:13:1
--> tests/ui/derive.rs:12:1
|
LL | / impl Clone for Qux {
LL | |
@ -10,7 +10,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
--> tests/ui/derive.rs:13:1
--> tests/ui/derive.rs:12:1
|
LL | / impl Clone for Qux {
LL | |
@ -23,7 +23,7 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::expl_impl_clone_on_copy)]`
error: you are implementing `Clone` explicitly on a `Copy` type
--> tests/ui/derive.rs:38:1
--> tests/ui/derive.rs:37:1
|
LL | / impl<'a> Clone for Lt<'a> {
LL | |
@ -34,7 +34,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
--> tests/ui/derive.rs:38:1
--> tests/ui/derive.rs:37:1
|
LL | / impl<'a> Clone for Lt<'a> {
LL | |
@ -45,7 +45,7 @@ LL | | }
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
--> tests/ui/derive.rs:50:1
--> tests/ui/derive.rs:49:1
|
LL | / impl Clone for BigArray {
LL | |
@ -56,7 +56,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
--> tests/ui/derive.rs:50:1
--> tests/ui/derive.rs:49:1
|
LL | / impl Clone for BigArray {
LL | |
@ -67,7 +67,7 @@ LL | | }
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
--> tests/ui/derive.rs:62:1
--> tests/ui/derive.rs:61:1
|
LL | / impl Clone for FnPtr {
LL | |
@ -78,7 +78,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
--> tests/ui/derive.rs:62:1
--> tests/ui/derive.rs:61:1
|
LL | / impl Clone for FnPtr {
LL | |
@ -89,7 +89,7 @@ LL | | }
| |_^
error: you are implementing `Clone` explicitly on a `Copy` type
--> tests/ui/derive.rs:83:1
--> tests/ui/derive.rs:82:1
|
LL | / impl<T: Clone> Clone for Generic2<T> {
LL | |
@ -100,7 +100,7 @@ LL | | }
| |_^
|
note: consider deriving `Clone` or removing `Copy`
--> tests/ui/derive.rs:83:1
--> tests/ui/derive.rs:82:1
|
LL | / impl<T: Clone> Clone for Generic2<T> {
LL | |

View file

@ -116,7 +116,7 @@ fn main() {
//~^ ERROR: this operation has no effect
(match a { 0 => 10, _ => 20 }) + if b { 3 } else { 4 };
//~^ ERROR: this operation has no effect
(if b { 1 } else { 2 });
((if b { 1 } else { 2 }));
//~^ ERROR: this operation has no effect
({ a }) + 3;
@ -212,3 +212,47 @@ fn issue_12050() {
//~^ ERROR: this operation has no effect
}
}
fn issue_13470() {
let x = 1i32;
let y = 1i32;
// Removes the + 0i32 while keeping the parentheses around x + y so the cast operation works
let _: u64 = (x + y) as u64;
//~^ ERROR: this operation has no effect
// both of the next two lines should look the same after rustfix
let _: u64 = 1u64 & (x + y) as u64;
//~^ ERROR: this operation has no effect
// Same as above, but with extra redundant parenthesis
let _: u64 = 1u64 & ((x + y)) as u64;
//~^ ERROR: this operation has no effect
// Should maintain parenthesis even if the surrounding expr has the same precedence
let _: u64 = 5u64 + ((x + y)) as u64;
//~^ ERROR: this operation has no effect
// If we don't maintain the parens here, the behavior changes
let _ = -(x + y);
//~^ ERROR: this operation has no effect
// Similarly, we need to maintain parens here
let _ = -(x / y);
//~^ ERROR: this operation has no effect
// Maintain parenthesis if the parent expr is of higher precedence
let _ = 2i32 * (x + y);
//~^ ERROR: this operation has no effect
// Maintain parenthesis if the parent expr is the same precedence
// as not all operations are associative
let _ = 2i32 - (x - y);
//~^ ERROR: this operation has no effect
// But make sure that inner parens still exist
let z = 1i32;
let _ = 2 + (x + (y * z));
//~^ ERROR: this operation has no effect
// Maintain parenthesis if the parent expr is of lower precedence
// This is for clarity, and clippy will not warn on these being unnecessary
let _ = 2i32 + (x * y);
//~^ ERROR: this operation has no effect
let x = 1i16;
let y = 1i16;
let _: u64 = 1u64 + ((x as i32 + y as i32) as u64);
//~^ ERROR: this operation has no effect
}

View file

@ -212,3 +212,47 @@ fn issue_12050() {
//~^ ERROR: this operation has no effect
}
}
fn issue_13470() {
let x = 1i32;
let y = 1i32;
// Removes the + 0i32 while keeping the parentheses around x + y so the cast operation works
let _: u64 = (x + y + 0i32) as u64;
//~^ ERROR: this operation has no effect
// both of the next two lines should look the same after rustfix
let _: u64 = 1u64 & (x + y + 0i32) as u64;
//~^ ERROR: this operation has no effect
// Same as above, but with extra redundant parenthesis
let _: u64 = 1u64 & ((x + y) + 0i32) as u64;
//~^ ERROR: this operation has no effect
// Should maintain parenthesis even if the surrounding expr has the same precedence
let _: u64 = 5u64 + ((x + y) + 0i32) as u64;
//~^ ERROR: this operation has no effect
// If we don't maintain the parens here, the behavior changes
let _ = -(x + y + 0i32);
//~^ ERROR: this operation has no effect
// Similarly, we need to maintain parens here
let _ = -(x / y / 1i32);
//~^ ERROR: this operation has no effect
// Maintain parenthesis if the parent expr is of higher precedence
let _ = 2i32 * (x + y + 0i32);
//~^ ERROR: this operation has no effect
// Maintain parenthesis if the parent expr is the same precedence
// as not all operations are associative
let _ = 2i32 - (x - y - 0i32);
//~^ ERROR: this operation has no effect
// But make sure that inner parens still exist
let z = 1i32;
let _ = 2 + (x + (y * z) + 0);
//~^ ERROR: this operation has no effect
// Maintain parenthesis if the parent expr is of lower precedence
// This is for clarity, and clippy will not warn on these being unnecessary
let _ = 2i32 + (x * y * 1i32);
//~^ ERROR: this operation has no effect
let x = 1i16;
let y = 1i16;
let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64);
//~^ ERROR: this operation has no effect
}

View file

@ -149,7 +149,7 @@ error: this operation has no effect
--> tests/ui/identity_op.rs:119:5
|
LL | (if b { 1 } else { 2 }) + 0;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((if b { 1 } else { 2 }))`
error: this operation has no effect
--> tests/ui/identity_op.rs:122:5
@ -313,5 +313,71 @@ error: this operation has no effect
LL | let _: i32 = **&&*&x + 0;
| ^^^^^^^^^^^ help: consider reducing it to: `***&&*&x`
error: aborting due to 52 previous errors
error: this operation has no effect
--> tests/ui/identity_op.rs:220:18
|
LL | let _: u64 = (x + y + 0i32) as u64;
| ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)`
error: this operation has no effect
--> tests/ui/identity_op.rs:223:25
|
LL | let _: u64 = 1u64 & (x + y + 0i32) as u64;
| ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)`
error: this operation has no effect
--> tests/ui/identity_op.rs:226:25
|
LL | let _: u64 = 1u64 & ((x + y) + 0i32) as u64;
| ^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x + y))`
error: this operation has no effect
--> tests/ui/identity_op.rs:229:25
|
LL | let _: u64 = 5u64 + ((x + y) + 0i32) as u64;
| ^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x + y))`
error: this operation has no effect
--> tests/ui/identity_op.rs:233:14
|
LL | let _ = -(x + y + 0i32);
| ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)`
error: this operation has no effect
--> tests/ui/identity_op.rs:236:14
|
LL | let _ = -(x / y / 1i32);
| ^^^^^^^^^^^^^^ help: consider reducing it to: `(x / y)`
error: this operation has no effect
--> tests/ui/identity_op.rs:239:20
|
LL | let _ = 2i32 * (x + y + 0i32);
| ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)`
error: this operation has no effect
--> tests/ui/identity_op.rs:243:20
|
LL | let _ = 2i32 - (x - y - 0i32);
| ^^^^^^^^^^^^^^ help: consider reducing it to: `(x - y)`
error: this operation has no effect
--> tests/ui/identity_op.rs:247:17
|
LL | let _ = 2 + (x + (y * z) + 0);
| ^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(x + (y * z))`
error: this operation has no effect
--> tests/ui/identity_op.rs:251:20
|
LL | let _ = 2i32 + (x * y * 1i32);
| ^^^^^^^^^^^^^^ help: consider reducing it to: `(x * y)`
error: this operation has no effect
--> tests/ui/identity_op.rs:256:25
|
LL | let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x as i32 + y as i32) as u64)`
error: aborting due to 63 previous errors

View file

@ -10,7 +10,7 @@
/// unimplemented!();
/// }
/// ```
///
///
/// With an explicit return type it should lint too
/// ```edition2015
/// fn main() -> () {
@ -18,7 +18,7 @@
/// unimplemented!();
/// }
/// ```
///
///
/// This should, too.
/// ```rust
/// fn main() {
@ -26,7 +26,7 @@
/// unimplemented!();
/// }
/// ```
///
///
/// This one too.
/// ```no_run
/// // the fn is not always the first line

View file

@ -96,12 +96,42 @@ impl MoveStruct {
}
fn func() -> Option<i32> {
macro_rules! opt_none {
() => {
None
};
}
fn f() -> Option<String> {
Some(String::new())
}
f()?;
let _val = f()?;
let s: &str = match &Some(String::new()) {
Some(v) => v,
None => return None,
};
f()?;
opt_none!()?;
match f() {
Some(x) => x,
None => return opt_none!(),
};
match f() {
Some(val) => {
println!("{val}");
val
},
None => return None,
};
Some(0)
}
@ -114,6 +144,10 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
x?;
let _val = func_returning_result()?;
func_returning_result()?;
// No warning
let y = if let Ok(x) = x {
x
@ -157,6 +191,28 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
Ok(y)
}
fn infer_check() {
let closure = |x: Result<u8, ()>| {
// `?` would fail here, as it expands to `Err(val.into())` which is not constrained.
let _val = match x {
Ok(val) => val,
Err(val) => return Err(val),
};
Ok(())
};
let closure = |x: Result<u8, ()>| -> Result<(), _> {
// `?` would fail here, as it expands to `Err(val.into())` which is not constrained.
let _val = match x {
Ok(val) => val,
Err(val) => return Err(val),
};
Ok(())
};
}
// see issue #8019
pub enum NotOption {
None,

View file

@ -124,6 +124,12 @@ impl MoveStruct {
}
fn func() -> Option<i32> {
macro_rules! opt_none {
() => {
None
};
}
fn f() -> Option<String> {
Some(String::new())
}
@ -132,6 +138,39 @@ fn func() -> Option<i32> {
return None;
}
let _val = match f() {
Some(val) => val,
None => return None,
};
let s: &str = match &Some(String::new()) {
Some(v) => v,
None => return None,
};
match f() {
Some(val) => val,
None => return None,
};
match opt_none!() {
Some(x) => x,
None => return None,
};
match f() {
Some(x) => x,
None => return opt_none!(),
};
match f() {
Some(val) => {
println!("{val}");
val
},
None => return None,
};
Some(0)
}
@ -146,6 +185,16 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
return x;
}
let _val = match func_returning_result() {
Ok(val) => val,
Err(err) => return Err(err),
};
match func_returning_result() {
Ok(val) => val,
Err(err) => return Err(err),
};
// No warning
let y = if let Ok(x) = x {
x
@ -189,6 +238,28 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
Ok(y)
}
fn infer_check() {
let closure = |x: Result<u8, ()>| {
// `?` would fail here, as it expands to `Err(val.into())` which is not constrained.
let _val = match x {
Ok(val) => val,
Err(val) => return Err(val),
};
Ok(())
};
let closure = |x: Result<u8, ()>| -> Result<(), _> {
// `?` would fail here, as it expands to `Err(val.into())` which is not constrained.
let _val = match x {
Ok(val) => val,
Err(val) => return Err(val),
};
Ok(())
};
}
// see issue #8019
pub enum NotOption {
None,

View file

@ -94,29 +94,76 @@ LL | | };
| |_________^ help: replace it with: `self.opt?`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:131:5
--> tests/ui/question_mark.rs:137:5
|
LL | / if f().is_none() {
LL | | return None;
LL | | }
| |_____^ help: replace it with: `f()?;`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:141:16
|
LL | let _val = match f() {
| ________________^
LL | | Some(val) => val,
LL | | None => return None,
LL | | };
| |_____^ help: try instead: `f()?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:151:5
|
LL | / match f() {
LL | | Some(val) => val,
LL | | None => return None,
LL | | };
| |_____^ help: try instead: `f()?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:156:5
|
LL | / match opt_none!() {
LL | | Some(x) => x,
LL | | None => return None,
LL | | };
| |_____^ help: try instead: `opt_none!()?`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:143:13
--> tests/ui/question_mark.rs:182:13
|
LL | let _ = if let Ok(x) = x { x } else { return x };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:145:5
--> tests/ui/question_mark.rs:184:5
|
LL | / if x.is_err() {
LL | | return x;
LL | | }
| |_____^ help: replace it with: `x?;`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:188:16
|
LL | let _val = match func_returning_result() {
| ________________^
LL | | Ok(val) => val,
LL | | Err(err) => return Err(err),
LL | | };
| |_____^ help: try instead: `func_returning_result()?`
error: this `match` expression can be replaced with `?`
--> tests/ui/question_mark.rs:193:5
|
LL | / match func_returning_result() {
LL | | Ok(val) => val,
LL | | Err(err) => return Err(err),
LL | | };
| |_____^ help: try instead: `func_returning_result()?`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:213:5
--> tests/ui/question_mark.rs:284:5
|
LL | / if let Err(err) = func_returning_result() {
LL | | return Err(err);
@ -124,7 +171,7 @@ LL | | }
| |_____^ help: replace it with: `func_returning_result()?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:220:5
--> tests/ui/question_mark.rs:291:5
|
LL | / if let Err(err) = func_returning_result() {
LL | | return Err(err);
@ -132,7 +179,7 @@ LL | | }
| |_____^ help: replace it with: `func_returning_result()?;`
error: this block may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:297:13
--> tests/ui/question_mark.rs:368:13
|
LL | / if a.is_none() {
LL | | return None;
@ -142,12 +189,12 @@ LL | | }
| |_____________^ help: replace it with: `a?;`
error: this `let...else` may be rewritten with the `?` operator
--> tests/ui/question_mark.rs:357:5
--> tests/ui/question_mark.rs:428:5
|
LL | / let Some(v) = bar.foo.owned.clone() else {
LL | | return None;
LL | | };
| |______^ help: replace it with: `let v = bar.foo.owned.clone()?;`
error: aborting due to 17 previous errors
error: aborting due to 22 previous errors

View file

@ -0,0 +1,8 @@
//@compile-flags: -C incremental=target/debug/test/incr
// see https://github.com/rust-lang/rust-clippy/issues/10969
fn main() {
let s = "Hello, world!";
println!("{}", s);
}

View file

@ -0,0 +1,8 @@
//@compile-flags: -C incremental=target/debug/test/incr
// see https://github.com/rust-lang/rust-clippy/issues/10969
fn main() {
let s = "Hello, world!";
println!("{}", s.to_string());
}

View file

@ -0,0 +1,11 @@
error: `to_string` applied to a type that implements `Display` in `println!` args
--> tests/ui/to_string_in_format_args_incremental.rs:7:21
|
LL | println!("{}", s.to_string());
| ^^^^^^^^^^^^ help: remove this
|
= note: `-D clippy::to-string-in-format-args` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::to_string_in_format_args)]`
error: aborting due to 1 previous error

View file

@ -0,0 +1,64 @@
//@aux-build:proc_macros.rs
#![warn(clippy::unnecessary_map_or)]
#![allow(clippy::no_effect)]
#![allow(clippy::eq_op)]
#![allow(clippy::unnecessary_lazy_evaluations)]
#[clippy::msrv = "1.70.0"]
#[macro_use]
extern crate proc_macros;
fn main() {
// should trigger
let _ = (Some(5) == Some(5));
let _ = (Some(5) != Some(5));
let _ = (Some(5) == Some(5));
let _ = Some(5).is_some_and(|n| {
let _ = n;
6 >= 5
});
let _ = Some(vec![5]).is_some_and(|n| n == [5]);
let _ = Some(vec![1]).is_some_and(|n| vec![2] == n);
let _ = Some(5).is_some_and(|n| n == n);
let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 });
let _ = Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5]);
let _ = (Ok::<i32, i32>(5) == Ok(5));
let _ = (Some(5) == Some(5)).then(|| 1);
// shouldnt trigger
let _ = Some(5).map_or(true, |n| n == 5);
let _ = Some(5).map_or(true, |n| 5 == n);
macro_rules! x {
() => {
Some(1)
};
}
// methods lints dont fire on macros
let _ = x!().map_or(false, |n| n == 1);
let _ = x!().map_or(false, |n| n == vec![1][0]);
msrv_1_69();
external! {
let _ = Some(5).map_or(false, |n| n == 5);
}
with_span! {
let _ = Some(5).map_or(false, |n| n == 5);
}
// check for presence of PartialEq, and alter suggestion to use `is_ok_and` if absent
struct S;
let r: Result<i32, S> = Ok(3);
let _ = r.is_ok_and(|x| x == 7);
#[derive(PartialEq)]
struct S2;
let r: Result<i32, S2> = Ok(4);
let _ = (r == Ok(8));
}
#[clippy::msrv = "1.69.0"]
fn msrv_1_69() {
// is_some_and added in 1.70.0
let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
}

View file

@ -0,0 +1,67 @@
//@aux-build:proc_macros.rs
#![warn(clippy::unnecessary_map_or)]
#![allow(clippy::no_effect)]
#![allow(clippy::eq_op)]
#![allow(clippy::unnecessary_lazy_evaluations)]
#[clippy::msrv = "1.70.0"]
#[macro_use]
extern crate proc_macros;
fn main() {
// should trigger
let _ = Some(5).map_or(false, |n| n == 5);
let _ = Some(5).map_or(true, |n| n != 5);
let _ = Some(5).map_or(false, |n| {
let _ = 1;
n == 5
});
let _ = Some(5).map_or(false, |n| {
let _ = n;
6 >= 5
});
let _ = Some(vec![5]).map_or(false, |n| n == [5]);
let _ = Some(vec![1]).map_or(false, |n| vec![2] == n);
let _ = Some(5).map_or(false, |n| n == n);
let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
let _ = Ok::<Vec<i32>, i32>(vec![5]).map_or(false, |n| n == [5]);
let _ = Ok::<i32, i32>(5).map_or(false, |n| n == 5);
let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
// shouldnt trigger
let _ = Some(5).map_or(true, |n| n == 5);
let _ = Some(5).map_or(true, |n| 5 == n);
macro_rules! x {
() => {
Some(1)
};
}
// methods lints dont fire on macros
let _ = x!().map_or(false, |n| n == 1);
let _ = x!().map_or(false, |n| n == vec![1][0]);
msrv_1_69();
external! {
let _ = Some(5).map_or(false, |n| n == 5);
}
with_span! {
let _ = Some(5).map_or(false, |n| n == 5);
}
// check for presence of PartialEq, and alter suggestion to use `is_ok_and` if absent
struct S;
let r: Result<i32, S> = Ok(3);
let _ = r.map_or(false, |x| x == 7);
#[derive(PartialEq)]
struct S2;
let r: Result<i32, S2> = Ok(4);
let _ = r.map_or(false, |x| x == 8);
}
#[clippy::msrv = "1.69.0"]
fn msrv_1_69() {
// is_some_and added in 1.70.0
let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
}

View file

@ -0,0 +1,99 @@
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:12:13
|
LL | let _ = Some(5).map_or(false, |n| n == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
|
= note: `-D clippy::unnecessary-map-or` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_map_or)]`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:13:13
|
LL | let _ = Some(5).map_or(true, |n| n != 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) != Some(5))`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:14:13
|
LL | let _ = Some(5).map_or(false, |n| {
| _____________^
LL | | let _ = 1;
LL | | n == 5
LL | | });
| |______^ help: use a standard comparison instead: `(Some(5) == Some(5))`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:18:13
|
LL | let _ = Some(5).map_or(false, |n| {
| _____________^
LL | | let _ = n;
LL | | 6 >= 5
LL | | });
| |______^
|
help: use is_some_and instead
|
LL ~ let _ = Some(5).is_some_and(|n| {
LL + let _ = n;
LL + 6 >= 5
LL ~ });
|
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:22:13
|
LL | let _ = Some(vec![5]).map_or(false, |n| n == [5]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![5]).is_some_and(|n| n == [5])`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:23:13
|
LL | let _ = Some(vec![1]).map_or(false, |n| vec![2] == n);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![1]).is_some_and(|n| vec![2] == n)`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:24:13
|
LL | let _ = Some(5).map_or(false, |n| n == n);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == n)`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:25:13
|
LL | let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 })`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:26:13
|
LL | let _ = Ok::<Vec<i32>, i32>(vec![5]).map_or(false, |n| n == [5]);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5])`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:27:13
|
LL | let _ = Ok::<i32, i32>(5).map_or(false, |n| n == 5);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Ok::<i32, i32>(5) == Ok(5))`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:28:13
|
LL | let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:55:13
|
LL | let _ = r.map_or(false, |x| x == 7);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)`
error: this `map_or` is redundant
--> tests/ui/unnecessary_map_or.rs:60:13
|
LL | let _ = r.map_or(false, |x| x == 8);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(r == Ok(8))`
error: aborting due to 13 previous errors