Skip to content

Commit 485a802

Browse files
committed
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.
1 parent 9210359 commit 485a802

File tree

17 files changed

+505
-149
lines changed

17 files changed

+505
-149
lines changed

src/librustc/traits/error_reporting.rs

-4
Original file line numberDiff line numberDiff line change
@@ -1564,10 +1564,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
15641564
err.note(&format!("required for the cast to the object type `{}`",
15651565
self.ty_to_string(object_ty)));
15661566
}
1567-
ObligationCauseCode::RepeatVec => {
1568-
err.note("the `Copy` trait is required because the \
1569-
repeated element will be copied");
1570-
}
15711567
ObligationCauseCode::VariableType(_) => {
15721568
err.note("all local variables must have a statically known size");
15731569
if !self.tcx.features().unsized_locals {

src/librustc/traits/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,6 @@ pub enum ObligationCauseCode<'tcx> {
195195
SizedReturnType,
196196
/// Yield type must be Sized
197197
SizedYieldType,
198-
/// [T,..n] --> T must be Copy
199-
RepeatVec,
200198

201199
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
202200
FieldSized { adt_kind: AdtKind, last: bool },

src/librustc/traits/structural_impls.rs

-1
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,6 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
488488
super::SizedArgumentType => Some(super::SizedArgumentType),
489489
super::SizedReturnType => Some(super::SizedReturnType),
490490
super::SizedYieldType => Some(super::SizedYieldType),
491-
super::RepeatVec => Some(super::RepeatVec),
492491
super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
493492
super::ConstSized => Some(super::ConstSized),
494493
super::SharedStatic => Some(super::SharedStatic),

src/librustc_mir/borrow_check/nll/type_check/mod.rs

+56-32
Original file line numberDiff line numberDiff line change
@@ -501,28 +501,38 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
501501
// FIXME use place_projection.is_empty() when is available
502502
if let Place::Base(_) = place {
503503
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
504-
let tcx = self.tcx();
505-
let trait_ref = ty::TraitRef {
506-
def_id: tcx.lang_items().copy_trait().unwrap(),
507-
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
504+
let is_promoted = match place {
505+
Place::Base(PlaceBase::Static(box Static {
506+
kind: StaticKind::Promoted(_),
507+
..
508+
})) => true,
509+
_ => false,
508510
};
509511

510-
// In order to have a Copy operand, the type T of the
511-
// value must be Copy. Note that we prove that T: Copy,
512-
// rather than using the `is_copy_modulo_regions`
513-
// test. This is important because
514-
// `is_copy_modulo_regions` ignores the resulting region
515-
// obligations and assumes they pass. This can result in
516-
// bounds from Copy impls being unsoundly ignored (e.g.,
517-
// #29149). Note that we decide to use Copy before knowing
518-
// whether the bounds fully apply: in effect, the rule is
519-
// that if a value of some type could implement Copy, then
520-
// it must.
521-
self.cx.prove_trait_ref(
522-
trait_ref,
523-
location.to_locations(),
524-
ConstraintCategory::CopyBound,
525-
);
512+
if !is_promoted {
513+
let tcx = self.tcx();
514+
let trait_ref = ty::TraitRef {
515+
def_id: tcx.lang_items().copy_trait().unwrap(),
516+
substs: tcx.mk_substs_trait(place_ty.ty, &[]),
517+
};
518+
519+
// In order to have a Copy operand, the type T of the
520+
// value must be Copy. Note that we prove that T: Copy,
521+
// rather than using the `is_copy_modulo_regions`
522+
// test. This is important because
523+
// `is_copy_modulo_regions` ignores the resulting region
524+
// obligations and assumes they pass. This can result in
525+
// bounds from Copy impls being unsoundly ignored (e.g.,
526+
// #29149). Note that we decide to use Copy before knowing
527+
// whether the bounds fully apply: in effect, the rule is
528+
// that if a value of some type could implement Copy, then
529+
// it must.
530+
self.cx.prove_trait_ref(
531+
trait_ref,
532+
location.to_locations(),
533+
ConstraintCategory::CopyBound,
534+
);
535+
}
526536
}
527537
}
528538

@@ -1953,18 +1963,32 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
19531963
}
19541964

19551965
Rvalue::Repeat(operand, len) => if *len > 1 {
1956-
let operand_ty = operand.ty(body, tcx);
1957-
1958-
let trait_ref = ty::TraitRef {
1959-
def_id: tcx.lang_items().copy_trait().unwrap(),
1960-
substs: tcx.mk_substs_trait(operand_ty, &[]),
1961-
};
1962-
1963-
self.prove_trait_ref(
1964-
trait_ref,
1965-
location.to_locations(),
1966-
ConstraintCategory::CopyBound,
1967-
);
1966+
if let Operand::Move(_) = operand {
1967+
// While this is located in `nll::typeck` this error is not an NLL error, it's
1968+
// a required check to make sure that repeated elements implement `Copy`.
1969+
let span = body.source_info(location).span;
1970+
let ty = operand.ty(body, tcx);
1971+
let is_copy = self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span);
1972+
if !is_copy {
1973+
let copy_path = self.tcx().def_path_str(
1974+
self.tcx().lang_items().copy_trait().unwrap());
1975+
self.tcx().sess
1976+
.struct_span_err(
1977+
span,
1978+
&format!("repeated expression does not implement `{}`", copy_path),
1979+
)
1980+
.span_label(span, &format!(
1981+
"the trait `{}` is not implemented for `{}`",
1982+
copy_path, ty,
1983+
))
1984+
.note(&format!(
1985+
"the `{}` trait is required because the repeated element will be \
1986+
copied",
1987+
copy_path,
1988+
))
1989+
.emit();
1990+
}
1991+
}
19681992
},
19691993

19701994
Rvalue::NullaryOp(_, ty) => {

src/librustc_mir/transform/promote_consts.rs

+15
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ pub enum Candidate {
6060
/// Borrow of a constant temporary.
6161
Ref(Location),
6262

63+
/// Promotion of the `x` in `[x; 32]`.
64+
Repeat(Location),
65+
6366
/// Currently applied to function calls where the callee has the unstable
6467
/// `#[rustc_args_required_const]` attribute as well as the SIMD shuffle
6568
/// intrinsic. The intrinsic requires the arguments are indeed constant and
@@ -322,6 +325,17 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
322325
_ => bug!()
323326
}
324327
}
328+
Candidate::Repeat(loc) => {
329+
let ref mut statement = blocks[loc.block].statements[loc.statement_index];
330+
match statement.kind {
331+
StatementKind::Assign(_, box Rvalue::Repeat(ref mut operand, _)) => {
332+
let ty = operand.ty(local_decls, self.tcx);
333+
let span = statement.source_info.span;
334+
mem::replace(operand, Operand::Copy(promoted_place(ty, span)))
335+
}
336+
_ => bug!()
337+
}
338+
},
325339
Candidate::Argument { bb, index } => {
326340
let terminator = blocks[bb].terminator_mut();
327341
match terminator.kind {
@@ -380,6 +394,7 @@ pub fn promote_candidates<'tcx>(
380394

381395
for candidate in candidates.into_iter().rev() {
382396
match candidate {
397+
Candidate::Repeat(Location { block, statement_index }) |
383398
Candidate::Ref(Location { block, statement_index }) => {
384399
match body[block].statements[statement_index].kind {
385400
StatementKind::Assign(Place::Base(PlaceBase::Local(local)), _) => {

0 commit comments

Comments
 (0)