Skip to content

Commit 92b1512

Browse files
committed
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 <[email protected]>
1 parent 03a50ae commit 92b1512

File tree

8 files changed

+83
-14
lines changed

8 files changed

+83
-14
lines changed

src/librustc/traits/error_reporting.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -2112,9 +2112,18 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
21122112
err.note(&format!("required by cast to type `{}`",
21132113
self.ty_to_string(target)));
21142114
}
2115-
ObligationCauseCode::RepeatVec => {
2115+
ObligationCauseCode::RepeatVec(suggest_const_in_array_repeat_expression) => {
21162116
err.note("the `Copy` trait is required because the \
21172117
repeated element will be copied");
2118+
if suggest_const_in_array_repeat_expression {
2119+
err.note("this array initializer can be evaluated at compile-time, for more \
2120+
information, see issue \
2121+
https://github.com/rust-lang/rust/issues/49147");
2122+
if tcx.sess.opts.unstable_features.is_nightly_build() {
2123+
err.help("add `#![feature(const_in_array_repeat_expression)]` to the \
2124+
crate attributes to enable");
2125+
}
2126+
}
21182127
}
21192128
ObligationCauseCode::VariableType(_) => {
21202129
err.note("all local variables must have a statically known size");

src/librustc/traits/mod.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,9 @@ pub enum ObligationCauseCode<'tcx> {
206206
SizedReturnType,
207207
/// Yield type must be Sized
208208
SizedYieldType,
209-
/// [T,..n] --> T must be Copy
210-
RepeatVec,
209+
/// [T,..n] --> T must be Copy. If `true`, suggest `const_in_array_repeat_expression` feature
210+
/// flag.
211+
RepeatVec(bool),
211212

212213
/// Types of fields (other than the last, except for packed structs) in a struct must be sized.
213214
FieldSized { adt_kind: AdtKind, last: bool },

src/librustc/traits/structural_impls.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ impl<'a, 'tcx> Lift<'tcx> for traits::ObligationCauseCode<'a> {
494494
super::SizedArgumentType => Some(super::SizedArgumentType),
495495
super::SizedReturnType => Some(super::SizedReturnType),
496496
super::SizedYieldType => Some(super::SizedYieldType),
497-
super::RepeatVec => Some(super::RepeatVec),
497+
super::RepeatVec(suggest_flag) => Some(super::RepeatVec(suggest_flag)),
498498
super::FieldSized { adt_kind, last } => Some(super::FieldSized { adt_kind, last }),
499499
super::ConstSized => Some(super::ConstSized),
500500
super::ConstPatternStructural => Some(super::ConstPatternStructural),

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

+9-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use crate::borrow_check::nll::type_check::free_region_relations::{
1616
};
1717
use crate::borrow_check::nll::universal_regions::{DefiningTy, UniversalRegions};
1818
use crate::borrow_check::nll::ToRegionVid;
19+
use crate::transform::promote_consts::should_suggest_const_in_array_repeat_expressions_attribute;
1920
use crate::dataflow::move_paths::MoveData;
2021
use crate::dataflow::FlowAtLocation;
2122
use crate::dataflow::MaybeInitializedPlaces;
@@ -1983,12 +1984,19 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
19831984
let span = body.source_info(location).span;
19841985
let ty = operand.ty(body, tcx);
19851986
if !self.infcx.type_is_copy_modulo_regions(self.param_env, ty, span) {
1987+
// To determine if `const_in_array_repeat_expression` feature gate should
1988+
// be mentioned, need to check if the rvalue is promotable.
1989+
let should_suggest =
1990+
should_suggest_const_in_array_repeat_expressions_attribute(
1991+
tcx, self.mir_def_id, body, operand);
1992+
debug!("check_rvalue: should_suggest={:?}", should_suggest);
1993+
19861994
self.infcx.report_selection_error(
19871995
&traits::Obligation::new(
19881996
ObligationCause::new(
19891997
span,
19901998
self.tcx().hir().def_index_to_hir_id(self.mir_def_id.index),
1991-
traits::ObligationCauseCode::RepeatVec,
1999+
traits::ObligationCauseCode::RepeatVec(should_suggest),
19922000
),
19932001
self.param_env,
19942002
ty::Predicate::Trait(ty::Binder::bind(ty::TraitPredicate {

src/librustc_mir/transform/promote_consts.rs

+25
Original file line numberDiff line numberDiff line change
@@ -1110,3 +1110,28 @@ pub fn promote_candidates<'tcx>(
11101110

11111111
promotions
11121112
}
1113+
1114+
/// This function returns `true` if the `const_in_array_repeat_expression` feature attribute should
1115+
/// be suggested. This function is probably quite expensive, it shouldn't be run in the happy path.
1116+
/// Feature attribute should be suggested if `operand` can be promoted and the feature is not
1117+
/// enabled.
1118+
crate fn should_suggest_const_in_array_repeat_expressions_attribute<'tcx>(
1119+
tcx: TyCtxt<'tcx>,
1120+
mir_def_id: DefId,
1121+
body: &Body<'tcx>,
1122+
operand: &Operand<'tcx>,
1123+
) -> bool {
1124+
let mut rpo = traversal::reverse_postorder(body);
1125+
let (temps, _) = collect_temps_and_candidates(tcx, body, &mut rpo);
1126+
let validator = Validator {
1127+
item: Item::new(tcx, mir_def_id, body),
1128+
temps: &temps,
1129+
explicit: false,
1130+
};
1131+
1132+
let should_promote = validator.validate_operand(operand).is_ok();
1133+
let feature_flag = tcx.features().const_in_array_repeat_expressions;
1134+
debug!("should_suggest_const_in_array_repeat_expressions_flag: mir_def_id={:?} \
1135+
should_promote={:?} feature_flag={:?}", mir_def_id, should_promote, feature_flag);
1136+
should_promote && !feature_flag
1137+
}

src/librustc_mir/transform/qualify_consts.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -878,13 +878,11 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
878878
}
879879
},
880880
ValueSource::Rvalue(&Rvalue::Repeat(ref operand, _)) => {
881-
let candidate = Candidate::Repeat(location);
882-
let not_promotable = IsNotImplicitlyPromotable::in_operand(self, operand) ||
883-
IsNotPromotable::in_operand(self, operand);
884-
debug!("assign: self.def_id={:?} operand={:?}", self.def_id, operand);
885-
if !not_promotable && self.tcx.features().const_in_array_repeat_expressions {
886-
debug!("assign: candidate={:?}", candidate);
887-
self.promotion_candidates.push(candidate);
881+
debug!("assign: self.cx.mode={:?} self.def_id={:?} location={:?} operand={:?}",
882+
self.cx.mode, self.def_id, location, operand);
883+
if self.should_promote_repeat_expression(operand) &&
884+
self.tcx.features().const_in_array_repeat_expressions {
885+
self.promotion_candidates.push(Candidate::Repeat(location));
888886
}
889887
},
890888
_ => {},
@@ -1149,6 +1147,15 @@ impl<'a, 'tcx> Checker<'a, 'tcx> {
11491147

11501148
candidates
11511149
}
1150+
1151+
/// Returns `true` if the operand of a repeat expression is promotable.
1152+
fn should_promote_repeat_expression(&self, operand: &Operand<'tcx>) -> bool {
1153+
let not_promotable = IsNotImplicitlyPromotable::in_operand(self, operand) ||
1154+
IsNotPromotable::in_operand(self, operand);
1155+
debug!("should_promote_repeat_expression: operand={:?} not_promotable={:?}",
1156+
operand, not_promotable);
1157+
!not_promotable
1158+
}
11521159
}
11531160

11541161
impl<'a, 'tcx> Visitor<'tcx> for Checker<'a, 'tcx> {

src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs

+7
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@
33

44
struct Bar;
55

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

12+
// This function would not compile with the feature gate, and tests that it is not suggested.
13+
fn bar() {
14+
let arr: [Option<String>; 2] = [Some("foo".to_string()); 2];
15+
//~^ ERROR the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied [E0277]
16+
}
17+
1118
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,25 @@
11
error[E0277]: the trait bound `std::option::Option<std::string::String>: std::marker::Copy` is not satisfied
2-
--> $DIR/feature-gate-const_in_array_repeat_expressions.rs:7:36
2+
--> $DIR/feature-gate-const_in_array_repeat_expressions.rs:8:36
33
|
44
LL | let arr: [Option<String>; 2] = [None::<String>; 2];
55
| ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option<std::string::String>`
66
|
77
= help: the following implementations were found:
88
<std::option::Option<T> as std::marker::Copy>
99
= note: the `Copy` trait is required because the repeated element will be copied
10+
= note: this array initializer can be evaluated at compile-time, for more information, see issue https://github.com/rust-lang/rust/issues/49147
11+
= help: add `#![feature(const_in_array_repeat_expression)]` to the crate attributes to enable
1012

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

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

0 commit comments

Comments
 (0)