Skip to content

Commit

Permalink
Auto merge of #61749 - davidtwco:rfc-2203-const-array-repeat-exprs, r…
Browse files Browse the repository at this point in the history
…=eddyb

rustc/rustc_mir: Implement RFC 2203.

This PR implements RFC 2203, allowing constants in array repeat
expressions. Part of #49147.

r? @eddyb
  • Loading branch information
bors committed Jul 18, 2019
2 parents 311376d + 4b1bc2d commit a336998
Show file tree
Hide file tree
Showing 25 changed files with 659 additions and 142 deletions.
Original file line number Diff line number Diff line change
@@ -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`.
90 changes: 57 additions & 33 deletions src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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,
);
}
}
}

Expand Down Expand Up @@ -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);
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,
);
}
}
},

Rvalue::NullaryOp(_, ty) => {
Expand Down
15 changes: 15 additions & 0 deletions src/librustc_mir/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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)), _) => {
Expand Down
Loading

0 comments on commit a336998

Please sign in to comment.