diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index cddb37c7d816f..4fbb172f0f94f 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -3530,6 +3530,24 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { Applicability::MaybeIncorrect, ); } + + if let Some(cow_did) = tcx.get_diagnostic_item(sym::Cow) + && let ty::Adt(adt_def, _) = return_ty.kind() + && adt_def.did() == cow_did + { + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(return_span) { + if let Some(pos) = snippet.rfind(".to_owned") { + let byte_pos = BytePos(pos as u32 + 1u32); + let to_owned_span = return_span.with_hi(return_span.lo() + byte_pos); + err.span_suggestion_short( + to_owned_span.shrink_to_hi(), + "try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T`", + "in", + Applicability::MaybeIncorrect, + ); + } + } + } } Err(err) diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 7b359dcd6b252..47cf9bdffa1bb 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -196,6 +196,7 @@ symbols! { Continue, ControlFlow, Copy, + Cow, Debug, Default, Deref, diff --git a/src/tools/clippy/clippy_utils/src/sym.rs b/src/tools/clippy/clippy_utils/src/sym.rs index 7d579d85d8087..71e62f0474634 100644 --- a/src/tools/clippy/clippy_utils/src/sym.rs +++ b/src/tools/clippy/clippy_utils/src/sym.rs @@ -50,7 +50,6 @@ generate! { Cargo_toml: "Cargo.toml", Child, Command, - Cow, Current, DOUBLE_QUOTE: "\"", DebugStruct, diff --git a/tests/ui/suggestions/cow-into-owned-suggestion.rs b/tests/ui/suggestions/cow-into-owned-suggestion.rs new file mode 100644 index 0000000000000..8d1019431df0f --- /dev/null +++ b/tests/ui/suggestions/cow-into-owned-suggestion.rs @@ -0,0 +1,23 @@ +//! Regression test for: https://github.com/rust-lang/rust/issues/144792 + +fn main() { + let _ = || { + let os_string = std::ffi::OsString::from("test"); + os_string.to_string_lossy().to_owned() + //~^ ERROR: cannot return value referencing local variable `os_string` [E0515] + }; + + let _ = || { + let s = "hello".to_owned(); + let cow = std::borrow::Cow::from(&s); + cow.to_owned() + //~^ ERROR: cannot return value referencing local variable `s` [E0515] + }; + + let _ = || { + let bytes = b"hello".to_owned(); + let cow = std::borrow::Cow::from(&bytes[..]); + cow.to_owned() + //~^ ERROR: cannot return value referencing local variable `bytes` [E0515] + }; +} diff --git a/tests/ui/suggestions/cow-into-owned-suggestion.stderr b/tests/ui/suggestions/cow-into-owned-suggestion.stderr new file mode 100644 index 0000000000000..8d30af9589133 --- /dev/null +++ b/tests/ui/suggestions/cow-into-owned-suggestion.stderr @@ -0,0 +1,43 @@ +error[E0515]: cannot return value referencing local variable `os_string` + --> $DIR/cow-into-owned-suggestion.rs:6:9 + | +LL | os_string.to_string_lossy().to_owned() + | ---------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | returns a value referencing data owned by the current function + | `os_string` is borrowed here + | +help: try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T` + | +LL | os_string.to_string_lossy().into_owned() + | ++ + +error[E0515]: cannot return value referencing local variable `s` + --> $DIR/cow-into-owned-suggestion.rs:13:9 + | +LL | let cow = std::borrow::Cow::from(&s); + | -- `s` is borrowed here +LL | cow.to_owned() + | ^^^^^^^^^^^^^^ returns a value referencing data owned by the current function + | +help: try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T` + | +LL | cow.into_owned() + | ++ + +error[E0515]: cannot return value referencing local variable `bytes` + --> $DIR/cow-into-owned-suggestion.rs:20:9 + | +LL | let cow = std::borrow::Cow::from(&bytes[..]); + | ----- `bytes` is borrowed here +LL | cow.to_owned() + | ^^^^^^^^^^^^^^ returns a value referencing data owned by the current function + | +help: try using `.into_owned()` if you meant to convert a `Cow<'_, T>` to an owned `T` + | +LL | cow.into_owned() + | ++ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0515`.