about summary refs log tree commit diff
diff options
context:
space:
mode:
authorDavid Wood <david@davidtw.co>2019-10-26 23:59:24 +0100
committerDavid Wood <david@davidtw.co>2019-10-28 18:37:49 +0000
commit92b151287fcda73db8e95eeca8be97d66905626d (patch)
tree6d5755c6e0e889c27150d38fa9c83ae6d65760fd
parent03a50ae9b87021d4a166c70d2c932f1cb0aa8f28 (diff)
downloadrust-92b151287fcda73db8e95eeca8be97d66905626d.tar.gz
rust-92b151287fcda73db8e95eeca8be97d66905626d.zip
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>
-rw-r--r--src/librustc/traits/error_reporting.rs11
-rw-r--r--src/librustc/traits/mod.rs5
-rw-r--r--src/librustc/traits/structural_impls.rs2
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs10
-rw-r--r--src/librustc_mir/transform/promote_consts.rs25
-rw-r--r--src/librustc_mir/transform/qualify_consts.rs21
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs7
-rw-r--r--src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr16
8 files changed, 83 insertions, 14 deletions
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index b2e5624f476..b55c0f29a70 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -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");
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index 04c1b4d927a..b8275299562 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -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 },
diff --git a/src/librustc/traits/structural_impls.rs b/src/librustc/traits/structural_impls.rs
index d9b796d063e..109e884f8bd 100644
--- a/src/librustc/traits/structural_impls.rs
+++ b/src/librustc/traits/structural_impls.rs
@@ -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),
diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
index b5560fe6751..9f2f174553f 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -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 {
diff --git a/src/librustc_mir/transform/promote_consts.rs b/src/librustc_mir/transform/promote_consts.rs
index 3af08090853..8def717f158 100644
--- a/src/librustc_mir/transform/promote_consts.rs
+++ b/src/librustc_mir/transform/promote_consts.rs
@@ -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
+}
diff --git a/src/librustc_mir/transform/qualify_consts.rs b/src/librustc_mir/transform/qualify_consts.rs
index 2f77cd5ddf7..3702dd9ad49 100644
--- a/src/librustc_mir/transform/qualify_consts.rs
+++ b/src/librustc_mir/transform/qualify_consts.rs
@@ -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> {
diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs
index be195271c10..c3c554d7d27 100644
--- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs
+++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs
@@ -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() {}
diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr
index eed69a0c28d..cd9242de88f 100644
--- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr
+++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr
@@ -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`.