From 4e6e68e27a36f38da58dcbadd31c8f5d591f4571 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Mon, 11 Apr 2022 16:38:48 +0000
Subject: [PATCH 1/5] Check that repeat expression elements are Copy (ignoring
 lifetimes) in typeck and that they are Copy (with proper lifetime checks) in
 borrowck

---
 compiler/rustc_borrowck/src/type_check/mod.rs | 53 +++++--------------
 compiler/rustc_typeck/src/check/expr.rs       | 28 ++++++++++
 .../ui/array-slice-vec/repeat_empty_ok.stderr |  8 +--
 .../issues/issue-61336-2.stderr               |  4 +-
 .../const-generics/issues/issue-61336.stderr  |  4 +-
 .../const-blocks/fn-call-in-non-const.rs      |  2 +-
 .../const-blocks/fn-call-in-non-const.stderr  | 12 +++--
 .../ui/consts/const-blocks/migrate-fail.rs    |  4 +-
 .../consts/const-blocks/migrate-fail.stderr   | 24 ++++++---
 src/test/ui/consts/const-blocks/nll-fail.rs   |  4 +-
 .../ui/consts/const-blocks/nll-fail.stderr    | 24 ++++++---
 .../ui/consts/const-blocks/trait-error.rs     |  2 +-
 .../ui/consts/const-blocks/trait-error.stderr | 15 ++++--
 src/test/ui/consts/const-fn-in-vec.stderr     |  4 +-
 src/test/ui/lifetimes/copy_modulo_regions.rs  | 19 +++++++
 .../ui/lifetimes/copy_modulo_regions.stderr   | 14 +++++
 src/test/ui/repeat-to-run-dtor-twice.stderr   |  4 +-
 17 files changed, 142 insertions(+), 83 deletions(-)
 create mode 100644 src/test/ui/lifetimes/copy_modulo_regions.rs
 create mode 100644 src/test/ui/lifetimes/copy_modulo_regions.stderr

diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 6dcdd46816e0d..c4a190b44cbd4 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -37,18 +37,13 @@ use rustc_middle::ty::{
 use rustc_span::def_id::CRATE_DEF_ID;
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::abi::VariantIdx;
-use rustc_trait_selection::infer::InferCtxtExt as _;
-use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::type_op;
 use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
 use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
 use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
 use rustc_trait_selection::traits::query::Fallible;
-use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
+use rustc_trait_selection::traits::PredicateObligation;
 
-use rustc_const_eval::transform::{
-    check_consts::ConstCx, promote_consts::is_const_fn_in_array_repeat_expression,
-};
 use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
 use rustc_mir_dataflow::move_paths::MoveData;
 use rustc_mir_dataflow::ResultsCursor;
@@ -1868,41 +1863,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
                         Operand::Move(place) => {
                             // Make sure that repeated elements implement `Copy`.
                             let span = body.source_info(location).span;
-                            let ty = operand.ty(body, tcx);
-                            if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
-                                let ccx = ConstCx::new_with_param_env(tcx, body, self.param_env);
-                                let is_const_fn =
-                                    is_const_fn_in_array_repeat_expression(&ccx, &place, &body);
-
-                                debug!("check_rvalue: is_const_fn={:?}", is_const_fn);
-
-                                let def_id = body.source.def_id().expect_local();
-                                let obligation = traits::Obligation::new(
-                                    ObligationCause::new(
-                                        span,
-                                        self.tcx().hir().local_def_id_to_hir_id(def_id),
-                                        traits::ObligationCauseCode::RepeatElementCopy {
-                                            is_const_fn,
-                                        },
-                                    ),
-                                    self.param_env,
-                                    ty::Binder::dummy(ty::TraitRef::new(
-                                        self.tcx().require_lang_item(
-                                            LangItem::Copy,
-                                            Some(self.last_span),
-                                        ),
-                                        tcx.mk_substs_trait(ty, &[]),
-                                    ))
-                                    .without_const()
-                                    .to_predicate(self.tcx()),
-                                );
-                                self.infcx.report_selection_error(
-                                    obligation.clone(),
-                                    &obligation,
-                                    &traits::SelectionError::Unimplemented,
-                                    false,
-                                );
-                            }
+                            let ty = place.ty(body, tcx).ty;
+                            let trait_ref = ty::TraitRef::new(
+                                tcx.require_lang_item(LangItem::Copy, Some(span)),
+                                tcx.mk_substs_trait(ty, &[]),
+                            );
+
+                            self.prove_trait_ref(
+                                trait_ref,
+                                Locations::Single(location),
+                                ConstraintCategory::CopyBound,
+                            );
                         }
                     }
                 }
diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 47cb1ea48cb54..7111bbaa3cde2 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1292,6 +1292,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return tcx.ty_error();
         }
 
+        let is_const = match &element.kind {
+            hir::ExprKind::ConstBlock(..) => true,
+            hir::ExprKind::Path(qpath) => {
+                let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
+                matches!(
+                    res,
+                    Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _)
+                )
+            }
+            _ => false,
+        };
+
+        if !is_const {
+            let is_const_fn = match element.kind {
+                hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
+                    ty::FnDef(def_id, _) => tcx.is_const_fn(def_id),
+                    _ => false,
+                },
+                _ => false,
+            };
+
+            if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
+                let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
+                let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn };
+                self.require_type_meets(element_ty, element.span, code, lang_item);
+            }
+        }
+
         tcx.mk_ty(ty::Array(t, count))
     }
 
diff --git a/src/test/ui/array-slice-vec/repeat_empty_ok.stderr b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr
index eba1a8e2278b7..cf5efdaab2a3f 100644
--- a/src/test/ui/array-slice-vec/repeat_empty_ok.stderr
+++ b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
-  --> $DIR/repeat_empty_ok.rs:8:19
+  --> $DIR/repeat_empty_ok.rs:8:20
    |
 LL |     let headers = [Header{value: &[]}; 128];
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
+   |                    ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
    |
    = note: the `Copy` trait is required because the repeated element will be copied
 help: consider annotating `Header<'_>` with `#[derive(Copy)]`
@@ -11,10 +11,10 @@ LL | #[derive(Copy)]
    |
 
 error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
-  --> $DIR/repeat_empty_ok.rs:13:19
+  --> $DIR/repeat_empty_ok.rs:13:20
    |
 LL |     let headers = [Header{value: &[0]}; 128];
-   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
+   |                    ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
    |
    = note: the `Copy` trait is required because the repeated element will be copied
 help: consider annotating `Header<'_>` with `#[derive(Copy)]`
diff --git a/src/test/ui/const-generics/issues/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr
index 48aaaf5e5440a..ccc42f08acfa4 100644
--- a/src/test/ui/const-generics/issues/issue-61336-2.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336-2.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-61336-2.rs:6:5
+  --> $DIR/issue-61336-2.rs:6:6
    |
 LL |     [x; { N }]
-   |     ^^^^^^^^^^ the trait `Copy` is not implemented for `T`
+   |      ^ the trait `Copy` is not implemented for `T`
    |
    = note: the `Copy` trait is required because the repeated element will be copied
 help: consider restricting type parameter `T`
diff --git a/src/test/ui/const-generics/issues/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr
index 665a1a677a1ab..a6a7fee0007bd 100644
--- a/src/test/ui/const-generics/issues/issue-61336.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `T: Copy` is not satisfied
-  --> $DIR/issue-61336.rs:6:5
+  --> $DIR/issue-61336.rs:6:6
    |
 LL |     [x; N]
-   |     ^^^^^^ the trait `Copy` is not implemented for `T`
+   |      ^ the trait `Copy` is not implemented for `T`
    |
    = note: the `Copy` trait is required because the repeated element will be copied
 help: consider restricting type parameter `T`
diff --git a/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs b/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs
index 19217843759c1..18b4dc714ded0 100644
--- a/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs
+++ b/src/test/ui/consts/const-blocks/fn-call-in-non-const.rs
@@ -12,5 +12,5 @@ const fn copy() -> u32 {
 fn main() {
     let _: [u32; 2] = [copy(); 2];
     let _: [Option<Bar>; 2] = [no_copy(); 2];
-    //~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied
+    //~^ ERROR the trait bound `Bar: Copy` is not satisfied
 }
diff --git a/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr
index 52a1669e33002..ef05f723aca03 100644
--- a/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr
+++ b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr
@@ -1,13 +1,17 @@
-error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/fn-call-in-non-const.rs:14:31
+error[E0277]: the trait bound `Bar: Copy` is not satisfied
+  --> $DIR/fn-call-in-non-const.rs:14:32
    |
 LL |     let _: [Option<Bar>; 2] = [no_copy(); 2];
-   |                               ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
+   |                                ^^^^^^^^^ the trait `Copy` is not implemented for `Bar`
    |
-   = help: the trait `Copy` is implemented for `Option<T>`
+   = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
    = note: the `Copy` trait is required because the repeated element will be copied
    = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
    = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
+help: consider annotating `Bar` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
+   |
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-blocks/migrate-fail.rs b/src/test/ui/consts/const-blocks/migrate-fail.rs
index bb12139a7bae9..d5a17249cc9dd 100644
--- a/src/test/ui/consts/const-blocks/migrate-fail.rs
+++ b/src/test/ui/consts/const-blocks/migrate-fail.rs
@@ -11,13 +11,13 @@ mod non_constants {
     fn no_impl_copy_empty_value_multiple_elements() {
         let x = None;
         let arr: [Option<Bar>; 2] = [x; 2];
-        //~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
+        //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
     }
 
     fn no_impl_copy_value_multiple_elements() {
         let x = Some(Bar);
         let arr: [Option<Bar>; 2] = [x; 2];
-        //~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
+        //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
     }
 }
 
diff --git a/src/test/ui/consts/const-blocks/migrate-fail.stderr b/src/test/ui/consts/const-blocks/migrate-fail.stderr
index 318fec60290ee..1898ab3b46955 100644
--- a/src/test/ui/consts/const-blocks/migrate-fail.stderr
+++ b/src/test/ui/consts/const-blocks/migrate-fail.stderr
@@ -1,20 +1,28 @@
-error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/migrate-fail.rs:13:37
+error[E0277]: the trait bound `Bar: Copy` is not satisfied
+  --> $DIR/migrate-fail.rs:13:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
-   = help: the trait `Copy` is implemented for `Option<T>`
+   = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
    = note: the `Copy` trait is required because the repeated element will be copied
+help: consider annotating `Bar` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
+   |
 
-error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/migrate-fail.rs:19:37
+error[E0277]: the trait bound `Bar: Copy` is not satisfied
+  --> $DIR/migrate-fail.rs:19:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
-   = help: the trait `Copy` is implemented for `Option<T>`
+   = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
    = note: the `Copy` trait is required because the repeated element will be copied
+help: consider annotating `Bar` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-blocks/nll-fail.rs b/src/test/ui/consts/const-blocks/nll-fail.rs
index 871387c1fd0cf..9d4aef39e5401 100644
--- a/src/test/ui/consts/const-blocks/nll-fail.rs
+++ b/src/test/ui/consts/const-blocks/nll-fail.rs
@@ -10,13 +10,13 @@ mod non_constants {
     fn no_impl_copy_empty_value_multiple_elements() {
         let x = None;
         let arr: [Option<Bar>; 2] = [x; 2];
-        //~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
+        //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
     }
 
     fn no_impl_copy_value_multiple_elements() {
         let x = Some(Bar);
         let arr: [Option<Bar>; 2] = [x; 2];
-        //~^ ERROR the trait bound `Option<Bar>: Copy` is not satisfied [E0277]
+        //~^ ERROR the trait bound `Bar: Copy` is not satisfied [E0277]
     }
 }
 
diff --git a/src/test/ui/consts/const-blocks/nll-fail.stderr b/src/test/ui/consts/const-blocks/nll-fail.stderr
index 5a34361aa83b6..3201a1e68e8e6 100644
--- a/src/test/ui/consts/const-blocks/nll-fail.stderr
+++ b/src/test/ui/consts/const-blocks/nll-fail.stderr
@@ -1,20 +1,28 @@
-error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/nll-fail.rs:12:37
+error[E0277]: the trait bound `Bar: Copy` is not satisfied
+  --> $DIR/nll-fail.rs:12:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
-   = help: the trait `Copy` is implemented for `Option<T>`
+   = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
    = note: the `Copy` trait is required because the repeated element will be copied
+help: consider annotating `Bar` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
+   |
 
-error[E0277]: the trait bound `Option<Bar>: Copy` is not satisfied
-  --> $DIR/nll-fail.rs:18:37
+error[E0277]: the trait bound `Bar: Copy` is not satisfied
+  --> $DIR/nll-fail.rs:18:38
    |
 LL |         let arr: [Option<Bar>; 2] = [x; 2];
-   |                                     ^^^^^^ the trait `Copy` is not implemented for `Option<Bar>`
+   |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
-   = help: the trait `Copy` is implemented for `Option<T>`
+   = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
    = note: the `Copy` trait is required because the repeated element will be copied
+help: consider annotating `Bar` with `#[derive(Copy)]`
+   |
+LL | #[derive(Copy)]
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/consts/const-blocks/trait-error.rs b/src/test/ui/consts/const-blocks/trait-error.rs
index 5a614cbdd1561..49d1e9b943420 100644
--- a/src/test/ui/consts/const-blocks/trait-error.rs
+++ b/src/test/ui/consts/const-blocks/trait-error.rs
@@ -3,5 +3,5 @@ struct Foo<T>(T);
 
 fn main() {
     [Foo(String::new()); 4];
-    //~^ ERROR the trait bound `Foo<String>: Copy` is not satisfied [E0277]
+    //~^ ERROR the trait bound `String: Copy` is not satisfied [E0277]
 }
diff --git a/src/test/ui/consts/const-blocks/trait-error.stderr b/src/test/ui/consts/const-blocks/trait-error.stderr
index 6979ff36176cd..8a6ca61e0c54e 100644
--- a/src/test/ui/consts/const-blocks/trait-error.stderr
+++ b/src/test/ui/consts/const-blocks/trait-error.stderr
@@ -1,11 +1,18 @@
-error[E0277]: the trait bound `Foo<String>: Copy` is not satisfied
-  --> $DIR/trait-error.rs:5:5
+error[E0277]: the trait bound `String: Copy` is not satisfied
+  --> $DIR/trait-error.rs:5:6
    |
 LL |     [Foo(String::new()); 4];
-   |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Foo<String>`
+   |      ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
    |
-   = help: the trait `Copy` is implemented for `Foo<T>`
+note: required because of the requirements on the impl of `Copy` for `Foo<String>`
+  --> $DIR/trait-error.rs:1:10
+   |
+LL | #[derive(Copy, Clone)]
+   |          ^^^^
    = note: the `Copy` trait is required because the repeated element will be copied
+   = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
+   = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
+   = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/consts/const-fn-in-vec.stderr b/src/test/ui/consts/const-fn-in-vec.stderr
index f02cb4f1ff193..0572dda74703a 100644
--- a/src/test/ui/consts/const-fn-in-vec.stderr
+++ b/src/test/ui/consts/const-fn-in-vec.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `String: Copy` is not satisfied
-  --> $DIR/const-fn-in-vec.rs:4:32
+  --> $DIR/const-fn-in-vec.rs:4:33
    |
 LL |     let strings: [String; 5] = [String::new(); 5];
-   |                                ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
+   |                                 ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
    |
    = note: the `Copy` trait is required because the repeated element will be copied
    = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
diff --git a/src/test/ui/lifetimes/copy_modulo_regions.rs b/src/test/ui/lifetimes/copy_modulo_regions.rs
new file mode 100644
index 0000000000000..1d5d90ffcb43d
--- /dev/null
+++ b/src/test/ui/lifetimes/copy_modulo_regions.rs
@@ -0,0 +1,19 @@
+#![feature(nll)]
+
+#[derive(Clone)]
+struct Foo<'a>(fn(&'a ()) -> &'a ());
+
+impl Copy for Foo<'static> {}
+
+fn mk_foo<'a>() -> Foo<'a> {
+    println!("mk_foo");
+    Foo(|x| x)
+}
+
+fn foo<'a>() -> [Foo<'a>; 100] {
+    [mk_foo::<'a>(); 100] //~ ERROR lifetime may not live long enough
+}
+
+fn main() {
+    foo();
+}
diff --git a/src/test/ui/lifetimes/copy_modulo_regions.stderr b/src/test/ui/lifetimes/copy_modulo_regions.stderr
new file mode 100644
index 0000000000000..e027bc45426ed
--- /dev/null
+++ b/src/test/ui/lifetimes/copy_modulo_regions.stderr
@@ -0,0 +1,14 @@
+error: lifetime may not live long enough
+  --> $DIR/copy_modulo_regions.rs:14:5
+   |
+LL | fn foo<'a>() -> [Foo<'a>; 100] {
+   |        -- lifetime `'a` defined here
+LL |     [mk_foo::<'a>(); 100]
+   |     ^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'a` must outlive `'static`
+   |
+   = note: requirement occurs because of the type `Foo<'_>`, which makes the generic argument `'_` invariant
+   = note: the struct `Foo<'a>` is invariant over the parameter `'a`
+   = help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-to-run-dtor-twice.stderr
index 904413712cde1..fd64ce8bceaee 100644
--- a/src/test/ui/repeat-to-run-dtor-twice.stderr
+++ b/src/test/ui/repeat-to-run-dtor-twice.stderr
@@ -1,8 +1,8 @@
 error[E0277]: the trait bound `Foo: Copy` is not satisfied
-  --> $DIR/repeat-to-run-dtor-twice.rs:17:13
+  --> $DIR/repeat-to-run-dtor-twice.rs:17:15
    |
 LL |     let _ = [ a; 5 ];
-   |             ^^^^^^^^ the trait `Copy` is not implemented for `Foo`
+   |               ^ the trait `Copy` is not implemented for `Foo`
    |
    = note: the `Copy` trait is required because the repeated element will be copied
 help: consider annotating `Foo` with `#[derive(Copy)]`

From bc14b6bea6a410f11a7ea5db84ad753673b78150 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Tue, 12 Apr 2022 07:28:07 +0000
Subject: [PATCH 2/5] Add new repeat expr test.

Also add repeat expr test folder and move all related tests to it
---
 src/test/ui/repeat-expr/infer.rs                 | 16 ++++++++++++++++
 .../{ => repeat-expr}/repeat-expr-in-static.rs   |  0
 .../repeat-to-run-dtor-twice.rs                  |  0
 .../repeat-to-run-dtor-twice.stderr              |  0
 src/test/ui/{ => repeat-expr}/repeat_count.rs    |  0
 .../ui/{ => repeat-expr}/repeat_count.stderr     |  0
 src/tools/tidy/src/ui_tests.rs                   |  2 +-
 7 files changed, 17 insertions(+), 1 deletion(-)
 create mode 100644 src/test/ui/repeat-expr/infer.rs
 rename src/test/ui/{ => repeat-expr}/repeat-expr-in-static.rs (100%)
 rename src/test/ui/{ => repeat-expr}/repeat-to-run-dtor-twice.rs (100%)
 rename src/test/ui/{ => repeat-expr}/repeat-to-run-dtor-twice.stderr (100%)
 rename src/test/ui/{ => repeat-expr}/repeat_count.rs (100%)
 rename src/test/ui/{ => repeat-expr}/repeat_count.stderr (100%)

diff --git a/src/test/ui/repeat-expr/infer.rs b/src/test/ui/repeat-expr/infer.rs
new file mode 100644
index 0000000000000..8197713b97ed0
--- /dev/null
+++ b/src/test/ui/repeat-expr/infer.rs
@@ -0,0 +1,16 @@
+// check-pass
+
+#[derive(Clone, Default)]
+struct MaybeCopy<T>(T);
+
+impl Copy for MaybeCopy<u8> {}
+
+fn is_copy<T: Copy>(x: T) {
+    println!("{}", std::any::type_name::<T>());
+}
+
+fn main() {
+    is_copy(MaybeCopy::default());
+    [MaybeCopy::default(); 13];
+    // didn't work, because `Copy` was only checked in the mir
+}
diff --git a/src/test/ui/repeat-expr-in-static.rs b/src/test/ui/repeat-expr/repeat-expr-in-static.rs
similarity index 100%
rename from src/test/ui/repeat-expr-in-static.rs
rename to src/test/ui/repeat-expr/repeat-expr-in-static.rs
diff --git a/src/test/ui/repeat-to-run-dtor-twice.rs b/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.rs
similarity index 100%
rename from src/test/ui/repeat-to-run-dtor-twice.rs
rename to src/test/ui/repeat-expr/repeat-to-run-dtor-twice.rs
diff --git a/src/test/ui/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr
similarity index 100%
rename from src/test/ui/repeat-to-run-dtor-twice.stderr
rename to src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr
diff --git a/src/test/ui/repeat_count.rs b/src/test/ui/repeat-expr/repeat_count.rs
similarity index 100%
rename from src/test/ui/repeat_count.rs
rename to src/test/ui/repeat-expr/repeat_count.rs
diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat-expr/repeat_count.stderr
similarity index 100%
rename from src/test/ui/repeat_count.stderr
rename to src/test/ui/repeat-expr/repeat_count.stderr
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 1f6f233648152..6b715f727b223 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -7,7 +7,7 @@ use std::path::Path;
 
 const ENTRY_LIMIT: usize = 1000;
 // FIXME: The following limits should be reduced eventually.
-const ROOT_ENTRY_LIMIT: usize = 980;
+const ROOT_ENTRY_LIMIT: usize = 977;
 const ISSUES_ENTRY_LIMIT: usize = 2278;
 
 fn check_entries(path: &Path, bad: &mut bool) {

From 018f9347fcc265b21e5269254c50b73ac8c2a3de Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Thu, 28 Apr 2022 09:40:42 +0000
Subject: [PATCH 3/5] Update the diagnostic message to match the new span

---
 .../src/traits/error_reporting/suggestions.rs                 | 2 +-
 src/test/ui/array-slice-vec/repeat_empty_ok.stderr            | 4 ++--
 src/test/ui/const-generics/issues/issue-61336-2.stderr        | 2 +-
 src/test/ui/const-generics/issues/issue-61336.stderr          | 2 +-
 src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr   | 2 +-
 src/test/ui/consts/const-blocks/migrate-fail.stderr           | 4 ++--
 src/test/ui/consts/const-blocks/nll-fail.stderr               | 4 ++--
 src/test/ui/consts/const-blocks/trait-error.stderr            | 2 +-
 src/test/ui/consts/const-fn-in-vec.stderr                     | 2 +-
 src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr       | 2 +-
 10 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index 0c1ca65c48f6a..187df6f7de0ff 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -2227,7 +2227,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> {
             }
             ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
                 err.note(
-                    "the `Copy` trait is required because the repeated element will be copied",
+                    "the `Copy` trait is required because this value will be copied for each element of the array",
                 );
 
                 if is_const_fn {
diff --git a/src/test/ui/array-slice-vec/repeat_empty_ok.stderr b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr
index cf5efdaab2a3f..724bdcd920ab4 100644
--- a/src/test/ui/array-slice-vec/repeat_empty_ok.stderr
+++ b/src/test/ui/array-slice-vec/repeat_empty_ok.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
 LL |     let headers = [Header{value: &[]}; 128];
    |                    ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider annotating `Header<'_>` with `#[derive(Copy)]`
    |
 LL | #[derive(Copy)]
@@ -16,7 +16,7 @@ error[E0277]: the trait bound `Header<'_>: Copy` is not satisfied
 LL |     let headers = [Header{value: &[0]}; 128];
    |                    ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Header<'_>`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider annotating `Header<'_>` with `#[derive(Copy)]`
    |
 LL | #[derive(Copy)]
diff --git a/src/test/ui/const-generics/issues/issue-61336-2.stderr b/src/test/ui/const-generics/issues/issue-61336-2.stderr
index ccc42f08acfa4..5bb3566962367 100644
--- a/src/test/ui/const-generics/issues/issue-61336-2.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336-2.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
 LL |     [x; { N }]
    |      ^ the trait `Copy` is not implemented for `T`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider restricting type parameter `T`
    |
 LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
diff --git a/src/test/ui/const-generics/issues/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr
index a6a7fee0007bd..8d9e545b45689 100644
--- a/src/test/ui/const-generics/issues/issue-61336.stderr
+++ b/src/test/ui/const-generics/issues/issue-61336.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `T: Copy` is not satisfied
 LL |     [x; N]
    |      ^ the trait `Copy` is not implemented for `T`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider restricting type parameter `T`
    |
 LL | fn g<T: std::marker::Copy, const N: usize>(x: T) -> [T; N] {
diff --git a/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr
index ef05f723aca03..5306fed225118 100644
--- a/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr
+++ b/src/test/ui/consts/const-blocks/fn-call-in-non-const.stderr
@@ -5,7 +5,7 @@ LL |     let _: [Option<Bar>; 2] = [no_copy(); 2];
    |                                ^^^^^^^^^ the trait `Copy` is not implemented for `Bar`
    |
    = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
    = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
 help: consider annotating `Bar` with `#[derive(Copy)]`
diff --git a/src/test/ui/consts/const-blocks/migrate-fail.stderr b/src/test/ui/consts/const-blocks/migrate-fail.stderr
index 1898ab3b46955..2e7ff5cb8b32c 100644
--- a/src/test/ui/consts/const-blocks/migrate-fail.stderr
+++ b/src/test/ui/consts/const-blocks/migrate-fail.stderr
@@ -5,7 +5,7 @@ LL |         let arr: [Option<Bar>; 2] = [x; 2];
    |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
    = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider annotating `Bar` with `#[derive(Copy)]`
    |
 LL | #[derive(Copy)]
@@ -18,7 +18,7 @@ LL |         let arr: [Option<Bar>; 2] = [x; 2];
    |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
    = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider annotating `Bar` with `#[derive(Copy)]`
    |
 LL | #[derive(Copy)]
diff --git a/src/test/ui/consts/const-blocks/nll-fail.stderr b/src/test/ui/consts/const-blocks/nll-fail.stderr
index 3201a1e68e8e6..c0d273b5a9a2a 100644
--- a/src/test/ui/consts/const-blocks/nll-fail.stderr
+++ b/src/test/ui/consts/const-blocks/nll-fail.stderr
@@ -5,7 +5,7 @@ LL |         let arr: [Option<Bar>; 2] = [x; 2];
    |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
    = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider annotating `Bar` with `#[derive(Copy)]`
    |
 LL | #[derive(Copy)]
@@ -18,7 +18,7 @@ LL |         let arr: [Option<Bar>; 2] = [x; 2];
    |                                      ^ the trait `Copy` is not implemented for `Bar`
    |
    = note: required because of the requirements on the impl of `Copy` for `Option<Bar>`
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider annotating `Bar` with `#[derive(Copy)]`
    |
 LL | #[derive(Copy)]
diff --git a/src/test/ui/consts/const-blocks/trait-error.stderr b/src/test/ui/consts/const-blocks/trait-error.stderr
index 8a6ca61e0c54e..ece200ad10b5b 100644
--- a/src/test/ui/consts/const-blocks/trait-error.stderr
+++ b/src/test/ui/consts/const-blocks/trait-error.stderr
@@ -9,7 +9,7 @@ note: required because of the requirements on the impl of `Copy` for `Foo<String
    |
 LL | #[derive(Copy, Clone)]
    |          ^^^^
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
    = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
    = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info)
diff --git a/src/test/ui/consts/const-fn-in-vec.stderr b/src/test/ui/consts/const-fn-in-vec.stderr
index 0572dda74703a..9eb7524b5044b 100644
--- a/src/test/ui/consts/const-fn-in-vec.stderr
+++ b/src/test/ui/consts/const-fn-in-vec.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `String: Copy` is not satisfied
 LL |     let strings: [String; 5] = [String::new(); 5];
    |                                 ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
    = help: consider creating a new `const` item and initializing it with the result of the function call to be used in the repeat position, like `const VAL: Type = const_fn();` and `let x = [VAL; 42];`
    = help: create an inline `const` block, see RFC #2920 <https://github.com/rust-lang/rfcs/pull/2920> for more information
 
diff --git a/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr
index fd64ce8bceaee..36b93616375e0 100644
--- a/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr
+++ b/src/test/ui/repeat-expr/repeat-to-run-dtor-twice.stderr
@@ -4,7 +4,7 @@ error[E0277]: the trait bound `Foo: Copy` is not satisfied
 LL |     let _ = [ a; 5 ];
    |               ^ the trait `Copy` is not implemented for `Foo`
    |
-   = note: the `Copy` trait is required because the repeated element will be copied
+   = note: the `Copy` trait is required because this value will be copied for each element of the array
 help: consider annotating `Foo` with `#[derive(Copy)]`
    |
 LL | #[derive(Copy)]

From be54947315b6d2892ed09281a7770e1f09c673e7 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Fri, 29 Apr 2022 18:49:02 +0000
Subject: [PATCH 4/5] Extract copy bound check into a function

---
 compiler/rustc_typeck/src/check/expr.rs | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 7111bbaa3cde2..8dd288e5555f0 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1292,6 +1292,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return tcx.ty_error();
         }
 
+        self.check_repeat_element_needs_copy_bound(element, count, element_ty);
+
+        tcx.mk_ty(ty::Array(t, count))
+    }
+
+    fn check_repeat_element_needs_copy_bound(
+        &self,
+        element: &hir::Expr<'_>,
+        count: ty::Const<'tcx>,
+        element_ty: Ty<'tcx>,
+    ) {
+        let tcx = self.tcx;
         let is_const = match &element.kind {
             hir::ExprKind::ConstBlock(..) => true,
             hir::ExprKind::Path(qpath) => {
@@ -1303,7 +1315,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             _ => false,
         };
-
         if !is_const {
             let is_const_fn = match element.kind {
                 hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
@@ -1319,8 +1330,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.require_type_meets(element_ty, element.span, code, lang_item);
             }
         }
-
-        tcx.mk_ty(ty::Array(t, count))
     }
 
     fn check_expr_tuple(

From 67ce547f474fbe34e8aafe4bfc284c3856673744 Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Fri, 29 Apr 2022 18:56:57 +0000
Subject: [PATCH 5/5] Refactor and document the repeat length check

---
 compiler/rustc_typeck/src/check/expr.rs | 41 +++++++++++++------------
 1 file changed, 22 insertions(+), 19 deletions(-)

diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs
index 8dd288e5555f0..a1e8d2040dd80 100644
--- a/compiler/rustc_typeck/src/check/expr.rs
+++ b/compiler/rustc_typeck/src/check/expr.rs
@@ -1304,31 +1304,34 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         element_ty: Ty<'tcx>,
     ) {
         let tcx = self.tcx;
-        let is_const = match &element.kind {
-            hir::ExprKind::ConstBlock(..) => true,
+        // Actual constants as the repeat element get inserted repeatedly instead of getting copied via Copy.
+        match &element.kind {
+            hir::ExprKind::ConstBlock(..) => return,
             hir::ExprKind::Path(qpath) => {
                 let res = self.typeck_results.borrow().qpath_res(qpath, element.hir_id);
-                matches!(
-                    res,
-                    Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _)
-                )
+                if let Res::Def(DefKind::Const | DefKind::AssocConst | DefKind::AnonConst, _) = res
+                {
+                    return;
+                }
             }
+            _ => {}
+        }
+        // If someone calls a const fn, they can extract that call out into a separate constant (or a const
+        // block in the future), so we check that to tell them that in the diagnostic. Does not affect typeck.
+        let is_const_fn = match element.kind {
+            hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
+                ty::FnDef(def_id, _) => tcx.is_const_fn(def_id),
+                _ => false,
+            },
             _ => false,
         };
-        if !is_const {
-            let is_const_fn = match element.kind {
-                hir::ExprKind::Call(func, _args) => match *self.node_ty(func.hir_id).kind() {
-                    ty::FnDef(def_id, _) => tcx.is_const_fn(def_id),
-                    _ => false,
-                },
-                _ => false,
-            };
 
-            if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
-                let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
-                let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn };
-                self.require_type_meets(element_ty, element.span, code, lang_item);
-            }
+        // If the length is 0, we don't create any elements, so we don't copy any. If the length is 1, we
+        // don't copy that one element, we move it. Only check for Copy if the length is larger.
+        if count.try_eval_usize(tcx, self.param_env).map_or(true, |len| len > 1) {
+            let lang_item = self.tcx.require_lang_item(LangItem::Copy, None);
+            let code = traits::ObligationCauseCode::RepeatElementCopy { is_const_fn };
+            self.require_type_meets(element_ty, element.span, code, lang_item);
         }
     }