diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d6cc68bcdab4..a7b3a2cab119 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1564,10 +1564,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { err.note(&format!("required for the cast to the object type `{}`", self.ty_to_string(object_ty))); } - ObligationCauseCode::RepeatVec => { - err.note("the `Copy` trait is required because the \ - repeated element will be copied"); - } ObligationCauseCode::VariableType(_) => { err.note("all local variables must have a statically known size"); if !self.tcx.features().unsized_locals { diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs index 1ca92d79fa5f..b90f4ef91ce9 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -195,8 +195,6 @@ pub enum ObligationCauseCode<'tcx> { SizedReturnType, /// Yield type must be Sized SizedYieldType, - /// [T,..n] --> T must be Copy - RepeatVec, /// Types of fields (other than the last, except for packed structs) in a struct must be sized. FieldSized { adt_kind: AdtKind, last: bool }, diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs index 129a400d28f4..7d160af1a561 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -488,7 +488,6 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> { super::SizedArgumentType => Some(super::SizedArgumentType), super::SizedReturnType => Some(super::SizedReturnType), super::SizedYieldType => Some(super::SizedYieldType), - super::RepeatVec => Some(super::RepeatVec), super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }), super::ConstSized => Some(super::ConstSized), super::SharedStatic => Some(super::SharedStatic), 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 cdbbe1d02bd9..90812599f93c 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -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); + let is_copy = self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span); + if !is_copy { + let copy_path = self.tcx().def_path_str( + self.tcx().lang_items().copy_trait().unwrap()); + self.tcx().sess + .struct_span_err( + span, + &format!("repeated expression does not implement `{}`", copy_path), + ) + .span_label(span, &format!( + "the trait `{}` is not implemented for `{}`", + copy_path, ty, + )) + .note(&format!( + "the `{}` trait is required because the repeated element will be \ + copied", + copy_path, + )) + .emit(); + } + } }, Rvalue::NullaryOp(_, ty) => { diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs index b1804fb0ab33..33eb4106d073 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 2dffafd6e54c..0b90076bd468 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -726,84 +726,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. + } 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; + // 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 { + debug!("assign: candidate={:?}", candidate); + self.promotion_candidates.push(candidate); + } + }, + _ => {}, } let mut dest = dest; @@ -933,15 +946,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 b02a7c21027d..f2dbceb31b9c 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/test/ui/const-generics/issue-61336-2.rs b/src/test/ui/const-generics/issue-61336-2.rs index 604c14ee120a..7bb36f41b8f9 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(x: T) -> [T; N] { [x; {N}] + //~^ ERROR array lengths can't depend on generic parameters } fn g(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 a7135b62f8cf..473ed46b104e 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 95930371d597..edc012cbb3d1 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(x: T) -> [T; N] { [x; N] + //~^ ERROR array lengths can't depend on generic parameters } fn g(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 9939a5998340..ae4ef3a906a4 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/migrate-borrowck.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.rs new file mode 100644 index 000000000000..9bed2b7197ce --- /dev/null +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.rs @@ -0,0 +1,138 @@ +// ignore-compile-mode-nll +// compile-flags: -Z borrowck=migrate +#![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 = None; + const ARR: [Option; 0] = [FOO; 0]; + } + + fn no_impl_copy_empty_value_single_element() { + const FOO: Option = None; + const ARR: [Option; 1] = [FOO; 1]; + } + + fn no_impl_copy_empty_value_multiple_elements() { + const FOO: Option = None; + const ARR: [Option; 2] = [FOO; 2]; + } + + fn no_impl_copy_value_no_elements() { + const FOO: Option = Some(Bar); + const ARR: [Option; 0] = [FOO; 0]; + } + + fn no_impl_copy_value_single_element() { + const FOO: Option = Some(Bar); + const ARR: [Option; 1] = [FOO; 1]; + } + + fn no_impl_copy_value_multiple_elements() { + const FOO: Option = Some(Bar); + const ARR: [Option; 2] = [FOO; 2]; + } + + fn impl_copy_empty_value_no_elements() { + const FOO: Option = None; + const ARR: [Option; 0] = [FOO; 0]; + } + + fn impl_copy_empty_value_one_element() { + const FOO: Option = None; + const ARR: [Option; 1] = [FOO; 1]; + } + + fn impl_copy_empty_value_multiple_elements() { + const FOO: Option = None; + const ARR: [Option; 2] = [FOO; 2]; + } + + fn impl_copy_value_no_elements() { + const FOO: Option = Some(4); + const ARR: [Option; 0] = [FOO; 0]; + } + + fn impl_copy_value_one_element() { + const FOO: Option = Some(4); + const ARR: [Option; 1] = [FOO; 1]; + } + + fn impl_copy_value_multiple_elements() { + const FOO: Option = Some(4); + const ARR: [Option; 2] = [FOO; 2]; + } +} + +mod non_constants { + use Bar; + + fn no_impl_copy_empty_value_no_elements() { + let x = None; + let arr: [Option; 0] = [x; 0]; + } + + fn no_impl_copy_empty_value_single_element() { + let x = None; + let arr: [Option; 1] = [x; 1]; + } + + fn no_impl_copy_empty_value_multiple_elements() { + let x = None; + let arr: [Option; 2] = [x; 2]; + //~^ ERROR repeated expression does not implement `std::marker::Copy` + } + + fn no_impl_copy_value_no_elements() { + let x = Some(Bar); + let arr: [Option; 0] = [x; 0]; + } + + fn no_impl_copy_value_single_element() { + let x = Some(Bar); + let arr: [Option; 1] = [x; 1]; + } + + fn no_impl_copy_value_multiple_elements() { + let x = Some(Bar); + let arr: [Option; 2] = [x; 2]; + //~^ ERROR repeated expression does not implement `std::marker::Copy` + } + + fn impl_copy_empty_value_no_elements() { + let x: Option = None; + let arr: [Option; 0] = [x; 0]; + } + + fn impl_copy_empty_value_one_element() { + let x: Option = None; + let arr: [Option; 1] = [x; 1]; + } + + fn impl_copy_empty_value_multiple_elements() { + let x: Option = None; + let arr: [Option; 2] = [x; 2]; + } + + fn impl_copy_value_no_elements() { + let x: Option = Some(4); + let arr: [Option; 0] = [x; 0]; + } + + fn impl_copy_value_one_element() { + let x: Option = Some(4); + let arr: [Option; 1] = [x; 1]; + } + + fn impl_copy_value_multiple_elements() { + let x: Option = Some(4); + let arr: [Option; 2] = [x; 2]; + } +} + +fn main() {} diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.stderr new file mode 100644 index 000000000000..7a9b6a099b72 --- /dev/null +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.stderr @@ -0,0 +1,18 @@ +error: repeated expression does not implement `std::marker::Copy` + --> $DIR/migrate-borrowck.rs:87:37 + | +LL | let arr: [Option; 2] = [x; 2]; + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = note: the `std::marker::Copy` trait is required because the repeated element will be copied + +error: repeated expression does not implement `std::marker::Copy` + --> $DIR/migrate-borrowck.rs:103:37 + | +LL | let arr: [Option; 2] = [x; 2]; + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = note: the `std::marker::Copy` trait is required because the repeated element will be copied + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.rs new file mode 100644 index 000000000000..054a0139109b --- /dev/null +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.rs @@ -0,0 +1,138 @@ +// ignore-compile-mode-nll +#![allow(warnings)] +#![feature(nll)] + +// Some type that is not copyable. +struct Bar; + +mod constants { + use Bar; + + fn no_impl_copy_empty_value_no_elements() { + const FOO: Option = None; + const ARR: [Option; 0] = [FOO; 0]; + } + + fn no_impl_copy_empty_value_single_element() { + const FOO: Option = None; + const ARR: [Option; 1] = [FOO; 1]; + } + + fn no_impl_copy_empty_value_multiple_elements() { + const FOO: Option = None; + const ARR: [Option; 2] = [FOO; 2]; + } + + fn no_impl_copy_value_no_elements() { + const FOO: Option = Some(Bar); + const ARR: [Option; 0] = [FOO; 0]; + } + + fn no_impl_copy_value_single_element() { + const FOO: Option = Some(Bar); + const ARR: [Option; 1] = [FOO; 1]; + } + + fn no_impl_copy_value_multiple_elements() { + const FOO: Option = Some(Bar); + const ARR: [Option; 2] = [FOO; 2]; + } + + fn impl_copy_empty_value_no_elements() { + const FOO: Option = None; + const ARR: [Option; 0] = [FOO; 0]; + } + + fn impl_copy_empty_value_one_element() { + const FOO: Option = None; + const ARR: [Option; 1] = [FOO; 1]; + } + + fn impl_copy_empty_value_multiple_elements() { + const FOO: Option = None; + const ARR: [Option; 2] = [FOO; 2]; + } + + fn impl_copy_value_no_elements() { + const FOO: Option = Some(4); + const ARR: [Option; 0] = [FOO; 0]; + } + + fn impl_copy_value_one_element() { + const FOO: Option = Some(4); + const ARR: [Option; 1] = [FOO; 1]; + } + + fn impl_copy_value_multiple_elements() { + const FOO: Option = Some(4); + const ARR: [Option; 2] = [FOO; 2]; + } +} + +mod non_constants { + use Bar; + + fn no_impl_copy_empty_value_no_elements() { + let x = None; + let arr: [Option; 0] = [x; 0]; + } + + fn no_impl_copy_empty_value_single_element() { + let x = None; + let arr: [Option; 1] = [x; 1]; + } + + fn no_impl_copy_empty_value_multiple_elements() { + let x = None; + let arr: [Option; 2] = [x; 2]; + //~^ ERROR repeated expression does not implement `std::marker::Copy` + } + + fn no_impl_copy_value_no_elements() { + let x = Some(Bar); + let arr: [Option; 0] = [x; 0]; + } + + fn no_impl_copy_value_single_element() { + let x = Some(Bar); + let arr: [Option; 1] = [x; 1]; + } + + fn no_impl_copy_value_multiple_elements() { + let x = Some(Bar); + let arr: [Option; 2] = [x; 2]; + //~^ ERROR repeated expression does not implement `std::marker::Copy` + } + + fn impl_copy_empty_value_no_elements() { + let x: Option = None; + let arr: [Option; 0] = [x; 0]; + } + + fn impl_copy_empty_value_one_element() { + let x: Option = None; + let arr: [Option; 1] = [x; 1]; + } + + fn impl_copy_empty_value_multiple_elements() { + let x: Option = None; + let arr: [Option; 2] = [x; 2]; + } + + fn impl_copy_value_no_elements() { + let x: Option = Some(4); + let arr: [Option; 0] = [x; 0]; + } + + fn impl_copy_value_one_element() { + let x: Option = Some(4); + let arr: [Option; 1] = [x; 1]; + } + + fn impl_copy_value_multiple_elements() { + let x: Option = Some(4); + let arr: [Option; 2] = [x; 2]; + } +} + +fn main() {} diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.stderr new file mode 100644 index 000000000000..5cd6d2a8f063 --- /dev/null +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.stderr @@ -0,0 +1,18 @@ +error: repeated expression does not implement `std::marker::Copy` + --> $DIR/nll-borrowck.rs:87:37 + | +LL | let arr: [Option; 2] = [x; 2]; + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = note: the `std::marker::Copy` trait is required because the repeated element will be copied + +error: repeated expression does not implement `std::marker::Copy` + --> $DIR/nll-borrowck.rs:103:37 + | +LL | let arr: [Option; 2] = [x; 2]; + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = note: the `std::marker::Copy` trait is required because the repeated element will be copied + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/repeat-to-run-dtor-twice.rs b/src/test/ui/repeat-to-run-dtor-twice.rs index 80eff2acdd27..14336435fe8c 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 repeated expression does not implement `std::marker::Copy` } diff --git a/src/test/ui/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-to-run-dtor-twice.stderr index 5434f6cef544..dff6332f61bf 100644 --- a/src/test/ui/repeat-to-run-dtor-twice.stderr +++ b/src/test/ui/repeat-to-run-dtor-twice.stderr @@ -1,11 +1,10 @@ -error[E0277]: the trait bound `Foo: std::marker::Copy` is not satisfied +error: repeated expression does not implement `std::marker::Copy` --> $DIR/repeat-to-run-dtor-twice.rs:17:13 | LL | let _ = [ a; 5 ]; | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Foo` | - = note: the `Copy` trait is required because the repeated element will be copied + = note: the `std::marker::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`.