Skip to content

Commit a336998

Browse files
committed
Auto merge of #61749 - davidtwco:rfc-2203-const-array-repeat-exprs, r=eddyb
rustc/rustc_mir: Implement RFC 2203. This PR implements RFC 2203, allowing constants in array repeat expressions. Part of #49147. r? @eddyb
2 parents 311376d + 4b1bc2d commit a336998

25 files changed

+659
-142
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# `const_in_array_repeat_expressions`
2+
3+
The tracking issue for this feature is: [#49147]
4+
5+
[#44109]: https://github.com/rust-lang/rust/issues/49147
6+
7+
------------------------
8+
9+
Relaxes the rules for repeat expressions, `[x; N]` such that `x` may also be `const` (strictly
10+
speaking rvalue promotable), in addition to `typeof(x): Copy`. The result of `[x; N]` where `x` is
11+
`const` is itself also `const`.

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

+57-33
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use rustc::mir::*;
3535
use rustc::traits::query::type_op;
3636
use rustc::traits::query::type_op::custom::CustomTypeOp;
3737
use rustc::traits::query::{Fallible, NoSolution};
38-
use rustc::traits::{ObligationCause, PredicateObligations};
38+
use rustc::traits::{self, ObligationCause, PredicateObligations};
3939
use rustc::ty::adjustment::{PointerCast};
4040
use rustc::ty::fold::TypeFoldable;
4141
use rustc::ty::subst::{Subst, SubstsRef, UnpackedKind, UserSubsts};
@@ -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+
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
1972+
self.infcx.report_selection_error(
1973+
&traits::Obligation::new(
1974+
ObligationCause::new(
1975+
span,
1976+
self.tcx().hir().def_index_to_hir_id(self.mir_def_id.index),
1977+
traits::ObligationCauseCode::RepeatVec,
1978+
),
1979+
self.param_env,
1980+
ty::Predicate::Trait(ty::Binder::bind(ty::TraitPredicate {
1981+
trait_ref: ty::TraitRef::new(
1982+
self.tcx().lang_items().copy_trait().unwrap(),
1983+
tcx.mk_substs_trait(ty, &[]),
1984+
),
1985+
})),
1986+
),
1987+
&traits::SelectionError::Unimplemented,
1988+
false,
1989+
);
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)