From 485a80255b13840551e08f34a268528bbb2a33d9 Mon Sep 17 00:00:00 2001 From: David Wood Date: Sun, 26 May 2019 12:57:00 +0100 Subject: [PATCH 1/5] rustc/rustc_mir: Implement RFC 2203. This commit implements RFC 2203, allowing constants in array repeat expressions. Firstly, the check that the array repeat expression implements `Copy` is removed and re-implemented in `rustc_mir::borrow_check::nll::type_check` by emitting an error when the MIR contains a `Operand::Move` and the type does not implement `Copy`. Next, the `qualify_consts` pass is modified to construct a `Candidate::Repeat` when it would be correct to promote a array repeat expression. Finally, the `promote_consts` pass is modified to promote the candidates previously identified. --- src/librustc/traits/error_reporting.rs | 4 - src/librustc/traits/mod.rs | 2 - src/librustc/traits/structural_impls.rs | 1 - .../borrow_check/nll/type_check/mod.rs | 88 +++++---- src/librustc_mir/transform/promote_consts.rs | 15 ++ src/librustc_mir/transform/qualify_consts.rs | 174 ++++++++++-------- src/librustc_typeck/check/expr.rs | 13 +- src/test/ui/const-generics/issue-61336-2.rs | 3 +- .../ui/const-generics/issue-61336-2.stderr | 16 +- src/test/ui/const-generics/issue-61336.rs | 3 +- src/test/ui/const-generics/issue-61336.stderr | 16 +- .../migrate-borrowck.rs | 138 ++++++++++++++ .../migrate-borrowck.stderr | 18 ++ .../nll-borrowck.rs | 138 ++++++++++++++ .../nll-borrowck.stderr | 18 ++ src/test/ui/repeat-to-run-dtor-twice.rs | 2 +- src/test/ui/repeat-to-run-dtor-twice.stderr | 5 +- 17 files changed, 505 insertions(+), 149 deletions(-) create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.rs create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.stderr create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.rs create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.stderr diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index d6cc68bcdab46..a7b3a2cab119a 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 1ca92d79fa5f6..b90f4ef91ce9c 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 129a400d28f4c..7d160af1a5619 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 cdbbe1d02bd92..90812599f93c8 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 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 2dffafd6e54c0..0b90076bd4688 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. - - // 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 { + 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 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/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/migrate-borrowck.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.rs new file mode 100644 index 0000000000000..9bed2b7197ce2 --- /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 0000000000000..7a9b6a099b728 --- /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 0000000000000..054a0139109b0 --- /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 0000000000000..5cd6d2a8f0637 --- /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 80eff2acdd27b..14336435fe8cd 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 5434f6cef544f..dff6332f61bf1 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`. From 3cca4ceed833493b7ce18c825f14ddd927920e10 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 12 Jun 2019 07:56:07 +0100 Subject: [PATCH 2/5] syntax: Add feature gate. This commit adds a `const_in_array_repeat_expressions` feature gate and only create `Candidate::Repeat` if it is enabled. --- .../const-in-array-repeat-expressions.md | 11 +++++++++++ src/librustc_mir/transform/qualify_consts.rs | 2 +- src/libsyntax/feature_gate.rs | 7 +++++-- src/libsyntax_pos/symbol.rs | 1 + .../migrate-borrowck.rs | 1 + .../migrate-borrowck.stderr | 4 ++-- .../nll-borrowck.rs | 2 +- ...eature-gate-const_in_array_repeat_expressions.rs | 11 +++++++++++ ...re-gate-const_in_array_repeat_expressions.stderr | 13 +++++++++++++ 9 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 src/doc/unstable-book/src/language-features/const-in-array-repeat-expressions.md create mode 100644 src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs create mode 100644 src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr 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/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs index 0b90076bd4688..f980c717d6e16 100644 --- a/src/librustc_mir/transform/qualify_consts.rs +++ b/src/librustc_mir/transform/qualify_consts.rs @@ -811,7 +811,7 @@ impl<'a, 'tcx> Checker<'a, 'tcx> { 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 { + if !not_promotable && self.tcx.features().const_in_array_repeat_expressions { debug!("assign: candidate={:?}", candidate); self.promotion_candidates.push(candidate); } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index fd1cb3d803b09..ca3e6d254bd1d 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -562,10 +562,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. @@ -580,6 +580,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 89fcf3b1f8f19..670e445a30bf8 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/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.rs index 9bed2b7197ce2..fb944df14c852 100644 --- 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 @@ -1,5 +1,6 @@ // ignore-compile-mode-nll // compile-flags: -Z borrowck=migrate +#![feature(constants_in_array_repeat_expressions)] #![allow(warnings)] // Some type that is not copyable. 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 index 7a9b6a099b728..5de0cd505eb77 100644 --- 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 @@ -1,5 +1,5 @@ error: repeated expression does not implement `std::marker::Copy` - --> $DIR/migrate-borrowck.rs:87:37 + --> $DIR/migrate-borrowck.rs:88:37 | LL | let arr: [Option; 2] = [x; 2]; | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` @@ -7,7 +7,7 @@ LL | let arr: [Option; 2] = [x; 2]; = 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 + --> $DIR/migrate-borrowck.rs:104:37 | LL | let arr: [Option; 2] = [x; 2]; | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` 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 index 054a0139109b0..eed7be5f16efa 100644 --- 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 @@ -1,6 +1,6 @@ // ignore-compile-mode-nll #![allow(warnings)] -#![feature(nll)] +#![feature(constants_in_array_repeat_expressions, nll)] // Some type that is not copyable. struct Bar; 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`. From 813c994a754b963660b2030699ee1b77c5886ed5 Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 12 Jun 2019 08:26:16 +0100 Subject: [PATCH 3/5] rustc_mir: Re-use `report_selection_error`. This commit replaces the new error that was being emitted in NLL type check with a call to `report_selection_error` so that the same trait error as before this PR is emitted. --- src/librustc/traits/error_reporting.rs | 4 ++ src/librustc/traits/mod.rs | 2 + src/librustc/traits/structural_impls.rs | 1 + .../borrow_check/nll/type_check/mod.rs | 40 +++++++++---------- .../migrate-borrowck.rs | 4 +- .../migrate-borrowck.stderr | 13 ++++-- .../nll-borrowck.rs | 4 +- .../nll-borrowck.stderr | 13 ++++-- src/test/ui/repeat-to-run-dtor-twice.rs | 2 +- src/test/ui/repeat-to-run-dtor-twice.stderr | 5 ++- 10 files changed, 53 insertions(+), 35 deletions(-) diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index a7b3a2cab119a..d6cc68bcdab46 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -1564,6 +1564,10 @@ 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 b90f4ef91ce9c..1ca92d79fa5f6 100644 --- a/src/librustc/traits/mod.rs +++ b/src/librustc/traits/mod.rs @@ -195,6 +195,8 @@ 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 7d160af1a5619..129a400d28f4c 100644 --- a/src/librustc/traits/structural_impls.rs +++ b/src/librustc/traits/structural_impls.rs @@ -488,6 +488,7 @@ 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 90812599f93c8..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}; @@ -1968,25 +1968,25 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { // 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(); + 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, + ); } } }, 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 index fb944df14c852..5e7f11799c8a0 100644 --- 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 @@ -86,7 +86,7 @@ mod non_constants { 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` + //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] } fn no_impl_copy_value_no_elements() { @@ -102,7 +102,7 @@ mod non_constants { 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` + //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] } fn impl_copy_empty_value_no_elements() { 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 index 5de0cd505eb77..71f5a8ccaa224 100644 --- 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 @@ -1,18 +1,23 @@ -error: repeated expression does not implement `std::marker::Copy` +error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied --> $DIR/migrate-borrowck.rs:88: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 + = help: the following implementations were found: + as std::marker::Copy> + = note: the `Copy` trait is required because the repeated element will be copied -error: repeated expression does not implement `std::marker::Copy` +error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied --> $DIR/migrate-borrowck.rs:104: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 + = 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-borrowck.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.rs index eed7be5f16efa..804aa6b7c6d71 100644 --- 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 @@ -85,7 +85,7 @@ mod non_constants { 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` + //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] } fn no_impl_copy_value_no_elements() { @@ -101,7 +101,7 @@ mod non_constants { 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` + //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] } fn impl_copy_empty_value_no_elements() { 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 index 5cd6d2a8f0637..0b2da5933a1c7 100644 --- 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 @@ -1,18 +1,23 @@ -error: repeated expression does not implement `std::marker::Copy` +error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied --> $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 + = help: the following implementations were found: + as std::marker::Copy> + = note: the `Copy` trait is required because the repeated element will be copied -error: repeated expression does not implement `std::marker::Copy` +error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied --> $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 + = 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/repeat-to-run-dtor-twice.rs b/src/test/ui/repeat-to-run-dtor-twice.rs index 14336435fe8cd..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 repeated expression does not implement `std::marker::Copy` + //~^ ERROR the trait bound `Foo: std::marker::Copy` is not satisfied [E0277] } diff --git a/src/test/ui/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-to-run-dtor-twice.stderr index dff6332f61bf1..5434f6cef544f 100644 --- a/src/test/ui/repeat-to-run-dtor-twice.stderr +++ b/src/test/ui/repeat-to-run-dtor-twice.stderr @@ -1,10 +1,11 @@ -error: repeated expression does not implement `std::marker::Copy` +error[E0277]: the trait bound `Foo: std::marker::Copy` is not satisfied --> $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 `std::marker::Copy` trait is required because the repeated element will be copied + = 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`. From a655438988c5f7d100a5423752b7ae0287d582fd Mon Sep 17 00:00:00 2001 From: David Wood Date: Wed, 12 Jun 2019 08:46:56 +0100 Subject: [PATCH 4/5] tests: Update and add tests for RFC 2203. --- .../migrate-fail.rs | 26 +++++++++++++++++++ ...ll-borrowck.stderr => migrate-fail.stderr} | 4 +-- .../{migrate-borrowck.rs => migrate-pass.rs} | 17 +++--------- .../nll-fail.rs | 25 ++++++++++++++++++ ...igrate-borrowck.stderr => nll-fail.stderr} | 4 +-- .../{nll-borrowck.rs => nll-pass.rs} | 17 +++--------- .../run-pass.rs | 12 +++++++++ .../trait-error.rs | 10 +++++++ .../trait-error.stderr | 13 ++++++++++ 9 files changed, 96 insertions(+), 32 deletions(-) create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs rename src/test/ui/consts/rfc-2203-const-array-repeat-exprs/{nll-borrowck.stderr => migrate-fail.stderr} (94%) rename src/test/ui/consts/rfc-2203-const-array-repeat-exprs/{migrate-borrowck.rs => migrate-pass.rs} (85%) create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs rename src/test/ui/consts/rfc-2203-const-array-repeat-exprs/{migrate-borrowck.stderr => nll-fail.stderr} (93%) rename src/test/ui/consts/rfc-2203-const-array-repeat-exprs/{nll-borrowck.rs => nll-pass.rs} (85%) create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/run-pass.rs create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr 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/nll-borrowck.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr similarity index 94% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.stderr rename to src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr index 0b2da5933a1c7..aad6763f15094 100644 --- 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/migrate-fail.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/nll-borrowck.rs:87:37 + --> $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` @@ -9,7 +9,7 @@ LL | let arr: [Option; 2] = [x; 2]; = 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-borrowck.rs:103:37 + --> $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` 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-pass.rs similarity index 85% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.rs rename to src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-pass.rs index 5e7f11799c8a0..bfa8ebcfdd32a 100644 --- 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-pass.rs @@ -1,6 +1,7 @@ -// ignore-compile-mode-nll +// check-pass // compile-flags: -Z borrowck=migrate -#![feature(constants_in_array_repeat_expressions)] +// ignore-compare-mode-nll +#![feature(const_in_array_repeat_expressions)] #![allow(warnings)] // Some type that is not copyable. @@ -83,12 +84,6 @@ mod non_constants { let arr: [Option; 1] = [x; 1]; } - 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_no_elements() { let x = Some(Bar); let arr: [Option; 0] = [x; 0]; @@ -99,12 +94,6 @@ mod non_constants { let arr: [Option; 1] = [x; 1]; } - 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 impl_copy_empty_value_no_elements() { let x: Option = None; let arr: [Option; 0] = [x; 0]; 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/migrate-borrowck.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr similarity index 93% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-borrowck.stderr rename to src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr index 71f5a8ccaa224..fd32484ff92c1 100644 --- 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/nll-fail.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/migrate-borrowck.rs:88:37 + --> $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` @@ -9,7 +9,7 @@ LL | let arr: [Option; 2] = [x; 2]; = 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-borrowck.rs:104:37 + --> $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` 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-pass.rs similarity index 85% rename from src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-borrowck.rs rename to src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-pass.rs index 804aa6b7c6d71..a304f877ab7ad 100644 --- 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-pass.rs @@ -1,6 +1,7 @@ -// ignore-compile-mode-nll +// check-pass +// ignore-compare-mode-nll #![allow(warnings)] -#![feature(constants_in_array_repeat_expressions, nll)] +#![feature(const_in_array_repeat_expressions, nll)] // Some type that is not copyable. struct Bar; @@ -82,12 +83,6 @@ mod non_constants { let arr: [Option; 1] = [x; 1]; } - 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_no_elements() { let x = Some(Bar); let arr: [Option; 0] = [x; 0]; @@ -98,12 +93,6 @@ mod non_constants { let arr: [Option; 1] = [x; 1]; } - 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 impl_copy_empty_value_no_elements() { let x: Option = None; let arr: [Option; 0] = [x; 0]; 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`. From 4b1bc2ded91915e232c38cc503b5f110556cf719 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 13 Jun 2019 17:30:49 +0100 Subject: [PATCH 5/5] tests: Add tests that use const fns. --- .../const-fns.rs | 26 +++++++++++++++++++ .../const-fns.stderr | 13 ++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-fns.rs create mode 100644 src/test/ui/consts/rfc-2203-const-array-repeat-exprs/const-fns.stderr 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`.