suggest const_in_array_repeat_expression flag

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>
This commit is contained in:
David Wood 2019-10-26 23:59:24 +01:00
parent 03a50ae9b8
commit 92b151287f
No known key found for this signature in database
GPG key ID: 2592E76C87381FD9
8 changed files with 83 additions and 14 deletions

View file

@ -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");

View file

@ -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 },

View file

@ -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),

View file

@ -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;
@ -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 {

View file

@ -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
}

View file

@ -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));
}
},
_ => {},
@ -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> {

View file

@ -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() {}

View file

@ -1,5 +1,5 @@
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>`
@ -7,7 +7,19 @@ LL | let arr: [Option<String>; 2] = [None::<String>; 2];
= 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`.