Skip to content

Commit

Permalink
suggest const_in_array_repeat_expression flag
Browse files Browse the repository at this point in the history
This commit adds a suggestion to add the
`#![feature(const_in_array_repeat_expression)]` attribute to the crate
when a promotable expression is used in a repeat expression.

Signed-off-by: David Wood <david@davidtw.co>
  • Loading branch information
davidtwco committed Oct 28, 2019
1 parent 03a50ae commit 92b1512
Show file tree
Hide file tree
Showing 8 changed files with 83 additions and 14 deletions.
11 changes: 10 additions & 1 deletion src/librustc/traits/error_reporting.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2112,9 +2112,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
err.note(&format!("required by cast to type `{}`",
self.ty_to_string(target)));
}
ObligationCauseCode::RepeatVec => {
ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expression) => {
err.note("the `Copy` trait is required because the \
repeated element will be copied");
if suggest_const_in_array_repeat_expression {
err.note("this array initializer can be evaluated at compile-time, for more \
information, see issue \
https://github.com/rust-lang/rust/issues/49147");
if tcx.sess.opts.unstable_features.is_nightly_build() {
err.help("add `#![feature(const_in_array_repeat_expression)]` to the \
crate attributes to enable");
}
}
}
ObligationCauseCode::VariableType(_) => {
err.note("all local variables must have a statically known size");
Expand Down
5 changes: 3 additions & 2 deletions src/librustc/traits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,8 +206,9 @@ pub enum ObligationCauseCode<'tcx> {
SizedReturnType,
/// Yield type must be Sized
SizedYieldType,
/// [T,..n] --> T must be Copy
RepeatVec,
/// [T,..n] --> T must be Copy. If `true`, suggest `const_in_array_repeat_expression` feature
/// flag.
RepeatVec(bool),

/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
FieldSized { adt_kind: AdtKind, last: bool },
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/traits/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -494,7 +494,7 @@ 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::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)),
super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
super::ConstSized => Some(super::ConstSized),
super::ConstPatternStructural => Some(super::ConstPatternStructural),
Expand Down
10 changes: 9 additions & 1 deletion src/librustc_mir/borrow_check/nll/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use crate::borrow_check::nll::type_check::free_region_relations::{
};
use crate::borrow_check::nll::universal_regions::{DefiningTy, UniversalRegions};
use crate::borrow_check::nll::ToRegionVid;
use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute;
use crate::dataflow::move_paths::MoveData;
use crate::dataflow::FlowAtLocation;
use crate::dataflow::MaybeInitializedPlaces;
Expand Down Expand Up @@ -1983,12 +1984,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
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) {
// To determine if `const_in_array_repeat_expression` feature gate should
// be mentioned, need to check if the rvalue is promotable.
let should_suggest =
should_suggest_const_in_array_repeat_expressions_attribute(
tcx, self.mir_def_id, body, operand);
debug!("check_rvalue: should_suggest={:?}", should_suggest);

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,
traits::ObligationCauseCode::RepeatVec(should_suggest),
),
self.param_env,
ty::Predicate::Trait(ty::Binder::bind(ty::TraitPredicate {
Expand Down
25 changes: 25 additions & 0 deletions src/librustc_mir/transform/promote_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1110,3 +1110,28 @@ pub fn promote_candidates<'tcx>(

promotions
}

/// This function returns `true` if the `const_in_array_repeat_expression` feature attribute should
/// be suggested. This function is probably quite expensive, it shouldn't be run in the happy path.
/// Feature attribute should be suggested if `operand` can be promoted and the feature is not
/// enabled.
crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>(
tcx: TyCtxt<'tcx>,
mir_def_id: DefId,
body: &Body<'tcx>,
operand: &Operand<'tcx>,
) -> bool {
let mut rpo = traversal::reverse_postorder(body);
let (temps, _) = collect_temps_and_candidates(tcx, body, &mut rpo);
let validator = Validator {
item: Item::new(tcx, mir_def_id, body),
temps: &temps,
explicit: false,
};

let should_promote = validator.validate_operand(operand).is_ok();
let feature_flag = tcx.features().const_in_array_repeat_expressions;
debug!("should_suggest_const_in_array_repeat_expressions_flag: mir_def_id={:?} \
should_promote={:?} feature_flag={:?}", mir_def_id, should_promote, feature_flag);
should_promote && !feature_flag
}
21 changes: 14 additions & 7 deletions src/librustc_mir/transform/qualify_consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -878,13 +878,11 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
}
},
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 && self.tcx.features().const_in_array_repeat_expressions {
debug!("assign: candidate={:?}", candidate);
self.promotion_candidates.push(candidate);
debug!("assign: self.cx.mode={:?} self.def_id={:?} location={:?} operand={:?}",
self.cx.mode, self.def_id, location, operand);
if self.should_promote_repeat_expression(operand) &&
self.tcx.features().const_in_array_repeat_expressions {
self.promotion_candidates.push(Candidate::Repeat(location));
}
},
_ => {},
Expand Down Expand Up @@ -1149,6 +1147,15 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {

candidates
}

/// Returns `true` if the operand of a repeat expression is promotable.
fn should_promote_repeat_expression(&self, operand: &Operand<'tcx>) -> bool {
let not_promotable = IsNotImplicitlyPromotable::in_operand(self, operand) ||
IsNotPromotable::in_operand(self, operand);
debug!("should_promote_repeat_expression: operand={:?} not_promotable={:?}",
operand, not_promotable);
!not_promotable
}
}

impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,16 @@

struct Bar;

// This function would compile with the feature gate, and tests that it is suggested.
fn foo() {
let arr: [Option<String>; 2] = [None::<String>; 2];
//~^ ERROR the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied [E0277]
}

// This function would not compile with the feature gate, and tests that it is not suggested.
fn bar() {
let arr: [Option<String>; 2] = [Some("foo".to_string()); 2];
//~^ ERROR the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied [E0277]
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -1,13 +1,25 @@
error[E0277]: the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied
--> $DIR/feature-gate-const_in_array_repeat_expressions.rs:7:36
--> $DIR/feature-gate-const_in_array_repeat_expressions.rs:8:36
|
LL | let arr: [Option<String>; 2] = [None::<String>; 2];
| ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<std::string::String>`
|
= help: the following implementations were found:
<std::option::Option<T> as std::marker::Copy>
= note: the `Copy` trait is required because the repeated element will be copied
= note: this array initializer can be evaluated at compile-time, for more information, see issue https://github.com/rust-lang/rust/issues/49147
= help: add `#![feature(const_in_array_repeat_expression)]` to the crate attributes to enable

error: aborting due to previous error
error[E0277]: the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied
--> $DIR/feature-gate-const_in_array_repeat_expressions.rs:14:36
|
LL | let arr: [Option<String>; 2] = [Some("foo".to_string()); 2];
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<std::string::String>`
|
= help: the following implementations were found:
<std::option::Option<T> as std::marker::Copy>
= note: the `Copy` trait is required because the repeated element will be copied

error: aborting due to 2 previous errors

For more information about this error, try `rustc --explain E0277`.

0 comments on commit 92b1512

Please sign in to comment.