about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-11-26 04:26:19 +0000
committerbors <bors@rust-lang.org>2017-11-26 04:26:19 +0000
commit2f84fb5cc1ac5f04bdf5a281997e02bcf4fc18d9 (patch)
treef420fc9945cea3345529c5af66b9d93eed0058a1 /src
parent693bb0dae24101f1699949ec02917167a6c172d5 (diff)
parent62cb74af3cb0abc4243a5e7db090749b0100d827 (diff)
downloadrust-2f84fb5cc1ac5f04bdf5a281997e02bcf4fc18d9.tar.gz
rust-2f84fb5cc1ac5f04bdf5a281997e02bcf4fc18d9.zip
Auto merge of #46033 - sinkuu:const-enum-match-check, r=arielb1
Do match-check for consts

Fixes #43195 (ICE caused by building MIR that contains non-exausitive match)
Diffstat (limited to 'src')
-rw-r--r--src/librustc/dep_graph/dep_node.rs1
-rw-r--r--src/librustc/ich/impls_ty.rs3
-rw-r--r--src/librustc/middle/const_val.rs9
-rw-r--r--src/librustc/ty/maps/mod.rs5
-rw-r--r--src/librustc/ty/maps/plumbing.rs1
-rw-r--r--src/librustc/ty/structural_impls.rs1
-rw-r--r--src/librustc_const_eval/check_match.rs42
-rw-r--r--src/librustc_const_eval/eval.rs22
-rw-r--r--src/librustc_const_eval/lib.rs10
-rw-r--r--src/test/compile-fail/const-match-check.rs44
10 files changed, 109 insertions, 29 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index db3aa9a1efa..d44fdd5d9b9 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -516,6 +516,7 @@ define_dep_nodes!( <'tcx>
     [] UsedTraitImports(DefId),
     [] HasTypeckTables(DefId),
     [] ConstEval { param_env: ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)> },
+    [] CheckMatch(DefId),
     [] SymbolName(DefId),
     [] InstanceSymbolName { instance: Instance<'tcx> },
     [] SpecializationGraph(DefId),
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 45e80b58a4f..9609ae5a0be 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -371,7 +371,8 @@ for ::middle::const_val::ErrKind<'gcx> {
             MiscBinaryOp |
             MiscCatchAll |
             IndexOpFeatureGated |
-            TypeckError => {
+            TypeckError |
+            CheckMatchError => {
                 // nothing to do
             }
             UnimplementedConstVal(s) => {
diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs
index 7b239980467..440af39a0d4 100644
--- a/src/librustc/middle/const_val.rs
+++ b/src/librustc/middle/const_val.rs
@@ -106,7 +106,8 @@ pub enum ErrKind<'tcx> {
 
     ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
 
-    TypeckError
+    TypeckError,
+    CheckMatchError,
 }
 
 impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
@@ -168,6 +169,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
             ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
 
             TypeckError => simple!("type-checking failed"),
+            CheckMatchError => simple!("match-checking failed"),
         }
     }
 
@@ -212,8 +214,9 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
         primary_span: Span,
         primary_kind: &str)
     {
-        if let ErrKind::TypeckError = self.kind {
-            return;
+        match self.kind {
+            ErrKind::TypeckError | ErrKind::CheckMatchError => return,
+            _ => {}
         }
         self.struct_error(tcx, primary_span, primary_kind).emit();
     }
diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs
index a477e779af9..18c60394a8e 100644
--- a/src/librustc/ty/maps/mod.rs
+++ b/src/librustc/ty/maps/mod.rs
@@ -37,7 +37,7 @@ use ty::{self, CrateInherentImpls, Ty, TyCtxt};
 use ty::steal::Steal;
 use ty::subst::Substs;
 use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
-use util::common::{profq_msg, ProfileQueriesMsg};
+use util::common::{profq_msg, ErrorReported, ProfileQueriesMsg};
 
 use rustc_data_structures::indexed_set::IdxSetBuf;
 use rustc_back::PanicStrategy;
@@ -205,6 +205,9 @@ define_maps! { <'tcx>
     [] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
         -> const_val::EvalResult<'tcx>,
 
+    [] fn check_match: CheckMatch(DefId)
+        -> Result<(), ErrorReported>,
+
     /// Performs the privacy check and computes "access levels".
     [] fn privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>,
 
diff --git a/src/librustc/ty/maps/plumbing.rs b/src/librustc/ty/maps/plumbing.rs
index c469991d848..7f8c8deb545 100644
--- a/src/librustc/ty/maps/plumbing.rs
+++ b/src/librustc/ty/maps/plumbing.rs
@@ -800,6 +800,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
         DepKind::SpecializationGraph => { force!(specialization_graph_of, def_id!()); }
         DepKind::ObjectSafety => { force!(is_object_safe, def_id!()); }
         DepKind::TraitImpls => { force!(trait_impls_of, def_id!()); }
+        DepKind::CheckMatch => { force!(check_match, def_id!()); }
 
         DepKind::ParamEnv => { force!(param_env, def_id!()); }
         DepKind::DescribeDef => { force!(describe_def, def_id!()); }
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 83207fbe3c3..08152942379 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -477,6 +477,7 @@ impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> {
             }
 
             TypeckError => TypeckError,
+            CheckMatchError => CheckMatchError,
         })
     }
 }
diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs
index 98ed8d99fda..762b9787c8d 100644
--- a/src/librustc_const_eval/check_match.rs
+++ b/src/librustc_const_eval/check_match.rs
@@ -24,9 +24,11 @@ use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::subst::Substs;
 use rustc::lint;
 use rustc_errors::DiagnosticBuilder;
+use rustc::util::common::ErrorReported;
 
 use rustc::hir::def::*;
-use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
+use rustc::hir::def_id::DefId;
+use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
 use rustc::hir::{self, Pat, PatKind};
 
 use rustc_back::slice;
@@ -42,19 +44,10 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
         NestedVisitorMap::OnlyBodies(&self.tcx.hir)
     }
 
-    fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
-                b: hir::BodyId, s: Span, id: ast::NodeId) {
-        intravisit::walk_fn(self, fk, fd, b, s, id);
-
-        let def_id = self.tcx.hir.local_def_id(id);
-
-        MatchVisitor {
-            tcx: self.tcx,
-            tables: self.tcx.body_tables(b),
-            region_scope_tree: &self.tcx.region_scope_tree(def_id),
-            param_env: self.tcx.param_env(def_id),
-            identity_substs: Substs::identity_for_item(self.tcx, def_id),
-        }.visit_body(self.tcx.hir.body(b));
+    fn visit_body(&mut self, body: &'tcx hir::Body) {
+        intravisit::walk_body(self, body);
+        let def_id = self.tcx.hir.body_owner_def_id(body.id());
+        let _ = self.tcx.check_match(def_id);
     }
 }
 
@@ -63,6 +56,27 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
     tcx.sess.abort_if_errors();
 }
 
+pub(crate) fn check_match<'a, 'tcx>(
+    tcx: TyCtxt<'a, 'tcx, 'tcx>,
+    def_id: DefId,
+) -> Result<(), ErrorReported> {
+    let body_id = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
+        tcx.hir.body_owned_by(id)
+    } else {
+        return Ok(());
+    };
+
+    tcx.sess.track_errors(|| {
+        MatchVisitor {
+            tcx,
+            tables: tcx.body_tables(body_id),
+            region_scope_tree: &tcx.region_scope_tree(def_id),
+            param_env: tcx.param_env(def_id),
+            identity_substs: Substs::identity_for_item(tcx, def_id),
+        }.visit_body(tcx.hir.body(body_id));
+    })
+}
+
 fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> DiagnosticBuilder<'a> {
     struct_span_err!(sess, sp, E0004, "{}", &error_message)
 }
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index a548c1df16e..eb4db6365cc 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -18,7 +18,6 @@ use rustc::hir::def::{Def, CtorKind};
 use rustc::hir::def_id::DefId;
 use rustc::ty::{self, Ty, TyCtxt};
 use rustc::ty::layout::LayoutOf;
-use rustc::ty::maps::Providers;
 use rustc::ty::util::IntTypeExt;
 use rustc::ty::subst::{Substs, Subst};
 use rustc::util::common::ErrorReported;
@@ -684,14 +683,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
     }
 }
 
-pub fn provide(providers: &mut Providers) {
-    *providers = Providers {
-        const_eval,
-        ..*providers
-    };
-}
-
-fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+pub(crate) fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                         key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
                         -> EvalResult<'tcx> {
     let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, key) {
@@ -705,8 +697,18 @@ fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 
     let tables = tcx.typeck_tables_of(def_id);
     let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
+        let body_id = tcx.hir.body_owned_by(id);
+
+        // Do match-check before building MIR
+        if tcx.check_match(def_id).is_err() {
+            return Err(ConstEvalErr {
+                span: tcx.def_span(key.value.0),
+                kind: CheckMatchError,
+            });
+        }
+
         tcx.mir_const_qualif(def_id);
-        tcx.hir.body(tcx.hir.body_owned_by(id))
+        tcx.hir.body(body_id)
     } else {
         tcx.extern_const_body(def_id).body
     };
diff --git a/src/librustc_const_eval/lib.rs b/src/librustc_const_eval/lib.rs
index 7b1c33cb271..714cead4bef 100644
--- a/src/librustc_const_eval/lib.rs
+++ b/src/librustc_const_eval/lib.rs
@@ -48,5 +48,15 @@ pub mod pattern;
 
 pub use eval::*;
 
+use rustc::ty::maps::Providers;
+
+pub fn provide(providers: &mut Providers) {
+    *providers = Providers {
+        const_eval: eval::const_eval,
+        check_match: check_match::check_match,
+        ..*providers
+    };
+}
+
 // Build the diagnostics array at the end so that the metadata includes error use sites.
 __build_diagnostic_array! { librustc_const_eval, DIAGNOSTICS }
diff --git a/src/test/compile-fail/const-match-check.rs b/src/test/compile-fail/const-match-check.rs
new file mode 100644
index 00000000000..36a6600b62d
--- /dev/null
+++ b/src/test/compile-fail/const-match-check.rs
@@ -0,0 +1,44 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// revisions: matchck eval1 eval2
+
+#[cfg(matchck)]
+const X: i32 = { let 0 = 0; 0 };
+//[matchck]~^ ERROR refutable pattern in local binding
+
+#[cfg(matchck)]
+static Y: i32 = { let 0 = 0; 0 };
+//[matchck]~^ ERROR refutable pattern in local binding
+
+#[cfg(matchck)]
+trait Bar {
+    const X: i32 = { let 0 = 0; 0 };
+    //[matchck]~^ ERROR refutable pattern in local binding
+}
+
+#[cfg(matchck)]
+impl Bar for () {
+    const X: i32 = { let 0 = 0; 0 };
+    //[matchck]~^ ERROR refutable pattern in local binding
+}
+
+#[cfg(eval1)]
+enum Foo {
+    A = { let 0 = 0; 0 },
+    //[eval1]~^ ERROR refutable pattern in local binding
+}
+
+fn main() {
+    #[cfg(eval2)]
+    let x: [i32; { let 0 = 0; 0 }] = [];
+    //[eval2]~^ ERROR refutable pattern in local binding
+    //[eval2]~| ERROR constant evaluation error
+}