Skip to content

Commit 6cc8f8d

Browse files
authored
Do not trigger inefficient_to_string after Rust 1.82 (#15729)
Starting with Rust version 1.82.0, the compiler generates similar code with and without the `with_ref` cfg: ```rust fn f(x: impl IntoIterator<Item = String>) { for y in x { println!("{y}"); } } fn main() { #[cfg(with_ref)] let a = ["foo", "bar"].iter().map(|&s| s.to_string()); #[cfg(not(with_ref))] let a = ["foo", "bar"].iter().map(|s| s.to_string()); f(a); } ``` The generated code is strictly identical with `-O`, and identical modulo some minor reordering without. changelog: [`inefficient_to_string`]: do not trigger for Rust ≥ 1.82.0
2 parents 12e0c4c + 951d35e commit 6cc8f8d

File tree

8 files changed

+36
-11
lines changed

8 files changed

+36
-11
lines changed

book/src/lint_configuration.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -845,6 +845,7 @@ The minimum rust version that the project supports. Defaults to the `rust-versio
845845
* [`from_over_into`](https://rust-lang.github.io/rust-clippy/master/index.html#from_over_into)
846846
* [`if_then_some_else_none`](https://rust-lang.github.io/rust-clippy/master/index.html#if_then_some_else_none)
847847
* [`index_refutable_slice`](https://rust-lang.github.io/rust-clippy/master/index.html#index_refutable_slice)
848+
* [`inefficient_to_string`](https://rust-lang.github.io/rust-clippy/master/index.html#inefficient_to_string)
848849
* [`io_other_error`](https://rust-lang.github.io/rust-clippy/master/index.html#io_other_error)
849850
* [`iter_kv_map`](https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map)
850851
* [`legacy_numeric_constants`](https://rust-lang.github.io/rust-clippy/master/index.html#legacy_numeric_constants)

clippy_config/src/conf.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,7 @@ define_Conf! {
741741
from_over_into,
742742
if_then_some_else_none,
743743
index_refutable_slice,
744+
inefficient_to_string,
744745
io_other_error,
745746
iter_kv_map,
746747
legacy_numeric_constants,

clippy_lints/src/methods/inefficient_to_string.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use clippy_utils::diagnostics::span_lint_and_then;
2+
use clippy_utils::msrvs::{self, Msrv};
23
use clippy_utils::source::snippet_with_applicability;
34
use clippy_utils::ty::{is_type_lang_item, peel_and_count_ty_refs};
45
use rustc_errors::Applicability;
@@ -16,6 +17,7 @@ pub fn check(
1617
method_name: Symbol,
1718
receiver: &hir::Expr<'_>,
1819
args: &[hir::Expr<'_>],
20+
msrv: Msrv,
1921
) {
2022
if args.is_empty()
2123
&& method_name == sym::to_string
@@ -26,6 +28,8 @@ pub fn check(
2628
&& let self_ty = args.type_at(0)
2729
&& let (deref_self_ty, deref_count, _) = peel_and_count_ty_refs(self_ty)
2830
&& deref_count >= 1
31+
// Since Rust 1.82, the specialized `ToString` is properly called
32+
&& !msrv.meets(cx, msrvs::SPECIALIZED_TO_STRING_FOR_REFS)
2933
&& specializes_tostring(cx, deref_self_ty)
3034
{
3135
span_lint_and_then(

clippy_lints/src/methods/mod.rs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,9 @@ declare_clippy_lint! {
475475
/// ### What it does
476476
/// Checks for usage of `ok().expect(..)`.
477477
///
478+
/// Note: This lint only triggers for code marked compatible
479+
/// with versions of the compiler older than Rust 1.82.0.
480+
///
478481
/// ### Why is this bad?
479482
/// Because you usually call `expect()` on the `Result`
480483
/// directly to get a better error message.
@@ -1078,9 +1081,9 @@ declare_clippy_lint! {
10781081
/// `T` implements `ToString` directly (like `&&str` or `&&String`).
10791082
///
10801083
/// ### Why is this bad?
1081-
/// This bypasses the specialized implementation of
1082-
/// `ToString` and instead goes through the more expensive string formatting
1083-
/// facilities.
1084+
/// In versions of the compiler before Rust 1.82.0, this bypasses the specialized
1085+
/// implementation of`ToString` and instead goes through the more expensive string
1086+
/// formatting facilities.
10841087
///
10851088
/// ### Example
10861089
/// ```no_run
@@ -4866,7 +4869,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
48664869
);
48674870
clone_on_copy::check(cx, expr, method_call.ident.name, receiver, args);
48684871
clone_on_ref_ptr::check(cx, expr, method_call.ident.name, receiver, args);
4869-
inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args);
4872+
inefficient_to_string::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);
48704873
single_char_add_str::check(cx, expr, receiver, args);
48714874
into_iter_on_ref::check(cx, expr, method_span, method_call.ident.name, receiver);
48724875
unnecessary_to_owned::check(cx, expr, method_call.ident.name, receiver, args, self.msrv);

clippy_utils/src/msrvs.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ msrv_aliases! {
2828
1,85,0 { UINT_FLOAT_MIDPOINT, CONST_SIZE_OF_VAL }
2929
1,84,0 { CONST_OPTION_AS_SLICE, MANUAL_DANGLING_PTR }
3030
1,83,0 { CONST_EXTERN_FN, CONST_FLOAT_BITS_CONV, CONST_FLOAT_CLASSIFY, CONST_MUT_REFS, CONST_UNWRAP }
31-
1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP }
31+
1,82,0 { IS_NONE_OR, REPEAT_N, RAW_REF_OP, SPECIALIZED_TO_STRING_FOR_REFS }
3232
1,81,0 { LINT_REASONS_STABILIZATION, ERROR_IN_CORE, EXPLICIT_SELF_TYPE_ELISION, DURATION_ABS_DIFF }
3333
1,80,0 { BOX_INTO_ITER, LAZY_CELL }
3434
1,79,0 { CONST_BLOCKS }

tests/ui/inefficient_to_string.fixed

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use std::borrow::Cow;
44

5+
#[clippy::msrv = "1.81"]
56
fn main() {
67
let rstr: &str = "hello";
78
let rrstr: &&str = &rstr;
@@ -34,3 +35,10 @@ fn main() {
3435
let _: String = (**rrrcow).to_string();
3536
//~^ inefficient_to_string
3637
}
38+
39+
#[clippy::msrv = "1.82"]
40+
fn sufficient_msrv() {
41+
let rstr: &str = "hello";
42+
let rrstr: &&str = &rstr;
43+
let _: String = rrstr.to_string();
44+
}

tests/ui/inefficient_to_string.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
use std::borrow::Cow;
44

5+
#[clippy::msrv = "1.81"]
56
fn main() {
67
let rstr: &str = "hello";
78
let rrstr: &&str = &rstr;
@@ -34,3 +35,10 @@ fn main() {
3435
let _: String = rrrcow.to_string();
3536
//~^ inefficient_to_string
3637
}
38+
39+
#[clippy::msrv = "1.82"]
40+
fn sufficient_msrv() {
41+
let rstr: &str = "hello";
42+
let rrstr: &&str = &rstr;
43+
let _: String = rrstr.to_string();
44+
}

tests/ui/inefficient_to_string.stderr

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: calling `to_string` on `&&str`
2-
--> tests/ui/inefficient_to_string.rs:10:21
2+
--> tests/ui/inefficient_to_string.rs:11:21
33
|
44
LL | let _: String = rrstr.to_string();
55
| ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstr).to_string()`
@@ -12,39 +12,39 @@ LL | #![deny(clippy::inefficient_to_string)]
1212
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1313

1414
error: calling `to_string` on `&&&str`
15-
--> tests/ui/inefficient_to_string.rs:12:21
15+
--> tests/ui/inefficient_to_string.rs:13:21
1616
|
1717
LL | let _: String = rrrstr.to_string();
1818
| ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrstr).to_string()`
1919
|
2020
= help: `&&str` implements `ToString` through a slower blanket impl, but `str` has a fast specialization of `ToString`
2121

2222
error: calling `to_string` on `&&std::string::String`
23-
--> tests/ui/inefficient_to_string.rs:21:21
23+
--> tests/ui/inefficient_to_string.rs:22:21
2424
|
2525
LL | let _: String = rrstring.to_string();
2626
| ^^^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrstring).to_string()`
2727
|
2828
= help: `&std::string::String` implements `ToString` through a slower blanket impl, but `std::string::String` has a fast specialization of `ToString`
2929

3030
error: calling `to_string` on `&&&std::string::String`
31-
--> tests/ui/inefficient_to_string.rs:23:21
31+
--> tests/ui/inefficient_to_string.rs:24:21
3232
|
3333
LL | let _: String = rrrstring.to_string();
3434
| ^^^^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrstring).to_string()`
3535
|
3636
= help: `&&std::string::String` implements `ToString` through a slower blanket impl, but `std::string::String` has a fast specialization of `ToString`
3737

3838
error: calling `to_string` on `&&std::borrow::Cow<'_, str>`
39-
--> tests/ui/inefficient_to_string.rs:32:21
39+
--> tests/ui/inefficient_to_string.rs:33:21
4040
|
4141
LL | let _: String = rrcow.to_string();
4242
| ^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(*rrcow).to_string()`
4343
|
4444
= help: `&std::borrow::Cow<'_, str>` implements `ToString` through a slower blanket impl, but `std::borrow::Cow<'_, str>` has a fast specialization of `ToString`
4545

4646
error: calling `to_string` on `&&&std::borrow::Cow<'_, str>`
47-
--> tests/ui/inefficient_to_string.rs:34:21
47+
--> tests/ui/inefficient_to_string.rs:35:21
4848
|
4949
LL | let _: String = rrrcow.to_string();
5050
| ^^^^^^^^^^^^^^^^^^ help: try dereferencing the receiver: `(**rrrcow).to_string()`

0 commit comments

Comments
 (0)