Skip to content

Commit

Permalink
rustc_const_eval: always require correct Substs.
Browse files Browse the repository at this point in the history
  • Loading branch information
eddyb committed Jul 27, 2017
1 parent 5c126bd commit 4c900c5
Show file tree
Hide file tree
Showing 12 changed files with 113 additions and 93 deletions.
2 changes: 1 addition & 1 deletion src/librustc/middle/const_val.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ pub fn eval_length(tcx: TyCtxt,
{
let count_expr = &tcx.hir.body(count).value;
let count_def_id = tcx.hir.body_owner_def_id(count);
let substs = Substs::empty();
let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id);
match tcx.at(count_expr.span).const_eval((count_def_id, substs)) {
Ok(Integral(Usize(count))) => {
let val = count.as_u64(tcx.sess.target.uint_type);
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1588,7 +1588,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
self.variants.iter().map(move |v| {
let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr());
if let VariantDiscr::Explicit(expr_did) = v.discr {
let substs = Substs::empty();
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
match tcx.const_eval((expr_did, substs)) {
Ok(ConstVal::Integral(v)) => {
discr = v;
Expand Down Expand Up @@ -1627,7 +1627,7 @@ impl<'a, 'gcx, 'tcx> AdtDef {
explicit_index -= distance;
}
ty::VariantDiscr::Explicit(expr_did) => {
let substs = Substs::empty();
let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did);
match tcx.const_eval((expr_did, substs)) {
Ok(ConstVal::Integral(v)) => {
explicit_value = v;
Expand Down
13 changes: 9 additions & 4 deletions src/librustc_const_eval/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ use rustc::middle::mem_categorization::{cmt};
use rustc::middle::region::RegionMaps;
use rustc::session::Session;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use rustc::lint;
use rustc_errors::{Diagnostic, Level, DiagnosticBuilder};

Expand Down Expand Up @@ -51,7 +52,8 @@ impl<'a, 'tcx> Visitor<'tcx> for OuterVisitor<'a, 'tcx> {
tcx: self.tcx,
tables: self.tcx.body_tables(b),
region_maps: &self.tcx.region_maps(def_id),
param_env: self.tcx.param_env(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));
}
}
Expand All @@ -69,6 +71,7 @@ struct MatchVisitor<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
param_env: ty::ParamEnv<'tcx>,
identity_substs: &'tcx Substs<'tcx>,
region_maps: &'a RegionMaps,
}

Expand Down Expand Up @@ -110,7 +113,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MatchVisitor<'a, 'tcx> {
}
}

impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
impl<'a, 'tcx> PatternContext<'a, 'tcx> {
fn report_inlining_errors(&self, pat_span: Span) {
for error in &self.errors {
match *error {
Expand Down Expand Up @@ -162,7 +165,8 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {

let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| (
arm.pats.iter().map(|pat| {
let mut patcx = PatternContext::new(self.tcx, self.tables);
let substs = self.identity_substs;
let mut patcx = PatternContext::new(self.tcx, self.tables, substs);
let pattern = expand_pattern(cx, patcx.lower_pattern(&pat));
if !patcx.errors.is_empty() {
patcx.report_inlining_errors(pat.span);
Expand Down Expand Up @@ -229,7 +233,8 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
fn check_irrefutable(&self, pat: &Pat, origin: &str) {
let module = self.tcx.hir.get_module_parent(pat.id);
MatchCheckCtxt::create_and_enter(self.tcx, module, |ref mut cx| {
let mut patcx = PatternContext::new(self.tcx, self.tables);
let substs = self.identity_substs;
let mut patcx = PatternContext::new(self.tcx, self.tables, substs);
let pattern = patcx.lower_pattern(pat);
let pattern_ty = pattern.ty;
let pats : Matrix = vec![vec![
Expand Down
53 changes: 15 additions & 38 deletions src/librustc_const_eval/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,13 @@ pub struct ConstContext<'a, 'tcx: 'a> {
}

impl<'a, 'tcx> ConstContext<'a, 'tcx> {
pub fn with_tables(tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>) -> Self {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
substs: &'tcx Substs<'tcx>) -> Self {
ConstContext {
tcx: tcx,
tables: tables,
substs: tcx.intern_substs(&[]),
tcx,
tables,
substs,
fn_args: None
}
}
Expand All @@ -118,14 +120,7 @@ type CastResult<'tcx> = Result<ConstVal<'tcx>, ErrKind<'tcx>>;
fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
e: &Expr) -> EvalResult<'tcx> {
let tcx = cx.tcx;
let ety = cx.tables.expr_ty(e);

// Avoid applying substitutions if they're empty, that'd ICE.
let ety = if cx.substs.is_empty() {
ety
} else {
ety.subst(tcx, cx.substs)
};
let ety = cx.tables.expr_ty(e).subst(tcx, cx.substs);

let result = match e.node {
hir::ExprUnary(hir::UnNeg, ref inner) => {
Expand Down Expand Up @@ -269,14 +264,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
}
hir::ExprCast(ref base, _) => {
let base_val = cx.eval(base)?;
let base_ty = cx.tables.expr_ty(base);

// Avoid applying substitutions if they're empty, that'd ICE.
let base_ty = if cx.substs.is_empty() {
base_ty
} else {
base_ty.subst(tcx, cx.substs)
};
let base_ty = cx.tables.expr_ty(base).subst(tcx, cx.substs);
if ety == base_ty {
base_val
} else {
Expand All @@ -287,15 +275,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>,
}
}
hir::ExprPath(ref qpath) => {
let substs = cx.tables.node_substs(e.id);

// Avoid applying substitutions if they're empty, that'd ICE.
let substs = if cx.substs.is_empty() {
substs
} else {
substs.subst(tcx, cx.substs)
};

let substs = cx.tables.node_substs(e.id).subst(tcx, cx.substs);
match cx.tables.qpath_def(qpath, e.id) {
Def::Const(def_id) |
Def::AssociatedConst(def_id) => {
Expand Down Expand Up @@ -538,7 +518,10 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
match ac {
// FIXME(eddyb) Use proper Instance resolution to
// get the correct Substs returned from here.
Some(ic) => Some((ic.def_id, Substs::empty())),
Some(ic) => {
let substs = Substs::identity_for_item(tcx, ic.def_id);
Some((ic.def_id, substs))
}
None => {
if trait_item.defaultness.has_value() {
Some((def_id, substs))
Expand Down Expand Up @@ -789,18 +772,12 @@ fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
});
};

let cx = ConstContext {
tcx,
tables: tcx.typeck_tables_of(def_id),
substs: substs,
fn_args: None
};

let tables = tcx.typeck_tables_of(def_id);
let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
tcx.mir_const_qualif(def_id);
tcx.hir.body(tcx.hir.body_owned_by(id))
} else {
tcx.sess.cstore.item_body(tcx, def_id)
};
cx.eval(&body.value)
ConstContext::new(tcx, tables, substs).eval(&body.value)
}
44 changes: 25 additions & 19 deletions src/librustc_const_eval/pattern.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,17 +266,19 @@ impl<'tcx> fmt::Display for Pattern<'tcx> {
}
}

pub struct PatternContext<'a, 'gcx: 'tcx, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'gcx, 'tcx>,
pub tables: &'a ty::TypeckTables<'gcx>,
pub struct PatternContext<'a, 'tcx: 'a> {
pub tcx: TyCtxt<'a, 'tcx, 'tcx>,
pub tables: &'a ty::TypeckTables<'tcx>,
pub substs: &'tcx Substs<'tcx>,
pub errors: Vec<PatternError<'tcx>>,
}

impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
pub fn from_hir(tcx: TyCtxt<'a, 'gcx, 'tcx>,
tables: &'a ty::TypeckTables<'gcx>,
impl<'a, 'tcx> Pattern<'tcx> {
pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
substs: &'tcx Substs<'tcx>,
pat: &hir::Pat) -> Self {
let mut pcx = PatternContext::new(tcx, tables);
let mut pcx = PatternContext::new(tcx, tables, substs);
let result = pcx.lower_pattern(pat);
if !pcx.errors.is_empty() {
span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors)
Expand All @@ -286,9 +288,11 @@ impl<'a, 'gcx, 'tcx> Pattern<'tcx> {
}
}

impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'gcx, 'tcx>, tables: &'a ty::TypeckTables<'gcx>) -> Self {
PatternContext { tcx: tcx, tables: tables, errors: vec![] }
impl<'a, 'tcx> PatternContext<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
substs: &'tcx Substs<'tcx>) -> Self {
PatternContext { tcx, tables, substs, errors: vec![] }
}

pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> {
Expand Down Expand Up @@ -583,20 +587,22 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
let def = self.tables.qpath_def(qpath, id);
let kind = match def {
Def::Const(def_id) | Def::AssociatedConst(def_id) => {
let tcx = self.tcx.global_tcx();
let substs = self.tables.node_substs(id);
match eval::lookup_const_by_id(tcx, def_id, substs) {
Some((def_id, _substs)) => {
// Enter the inlined constant's tables temporarily.
match eval::lookup_const_by_id(self.tcx, def_id, substs) {
Some((def_id, substs)) => {
// Enter the inlined constant's tables&substs temporarily.
let old_tables = self.tables;
self.tables = tcx.typeck_tables_of(def_id);
let body = if let Some(id) = tcx.hir.as_local_node_id(def_id) {
tcx.hir.body(tcx.hir.body_owned_by(id))
let old_substs = self.substs;
self.tables = self.tcx.typeck_tables_of(def_id);
self.substs = substs;
let body = if let Some(id) = self.tcx.hir.as_local_node_id(def_id) {
self.tcx.hir.body(self.tcx.hir.body_owned_by(id))
} else {
tcx.sess.cstore.item_body(tcx, def_id)
self.tcx.sess.cstore.item_body(self.tcx, def_id)
};
let pat = self.lower_const_expr(&body.value, pat_id, span);
self.tables = old_tables;
self.substs = old_substs;
return pat;
}
None => {
Expand All @@ -616,7 +622,7 @@ impl<'a, 'gcx, 'tcx> PatternContext<'a, 'gcx, 'tcx> {
}

fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> {
let const_cx = eval::ConstContext::with_tables(self.tcx.global_tcx(), self.tables);
let const_cx = eval::ConstContext::new(self.tcx, self.tables, self.substs);
match const_cx.eval(expr) {
Ok(value) => {
if let ConstVal::Variant(def_id) = value {
Expand Down
9 changes: 8 additions & 1 deletion src/librustc_lint/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,14 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits {
false
}
} else {
let const_cx = ConstContext::with_tables(cx.tcx, cx.tables);
// HACK(eddyb) This might be quite inefficient.
// This would be better left to MIR constant propagation,
// perhaps even at trans time (like is the case already
// when the value being shifted is *also* constant).
let parent_item = cx.tcx.hir.get_parent(e.id);
let parent_def_id = cx.tcx.hir.local_def_id(parent_item);
let substs = Substs::identity_for_item(cx.tcx, parent_def_id);
let const_cx = ConstContext::new(cx.tcx, cx.tables, substs);
match const_cx.eval(&r) {
Ok(ConstVal::Integral(i)) => {
i.is_negative() ||
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_mir/build/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
let lvalue = Lvalue::Local(Local::new(index + 1));

if let Some(pattern) = pattern {
let pattern = Pattern::from_hir(self.hir.tcx(), self.hir.tables(), pattern);
let pattern = Pattern::from_hir(self.hir.tcx().global_tcx(),
self.hir.tables(),
self.hir.identity_substs,
pattern);
scope = self.declare_bindings(scope, ast_body.span, &pattern);
unpack!(block = self.lvalue_into_pattern(block, pattern, &lvalue));
}
Expand Down
5 changes: 4 additions & 1 deletion src/librustc_mir/hair/cx/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,10 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
first_statement_index: index as u32,
});

let pattern = Pattern::from_hir(cx.tcx, cx.tables(), &local.pat);
let pattern = Pattern::from_hir(cx.tcx.global_tcx(),
cx.tables(),
cx.identity_substs,
&local.pat);
result.push(StmtRef::Mirror(Box::new(Stmt {
span: stmt.span,
kind: StmtKind::Let {
Expand Down
6 changes: 4 additions & 2 deletions src/librustc_mir/hair/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
hir::ExprRepeat(ref v, count) => {
let c = &cx.tcx.hir.body(count).value;
let def_id = cx.tcx.hir.body_owner_def_id(count);
let substs = Substs::empty();
let substs = Substs::identity_for_item(cx.tcx.global_tcx(), def_id);
let count = match cx.tcx.at(c.span).const_eval((def_id, substs)) {
Ok(ConstVal::Integral(ConstInt::Usize(u))) => u,
Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other),
Expand Down Expand Up @@ -604,7 +604,9 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {

fn convert_arm<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
Arm {
patterns: arm.pats.iter().map(|p| Pattern::from_hir(cx.tcx, cx.tables(), p)).collect(),
patterns: arm.pats.iter().map(|p| {
Pattern::from_hir(cx.tcx.global_tcx(), cx.tables(), cx.identity_substs, p)
}).collect(),
guard: arm.guard.to_ref(),
body: arm.body.to_ref(),
}
Expand Down
26 changes: 19 additions & 7 deletions src/librustc_mir/hair/cx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use rustc::middle::region::RegionMaps;
use rustc::infer::InferCtxt;
use rustc::ty::subst::Subst;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::subst::Substs;
use syntax::symbol::Symbol;
use rustc::hir;
use rustc_const_math::{ConstInt, ConstUsize};
Expand All @@ -35,7 +36,12 @@ use std::rc::Rc;
pub struct Cx<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
tcx: TyCtxt<'a, 'gcx, 'tcx>,
infcx: &'a InferCtxt<'a, 'gcx, 'tcx>,

pub param_env: ty::ParamEnv<'tcx>,

/// Identity `Substs` for use with const-evaluation.
pub identity_substs: &'gcx Substs<'gcx>,

pub region_maps: Rc<RegionMaps>,
pub tables: &'a ty::TypeckTables<'gcx>,

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

let param_env = tcx.param_env(src_def_id);
let region_maps = tcx.region_maps(src_def_id);
let tables = tcx.typeck_tables_of(src_def_id);

let attrs = tcx.hir.attrs(src_id);

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

Cx { tcx, infcx, param_env, region_maps, tables, constness, src, check_overflow }
Cx {
tcx,
infcx,
param_env: tcx.param_env(src_def_id),
identity_substs: Substs::identity_for_item(tcx.global_tcx(), src_def_id),
region_maps: tcx.region_maps(src_def_id),
tables: tcx.typeck_tables_of(src_def_id),
constness,
src,
check_overflow,
}
}
}

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

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

pub fn fatal_const_eval_err(&self,
pub fn fatal_const_eval_err(&mut self,
err: &ConstEvalErr<'tcx>,
primary_span: Span,
primary_kind: &str)
Expand Down
Loading

0 comments on commit 4c900c5

Please sign in to comment.