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 0000000000000..09d1b19b4c3c3 --- /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 cdbbe1d02bd92..dbb5a52e0aaa8 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 b1804fb0ab331..33eb4106d0735 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 21b8f06d0895f..4308af7c5ad8d 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 b02a7c21027d4..f2dbceb31b9ca 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 ed7d6c35fb97a..6a3f58ec89e19 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 a983180ac01e1..8da3e6c19d5e3 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 604c14ee120a8..7bb36f41b8f9d 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 a7135b62f8cff..473ed46b104e9 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 95930371d5974..edc012cbb3d13 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 9939a5998340f..ae4ef3a906a4f 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 0000000000000..68a9227dea96e --- /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 { + None +} + +const fn type_copy() -> u32 { + 3 +} + +fn no_copy() { + const ARR: [Option; 2] = [type_no_copy(); 2]; + //~^ ERROR the trait bound `std::option::Option: 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 0000000000000..82272af958a2e --- /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: std::marker::Copy` is not satisfied + --> $DIR/const-fns.rs:18:35 + | +LL | const ARR: [Option; 2] = [type_no_copy(); 2]; + | ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = help: the following implementations were found: + 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 0000000000000..3b7d7e5b51a22 --- /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; 2] = [x; 2]; + //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + } + + fn no_impl_copy_value_multiple_elements() { + let x = Some(Bar); + let arr: [Option; 2] = [x; 2]; + //~^ ERROR the trait bound `std::option::Option: 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 0000000000000..aad6763f15094 --- /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: std::marker::Copy` is not satisfied + --> $DIR/migrate-fail.rs:15:37 + | +LL | let arr: [Option; 2] = [x; 2]; + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = help: the following implementations were found: + 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: std::marker::Copy` is not satisfied + --> $DIR/migrate-fail.rs:21:37 + | +LL | let arr: [Option; 2] = [x; 2]; + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = help: the following implementations were found: + 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 0000000000000..bfa8ebcfdd32a --- /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 = 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_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 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-fail.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs new file mode 100644 index 0000000000000..dc1193a2fe8f3 --- /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; 2] = [x; 2]; + //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + } + + fn no_impl_copy_value_multiple_elements() { + let x = Some(Bar); + let arr: [Option; 2] = [x; 2]; + //~^ ERROR the trait bound `std::option::Option: 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 0000000000000..fd32484ff92c1 --- /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: std::marker::Copy` is not satisfied + --> $DIR/nll-fail.rs:14:37 + | +LL | let arr: [Option; 2] = [x; 2]; + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = help: the following implementations were found: + 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: std::marker::Copy` is not satisfied + --> $DIR/nll-fail.rs:20:37 + | +LL | let arr: [Option; 2] = [x; 2]; + | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = help: the following implementations were found: + 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 0000000000000..a304f877ab7ad --- /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 = 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_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 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/run-pass.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs new file mode 100644 index 0000000000000..27bf5dabf566b --- /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 = None; + const ARR: [Option; 2] = [FOO; 2]; + + assert_eq!(ARR, [None::, None::]); +} 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 0000000000000..35484d265bb5e --- /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); + +fn main() { + [Foo(String::new()); 4]; + //~^ ERROR the trait bound `Foo: 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 0000000000000..186909e469e05 --- /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::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` + | + = help: the following implementations were found: + 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 0000000000000..be195271c10ce --- /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; 2] = [None::; 2]; + //~^ ERROR the trait bound `std::option::Option: 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 0000000000000..eed69a0c28db8 --- /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::marker::Copy` is not satisfied + --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:7:36 + | +LL | let arr: [Option; 2] = [None::; 2]; + | ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | + = help: the following implementations were found: + 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 80eff2acdd27b..d857178166a88 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] }