about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-08-05 13:33:57 +0000
committerbors <bors@rust-lang.org>2023-08-05 13:33:57 +0000
commitfbc11e96901a1f1a0cc865867f38684af250249f (patch)
treee1690f941fcd6c88d88ff6d6decea23477e1bc6e
parent28b6607b5f525d57515dd0ca28ead5c54f54533a (diff)
parent9ad3be3787da49c4bd3e4690969be9d1b2b223e5 (diff)
downloadrust-fbc11e96901a1f1a0cc865867f38684af250249f.tar.gz
rust-fbc11e96901a1f1a0cc865867f38684af250249f.zip
Auto merge of #114514 - matthiaskrgr:rollup-1rv4f3h, r=matthiaskrgr
Rollup of 3 pull requests

Successful merges:

 - #114029 (Explain more clearly why `fn() -> T` can't be `#[derive(Clone)]`)
 - #114248 (Make lint missing-copy-implementations honor negative `Copy` impls)
 - #114498 (Print tidy command with bless tidy check failure)

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_lint/src/builtin.rs23
-rw-r--r--library/core/src/clone.rs40
-rw-r--r--src/tools/tidy/src/fluent_alphabetical.rs2
-rw-r--r--tests/ui/lint/missing-copy-implementations-negative-copy.rs15
4 files changed, 79 insertions, 1 deletions
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index c290462fc20..2c9d212a6a6 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -58,6 +58,7 @@ use rustc_middle::lint::in_external_macro;
 use rustc_middle::ty::layout::LayoutOf;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::GenericArgKind;
+use rustc_middle::ty::ToPredicate;
 use rustc_middle::ty::TypeVisitableExt;
 use rustc_middle::ty::{self, Ty, TyCtxt, VariantDef};
 use rustc_session::config::ExpectedValues;
@@ -68,6 +69,7 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
 use rustc_span::{BytePos, InnerSpan, Span};
 use rustc_target::abi::Abi;
 use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
+use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
 use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy};
 
 use crate::nonstandard_style::{method_context, MethodLateContext};
@@ -673,6 +675,9 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
         if ty.is_copy_modulo_regions(cx.tcx, param_env) {
             return;
         }
+        if type_implements_negative_copy_modulo_regions(cx.tcx, ty, param_env) {
+            return;
+        }
 
         // We shouldn't recommend implementing `Copy` on stateful things,
         // such as iterators.
@@ -708,6 +713,24 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
     }
 }
 
+/// Check whether a `ty` has a negative `Copy` implementation, ignoring outlives constraints.
+fn type_implements_negative_copy_modulo_regions<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+    param_env: ty::ParamEnv<'tcx>,
+) -> bool {
+    let trait_ref = ty::TraitRef::new(tcx, tcx.require_lang_item(hir::LangItem::Copy, None), [ty]);
+    let pred = ty::TraitPredicate { trait_ref, polarity: ty::ImplPolarity::Negative };
+    let obligation = traits::Obligation {
+        cause: traits::ObligationCause::dummy(),
+        param_env,
+        recursion_depth: 0,
+        predicate: ty::Binder::dummy(pred).to_predicate(tcx),
+    };
+
+    tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
+}
+
 declare_lint! {
     /// The `missing_debug_implementations` lint detects missing
     /// implementations of [`fmt::Debug`] for public types.
diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs
index a6d6230d3a6..d7ca9c22dad 100644
--- a/library/core/src/clone.rs
+++ b/library/core/src/clone.rs
@@ -86,6 +86,46 @@
 /// }
 /// ```
 ///
+/// If we `derive`:
+///
+/// ```
+/// #[derive(Copy, Clone)]
+/// struct Generate<T>(fn() -> T);
+/// ```
+///
+/// the auto-derived implementations will have unnecessary `T: Copy` and `T: Clone` bounds:
+///
+/// ```
+/// # struct Generate<T>(fn() -> T);
+///
+/// // Automatically derived
+/// impl<T: Copy> Copy for Generate<T> { }
+///
+/// // Automatically derived
+/// impl<T: Clone> Clone for Generate<T> {
+///     fn clone(&self) -> Generate<T> {
+///         Generate(Clone::clone(&self.0))
+///     }
+/// }
+/// ```
+///
+/// The bounds are unnecessary because clearly the function itself should be
+/// copy- and cloneable even if its return type is not:
+///
+/// ```compile_fail,E0599
+/// #[derive(Copy, Clone)]
+/// struct Generate<T>(fn() -> T);
+///
+/// struct NotCloneable;
+///
+/// fn generate_not_cloneable() -> NotCloneable {
+///     NotCloneable
+/// }
+///
+/// Generate(generate_not_cloneable).clone(); // error: trait bounds were not satisfied
+/// // Note: With the manual implementations the above line will compile.
+/// ```
+///
 /// ## Additional implementors
 ///
 /// In addition to the [implementors listed below][impls],
diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs
index 5f8eaebf531..67b745373f0 100644
--- a/src/tools/tidy/src/fluent_alphabetical.rs
+++ b/src/tools/tidy/src/fluent_alphabetical.rs
@@ -23,7 +23,7 @@ fn check_alphabetic(filename: &str, fluent: &str, bad: &mut bool) {
                 tidy_error!(
                     bad,
                     "{filename}: message `{}` appears before `{}`, but is alphabetically later than it
-run tidy with `--bless` to sort the file correctly",
+run `./x.py test tidy --bless` to sort the file correctly",
                     name.as_str(),
                     next.as_str()
                 );
diff --git a/tests/ui/lint/missing-copy-implementations-negative-copy.rs b/tests/ui/lint/missing-copy-implementations-negative-copy.rs
new file mode 100644
index 00000000000..b29d2209fa9
--- /dev/null
+++ b/tests/ui/lint/missing-copy-implementations-negative-copy.rs
@@ -0,0 +1,15 @@
+// Regression test for issue #101980.
+// Ensure that we don't suggest impl'ing `Copy` for a type if it already impl's `!Copy`.
+
+// check-pass
+
+#![feature(negative_impls)]
+#![deny(missing_copy_implementations)]
+
+pub struct Struct {
+    pub field: i32,
+}
+
+impl !Copy for Struct {}
+
+fn main() {}