about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-07-18 20:41:40 +0000
committerbors <bors@rust-lang.org>2019-07-18 20:41:40 +0000
commita3369981deff35f1c8d9a29e99358593959bd06e (patch)
tree089b75e27e6cad0354cdd93f52b46870c5338994
parent311376d30dc1cfa622142a9f50317b1e0cb4608a (diff)
parent4b1bc2ded91915e232c38cc503b5f110556cf719 (diff)
downloadrust-a3369981deff35f1c8d9a29e99358593959bd06e.tar.gz
rust-a3369981deff35f1c8d9a29e99358593959bd06e.zip
Auto merge of #61749 - davidtwco:rfc-2203-const-array-repeat-exprs, r=eddyb
rustc/rustc_mir: Implement RFC 2203.

This PR implements RFC 2203, allowing constants in array repeat
expressions. Part of #49147.

r? @eddyb
-rw-r--r--src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md11
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs90
-rw-r--r--src/librustc_mir/transform/promote_consts.rs15
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs174
-rw-r--r--src/librustc_typeck/check/expr.rs13
-rw-r--r--src/libsyntax/feature_gate.rs7
-rw-r--r--src/libsyntax_pos/symbol.rs1
-rw-r--r--src/test/ui/const-generics/issue-61336-2.rs3
-rw-r--r--src/test/ui/const-generics/issue-61336-2.stderr16
-rw-r--r--src/test/ui/const-generics/issue-61336.rs3
-rw-r--r--src/test/ui/const-generics/issue-61336.stderr16
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-fns.rs26
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-fns.stderr13
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs26
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr23
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs128
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs25
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr23
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs127
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs12
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs10
-rw-r--r--src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr13
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs11
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr13
-rw-r--r--src/test/ui/repeat-to-run-dtor-twice.rs2
25 files changed, 659 insertions, 142 deletions
diff --git a/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md b/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md
new file mode 100644
index 00000000000..09d1b19b4c3
--- /dev/null
+++ b/src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md
@@ -0,0 +1,11 @@
+# `const_in_array_repeat_expressions`
+
+The tracking issue for this feature is: [#49147]
+
+[#44109]: https://github.com/rust-lang/rust/issues/49147
+
+------------------------
+
+Relaxes the rules for repeat expressions, `[x; N]` such that `x` may also be `const` (strictly
+speaking rvalue promotable), in addition to `typeof(x): Copy`. The result of `[x; N]` where `x` is
+`const` is itself also `const`.
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index cdbbe1d02bd..dbb5a52e0aa 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -35,7 +35,7 @@ use rustc::mir::*;
 use rustc::traits::query::type_op;
 use rustc::traits::query::type_op::custom::CustomTypeOp;
 use rustc::traits::query::{Fallible, NoSolution};
-use rustc::traits::{ObligationCause, PredicateObligations};
+use rustc::traits::{self, ObligationCause, PredicateObligations};
 use rustc::ty::adjustment::{PointerCast};
 use rustc::ty::fold::TypeFoldable;
 use rustc::ty::subst::{Subst, SubstsRef, UnpackedKind, UserSubsts};
@@ -501,28 +501,38 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
             // FIXME use place_projection.is_empty() when is available
             if let Place::Base(_) = place {
                 if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
-                    let tcx = self.tcx();
-                    let trait_ref = ty::TraitRef {
-                        def_id: tcx.lang_items().copy_trait().unwrap(),
-                        substs: tcx.mk_substs_trait(place_ty.ty, &[]),
+                    let is_promoted = match place {
+                        Place::Base(PlaceBase::Static(box Static {
+                            kind: StaticKind::Promoted(_),
+                            ..
+                        })) => true,
+                        _ => false,
                     };
 
-                    // In order to have a Copy operand, the type T of the
-                    // value must be Copy. Note that we prove that T: Copy,
-                    // rather than using the `is_copy_modulo_regions`
-                    // test. This is important because
-                    // `is_copy_modulo_regions` ignores the resulting region
-                    // obligations and assumes they pass. This can result in
-                    // bounds from Copy impls being unsoundly ignored (e.g.,
-                    // #29149). Note that we decide to use Copy before knowing
-                    // whether the bounds fully apply: in effect, the rule is
-                    // that if a value of some type could implement Copy, then
-                    // it must.
-                    self.cx.prove_trait_ref(
-                        trait_ref,
-                        location.to_locations(),
-                        ConstraintCategory::CopyBound,
-                    );
+                    if !is_promoted {
+                        let tcx = self.tcx();
+                        let trait_ref = ty::TraitRef {
+                            def_id: tcx.lang_items().copy_trait().unwrap(),
+                            substs: tcx.mk_substs_trait(place_ty.ty, &[]),
+                        };
+
+                        // In order to have a Copy operand, the type T of the
+                        // value must be Copy. Note that we prove that T: Copy,
+                        // rather than using the `is_copy_modulo_regions`
+                        // test. This is important because
+                        // `is_copy_modulo_regions` ignores the resulting region
+                        // obligations and assumes they pass. This can result in
+                        // bounds from Copy impls being unsoundly ignored (e.g.,
+                        // #29149). Note that we decide to use Copy before knowing
+                        // whether the bounds fully apply: in effect, the rule is
+                        // that if a value of some type could implement Copy, then
+                        // it must.
+                        self.cx.prove_trait_ref(
+                            trait_ref,
+                            location.to_locations(),
+                            ConstraintCategory::CopyBound,
+                        );
+                    }
                 }
             }
 
@@ -1953,18 +1963,32 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
             }
 
             Rvalue::Repeat(operand, len) => if *len > 1 {
-                let operand_ty = operand.ty(body, tcx);
-
-                let trait_ref = ty::TraitRef {
-                    def_id: tcx.lang_items().copy_trait().unwrap(),
-                    substs: tcx.mk_substs_trait(operand_ty, &[]),
-                };
-
-                self.prove_trait_ref(
-                    trait_ref,
-                    location.to_locations(),
-                    ConstraintCategory::CopyBound,
-                );
+                if let Operand::Move(_) = operand {
+                    // While this is located in `nll::typeck` this error is not an NLL error, it's
+                    // a required check to 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) {
+                        self.infcx.report_selection_error(
+                            &traits::Obligation::new(
+                                ObligationCause::new(
+                                    span,
+                                    self.tcx().hir().def_index_to_hir_id(self.mir_def_id.index),
+                                    traits::ObligationCauseCode::RepeatVec,
+                                ),
+                                self.param_env,
+                                ty::Predicate::Trait(ty::Binder::bind(ty::TraitPredicate {
+                                    trait_ref: ty::TraitRef::new(
+                                        self.tcx().lang_items().copy_trait().unwrap(),
+                                        tcx.mk_substs_trait(ty, &[]),
+                                    ),
+                                })),
+                            ),
+                            &traits::SelectionError::Unimplemented,
+                            false,
+                        );
+                    }
+                }
             },
 
             Rvalue::NullaryOp(_, ty) => {
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index b1804fb0ab3..33eb4106d07 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -60,6 +60,9 @@ pub enum Candidate {
     /// Borrow of a constant temporary.
     Ref(Location),
 
+    /// Promotion of the `x` in `[x; 32]`.
+    Repeat(Location),
+
     /// Currently applied to function calls where the callee has the unstable
     /// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle
     /// intrinsic. The intrinsic requires the arguments are indeed constant and
@@ -322,6 +325,17 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
                         _ => bug!()
                     }
                 }
+                Candidate::Repeat(loc) => {
+                    let ref mut statement = blocks[loc.block].statements[loc.statement_index];
+                    match statement.kind {
+                        StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => {
+                            let ty = operand.ty(local_decls, self.tcx);
+                            let span = statement.source_info.span;
+                            mem::replace(operand, Operand::Copy(promoted_place(ty, span)))
+                        }
+                        _ => bug!()
+                    }
+                },
                 Candidate::Argument { bb, index } => {
                     let terminator = blocks[bb].terminator_mut();
                     match terminator.kind {
@@ -380,6 +394,7 @@ pub fn promote_candidates<'tcx>(
 
     for candidate in candidates.into_iter().rev() {
         match candidate {
+            Candidate::Repeat(Location { block, statement_index }) |
             Candidate::Ref(Location { block, statement_index }) => {
                 match body[block].statements[statement_index].kind {
                     StatementKind::Assign(Place::Base(PlaceBase::Local(local)), _) => {
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 21b8f06d089..4308af7c5ad 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -728,84 +728,97 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
 
         let mut qualifs = self.qualifs_in_value(source);
 
-        if let ValueSource::Rvalue(&Rvalue::Ref(_, kind, ref place)) = source {
-            // Getting `true` from `HasMutInterior::in_rvalue` means
-            // the borrowed place is disallowed from being borrowed,
-            // due to either a mutable borrow (with some exceptions),
-            // or an shared borrow of a value with interior mutability.
-            // Then `HasMutInterior` is replaced with `IsNotPromotable`,
-            // to avoid duplicate errors (e.g. from reborrowing).
-            if qualifs[HasMutInterior] {
-                qualifs[HasMutInterior] = false;
-                qualifs[IsNotPromotable] = true;
+        match source {
+            ValueSource::Rvalue(&Rvalue::Ref(_, kind, ref place)) => {
+                // Getting `true` from `HasMutInterior::in_rvalue` means
+                // the borrowed place is disallowed from being borrowed,
+                // due to either a mutable borrow (with some exceptions),
+                // or an shared borrow of a value with interior mutability.
+                // Then `HasMutInterior` is replaced with `IsNotPromotable`,
+                // to avoid duplicate errors (e.g. from reborrowing).
+                if qualifs[HasMutInterior] {
+                    qualifs[HasMutInterior] = false;
+                    qualifs[IsNotPromotable] = true;
 
-                if self.mode.requires_const_checking() {
-                    if !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
-                        if let BorrowKind::Mut { .. } = kind {
-                            let mut err = struct_span_err!(self.tcx.sess,  self.span, E0017,
-                                                        "references in {}s may only refer \
-                                                            to immutable values", self.mode);
-                            err.span_label(self.span, format!("{}s require immutable values",
-                                                                self.mode));
-                            if self.tcx.sess.teach(&err.get_code().unwrap()) {
-                                err.note("References in statics and constants may only refer to \
-                                        immutable values.\n\n\
-                                        Statics are shared everywhere, and if they refer to \
-                                        mutable data one might violate memory safety since \
-                                        holding multiple mutable references to shared data is \
-                                        not allowed.\n\n\
-                                        If you really want global mutable state, try using \
-                                        static mut or a global UnsafeCell.");
+                    if self.mode.requires_const_checking() {
+                        if !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
+                            if let BorrowKind::Mut { .. } = kind {
+                                let mut err = struct_span_err!(self.tcx.sess,  self.span, E0017,
+                                                               "references in {}s may only refer \
+                                                                to immutable values", self.mode);
+                                err.span_label(self.span, format!("{}s require immutable values",
+                                                                    self.mode));
+                                if self.tcx.sess.teach(&err.get_code().unwrap()) {
+                                    err.note("References in statics and constants may only refer \
+                                              to immutable values.\n\n\
+                                              Statics are shared everywhere, and if they refer to \
+                                              mutable data one might violate memory safety since \
+                                              holding multiple mutable references to shared data \
+                                              is not allowed.\n\n\
+                                              If you really want global mutable state, try using \
+                                              static mut or a global UnsafeCell.");
+                                }
+                                err.emit();
+                            } else {
+                                span_err!(self.tcx.sess, self.span, E0492,
+                                          "cannot borrow a constant which may contain \
+                                           interior mutability, create a static instead");
                             }
-                            err.emit();
-                        } else {
-                            span_err!(self.tcx.sess, self.span, E0492,
-                                    "cannot borrow a constant which may contain \
-                                    interior mutability, create a static instead");
                         }
                     }
-                }
-            } else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind {
-                // Don't promote BorrowKind::Shallow borrows, as they don't
-                // reach codegen.
-
-                // We might have a candidate for promotion.
-                let candidate = Candidate::Ref(location);
-                // Start by traversing to the "base", with non-deref projections removed.
-                let mut place = place;
-                while let Place::Projection(ref proj) = *place {
-                    if proj.elem == ProjectionElem::Deref {
-                        break;
+                } else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind {
+                    // Don't promote BorrowKind::Shallow borrows, as they don't
+                    // reach codegen.
+
+                    // We might have a candidate for promotion.
+                    let candidate = Candidate::Ref(location);
+                    // Start by traversing to the "base", with non-deref projections removed.
+                    let mut place = place;
+                    while let Place::Projection(ref proj) = *place {
+                        if proj.elem == ProjectionElem::Deref {
+                            break;
+                        }
+                        place = &proj.base;
                     }
-                    place = &proj.base;
-                }
-                debug!("qualify_consts: promotion candidate: place={:?}", place);
-                // We can only promote interior borrows of promotable temps (non-temps
-                // don't get promoted anyway).
-                // (If we bailed out of the loop due to a `Deref` above, we will definitely
-                // not enter the conditional here.)
-                if let Place::Base(PlaceBase::Local(local)) = *place {
-                    if self.body.local_kind(local) == LocalKind::Temp {
-                        debug!("qualify_consts: promotion candidate: local={:?}", local);
-                        // The borrowed place doesn't have `HasMutInterior`
-                        // (from `in_rvalue`), so we can safely ignore
-                        // `HasMutInterior` from the local's qualifications.
-                        // This allows borrowing fields which don't have
-                        // `HasMutInterior`, from a type that does, e.g.:
-                        // `let _: &'static _ = &(Cell::new(1), 2).1;`
-                        let mut local_qualifs = self.qualifs_in_local(local);
-                        // Any qualifications, except HasMutInterior (see above), disqualify
-                        // from promotion.
-                        // This is, in particular, the "implicit promotion" version of
-                        // the check making sure that we don't run drop glue during const-eval.
-                        local_qualifs[HasMutInterior] = false;
-                        if !local_qualifs.0.iter().any(|&qualif| qualif) {
-                            debug!("qualify_consts: promotion candidate: {:?}", candidate);
-                            self.promotion_candidates.push(candidate);
+                    debug!("qualify_consts: promotion candidate: place={:?}", place);
+                    // We can only promote interior borrows of promotable temps (non-temps
+                    // don't get promoted anyway).
+                    // (If we bailed out of the loop due to a `Deref` above, we will definitely
+                    // not enter the conditional here.)
+                    if let Place::Base(PlaceBase::Local(local)) = *place {
+                        if self.body.local_kind(local) == LocalKind::Temp {
+                            debug!("qualify_consts: promotion candidate: local={:?}", local);
+                            // The borrowed place doesn't have `HasMutInterior`
+                            // (from `in_rvalue`), so we can safely ignore
+                            // `HasMutInterior` from the local's qualifications.
+                            // This allows borrowing fields which don't have
+                            // `HasMutInterior`, from a type that does, e.g.:
+                            // `let _: &'static _ = &(Cell::new(1), 2).1;`
+                            let mut local_qualifs = self.qualifs_in_local(local);
+                            // Any qualifications, except HasMutInterior (see above), disqualify
+                            // from promotion.
+                            // This is, in particular, the "implicit promotion" version of
+                            // the check making sure that we don't run drop glue during const-eval.
+                            local_qualifs[HasMutInterior] = false;
+                            if !local_qualifs.0.iter().any(|&qualif| qualif) {
+                                debug!("qualify_consts: promotion candidate: {:?}", candidate);
+                                self.promotion_candidates.push(candidate);
+                            }
                         }
                     }
                 }
-            }
+            },
+            ValueSource::Rvalue(&Rvalue::Repeat(ref operand, _)) => {
+                let candidate = Candidate::Repeat(location);
+                let not_promotable = IsNotImplicitlyPromotable::in_operand(self, operand) ||
+                                     IsNotPromotable::in_operand(self, operand);
+                debug!("assign: self.def_id={:?} operand={:?}", self.def_id, operand);
+                if !not_promotable && self.tcx.features().const_in_array_repeat_expressions {
+                    debug!("assign: candidate={:?}", candidate);
+                    self.promotion_candidates.push(candidate);
+                }
+            },
+            _ => {},
         }
 
         let mut dest = dest;
@@ -935,15 +948,20 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
         debug!("qualify_const: promotion_candidates={:?}", self.promotion_candidates);
         for candidate in &self.promotion_candidates {
             match *candidate {
+                Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
+                    if let StatementKind::Assign(_, box Rvalue::Repeat(
+                        Operand::Move(Place::Base(PlaceBase::Local(index))),
+                        _
+                    )) = self.body[bb].statements[stmt_idx].kind {
+                        promoted_temps.insert(index);
+                    }
+                }
                 Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
-                    match self.body[bb].statements[stmt_idx].kind {
-                        StatementKind::Assign(
-                            _,
-                            box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index)))
-                        ) => {
-                            promoted_temps.insert(index);
-                        }
-                        _ => {}
+                    if let StatementKind::Assign(
+                        _,
+                        box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index)))
+                    ) = self.body[bb].statements[stmt_idx].kind {
+                        promoted_temps.insert(index);
                     }
                 }
                 Candidate::Argument { .. } => {}
diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs
index b02a7c21027..f2dbceb31b9 100644
--- a/src/librustc_typeck/check/expr.rs
+++ b/src/librustc_typeck/check/expr.rs
@@ -13,7 +13,6 @@ use crate::check::report_unexpected_variant_res;
 use crate::check::Needs;
 use crate::check::TupleArgumentsFlag::DontTupleArguments;
 use crate::check::method::SelfSource;
-use crate::middle::lang_items;
 use crate::util::common::ErrorReported;
 use crate::util::nodemap::FxHashMap;
 use crate::astconv::AstConv as _;
@@ -863,7 +862,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         element: &'tcx hir::Expr,
         count: &'tcx hir::AnonConst,
         expected: Expectation<'tcx>,
-        expr: &'tcx hir::Expr,
+        _expr: &'tcx hir::Expr,
     ) -> Ty<'tcx> {
         let tcx = self.tcx;
         let count_def_id = tcx.hir().local_def_id(count.hir_id);
@@ -911,16 +910,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
         };
 
-        if let Ok(count) = count {
-            let zero_or_one = count.assert_usize(tcx).map_or(false, |count| count <= 1);
-            if !zero_or_one {
-                // For [foo, ..n] where n > 1, `foo` must have
-                // Copy type:
-                let lang_item = tcx.require_lang_item(lang_items::CopyTraitLangItem);
-                self.require_type_meets(t, expr.span, traits::RepeatVec, lang_item);
-            }
-        }
-
         if element_ty.references_error() {
             tcx.types.err
         } else if let Ok(count) = count {
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index ed7d6c35fb9..6a3f58ec89e 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -559,10 +559,10 @@ declare_features! (
     // Allows `if/while p && let q = r && ...` chains.
     (active, let_chains, "1.37.0", Some(53667), None),
 
-    // #[repr(transparent)] on enums.
+    // Allows #[repr(transparent)] on enums (RFC 2645).
     (active, transparent_enums, "1.37.0", Some(60405), None),
 
-    // #[repr(transparent)] on unions.
+    // Allows #[repr(transparent)] on unions (RFC 2645).
     (active, transparent_unions, "1.37.0", Some(60405), None),
 
     // Allows explicit discriminants on non-unit enum variants.
@@ -577,6 +577,9 @@ declare_features! (
     // Allows the use of `#[cfg(doctest)]`, set when rustdoc is collecting doctests
     (active, cfg_doctest, "1.37.0", Some(62210), None),
 
+    // Allows `[x; N]` where `x` is a constant (RFC 2203).
+    (active, const_in_array_repeat_expressions, "1.37.0", Some(49147), None),
+
     // -------------------------------------------------------------------------
     // feature-group-end: actual feature gates
     // -------------------------------------------------------------------------
diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs
index a983180ac01..8da3e6c19d5 100644
--- a/src/libsyntax_pos/symbol.rs
+++ b/src/libsyntax_pos/symbol.rs
@@ -199,6 +199,7 @@ symbols! {
         const_fn_union,
         const_generics,
         const_indexing,
+        const_in_array_repeat_expressions,
         const_let,
         const_panic,
         const_raw_ptr_deref,
diff --git a/src/test/ui/const-generics/issue-61336-2.rs b/src/test/ui/const-generics/issue-61336-2.rs
index 604c14ee120..7bb36f41b8f 100644
--- a/src/test/ui/const-generics/issue-61336-2.rs
+++ b/src/test/ui/const-generics/issue-61336-2.rs
@@ -3,11 +3,12 @@
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; {N}]
+    //~^ ERROR array lengths can't depend on generic parameters
 }
 
 fn g<T, const N: usize>(x: T) -> [T; N] {
     [x; {N}]
-    //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277]
+    //~^ ERROR array lengths can't depend on generic parameters
 }
 
 fn main() {
diff --git a/src/test/ui/const-generics/issue-61336-2.stderr b/src/test/ui/const-generics/issue-61336-2.stderr
index a7135b62f8c..473ed46b104 100644
--- a/src/test/ui/const-generics/issue-61336-2.stderr
+++ b/src/test/ui/const-generics/issue-61336-2.stderr
@@ -4,15 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t
 LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
 
-error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
-  --> $DIR/issue-61336-2.rs:9:5
+error: array lengths can't depend on generic parameters
+  --> $DIR/issue-61336-2.rs:5:9
    |
 LL |     [x; {N}]
-   |     ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |         ^^^
+
+error: array lengths can't depend on generic parameters
+  --> $DIR/issue-61336-2.rs:10:9
    |
-   = help: consider adding a `where T: std::marker::Copy` bound
-   = note: the `Copy` trait is required because the repeated element will be copied
+LL |     [x; {N}]
+   |         ^^^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/const-generics/issue-61336.rs b/src/test/ui/const-generics/issue-61336.rs
index 95930371d59..edc012cbb3d 100644
--- a/src/test/ui/const-generics/issue-61336.rs
+++ b/src/test/ui/const-generics/issue-61336.rs
@@ -3,11 +3,12 @@
 
 fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
     [x; N]
+    //~^ ERROR array lengths can't depend on generic parameters
 }
 
 fn g<T, const N: usize>(x: T) -> [T; N] {
     [x; N]
-    //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277]
+    //~^ ERROR array lengths can't depend on generic parameters
 }
 
 fn main() {
diff --git a/src/test/ui/const-generics/issue-61336.stderr b/src/test/ui/const-generics/issue-61336.stderr
index 9939a599834..ae4ef3a906a 100644
--- a/src/test/ui/const-generics/issue-61336.stderr
+++ b/src/test/ui/const-generics/issue-61336.stderr
@@ -4,15 +4,17 @@ warning: the feature `const_generics` is incomplete and may cause the compiler t
 LL | #![feature(const_generics)]
    |            ^^^^^^^^^^^^^^
 
-error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied
-  --> $DIR/issue-61336.rs:9:5
+error: array lengths can't depend on generic parameters
+  --> $DIR/issue-61336.rs:5:9
    |
 LL |     [x; N]
-   |     ^^^^^^ the trait `std::marker::Copy` is not implemented for `T`
+   |         ^
+
+error: array lengths can't depend on generic parameters
+  --> $DIR/issue-61336.rs:10:9
    |
-   = help: consider adding a `where T: std::marker::Copy` bound
-   = note: the `Copy` trait is required because the repeated element will be copied
+LL |     [x; N]
+   |         ^
 
-error: aborting due to previous error
+error: aborting due to 2 previous errors
 
-For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-fns.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-fns.rs
new file mode 100644
index 00000000000..68a9227dea9
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-fns.rs
@@ -0,0 +1,26 @@
+// ignore-tidy-linelength
+// ignore-compare-mode-nll
+#![feature(const_in_array_repeat_expressions, nll)]
+#![allow(warnings)]
+
+// Some type that is not copyable.
+struct Bar;
+
+const fn type_no_copy() -> Option<Bar> {
+    None
+}
+
+const fn type_copy() -> u32 {
+    3
+}
+
+fn no_copy() {
+    const ARR: [Option<Bar>; 2] = [type_no_copy(); 2];
+    //~^ ERROR the trait bound `std::option::Option<Bar>: std::marker::Copy` is not satisfied [E0277]
+}
+
+fn copy() {
+    const ARR: [u32; 2] = [type_copy(); 2];
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-fns.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-fns.stderr
new file mode 100644
index 00000000000..82272af958a
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-fns.stderr
@@ -0,0 +1,13 @@
+error[E0277]: the trait bound `std::option::Option<Bar>: std::marker::Copy` is not satisfied
+  --> $DIR/const-fns.rs:18:35
+   |
+LL |     const ARR: [Option<Bar>; 2] = [type_no_copy(); 2];
+   |                                   ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<Bar>`
+   |
+   = help: the following implementations were found:
+             <std::option::Option<T> as std::marker::Copy>
+   = note: the `Copy` trait is required because the repeated element will be copied
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs
new file mode 100644
index 00000000000..3b7d7e5b51a
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs
@@ -0,0 +1,26 @@
+// ignore-tidy-linelength
+// ignore-compare-mode-nll
+// compile-flags: -Z borrowck=migrate
+#![feature(const_in_array_repeat_expressions)]
+#![allow(warnings)]
+
+// Some type that is not copyable.
+struct Bar;
+
+mod non_constants {
+    use Bar;
+
+    fn no_impl_copy_empty_value_multiple_elements() {
+        let x = None;
+        let arr: [Option<Bar>; 2] = [x; 2];
+        //~^ ERROR the trait bound `std::option::Option<Bar>: std::marker::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 `std::option::Option<Bar>: std::marker::Copy` is not satisfied [E0277]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr
new file mode 100644
index 00000000000..aad6763f150
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `std::option::Option<Bar>: std::marker::Copy` is not satisfied
+  --> $DIR/migrate-fail.rs:15:37
+   |
+LL |         let arr: [Option<Bar>; 2] = [x; 2];
+   |                                     ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<Bar>`
+   |
+   = help: the following implementations were found:
+             <std::option::Option<T> as std::marker::Copy>
+   = note: the `Copy` trait is required because the repeated element will be copied
+
+error[E0277]: the trait bound `std::option::Option<Bar>: std::marker::Copy` is not satisfied
+  --> $DIR/migrate-fail.rs:21:37
+   |
+LL |         let arr: [Option<Bar>; 2] = [x; 2];
+   |                                     ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<Bar>`
+   |
+   = help: the following implementations were found:
+             <std::option::Option<T> as std::marker::Copy>
+   = note: the `Copy` trait is required because the repeated element will be copied
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs
new file mode 100644
index 00000000000..bfa8ebcfdd3
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs
@@ -0,0 +1,128 @@
+// check-pass
+// compile-flags: -Z borrowck=migrate
+// ignore-compare-mode-nll
+#![feature(const_in_array_repeat_expressions)]
+#![allow(warnings)]
+
+// Some type that is not copyable.
+struct Bar;
+
+mod constants {
+    use Bar;
+
+    fn no_impl_copy_empty_value_no_elements() {
+        const FOO: Option<Bar> = None;
+        const ARR: [Option<Bar>; 0] = [FOO; 0];
+    }
+
+    fn no_impl_copy_empty_value_single_element() {
+        const FOO: Option<Bar> = None;
+        const ARR: [Option<Bar>; 1] = [FOO; 1];
+    }
+
+    fn no_impl_copy_empty_value_multiple_elements() {
+        const FOO: Option<Bar> = None;
+        const ARR: [Option<Bar>; 2] = [FOO; 2];
+    }
+
+    fn no_impl_copy_value_no_elements() {
+        const FOO: Option<Bar> = Some(Bar);
+        const ARR: [Option<Bar>; 0] = [FOO; 0];
+    }
+
+    fn no_impl_copy_value_single_element() {
+        const FOO: Option<Bar> = Some(Bar);
+        const ARR: [Option<Bar>; 1] = [FOO; 1];
+    }
+
+    fn no_impl_copy_value_multiple_elements() {
+        const FOO: Option<Bar> = Some(Bar);
+        const ARR: [Option<Bar>; 2] = [FOO; 2];
+    }
+
+    fn impl_copy_empty_value_no_elements() {
+        const FOO: Option<u32> = None;
+        const ARR: [Option<u32>; 0] = [FOO; 0];
+    }
+
+    fn impl_copy_empty_value_one_element() {
+        const FOO: Option<u32> = None;
+        const ARR: [Option<u32>; 1] = [FOO; 1];
+    }
+
+    fn impl_copy_empty_value_multiple_elements() {
+        const FOO: Option<u32> = None;
+        const ARR: [Option<u32>; 2] = [FOO; 2];
+    }
+
+    fn impl_copy_value_no_elements() {
+        const FOO: Option<u32> = Some(4);
+        const ARR: [Option<u32>; 0] = [FOO; 0];
+    }
+
+    fn impl_copy_value_one_element() {
+        const FOO: Option<u32> = Some(4);
+        const ARR: [Option<u32>; 1] = [FOO; 1];
+    }
+
+    fn impl_copy_value_multiple_elements() {
+        const FOO: Option<u32> = Some(4);
+        const ARR: [Option<u32>; 2] = [FOO; 2];
+    }
+}
+
+mod non_constants {
+    use Bar;
+
+    fn no_impl_copy_empty_value_no_elements() {
+        let x = None;
+        let arr: [Option<Bar>; 0] = [x; 0];
+    }
+
+    fn no_impl_copy_empty_value_single_element() {
+        let x = None;
+        let arr: [Option<Bar>; 1] = [x; 1];
+    }
+
+    fn no_impl_copy_value_no_elements() {
+        let x = Some(Bar);
+        let arr: [Option<Bar>; 0] = [x; 0];
+    }
+
+    fn no_impl_copy_value_single_element() {
+        let x = Some(Bar);
+        let arr: [Option<Bar>; 1] = [x; 1];
+    }
+
+    fn impl_copy_empty_value_no_elements() {
+        let x: Option<u32> = None;
+        let arr: [Option<u32>; 0] = [x; 0];
+    }
+
+    fn impl_copy_empty_value_one_element() {
+        let x: Option<u32> = None;
+        let arr: [Option<u32>; 1] = [x; 1];
+    }
+
+    fn impl_copy_empty_value_multiple_elements() {
+        let x: Option<u32> = None;
+        let arr: [Option<u32>; 2] = [x; 2];
+    }
+
+    fn impl_copy_value_no_elements() {
+        let x: Option<u32> = Some(4);
+        let arr: [Option<u32>; 0] = [x; 0];
+    }
+
+    fn impl_copy_value_one_element() {
+        let x: Option<u32> = Some(4);
+        let arr: [Option<u32>; 1] = [x; 1];
+    }
+
+    fn impl_copy_value_multiple_elements() {
+        let x: Option<u32> = Some(4);
+        let arr: [Option<u32>; 2] = [x; 2];
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs
new file mode 100644
index 00000000000..dc1193a2fe8
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs
@@ -0,0 +1,25 @@
+// ignore-tidy-linelength
+// ignore-compare-mode-nll
+#![feature(const_in_array_repeat_expressions, nll)]
+#![allow(warnings)]
+
+// Some type that is not copyable.
+struct Bar;
+
+mod non_constants {
+    use Bar;
+
+    fn no_impl_copy_empty_value_multiple_elements() {
+        let x = None;
+        let arr: [Option<Bar>; 2] = [x; 2];
+        //~^ ERROR the trait bound `std::option::Option<Bar>: std::marker::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 `std::option::Option<Bar>: std::marker::Copy` is not satisfied [E0277]
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr
new file mode 100644
index 00000000000..fd32484ff92
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr
@@ -0,0 +1,23 @@
+error[E0277]: the trait bound `std::option::Option<Bar>: std::marker::Copy` is not satisfied
+  --> $DIR/nll-fail.rs:14:37
+   |
+LL |         let arr: [Option<Bar>; 2] = [x; 2];
+   |                                     ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<Bar>`
+   |
+   = help: the following implementations were found:
+             <std::option::Option<T> as std::marker::Copy>
+   = note: the `Copy` trait is required because the repeated element will be copied
+
+error[E0277]: the trait bound `std::option::Option<Bar>: std::marker::Copy` is not satisfied
+  --> $DIR/nll-fail.rs:20:37
+   |
+LL |         let arr: [Option<Bar>; 2] = [x; 2];
+   |                                     ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<Bar>`
+   |
+   = help: the following implementations were found:
+             <std::option::Option<T> as std::marker::Copy>
+   = note: the `Copy` trait is required because the repeated element will be copied
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs
new file mode 100644
index 00000000000..a304f877ab7
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs
@@ -0,0 +1,127 @@
+// check-pass
+// ignore-compare-mode-nll
+#![allow(warnings)]
+#![feature(const_in_array_repeat_expressions, nll)]
+
+// Some type that is not copyable.
+struct Bar;
+
+mod constants {
+    use Bar;
+
+    fn no_impl_copy_empty_value_no_elements() {
+        const FOO: Option<Bar> = None;
+        const ARR: [Option<Bar>; 0] = [FOO; 0];
+    }
+
+    fn no_impl_copy_empty_value_single_element() {
+        const FOO: Option<Bar> = None;
+        const ARR: [Option<Bar>; 1] = [FOO; 1];
+    }
+
+    fn no_impl_copy_empty_value_multiple_elements() {
+        const FOO: Option<Bar> = None;
+        const ARR: [Option<Bar>; 2] = [FOO; 2];
+    }
+
+    fn no_impl_copy_value_no_elements() {
+        const FOO: Option<Bar> = Some(Bar);
+        const ARR: [Option<Bar>; 0] = [FOO; 0];
+    }
+
+    fn no_impl_copy_value_single_element() {
+        const FOO: Option<Bar> = Some(Bar);
+        const ARR: [Option<Bar>; 1] = [FOO; 1];
+    }
+
+    fn no_impl_copy_value_multiple_elements() {
+        const FOO: Option<Bar> = Some(Bar);
+        const ARR: [Option<Bar>; 2] = [FOO; 2];
+    }
+
+    fn impl_copy_empty_value_no_elements() {
+        const FOO: Option<u32> = None;
+        const ARR: [Option<u32>; 0] = [FOO; 0];
+    }
+
+    fn impl_copy_empty_value_one_element() {
+        const FOO: Option<u32> = None;
+        const ARR: [Option<u32>; 1] = [FOO; 1];
+    }
+
+    fn impl_copy_empty_value_multiple_elements() {
+        const FOO: Option<u32> = None;
+        const ARR: [Option<u32>; 2] = [FOO; 2];
+    }
+
+    fn impl_copy_value_no_elements() {
+        const FOO: Option<u32> = Some(4);
+        const ARR: [Option<u32>; 0] = [FOO; 0];
+    }
+
+    fn impl_copy_value_one_element() {
+        const FOO: Option<u32> = Some(4);
+        const ARR: [Option<u32>; 1] = [FOO; 1];
+    }
+
+    fn impl_copy_value_multiple_elements() {
+        const FOO: Option<u32> = Some(4);
+        const ARR: [Option<u32>; 2] = [FOO; 2];
+    }
+}
+
+mod non_constants {
+    use Bar;
+
+    fn no_impl_copy_empty_value_no_elements() {
+        let x = None;
+        let arr: [Option<Bar>; 0] = [x; 0];
+    }
+
+    fn no_impl_copy_empty_value_single_element() {
+        let x = None;
+        let arr: [Option<Bar>; 1] = [x; 1];
+    }
+
+    fn no_impl_copy_value_no_elements() {
+        let x = Some(Bar);
+        let arr: [Option<Bar>; 0] = [x; 0];
+    }
+
+    fn no_impl_copy_value_single_element() {
+        let x = Some(Bar);
+        let arr: [Option<Bar>; 1] = [x; 1];
+    }
+
+    fn impl_copy_empty_value_no_elements() {
+        let x: Option<u32> = None;
+        let arr: [Option<u32>; 0] = [x; 0];
+    }
+
+    fn impl_copy_empty_value_one_element() {
+        let x: Option<u32> = None;
+        let arr: [Option<u32>; 1] = [x; 1];
+    }
+
+    fn impl_copy_empty_value_multiple_elements() {
+        let x: Option<u32> = None;
+        let arr: [Option<u32>; 2] = [x; 2];
+    }
+
+    fn impl_copy_value_no_elements() {
+        let x: Option<u32> = Some(4);
+        let arr: [Option<u32>; 0] = [x; 0];
+    }
+
+    fn impl_copy_value_one_element() {
+        let x: Option<u32> = Some(4);
+        let arr: [Option<u32>; 1] = [x; 1];
+    }
+
+    fn impl_copy_value_multiple_elements() {
+        let x: Option<u32> = Some(4);
+        let arr: [Option<u32>; 2] = [x; 2];
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs
new file mode 100644
index 00000000000..27bf5dabf56
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs
@@ -0,0 +1,12 @@
+// run-pass
+#![feature(const_in_array_repeat_expressions)]
+
+#[derive(Debug, Eq, PartialEq)]
+struct Bar;
+
+fn main() {
+    const FOO: Option<Bar> = None;
+    const ARR: [Option<Bar>; 2] = [FOO; 2];
+
+    assert_eq!(ARR, [None::<Bar>, None::<Bar>]);
+}
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs
new file mode 100644
index 00000000000..35484d265bb
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs
@@ -0,0 +1,10 @@
+// ignore-tidy-linelength
+#![feature(const_in_array_repeat_expressions)]
+
+#[derive(Copy, Clone)]
+struct Foo<T>(T);
+
+fn main() {
+    [Foo(String::new()); 4];
+    //~^ ERROR the trait bound `Foo<std::string::String>: std::marker::Copy` is not satisfied [E0277]
+}
diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr
new file mode 100644
index 00000000000..186909e469e
--- /dev/null
+++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr
@@ -0,0 +1,13 @@
+error[E0277]: the trait bound `Foo<std::string::String>: std::marker::Copy` is not satisfied
+  --> $DIR/trait-error.rs:8:5
+   |
+LL |     [Foo(String::new()); 4];
+   |     ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Foo<std::string::String>`
+   |
+   = help: the following implementations were found:
+             <Foo<T> as std::marker::Copy>
+   = note: the `Copy` trait is required because the repeated element will be copied
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs
new file mode 100644
index 00000000000..be195271c10
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs
@@ -0,0 +1,11 @@
+// ignore-tidy-linelength
+#![allow(warnings)]
+
+struct Bar;
+
+fn foo() {
+    let arr: [Option<String>; 2] = [None::<String>; 2];
+    //~^ ERROR the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied [E0277]
+}
+
+fn main() {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr
new file mode 100644
index 00000000000..eed69a0c28d
--- /dev/null
+++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr
@@ -0,0 +1,13 @@
+error[E0277]: the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied
+  --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:7:36
+   |
+LL |     let arr: [Option<String>; 2] = [None::<String>; 2];
+   |                                    ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<std::string::String>`
+   |
+   = help: the following implementations were found:
+             <std::option::Option<T> as std::marker::Copy>
+   = note: the `Copy` trait is required because the repeated element will be copied
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/repeat-to-run-dtor-twice.rs b/src/test/ui/repeat-to-run-dtor-twice.rs
index 80eff2acdd2..d857178166a 100644
--- a/src/test/ui/repeat-to-run-dtor-twice.rs
+++ b/src/test/ui/repeat-to-run-dtor-twice.rs
@@ -15,5 +15,5 @@ impl Drop for Foo {
 fn main() {
     let a = Foo { x: 3 };
     let _ = [ a; 5 ];
-    //~^ ERROR `Foo: std::marker::Copy` is not satisfied
+    //~^ ERROR the trait bound `Foo: std::marker::Copy` is not satisfied [E0277]
 }