mirror of
https://github.com/rust-lang/rust.git
synced 2024-12-02 11:44:28 +00:00
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:
parent
9210359b18
commit
485a80255b
@ -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 {
|
||||
|
@ -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 },
|
||||
|
@ -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),
|
||||
|
@ -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) => {
|
||||
|
@ -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)), _) => {
|
||||
|
@ -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 { .. } => {}
|
||||
|
@ -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 {
|
||||
|
@ -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() {
|
||||
|
@ -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`.
|
||||
|
@ -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() {
|
||||
|
@ -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`.
|
||||
|
@ -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() {}
|
@ -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
|
||||
|
@ -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() {}
|
@ -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
|
||||
|
@ -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`
|
||||
}
|
||||
|
@ -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`.
|
||||
|
Loading…
Reference in New Issue
Block a user