Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc/rustc_mir: Implement RFC 2203. #61749

Merged
merged 5 commits into from
Jul 19, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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!()
davidtwco marked this conversation as resolved.
Show resolved Hide resolved
}
},
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