about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs22
-rw-r--r--tests/ui/moves/move-fn-self-receiver.stderr2
2 files changed, 22 insertions, 2 deletions
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 08c2a690b30..5f28500389d 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -11,7 +11,7 @@ use rustc_hir::def::{CtorKind, Namespace};
 use rustc_hir::CoroutineKind;
 use rustc_index::IndexSlice;
 use rustc_infer::infer::BoundRegionConversionTime;
-use rustc_infer::traits::{FulfillmentErrorCode, SelectionError, TraitEngineExt};
+use rustc_infer::traits::{FulfillmentErrorCode, SelectionError, TraitEngine, TraitEngineExt};
 use rustc_middle::mir::tcx::PlaceTy;
 use rustc_middle::mir::{
     AggregateKind, CallSource, ConstOperand, FakeReadCause, Local, LocalInfo, LocalKind, Location,
@@ -1211,7 +1211,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                                         .collect::<Vec<_>>();
                                     fulfill_cx
                                         .register_predicate_obligations(self.infcx, obligations);
+                                    // We also register the parent obligation for the type at hand
+                                    // implementing `Clone`, to account for bounds that also need
+                                    // to be evaluated, like ensuring that `Self: Clone`.
+                                    let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty]);
+                                    let obligation = Obligation::new(
+                                        tcx,
+                                        ObligationCause::dummy(),
+                                        self.param_env,
+                                        trait_ref,
+                                    );
+                                    fulfill_cx
+                                        .register_predicate_obligation(self.infcx, obligation);
                                     let errors = fulfill_cx.select_all_or_error(self.infcx);
+                                    // We remove the last predicate failure, which corresponds to
+                                    // the top-level obligation, because most of the type we only
+                                    // care about the other ones, *except* when it is the only one.
+                                    // This seems to only be relevant for arbitrary self-types.
+                                    // Look at `tests/ui/moves/move-fn-self-receiver.rs`.
+                                    let errors = match &errors[..] {
+                                        errors @ [] | errors @ [_] | [errors @ .., _] => errors,
+                                    };
                                     let msg = match &errors[..] {
                                         [] => "you can `clone` the value and consume it, but this \
                                                might not be your desired behavior"
diff --git a/tests/ui/moves/move-fn-self-receiver.stderr b/tests/ui/moves/move-fn-self-receiver.stderr
index 0abfcd112ef..462deacbe8d 100644
--- a/tests/ui/moves/move-fn-self-receiver.stderr
+++ b/tests/ui/moves/move-fn-self-receiver.stderr
@@ -55,7 +55,7 @@ note: `Foo::use_box_self` takes ownership of the receiver `self`, which moves `b
    |
 LL |     fn use_box_self(self: Box<Self>) {}
    |                     ^^^^
-help: you can `clone` the value and consume it, but this might not be your desired behavior
+help: you could `clone` the value and consume it, if the `Box<Foo>: Clone` trait bound could be satisfied
    |
 LL |     boxed_foo.clone().use_box_self();
    |              ++++++++