Skip to content

Commit 2f84fb5

Browse files
committed
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)
2 parents 693bb0d + 62cb74a commit 2f84fb5

File tree

10 files changed

+109
-29
lines changed

10 files changed

+109
-29
lines changed

src/librustc/dep_graph/dep_node.rs

+1
Original file line numberDiff line numberDiff line change
@@ -516,6 +516,7 @@ define_dep_nodes!( <'tcx>
516516
[] UsedTraitImports(DefId),
517517
[] HasTypeckTables(DefId),
518518
[] ConstEval { param_env: ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)> },
519+
[] CheckMatch(DefId),
519520
[] SymbolName(DefId),
520521
[] InstanceSymbolName { instance: Instance<'tcx> },
521522
[] SpecializationGraph(DefId),

src/librustc/ich/impls_ty.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,8 @@ for ::middle::const_val::ErrKind<'gcx> {
371371
MiscBinaryOp |
372372
MiscCatchAll |
373373
IndexOpFeatureGated |
374-
TypeckError => {
374+
TypeckError |
375+
CheckMatchError => {
375376
// nothing to do
376377
}
377378
UnimplementedConstVal(s) => {

src/librustc/middle/const_val.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ pub enum ErrKind<'tcx> {
106106

107107
ErroneousReferencedConstant(Box<ConstEvalErr<'tcx>>),
108108

109-
TypeckError
109+
TypeckError,
110+
CheckMatchError,
110111
}
111112

112113
impl<'tcx> From<ConstMathErr> for ErrKind<'tcx> {
@@ -168,6 +169,7 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
168169
ErroneousReferencedConstant(_) => simple!("could not evaluate referenced constant"),
169170

170171
TypeckError => simple!("type-checking failed"),
172+
CheckMatchError => simple!("match-checking failed"),
171173
}
172174
}
173175

@@ -212,8 +214,9 @@ impl<'a, 'gcx, 'tcx> ConstEvalErr<'tcx> {
212214
primary_span: Span,
213215
primary_kind: &str)
214216
{
215-
if let ErrKind::TypeckError = self.kind {
216-
return;
217+
match self.kind {
218+
ErrKind::TypeckError | ErrKind::CheckMatchError => return,
219+
_ => {}
217220
}
218221
self.struct_error(tcx, primary_span, primary_kind).emit();
219222
}

src/librustc/ty/maps/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ use ty::{self, CrateInherentImpls, Ty, TyCtxt};
3737
use ty::steal::Steal;
3838
use ty::subst::Substs;
3939
use util::nodemap::{DefIdSet, DefIdMap, ItemLocalSet};
40-
use util::common::{profq_msg, ProfileQueriesMsg};
40+
use util::common::{profq_msg, ErrorReported, ProfileQueriesMsg};
4141

4242
use rustc_data_structures::indexed_set::IdxSetBuf;
4343
use rustc_back::PanicStrategy;
@@ -205,6 +205,9 @@ define_maps! { <'tcx>
205205
[] fn const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
206206
-> const_val::EvalResult<'tcx>,
207207

208+
[] fn check_match: CheckMatch(DefId)
209+
-> Result<(), ErrorReported>,
210+
208211
/// Performs the privacy check and computes "access levels".
209212
[] fn privacy_access_levels: PrivacyAccessLevels(CrateNum) -> Rc<AccessLevels>,
210213

src/librustc/ty/maps/plumbing.rs

+1
Original file line numberDiff line numberDiff line change
@@ -800,6 +800,7 @@ pub fn force_from_dep_node<'a, 'gcx, 'lcx>(tcx: TyCtxt<'a, 'gcx, 'lcx>,
800800
DepKind::SpecializationGraph => { force!(specialization_graph_of, def_id!()); }
801801
DepKind::ObjectSafety => { force!(is_object_safe, def_id!()); }
802802
DepKind::TraitImpls => { force!(trait_impls_of, def_id!()); }
803+
DepKind::CheckMatch => { force!(check_match, def_id!()); }
803804

804805
DepKind::ParamEnv => { force!(param_env, def_id!()); }
805806
DepKind::DescribeDef => { force!(describe_def, def_id!()); }

src/librustc/ty/structural_impls.rs

+1
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,7 @@ impl<'a, 'tcx> Lift<'tcx> for const_val::ErrKind<'a> {
477477
}
478478

479479
TypeckError => TypeckError,
480+
CheckMatchError => CheckMatchError,
480481
})
481482
}
482483
}

src/librustc_const_eval/check_match.rs

+28-14
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,11 @@ use rustc::ty::{self, Ty, TyCtxt};
2424
use rustc::ty::subst::Substs;
2525
use rustc::lint;
2626
use rustc_errors::DiagnosticBuilder;
27+
use rustc::util::common::ErrorReported;
2728

2829
use rustc::hir::def::*;
29-
use rustc::hir::intravisit::{self, Visitor, FnKind, NestedVisitorMap};
30+
use rustc::hir::def_id::DefId;
31+
use rustc::hir::intravisit::{self, Visitor, NestedVisitorMap};
3032
use rustc::hir::{self, Pat, PatKind};
3133

3234
use rustc_back::slice;
@@ -42,19 +44,10 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
4244
NestedVisitorMap::OnlyBodies(&self.tcx.hir)
4345
}
4446

45-
fn visit_fn(&mut self, fk: FnKind<'tcx>, fd: &'tcx hir::FnDecl,
46-
b: hir::BodyId, s: Span, id: ast::NodeId) {
47-
intravisit::walk_fn(self, fk, fd, b, s, id);
48-
49-
let def_id = self.tcx.hir.local_def_id(id);
50-
51-
MatchVisitor {
52-
tcx: self.tcx,
53-
tables: self.tcx.body_tables(b),
54-
region_scope_tree: &self.tcx.region_scope_tree(def_id),
55-
param_env: self.tcx.param_env(def_id),
56-
identity_substs: Substs::identity_for_item(self.tcx, def_id),
57-
}.visit_body(self.tcx.hir.body(b));
47+
fn visit_body(&mut self, body: &'tcx hir::Body) {
48+
intravisit::walk_body(self, body);
49+
let def_id = self.tcx.hir.body_owner_def_id(body.id());
50+
let _ = self.tcx.check_match(def_id);
5851
}
5952
}
6053

@@ -63,6 +56,27 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
6356
tcx.sess.abort_if_errors();
6457
}
6558

59+
pub(crate) fn check_match<'a, 'tcx>(
60+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
61+
def_id: DefId,
62+
) -> Result<(), ErrorReported> {
63+
let body_id = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
64+
tcx.hir.body_owned_by(id)
65+
} else {
66+
return Ok(());
67+
};
68+
69+
tcx.sess.track_errors(|| {
70+
MatchVisitor {
71+
tcx,
72+
tables: tcx.body_tables(body_id),
73+
region_scope_tree: &tcx.region_scope_tree(def_id),
74+
param_env: tcx.param_env(def_id),
75+
identity_substs: Substs::identity_for_item(tcx, def_id),
76+
}.visit_body(tcx.hir.body(body_id));
77+
})
78+
}
79+
6680
fn create_e0004<'a>(sess: &'a Session, sp: Span, error_message: String) -> DiagnosticBuilder<'a> {
6781
struct_span_err!(sess, sp, E0004, "{}", &error_message)
6882
}

src/librustc_const_eval/eval.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ use rustc::hir::def::{Def, CtorKind};
1818
use rustc::hir::def_id::DefId;
1919
use rustc::ty::{self, Ty, TyCtxt};
2020
use rustc::ty::layout::LayoutOf;
21-
use rustc::ty::maps::Providers;
2221
use rustc::ty::util::IntTypeExt;
2322
use rustc::ty::subst::{Substs, Subst};
2423
use rustc::util::common::ErrorReported;
@@ -684,14 +683,7 @@ impl<'a, 'tcx> ConstContext<'a, 'tcx> {
684683
}
685684
}
686685

687-
pub fn provide(providers: &mut Providers) {
688-
*providers = Providers {
689-
const_eval,
690-
..*providers
691-
};
692-
}
693-
694-
fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
686+
pub(crate) fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
695687
key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>)
696688
-> EvalResult<'tcx> {
697689
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>,
705697

706698
let tables = tcx.typeck_tables_of(def_id);
707699
let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
700+
let body_id = tcx.hir.body_owned_by(id);
701+
702+
// Do match-check before building MIR
703+
if tcx.check_match(def_id).is_err() {
704+
return Err(ConstEvalErr {
705+
span: tcx.def_span(key.value.0),
706+
kind: CheckMatchError,
707+
});
708+
}
709+
708710
tcx.mir_const_qualif(def_id);
709-
tcx.hir.body(tcx.hir.body_owned_by(id))
711+
tcx.hir.body(body_id)
710712
} else {
711713
tcx.extern_const_body(def_id).body
712714
};

src/librustc_const_eval/lib.rs

+10
Original file line numberDiff line numberDiff line change
@@ -48,5 +48,15 @@ pub mod pattern;
4848

4949
pub use eval::*;
5050

51+
use rustc::ty::maps::Providers;
52+
53+
pub fn provide(providers: &mut Providers) {
54+
*providers = Providers {
55+
const_eval: eval::const_eval,
56+
check_match: check_match::check_match,
57+
..*providers
58+
};
59+
}
60+
5161
// Build the diagnostics array at the end so that the metadata includes error use sites.
5262
__build_diagnostic_array! { librustc_const_eval, DIAGNOSTICS }
+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
// revisions: matchck eval1 eval2
12+
13+
#[cfg(matchck)]
14+
const X: i32 = { let 0 = 0; 0 };
15+
//[matchck]~^ ERROR refutable pattern in local binding
16+
17+
#[cfg(matchck)]
18+
static Y: i32 = { let 0 = 0; 0 };
19+
//[matchck]~^ ERROR refutable pattern in local binding
20+
21+
#[cfg(matchck)]
22+
trait Bar {
23+
const X: i32 = { let 0 = 0; 0 };
24+
//[matchck]~^ ERROR refutable pattern in local binding
25+
}
26+
27+
#[cfg(matchck)]
28+
impl Bar for () {
29+
const X: i32 = { let 0 = 0; 0 };
30+
//[matchck]~^ ERROR refutable pattern in local binding
31+
}
32+
33+
#[cfg(eval1)]
34+
enum Foo {
35+
A = { let 0 = 0; 0 },
36+
//[eval1]~^ ERROR refutable pattern in local binding
37+
}
38+
39+
fn main() {
40+
#[cfg(eval2)]
41+
let x: [i32; { let 0 = 0; 0 }] = [];
42+
//[eval2]~^ ERROR refutable pattern in local binding
43+
//[eval2]~| ERROR constant evaluation error
44+
}

0 commit comments

Comments
 (0)