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)
This commit is contained in:
commit
2f84fb5cc1
10 changed files with 109 additions and 29 deletions
|
|
@ -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),
|
||||
|
|
|
|||
|
|
@ -371,7 +371,8 @@ for ::middle::const_val::ErrKind<'gcx> {
|
|||
MiscBinaryOp |
|
||||
MiscCatchAll |
|
||||
IndexOpFeatureGated |
|
||||
TypeckError => {
|
||||
TypeckError |
|
||||
CheckMatchError => {
|
||||
// nothing to do
|
||||
}
|
||||
UnimplementedConstVal(s) => {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
||||
|
|
|
|||
|
|
@ -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!()); }
|
||||
|
|
|
|||
|
|
@ -477,6 +477,7 @@ impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> {
|
|||
}
|
||||
|
||||
TypeckError => TypeckError,
|
||||
CheckMatchError => CheckMatchError,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
44
src/test/compile-fail/const-match-check.rs
Normal file
44
src/test/compile-fail/const-match-check.rs
Normal file
|
|
@ -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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue