Skip to content

Commit 4c900c5

Browse files
committed
rustc_const_eval: always require correct Substs.
1 parent 5c126bd commit 4c900c5

File tree

12 files changed

+113
-93
lines changed

12 files changed

+113
-93
lines changed

src/librustc/middle/const_val.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ pub fn eval_length(tcx: TyCtxt,
229229
{
230230
let count_expr = &tcx.hir.body(count).value;
231231
let count_def_id = tcx.hir.body_owner_def_id(count);
232-
let substs = Substs::empty();
232+
let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
233233
match tcx.at(count_expr.span).const_eval((count_def_id, substs)) {
234234
Ok(Integral(Usize(count))) => {
235235
let val = count.as_u64(tcx.sess.target.uint_type);

src/librustc/ty/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1588,7 +1588,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
15881588
self.variants.iter().map(move |v| {
15891589
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
15901590
if let VariantDiscr::Explicit(expr_did) = v.discr {
1591-
let substs = Substs::empty();
1591+
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
15921592
match tcx.const_eval((expr_did, substs)) {
15931593
Ok(ConstVal::Integral(v)) => {
15941594
discr = v;
@@ -1627,7 +1627,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
16271627
explicit_index -= distance;
16281628
}
16291629
ty::VariantDiscr::Explicit(expr_did) => {
1630-
let substs = Substs::empty();
1630+
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
16311631
match tcx.const_eval((expr_did, substs)) {
16321632
Ok(ConstVal::Integral(v)) => {
16331633
explicit_value = v;

src/librustc_const_eval/check_match.rs

+9-4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use rustc::middle::mem_categorization::{cmt};
2121
use rustc::middle::region::RegionMaps;
2222
use rustc::session::Session;
2323
use rustc::ty::{self, Ty, TyCtxt};
24+
use rustc::ty::subst::Substs;
2425
use rustc::lint;
2526
use rustc_errors::{Diagnostic, Level, DiagnosticBuilder};
2627

@@ -51,7 +52,8 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
5152
tcx: self.tcx,
5253
tables: self.tcx.body_tables(b),
5354
region_maps: &self.tcx.region_maps(def_id),
54-
param_env: self.tcx.param_env(def_id)
55+
param_env: self.tcx.param_env(def_id),
56+
identity_substs: Substs::identity_for_item(self.tcx, def_id),
5557
}.visit_body(self.tcx.hir.body(b));
5658
}
5759
}
@@ -69,6 +71,7 @@ struct MatchVisitor<'a, 'tcx: 'a> {
6971
tcx: TyCtxt<'a, 'tcx, 'tcx>,
7072
tables: &'a ty::TypeckTables<'tcx>,
7173
param_env: ty::ParamEnv<'tcx>,
74+
identity_substs: &'tcx Substs<'tcx>,
7275
region_maps: &'a RegionMaps,
7376
}
7477

@@ -110,7 +113,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
110113
}
111114
}
112115

113-
impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
116+
impl<'a, 'tcx> PatternContext<'a, 'tcx> {
114117
fn report_inlining_errors(&self, pat_span: Span) {
115118
for error in &self.errors {
116119
match *error {
@@ -162,7 +165,8 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
162165

163166
let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
164167
arm.pats.iter().map(|pat| {
165-
let mut patcx = PatternContext::new(self.tcx, self.tables);
168+
let substs = self.identity_substs;
169+
let mut patcx = PatternContext::new(self.tcx, self.tables, substs);
166170
let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
167171
if !patcx.errors.is_empty() {
168172
patcx.report_inlining_errors(pat.span);
@@ -229,7 +233,8 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
229233
fn check_irrefutable(&self, pat: &Pat, origin: &str) {
230234
let module = self.tcx.hir.get_module_parent(pat.id);
231235
MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
232-
let mut patcx = PatternContext::new(self.tcx, self.tables);
236+
let substs = self.identity_substs;
237+
let mut patcx = PatternContext::new(self.tcx, self.tables, substs);
233238
let pattern = patcx.lower_pattern(pat);
234239
let pattern_ty = pattern.ty;
235240
let pats : Matrix = vec![vec![

src/librustc_const_eval/eval.rs

+15-38
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,13 @@ pub struct ConstContext<'a, 'tcx: 'a> {
9494
}
9595

9696
impl<'a, 'tcx> ConstContext<'a, 'tcx> {
97-
pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
97+
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
98+
tables: &'a ty::TypeckTables<'tcx>,
99+
substs: &'tcx Substs<'tcx>) -> Self {
98100
ConstContext {
99-
tcx: tcx,
100-
tables: tables,
101-
substs: tcx.intern_substs(&[]),
101+
tcx,
102+
tables,
103+
substs,
102104
fn_args: None
103105
}
104106
}
@@ -118,14 +120,7 @@ type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
118120
fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
119121
e: &Expr) -> EvalResult<'tcx> {
120122
let tcx = cx.tcx;
121-
let ety = cx.tables.expr_ty(e);
122-
123-
// Avoid applying substitutions if they're empty, that'd ICE.
124-
let ety = if cx.substs.is_empty() {
125-
ety
126-
} else {
127-
ety.subst(tcx, cx.substs)
128-
};
123+
let ety = cx.tables.expr_ty(e).subst(tcx, cx.substs);
129124

130125
let result = match e.node {
131126
hir::ExprUnary(hir::UnNeg, ref inner) => {
@@ -269,14 +264,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
269264
}
270265
hir::ExprCast(ref base, _) => {
271266
let base_val = cx.eval(base)?;
272-
let base_ty = cx.tables.expr_ty(base);
273-
274-
// Avoid applying substitutions if they're empty, that'd ICE.
275-
let base_ty = if cx.substs.is_empty() {
276-
base_ty
277-
} else {
278-
base_ty.subst(tcx, cx.substs)
279-
};
267+
let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs);
280268
if ety == base_ty {
281269
base_val
282270
} else {
@@ -287,15 +275,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
287275
}
288276
}
289277
hir::ExprPath(ref qpath) => {
290-
let substs = cx.tables.node_substs(e.id);
291-
292-
// Avoid applying substitutions if they're empty, that'd ICE.
293-
let substs = if cx.substs.is_empty() {
294-
substs
295-
} else {
296-
substs.subst(tcx, cx.substs)
297-
};
298-
278+
let substs = cx.tables.node_substs(e.id).subst(tcx, cx.substs);
299279
match cx.tables.qpath_def(qpath, e.id) {
300280
Def::Const(def_id) |
301281
Def::AssociatedConst(def_id) => {
@@ -538,7 +518,10 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
538518
match ac {
539519
// FIXME(eddyb) Use proper Instance resolution to
540520
// get the correct Substs returned from here.
541-
Some(ic) => Some((ic.def_id, Substs::empty())),
521+
Some(ic) => {
522+
let substs = Substs::identity_for_item(tcx, ic.def_id);
523+
Some((ic.def_id, substs))
524+
}
542525
None => {
543526
if trait_item.defaultness.has_value() {
544527
Some((def_id, substs))
@@ -789,18 +772,12 @@ fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
789772
});
790773
};
791774

792-
let cx = ConstContext {
793-
tcx,
794-
tables: tcx.typeck_tables_of(def_id),
795-
substs: substs,
796-
fn_args: None
797-
};
798-
775+
let tables = tcx.typeck_tables_of(def_id);
799776
let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
800777
tcx.mir_const_qualif(def_id);
801778
tcx.hir.body(tcx.hir.body_owned_by(id))
802779
} else {
803780
tcx.sess.cstore.item_body(tcx, def_id)
804781
};
805-
cx.eval(&body.value)
782+
ConstContext::new(tcx, tables, substs).eval(&body.value)
806783
}

src/librustc_const_eval/pattern.rs

+25-19
Original file line numberDiff line numberDiff line change
@@ -266,17 +266,19 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
266266
}
267267
}
268268

269-
pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
270-
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
271-
pub tables: &'a ty::TypeckTables<'gcx>,
269+
pub struct PatternContext<'a, 'tcx: 'a> {
270+
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
271+
pub tables: &'a ty::TypeckTables<'tcx>,
272+
pub substs: &'tcx Substs<'tcx>,
272273
pub errors: Vec<PatternError<'tcx>>,
273274
}
274275

275-
impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
276-
pub fn from_hir(tcx: TyCtxt<'a, 'gcx, 'tcx>,
277-
tables: &'a ty::TypeckTables<'gcx>,
276+
impl<'a, 'tcx> Pattern<'tcx> {
277+
pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>,
278+
tables: &'a ty::TypeckTables<'tcx>,
279+
substs: &'tcx Substs<'tcx>,
278280
pat: &hir::Pat) -> Self {
279-
let mut pcx = PatternContext::new(tcx, tables);
281+
let mut pcx = PatternContext::new(tcx, tables, substs);
280282
let result = pcx.lower_pattern(pat);
281283
if !pcx.errors.is_empty() {
282284
span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors)
@@ -286,9 +288,11 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
286288
}
287289
}
288290

289-
impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
290-
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, tables: &'a ty::TypeckTables<'gcx>) -> Self {
291-
PatternContext { tcx: tcx, tables: tables, errors: vec![] }
291+
impl<'a, 'tcx> PatternContext<'a, 'tcx> {
292+
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
293+
tables: &'a ty::TypeckTables<'tcx>,
294+
substs: &'tcx Substs<'tcx>) -> Self {
295+
PatternContext { tcx, tables, substs, errors: vec![] }
292296
}
293297

294298
pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
@@ -583,20 +587,22 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
583587
let def = self.tables.qpath_def(qpath, id);
584588
let kind = match def {
585589
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
586-
let tcx = self.tcx.global_tcx();
587590
let substs = self.tables.node_substs(id);
588-
match eval::lookup_const_by_id(tcx, def_id, substs) {
589-
Some((def_id, _substs)) => {
590-
// Enter the inlined constant's tables temporarily.
591+
match eval::lookup_const_by_id(self.tcx, def_id, substs) {
592+
Some((def_id, substs)) => {
593+
// Enter the inlined constant's tables&substs temporarily.
591594
let old_tables = self.tables;
592-
self.tables = tcx.typeck_tables_of(def_id);
593-
let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
594-
tcx.hir.body(tcx.hir.body_owned_by(id))
595+
let old_substs = self.substs;
596+
self.tables = self.tcx.typeck_tables_of(def_id);
597+
self.substs = substs;
598+
let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
599+
self.tcx.hir.body(self.tcx.hir.body_owned_by(id))
595600
} else {
596-
tcx.sess.cstore.item_body(tcx, def_id)
601+
self.tcx.sess.cstore.item_body(self.tcx, def_id)
597602
};
598603
let pat = self.lower_const_expr(&body.value, pat_id, span);
599604
self.tables = old_tables;
605+
self.substs = old_substs;
600606
return pat;
601607
}
602608
None => {
@@ -616,7 +622,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
616622
}
617623

618624
fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
619-
let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
625+
let const_cx = eval::ConstContext::new(self.tcx, self.tables, self.substs);
620626
match const_cx.eval(expr) {
621627
Ok(value) => {
622628
if let ConstVal::Variant(def_id) = value {

src/librustc_lint/types.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
106106
false
107107
}
108108
} else {
109-
let const_cx = ConstContext::with_tables(cx.tcx, cx.tables);
109+
// HACK(eddyb) This might be quite inefficient.
110+
// This would be better left to MIR constant propagation,
111+
// perhaps even at trans time (like is the case already
112+
// when the value being shifted is *also* constant).
113+
let parent_item = cx.tcx.hir.get_parent(e.id);
114+
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
115+
let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
116+
let const_cx = ConstContext::new(cx.tcx, cx.tables, substs);
110117
match const_cx.eval(&r) {
111118
Ok(ConstVal::Integral(i)) => {
112119
i.is_negative() ||

src/librustc_mir/build/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
513513
let lvalue = Lvalue::Local(Local::new(index + 1));
514514

515515
if let Some(pattern) = pattern {
516-
let pattern = Pattern::from_hir(self.hir.tcx(), self.hir.tables(), pattern);
516+
let pattern = Pattern::from_hir(self.hir.tcx().global_tcx(),
517+
self.hir.tables(),
518+
self.hir.identity_substs,
519+
pattern);
517520
scope = self.declare_bindings(scope, ast_body.span, &pattern);
518521
unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
519522
}

src/librustc_mir/hair/cx/block.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,10 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
7070
first_statement_index: index as u32,
7171
});
7272

73-
let pattern = Pattern::from_hir(cx.tcx, cx.tables(), &local.pat);
73+
let pattern = Pattern::from_hir(cx.tcx.global_tcx(),
74+
cx.tables(),
75+
cx.identity_substs,
76+
&local.pat);
7477
result.push(StmtRef::Mirror(Box::new(Stmt {
7578
span: stmt.span,
7679
kind: StmtKind::Let {

src/librustc_mir/hair/cx/expr.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
466466
hir::ExprRepeat(ref v, count) => {
467467
let c = &cx.tcx.hir.body(count).value;
468468
let def_id = cx.tcx.hir.body_owner_def_id(count);
469-
let substs = Substs::empty();
469+
let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id);
470470
let count = match cx.tcx.at(c.span).const_eval((def_id, substs)) {
471471
Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
472472
Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
@@ -604,7 +604,9 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
604604

605605
fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
606606
Arm {
607-
patterns: arm.pats.iter().map(|p| Pattern::from_hir(cx.tcx, cx.tables(), p)).collect(),
607+
patterns: arm.pats.iter().map(|p| {
608+
Pattern::from_hir(cx.tcx.global_tcx(), cx.tables(), cx.identity_substs, p)
609+
}).collect(),
608610
guard: arm.guard.to_ref(),
609611
body: arm.body.to_ref(),
610612
}

src/librustc_mir/hair/cx/mod.rs

+19-7
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ use rustc::middle::region::RegionMaps;
2626
use rustc::infer::InferCtxt;
2727
use rustc::ty::subst::Subst;
2828
use rustc::ty::{self, Ty, TyCtxt};
29+
use rustc::ty::subst::Substs;
2930
use syntax::symbol::Symbol;
3031
use rustc::hir;
3132
use rustc_const_math::{ConstInt, ConstUsize};
@@ -35,7 +36,12 @@ use std::rc::Rc;
3536
pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
3637
tcx: TyCtxt<'a, 'gcx, 'tcx>,
3738
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,
39+
3840
pub param_env: ty::ParamEnv<'tcx>,
41+
42+
/// Identity `Substs` for use with const-evaluation.
43+
pub identity_substs: &'gcx Substs<'gcx>,
44+
3945
pub region_maps: Rc<RegionMaps>,
4046
pub tables: &'a ty::TypeckTables<'gcx>,
4147

@@ -66,10 +72,6 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
6672
let src_id = src.item_id();
6773
let src_def_id = tcx.hir.local_def_id(src_id);
6874

69-
let param_env = tcx.param_env(src_def_id);
70-
let region_maps = tcx.region_maps(src_def_id);
71-
let tables = tcx.typeck_tables_of(src_def_id);
72-
7375
let attrs = tcx.hir.attrs(src_id);
7476

7577
// Some functions always have overflow checks enabled,
@@ -84,7 +86,17 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
8486
// Constants and const fn's always need overflow checks.
8587
check_overflow |= constness == hir::Constness::Const;
8688

87-
Cx { tcx, infcx, param_env, region_maps, tables, constness, src, check_overflow }
89+
Cx {
90+
tcx,
91+
infcx,
92+
param_env: tcx.param_env(src_def_id),
93+
identity_substs: Substs::identity_for_item(tcx.global_tcx(), src_def_id),
94+
region_maps: tcx.region_maps(src_def_id),
95+
tables: tcx.typeck_tables_of(src_def_id),
96+
constness,
97+
src,
98+
check_overflow,
99+
}
88100
}
89101
}
90102

@@ -123,13 +135,13 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
123135

124136
pub fn const_eval_literal(&mut self, e: &hir::Expr) -> Literal<'tcx> {
125137
let tcx = self.tcx.global_tcx();
126-
match ConstContext::with_tables(tcx, self.tables()).eval(e) {
138+
match ConstContext::new(tcx, self.tables(), self.identity_substs).eval(e) {
127139
Ok(value) => Literal::Value { value: value },
128140
Err(s) => self.fatal_const_eval_err(&s, e.span, "expression")
129141
}
130142
}
131143

132-
pub fn fatal_const_eval_err(&self,
144+
pub fn fatal_const_eval_err(&mut self,
133145
err: &ConstEvalErr<'tcx>,
134146
primary_span: Span,
135147
primary_kind: &str)

0 commit comments

Comments
 (0)