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.
This commit is contained in:
David Wood 2019-05-26 12:57:00 +01:00
parent 9210359b18
commit 485a80255b
No known key found for this signature in database
GPG Key ID: 2592E76C87381FD9
17 changed files with 504 additions and 148 deletions

View File

@ -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 {

View File

@ -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 },

View File

@ -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),

View File

@ -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) => {

View File

@ -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)), _) => {

View File

@ -726,84 +726,97 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
let mut qualifs = self.qualifs_in_value(source);
if let ValueSource::Rvalue(&Rvalue::Ref(_, kind, ref place)) = source {
// Getting `true` from `HasMutInterior::in_rvalue` means
// the borrowed place is disallowed from being borrowed,
// due to either a mutable borrow (with some exceptions),
// or an shared borrow of a value with interior mutability.
// Then `HasMutInterior` is replaced with `IsNotPromotable`,
// to avoid duplicate errors (e.g. from reborrowing).
if qualifs[HasMutInterior] {
qualifs[HasMutInterior] = false;
qualifs[IsNotPromotable] = true;
match source {
ValueSource::Rvalue(&Rvalue::Ref(_, kind, ref place)) => {
// Getting `true` from `HasMutInterior::in_rvalue` means
// the borrowed place is disallowed from being borrowed,
// due to either a mutable borrow (with some exceptions),
// or an shared borrow of a value with interior mutability.
// Then `HasMutInterior` is replaced with `IsNotPromotable`,
// to avoid duplicate errors (e.g. from reborrowing).
if qualifs[HasMutInterior] {
qualifs[HasMutInterior] = false;
qualifs[IsNotPromotable] = true;
if self.mode.requires_const_checking() {
if !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
if let BorrowKind::Mut { .. } = kind {
let mut err = struct_span_err!(self.tcx.sess, self.span, E0017,
"references in {}s may only refer \
to immutable values", self.mode);
err.span_label(self.span, format!("{}s require immutable values",
self.mode));
if self.tcx.sess.teach(&err.get_code().unwrap()) {
err.note("References in statics and constants may only refer to \
immutable values.\n\n\
Statics are shared everywhere, and if they refer to \
mutable data one might violate memory safety since \
holding multiple mutable references to shared data is \
not allowed.\n\n\
If you really want global mutable state, try using \
static mut or a global UnsafeCell.");
if self.mode.requires_const_checking() {
if !self.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you {
if let BorrowKind::Mut { .. } = kind {
let mut err = struct_span_err!(self.tcx.sess, self.span, E0017,
"references in {}s may only refer \
to immutable values", self.mode);
err.span_label(self.span, format!("{}s require immutable values",
self.mode));
if self.tcx.sess.teach(&err.get_code().unwrap()) {
err.note("References in statics and constants may only refer \
to immutable values.\n\n\
Statics are shared everywhere, and if they refer to \
mutable data one might violate memory safety since \
holding multiple mutable references to shared data \
is not allowed.\n\n\
If you really want global mutable state, try using \
static mut or a global UnsafeCell.");
}
err.emit();
} else {
span_err!(self.tcx.sess, self.span, E0492,
"cannot borrow a constant which may contain \
interior mutability, create a static instead");
}
err.emit();
} else {
span_err!(self.tcx.sess, self.span, E0492,
"cannot borrow a constant which may contain \
interior mutability, create a static instead");
}
}
}
} else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind {
// Don't promote BorrowKind::Shallow borrows, as they don't
// reach codegen.
} else if let BorrowKind::Mut { .. } | BorrowKind::Shared = kind {
// Don't promote BorrowKind::Shallow borrows, as they don't
// reach codegen.
// We might have a candidate for promotion.
let candidate = Candidate::Ref(location);
// Start by traversing to the "base", with non-deref projections removed.
let mut place = place;
while let Place::Projection(ref proj) = *place {
if proj.elem == ProjectionElem::Deref {
break;
// We might have a candidate for promotion.
let candidate = Candidate::Ref(location);
// Start by traversing to the "base", with non-deref projections removed.
let mut place = place;
while let Place::Projection(ref proj) = *place {
if proj.elem == ProjectionElem::Deref {
break;
}
place = &proj.base;
}
place = &proj.base;
}
debug!("qualify_consts: promotion candidate: place={:?}", place);
// We can only promote interior borrows of promotable temps (non-temps
// don't get promoted anyway).
// (If we bailed out of the loop due to a `Deref` above, we will definitely
// not enter the conditional here.)
if let Place::Base(PlaceBase::Local(local)) = *place {
if self.body.local_kind(local) == LocalKind::Temp {
debug!("qualify_consts: promotion candidate: local={:?}", local);
// The borrowed place doesn't have `HasMutInterior`
// (from `in_rvalue`), so we can safely ignore
// `HasMutInterior` from the local's qualifications.
// This allows borrowing fields which don't have
// `HasMutInterior`, from a type that does, e.g.:
// `let _: &'static _ = &(Cell::new(1), 2).1;`
let mut local_qualifs = self.qualifs_in_local(local);
// Any qualifications, except HasMutInterior (see above), disqualify
// from promotion.
// This is, in particular, the "implicit promotion" version of
// the check making sure that we don't run drop glue during const-eval.
local_qualifs[HasMutInterior] = false;
if !local_qualifs.0.iter().any(|&qualif| qualif) {
debug!("qualify_consts: promotion candidate: {:?}", candidate);
self.promotion_candidates.push(candidate);
debug!("qualify_consts: promotion candidate: place={:?}", place);
// We can only promote interior borrows of promotable temps (non-temps
// don't get promoted anyway).
// (If we bailed out of the loop due to a `Deref` above, we will definitely
// not enter the conditional here.)
if let Place::Base(PlaceBase::Local(local)) = *place {
if self.body.local_kind(local) == LocalKind::Temp {
debug!("qualify_consts: promotion candidate: local={:?}", local);
// The borrowed place doesn't have `HasMutInterior`
// (from `in_rvalue`), so we can safely ignore
// `HasMutInterior` from the local's qualifications.
// This allows borrowing fields which don't have
// `HasMutInterior`, from a type that does, e.g.:
// `let _: &'static _ = &(Cell::new(1), 2).1;`
let mut local_qualifs = self.qualifs_in_local(local);
// Any qualifications, except HasMutInterior (see above), disqualify
// from promotion.
// This is, in particular, the "implicit promotion" version of
// the check making sure that we don't run drop glue during const-eval.
local_qualifs[HasMutInterior] = false;
if !local_qualifs.0.iter().any(|&qualif| qualif) {
debug!("qualify_consts: promotion candidate: {:?}", candidate);
self.promotion_candidates.push(candidate);
}
}
}
}
}
},
ValueSource::Rvalue(&Rvalue::Repeat(ref operand, _)) => {
let candidate = Candidate::Repeat(location);
let not_promotable = IsNotImplicitlyPromotable::in_operand(self, operand) ||
IsNotPromotable::in_operand(self, operand);
debug!("assign: self.def_id={:?} operand={:?}", self.def_id, operand);
if !not_promotable {
debug!("assign: candidate={:?}", candidate);
self.promotion_candidates.push(candidate);
}
},
_ => {},
}
let mut dest = dest;
@ -933,15 +946,20 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
debug!("qualify_const: promotion_candidates={:?}", self.promotion_candidates);
for candidate in &self.promotion_candidates {
match *candidate {
Candidate::Repeat(Location { block: bb, statement_index: stmt_idx }) => {
if let StatementKind::Assign(_, box Rvalue::Repeat(
Operand::Move(Place::Base(PlaceBase::Local(index))),
_
)) = self.body[bb].statements[stmt_idx].kind {
promoted_temps.insert(index);
}
}
Candidate::Ref(Location { block: bb, statement_index: stmt_idx }) => {
match self.body[bb].statements[stmt_idx].kind {
StatementKind::Assign(
_,
box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index)))
) => {
promoted_temps.insert(index);
}
_ => {}
if let StatementKind::Assign(
_,
box Rvalue::Ref(_, _, Place::Base(PlaceBase::Local(index)))
) = self.body[bb].statements[stmt_idx].kind {
promoted_temps.insert(index);
}
}
Candidate::Argument { .. } => {}

View File

@ -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 {

View File

@ -3,11 +3,12 @@
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; {N}]
//~^ ERROR array lengths can't depend on generic parameters
}
fn g<T, const N: usize>(x: T) -> [T; N] {
[x; {N}]
//~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277]
//~^ ERROR array lengths can't depend on generic parameters
}
fn main() {

View File

@ -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`.

View File

@ -3,11 +3,12 @@
fn f<T: Copy, const N: usize>(x: T) -> [T; N] {
[x; N]
//~^ ERROR array lengths can't depend on generic parameters
}
fn g<T, const N: usize>(x: T) -> [T; N] {
[x; N]
//~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277]
//~^ ERROR array lengths can't depend on generic parameters
}
fn main() {

View File

@ -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`.

View File

@ -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<Bar> = None;
const ARR: [Option<Bar>; 0] = [FOO; 0];
}
fn no_impl_copy_empty_value_single_element() {
const FOO: Option<Bar> = None;
const ARR: [Option<Bar>; 1] = [FOO; 1];
}
fn no_impl_copy_empty_value_multiple_elements() {
const FOO: Option<Bar> = None;
const ARR: [Option<Bar>; 2] = [FOO; 2];
}
fn no_impl_copy_value_no_elements() {
const FOO: Option<Bar> = Some(Bar);
const ARR: [Option<Bar>; 0] = [FOO; 0];
}
fn no_impl_copy_value_single_element() {
const FOO: Option<Bar> = Some(Bar);
const ARR: [Option<Bar>; 1] = [FOO; 1];
}
fn no_impl_copy_value_multiple_elements() {
const FOO: Option<Bar> = Some(Bar);
const ARR: [Option<Bar>; 2] = [FOO; 2];
}
fn impl_copy_empty_value_no_elements() {
const FOO: Option<u32> = None;
const ARR: [Option<u32>; 0] = [FOO; 0];
}
fn impl_copy_empty_value_one_element() {
const FOO: Option<u32> = None;
const ARR: [Option<u32>; 1] = [FOO; 1];
}
fn impl_copy_empty_value_multiple_elements() {
const FOO: Option<u32> = None;
const ARR: [Option<u32>; 2] = [FOO; 2];
}
fn impl_copy_value_no_elements() {
const FOO: Option<u32> = Some(4);
const ARR: [Option<u32>; 0] = [FOO; 0];
}
fn impl_copy_value_one_element() {
const FOO: Option<u32> = Some(4);
const ARR: [Option<u32>; 1] = [FOO; 1];
}
fn impl_copy_value_multiple_elements() {
const FOO: Option<u32> = Some(4);
const ARR: [Option<u32>; 2] = [FOO; 2];
}
}
mod non_constants {
use Bar;
fn no_impl_copy_empty_value_no_elements() {
let x = None;
let arr: [Option<Bar>; 0] = [x; 0];
}
fn no_impl_copy_empty_value_single_element() {
let x = None;
let arr: [Option<Bar>; 1] = [x; 1];
}
fn no_impl_copy_empty_value_multiple_elements() {
let x = None;
let arr: [Option<Bar>; 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<Bar>; 0] = [x; 0];
}
fn no_impl_copy_value_single_element() {
let x = Some(Bar);
let arr: [Option<Bar>; 1] = [x; 1];
}
fn no_impl_copy_value_multiple_elements() {
let x = Some(Bar);
let arr: [Option<Bar>; 2] = [x; 2];
//~^ ERROR repeated expression does not implement `std::marker::Copy`
}
fn impl_copy_empty_value_no_elements() {
let x: Option<u32> = None;
let arr: [Option<u32>; 0] = [x; 0];
}
fn impl_copy_empty_value_one_element() {
let x: Option<u32> = None;
let arr: [Option<u32>; 1] = [x; 1];
}
fn impl_copy_empty_value_multiple_elements() {
let x: Option<u32> = None;
let arr: [Option<u32>; 2] = [x; 2];
}
fn impl_copy_value_no_elements() {
let x: Option<u32> = Some(4);
let arr: [Option<u32>; 0] = [x; 0];
}
fn impl_copy_value_one_element() {
let x: Option<u32> = Some(4);
let arr: [Option<u32>; 1] = [x; 1];
}
fn impl_copy_value_multiple_elements() {
let x: Option<u32> = Some(4);
let arr: [Option<u32>; 2] = [x; 2];
}
}
fn main() {}

View File

@ -0,0 +1,18 @@
error: repeated expression does not implement `std::marker::Copy`
--> $DIR/migrate-borrowck.rs:87:37
|
LL | let arr: [Option<Bar>; 2] = [x; 2];
| ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<Bar>`
|
= 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<Bar>; 2] = [x; 2];
| ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<Bar>`
|
= note: the `std::marker::Copy` trait is required because the repeated element will be copied
error: aborting due to 2 previous errors

View File

@ -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<Bar> = None;
const ARR: [Option<Bar>; 0] = [FOO; 0];
}
fn no_impl_copy_empty_value_single_element() {
const FOO: Option<Bar> = None;
const ARR: [Option<Bar>; 1] = [FOO; 1];
}
fn no_impl_copy_empty_value_multiple_elements() {
const FOO: Option<Bar> = None;
const ARR: [Option<Bar>; 2] = [FOO; 2];
}
fn no_impl_copy_value_no_elements() {
const FOO: Option<Bar> = Some(Bar);
const ARR: [Option<Bar>; 0] = [FOO; 0];
}
fn no_impl_copy_value_single_element() {
const FOO: Option<Bar> = Some(Bar);
const ARR: [Option<Bar>; 1] = [FOO; 1];
}
fn no_impl_copy_value_multiple_elements() {
const FOO: Option<Bar> = Some(Bar);
const ARR: [Option<Bar>; 2] = [FOO; 2];
}
fn impl_copy_empty_value_no_elements() {
const FOO: Option<u32> = None;
const ARR: [Option<u32>; 0] = [FOO; 0];
}
fn impl_copy_empty_value_one_element() {
const FOO: Option<u32> = None;
const ARR: [Option<u32>; 1] = [FOO; 1];
}
fn impl_copy_empty_value_multiple_elements() {
const FOO: Option<u32> = None;
const ARR: [Option<u32>; 2] = [FOO; 2];
}
fn impl_copy_value_no_elements() {
const FOO: Option<u32> = Some(4);
const ARR: [Option<u32>; 0] = [FOO; 0];
}
fn impl_copy_value_one_element() {
const FOO: Option<u32> = Some(4);
const ARR: [Option<u32>; 1] = [FOO; 1];
}
fn impl_copy_value_multiple_elements() {
const FOO: Option<u32> = Some(4);
const ARR: [Option<u32>; 2] = [FOO; 2];
}
}
mod non_constants {
use Bar;
fn no_impl_copy_empty_value_no_elements() {
let x = None;
let arr: [Option<Bar>; 0] = [x; 0];
}
fn no_impl_copy_empty_value_single_element() {
let x = None;
let arr: [Option<Bar>; 1] = [x; 1];
}
fn no_impl_copy_empty_value_multiple_elements() {
let x = None;
let arr: [Option<Bar>; 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<Bar>; 0] = [x; 0];
}
fn no_impl_copy_value_single_element() {
let x = Some(Bar);
let arr: [Option<Bar>; 1] = [x; 1];
}
fn no_impl_copy_value_multiple_elements() {
let x = Some(Bar);
let arr: [Option<Bar>; 2] = [x; 2];
//~^ ERROR repeated expression does not implement `std::marker::Copy`
}
fn impl_copy_empty_value_no_elements() {
let x: Option<u32> = None;
let arr: [Option<u32>; 0] = [x; 0];
}
fn impl_copy_empty_value_one_element() {
let x: Option<u32> = None;
let arr: [Option<u32>; 1] = [x; 1];
}
fn impl_copy_empty_value_multiple_elements() {
let x: Option<u32> = None;
let arr: [Option<u32>; 2] = [x; 2];
}
fn impl_copy_value_no_elements() {
let x: Option<u32> = Some(4);
let arr: [Option<u32>; 0] = [x; 0];
}
fn impl_copy_value_one_element() {
let x: Option<u32> = Some(4);
let arr: [Option<u32>; 1] = [x; 1];
}
fn impl_copy_value_multiple_elements() {
let x: Option<u32> = Some(4);
let arr: [Option<u32>; 2] = [x; 2];
}
}
fn main() {}

View File

@ -0,0 +1,18 @@
error: repeated expression does not implement `std::marker::Copy`
--> $DIR/nll-borrowck.rs:87:37
|
LL | let arr: [Option<Bar>; 2] = [x; 2];
| ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<Bar>`
|
= 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<Bar>; 2] = [x; 2];
| ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<Bar>`
|
= note: the `std::marker::Copy` trait is required because the repeated element will be copied
error: aborting due to 2 previous errors

View File

@ -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`
}

View File

@ -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`.