From 4c900c52482fd398cbec4d1d433fcc2e6888ff1b Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 26 Jul 2017 15:54:44 +0300 Subject: [PATCH 1/2] rustc_const_eval: always require correct Substs. --- src/librustc/middle/const_val.rs | 2 +- src/librustc/ty/mod.rs | 4 +- src/librustc_const_eval/check_match.rs | 13 +++++-- src/librustc_const_eval/eval.rs | 53 ++++++++------------------ src/librustc_const_eval/pattern.rs | 44 ++++++++++++--------- src/librustc_lint/types.rs | 9 ++++- src/librustc_mir/build/mod.rs | 5 ++- src/librustc_mir/hair/cx/block.rs | 5 ++- src/librustc_mir/hair/cx/expr.rs | 6 ++- src/librustc_mir/hair/cx/mod.rs | 26 +++++++++---- src/librustc_passes/consts.rs | 37 ++++++++++-------- src/librustc_typeck/collect.rs | 2 +- 12 files changed, 113 insertions(+), 93 deletions(-) diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 2637afdea5bcf..33e9df1e413c7 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -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); diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 2a11b19f85561..70aee6ffcf357 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -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; @@ -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; diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index fcdabf89e3cdd..e7a12df0a27ae 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -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}; @@ -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)); } } @@ -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, } @@ -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 { @@ -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); @@ -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![ diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index 72fa858e4cba8..bcf5fd2b13db1 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -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 } } @@ -118,14 +120,7 @@ type CastResult<'tcx> = Result, 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) => { @@ -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 { @@ -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) => { @@ -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)) @@ -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) } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 0a966b0c17071..07c45d3ee5192 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -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>, } -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) @@ -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> { @@ -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 => { @@ -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 { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index 1237132f61542..be7976b7a93b2 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -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() || diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index eb1414d42e179..9615dfa5093c3 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -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)); } diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index fad070ca8d8f9..f39c354fb3020 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -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 { diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index 0010f312ef985..db3b15d44bcc2 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -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), @@ -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(), } diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 2bb6b39966a82..2d6dce8adf532 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -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}; @@ -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, pub tables: &'a ty::TypeckTables<'gcx>, @@ -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, @@ -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, + } } } @@ -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) diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 468646c1ced8f..76a576cd17b07 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -39,6 +39,7 @@ use rustc::middle::mem_categorization as mc; use rustc::middle::mem_categorization::Categorization; use rustc::mir::transform::MirSource; use rustc::ty::{self, Ty, TyCtxt}; +use rustc::ty::subst::Substs; use rustc::traits::Reveal; use rustc::util::common::ErrorReported; use rustc::util::nodemap::NodeSet; @@ -58,13 +59,17 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> { promotable: bool, mut_rvalue_borrows: NodeSet, param_env: ty::ParamEnv<'tcx>, + identity_substs: &'tcx Substs<'tcx>, tables: &'a ty::TypeckTables<'tcx>, } impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { + fn const_cx(&self) -> ConstContext<'a, 'gcx> { + ConstContext::new(self.tcx, self.tables, self.identity_substs) + } + fn check_const_eval(&self, expr: &'gcx hir::Expr) { - let const_cx = ConstContext::with_tables(self.tcx, self.tables); - if let Err(err) = const_cx.eval(expr) { + if let Err(err) = self.const_cx().eval(expr) { match err.kind { UnimplementedConstVal(_) => {} IndexOpFeatureGated => {} @@ -121,25 +126,26 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { } let item_id = self.tcx.hir.body_owner(body_id); + let item_def_id = self.tcx.hir.local_def_id(item_id); let outer_in_fn = self.in_fn; + let outer_tables = self.tables; + let outer_param_env = self.param_env; + let outer_identity_substs = self.identity_substs; + self.in_fn = match MirSource::from_node(self.tcx, item_id) { MirSource::Fn(_) => true, _ => false }; - - let outer_tables = self.tables; - let item_def_id = self.tcx.hir.local_def_id(item_id); self.tables = self.tcx.typeck_tables_of(item_def_id); + self.param_env = self.tcx.param_env(item_def_id); + self.identity_substs = Substs::identity_for_item(self.tcx, item_def_id); let body = self.tcx.hir.body(body_id); if !self.in_fn { self.check_const_eval(&body.value); } - let outer_penv = self.param_env; - self.param_env = self.tcx.param_env(item_def_id); - let tcx = self.tcx; let param_env = self.param_env; let region_maps = self.tcx.region_maps(item_def_id); @@ -148,9 +154,10 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.visit_body(body); - self.param_env = outer_penv; - self.tables = outer_tables; self.in_fn = outer_in_fn; + self.tables = outer_tables; + self.param_env = outer_param_env; + self.identity_substs = outer_identity_substs; } fn visit_pat(&mut self, p: &'tcx hir::Pat) { @@ -159,8 +166,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { self.check_const_eval(lit); } PatKind::Range(ref start, ref end, RangeEnd::Excluded) => { - let const_cx = ConstContext::with_tables(self.tcx, self.tables); - match const_cx.compare_lit_exprs(p.span, start, end) { + match self.const_cx().compare_lit_exprs(p.span, start, end) { Ok(Ordering::Less) => {} Ok(Ordering::Equal) | Ok(Ordering::Greater) => { @@ -173,8 +179,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { } } PatKind::Range(ref start, ref end, RangeEnd::Included) => { - let const_cx = ConstContext::with_tables(self.tcx, self.tables); - match const_cx.compare_lit_exprs(p.span, start, end) { + match self.const_cx().compare_lit_exprs(p.span, start, end) { Ok(Ordering::Less) | Ok(Ordering::Equal) => {} Ok(Ordering::Greater) => { @@ -240,8 +245,7 @@ impl<'a, 'tcx> Visitor<'tcx> for CheckCrateVisitor<'a, 'tcx> { } if self.in_fn && self.promotable { - let const_cx = ConstContext::with_tables(self.tcx, self.tables); - match const_cx.eval(ex) { + match self.const_cx().eval(ex) { Ok(_) => {} Err(ConstEvalErr { kind: UnimplementedConstVal(_), .. }) | Err(ConstEvalErr { kind: MiscCatchAll, .. }) | @@ -472,6 +476,7 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) { promotable: false, mut_rvalue_borrows: NodeSet(), param_env: ty::ParamEnv::empty(Reveal::UserFacing), + identity_substs: Substs::empty(), }.as_deep_visitor()); tcx.sess.abort_if_errors(); } diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 143079b0a0823..45ed6ecffd86a 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -560,7 +560,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, let wrapped_discr = prev_discr.map_or(initial, |d| d.wrap_incr()); prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); - let substs = Substs::empty(); + let substs = Substs::identity_for_item(tcx, expr_did); let result = tcx.at(variant.span).const_eval((expr_did, substs)); // enum variant evaluation happens before the global constant check From 60cf5428b3c3671da8ebfd7e885f8b06150655eb Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Wed, 26 Jul 2017 15:51:53 +0300 Subject: [PATCH 2/2] rustc_const_eval: keep track of the appropriate ParamEnv. --- src/librustc/middle/const_val.rs | 6 ++- src/librustc/ty/maps.rs | 9 ++-- src/librustc/ty/mod.rs | 6 ++- src/librustc/ty/structural_impls.rs | 2 +- src/librustc_const_eval/check_match.rs | 10 ++-- src/librustc_const_eval/eval.rs | 68 +++++++++++++------------- src/librustc_const_eval/pattern.rs | 23 ++++++--- src/librustc_lint/types.rs | 4 +- src/librustc_mir/build/mod.rs | 2 +- src/librustc_mir/hair/cx/block.rs | 2 +- src/librustc_mir/hair/cx/expr.rs | 7 ++- src/librustc_mir/hair/cx/mod.rs | 7 ++- src/librustc_passes/consts.rs | 2 +- src/librustc_typeck/collect.rs | 4 +- src/test/run-pass/issue-43357.rs | 19 +++++++ 15 files changed, 107 insertions(+), 64 deletions(-) create mode 100644 src/test/run-pass/issue-43357.rs diff --git a/src/librustc/middle/const_val.rs b/src/librustc/middle/const_val.rs index 33e9df1e413c7..b6b1648f39687 100644 --- a/src/librustc/middle/const_val.rs +++ b/src/librustc/middle/const_val.rs @@ -14,7 +14,8 @@ pub use rustc_const_math::ConstInt; use hir; use hir::def::Def; use hir::def_id::DefId; -use ty::{TyCtxt, layout}; +use traits::Reveal; +use ty::{self, TyCtxt, layout}; use ty::subst::Substs; use util::common::ErrorReported; use rustc_const_math::*; @@ -229,8 +230,9 @@ 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 param_env = ty::ParamEnv::empty(Reveal::UserFacing); let substs = Substs::identity_for_item(tcx.global_tcx(), count_def_id); - match tcx.at(count_expr.span).const_eval((count_def_id, substs)) { + match tcx.at(count_expr.span).const_eval(param_env.and((count_def_id, substs))) { Ok(Integral(Usize(count))) => { let val = count.as_u64(tcx.sess.target.uint_type); assert_eq!(val as usize as u64, val); diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index e94308f351011..7a45a706ea405 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -372,8 +372,8 @@ impl<'tcx> QueryDescription for queries::reachable_set<'tcx> { } impl<'tcx> QueryDescription for queries::const_eval<'tcx> { - fn describe(tcx: TyCtxt, (def_id, _): (DefId, &'tcx Substs<'tcx>)) -> String { - format!("const-evaluating `{}`", tcx.item_path_str(def_id)) + fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> String { + format!("const-evaluating `{}`", tcx.item_path_str(key.value.0)) } } @@ -935,7 +935,7 @@ define_maps! { <'tcx> /// Results of evaluating const items or constants embedded in /// other items (such as enum variant explicit discriminants). - [] const_eval: const_eval_dep_node((DefId, &'tcx Substs<'tcx>)) + [] const_eval: const_eval_dep_node(ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> const_val::EvalResult<'tcx>, /// Performs the privacy check and computes "access levels". @@ -1032,8 +1032,9 @@ fn typeck_item_bodies_dep_node<'tcx>(_: CrateNum) -> DepConstructor<'tcx> { DepConstructor::TypeckBodiesKrate } -fn const_eval_dep_node<'tcx>((def_id, substs): (DefId, &'tcx Substs<'tcx>)) +fn const_eval_dep_node<'tcx>(key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> DepConstructor<'tcx> { + let (def_id, substs) = key.value; DepConstructor::ConstEval { def_id, substs } } diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 70aee6ffcf357..804f47b5283f2 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -1582,6 +1582,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { #[inline] pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> impl Iterator + 'a { + let param_env = ParamEnv::empty(traits::Reveal::UserFacing); let repr_type = self.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx.global_tcx()); let mut prev_discr = None::; @@ -1589,7 +1590,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { let mut discr = prev_discr.map_or(initial, |d| d.wrap_incr()); if let VariantDiscr::Explicit(expr_did) = v.discr { let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); - match tcx.const_eval((expr_did, substs)) { + match tcx.const_eval(param_env.and((expr_did, substs))) { Ok(ConstVal::Integral(v)) => { discr = v; } @@ -1617,6 +1618,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { tcx: TyCtxt<'a, 'gcx, 'tcx>, variant_index: usize) -> ConstInt { + let param_env = ParamEnv::empty(traits::Reveal::UserFacing); let repr_type = self.repr.discr_type(); let mut explicit_value = repr_type.initial_discriminant(tcx.global_tcx()); let mut explicit_index = variant_index; @@ -1628,7 +1630,7 @@ impl<'a, 'gcx, 'tcx> AdtDef { } ty::VariantDiscr::Explicit(expr_did) => { let substs = Substs::identity_for_item(tcx.global_tcx(), expr_did); - match tcx.const_eval((expr_did, substs)) { + match tcx.const_eval(param_env.and((expr_did, substs))) { Ok(ConstVal::Integral(v)) => { explicit_value = v; break; diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index b81bd595e25b0..f261a56cdccdd 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -398,7 +398,7 @@ macro_rules! CopyImpls { } } -CopyImpls! { (), hir::Unsafety, abi::Abi } +CopyImpls! { (), hir::Unsafety, abi::Abi, hir::def_id::DefId } impl<'tcx, T:TypeFoldable<'tcx>, U:TypeFoldable<'tcx>> TypeFoldable<'tcx> for (T, U) { fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> (T, U) { diff --git a/src/librustc_const_eval/check_match.rs b/src/librustc_const_eval/check_match.rs index e7a12df0a27ae..95c8613232ec2 100644 --- a/src/librustc_const_eval/check_match.rs +++ b/src/librustc_const_eval/check_match.rs @@ -165,8 +165,9 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> { let inlined_arms : Vec<(Vec<_>, _)> = arms.iter().map(|arm| ( arm.pats.iter().map(|pat| { - let substs = self.identity_substs; - let mut patcx = PatternContext::new(self.tcx, self.tables, substs); + let mut patcx = PatternContext::new(self.tcx, + self.param_env.and(self.identity_substs), + self.tables); let pattern = expand_pattern(cx, patcx.lower_pattern(&pat)); if !patcx.errors.is_empty() { patcx.report_inlining_errors(pat.span); @@ -233,8 +234,9 @@ 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 substs = self.identity_substs; - let mut patcx = PatternContext::new(self.tcx, self.tables, substs); + let mut patcx = PatternContext::new(self.tcx, + self.param_env.and(self.identity_substs), + self.tables); let pattern = patcx.lower_pattern(pat); let pattern_ty = pattern.ty; let pats : Matrix = vec![vec![ diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs index bcf5fd2b13db1..463f256fe6c6f 100644 --- a/src/librustc_const_eval/eval.rs +++ b/src/librustc_const_eval/eval.rs @@ -21,7 +21,6 @@ use rustc::ty::{self, Ty, TyCtxt}; use rustc::ty::maps::Providers; use rustc::ty::util::IntTypeExt; use rustc::ty::subst::{Substs, Subst}; -use rustc::traits::Reveal; use rustc::util::common::ErrorReported; use rustc::util::nodemap::DefIdMap; @@ -49,24 +48,21 @@ macro_rules! math { } } -/// * `def_id` is the id of the constant. -/// * `substs` is the monomorphized substitutions for the expression. -/// -/// `substs` is optional and is used for associated constants. -/// This generally happens in late/trans const evaluation. +/// * `DefId` is the id of the constant. +/// * `Substs` is the monomorphized substitutions for the expression. pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>) + key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> Option<(DefId, &'tcx Substs<'tcx>)> { + let (def_id, _) = key.value; if let Some(node_id) = tcx.hir.as_local_node_id(def_id) { match tcx.hir.find(node_id) { Some(hir_map::NodeTraitItem(_)) => { // If we have a trait item and the substitutions for it, // `resolve_trait_associated_const` will select an impl // or the default. - resolve_trait_associated_const(tcx, def_id, substs) + resolve_trait_associated_const(tcx, key) } - _ => Some((def_id, substs)) + _ => Some(key.value) } } else { match tcx.describe_def(def_id) { @@ -76,12 +72,12 @@ pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // trait-associated const if the caller gives us the // substitutions for the reference to it. if tcx.trait_of_item(def_id).is_some() { - resolve_trait_associated_const(tcx, def_id, substs) + resolve_trait_associated_const(tcx, key) } else { - Some((def_id, substs)) + Some(key.value) } } - _ => Some((def_id, substs)) + _ => Some(key.value) } } } @@ -89,18 +85,21 @@ pub fn lookup_const_by_id<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, pub struct ConstContext<'a, 'tcx: 'a> { tcx: TyCtxt<'a, 'tcx, 'tcx>, tables: &'a ty::TypeckTables<'tcx>, + param_env: ty::ParamEnv<'tcx>, substs: &'tcx Substs<'tcx>, fn_args: Option>> } impl<'a, 'tcx> ConstContext<'a, 'tcx> { pub fn new(tcx: TyCtxt<'a, 'tcx, 'tcx>, - tables: &'a ty::TypeckTables<'tcx>, - substs: &'tcx Substs<'tcx>) -> Self { + param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>, + tables: &'a ty::TypeckTables<'tcx>) + -> Self { ConstContext { tcx, + param_env: param_env_and_substs.param_env, tables, - substs, + substs: param_env_and_substs.value, fn_args: None } } @@ -279,7 +278,7 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, match cx.tables.qpath_def(qpath, e.id) { Def::Const(def_id) | Def::AssociatedConst(def_id) => { - match tcx.at(e.span).const_eval((def_id, substs)) { + match tcx.at(e.span).const_eval(cx.param_env.and((def_id, substs))) { Ok(val) => val, Err(ConstEvalErr { kind: TypeckError, .. }) => { signal!(e, TypeckError); @@ -323,10 +322,9 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, if tcx.fn_sig(def_id).abi() == Abi::RustIntrinsic { let layout_of = |ty: Ty<'tcx>| { - ty.layout(tcx, ty::ParamEnv::empty(traits::Reveal::All)) - .map_err(|err| { - ConstEvalErr { span: e.span, kind: LayoutError(err) } - }) + ty.layout(tcx, cx.param_env).map_err(|err| { + ConstEvalErr { span: e.span, kind: LayoutError(err) } + }) }; match &tcx.item_name(def_id).as_str()[..] { "size_of" => { @@ -377,7 +375,8 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } debug!("const call({:?})", call_args); let callee_cx = ConstContext { - tcx: tcx, + tcx, + param_env: cx.param_env, tables: tcx.typeck_tables_of(def_id), substs: substs, fn_args: Some(call_args) @@ -477,9 +476,10 @@ fn eval_const_expr_partial<'a, 'tcx>(cx: &ConstContext<'a, 'tcx>, } fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>) + key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> Option<(DefId, &'tcx Substs<'tcx>)> { + let param_env = key.param_env; + let (def_id, substs) = key.value; let trait_item = tcx.associated_item(def_id); let trait_id = trait_item.container.id(); let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs)); @@ -487,7 +487,6 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, trait_ref); tcx.infer_ctxt().enter(|infcx| { - let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let mut selcx = traits::SelectionContext::new(&infcx); let obligation = traits::Obligation::new(traits::ObligationCause::dummy(), param_env, @@ -506,10 +505,8 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, }; // NOTE: this code does not currently account for specialization, but when - // it does so, it should hook into the Reveal to determine when the - // constant should resolve; this will also require plumbing through to this - // function whether we are in "trans mode" to pick the right Reveal - // when constructing the inference context above. + // it does so, it should hook into the param_env.reveal to determine when the + // constant should resolve. match selection { traits::VtableImpl(ref impl_data) => { let name = trait_item.name; @@ -524,15 +521,16 @@ fn resolve_trait_associated_const<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } None => { if trait_item.defaultness.has_value() { - Some((def_id, substs)) + Some(key.value) } else { None } } } } + traits::VtableParam(_) => None, _ => { - bug!("resolve_trait_associated_const: unexpected vtable type") + bug!("resolve_trait_associated_const: unexpected vtable type {:?}", selection) } } }) @@ -761,13 +759,13 @@ pub fn provide(providers: &mut Providers) { } fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - (def_id, substs): (DefId, &'tcx Substs<'tcx>)) + key: ty::ParamEnvAnd<'tcx, (DefId, &'tcx Substs<'tcx>)>) -> EvalResult<'tcx> { - let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, def_id, substs) { + let (def_id, substs) = if let Some(resolved) = lookup_const_by_id(tcx, key) { resolved } else { return Err(ConstEvalErr { - span: tcx.def_span(def_id), + span: tcx.def_span(key.value.0), kind: TypeckError }); }; @@ -779,5 +777,5 @@ fn const_eval<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, } else { tcx.sess.cstore.item_body(tcx, def_id) }; - ConstContext::new(tcx, tables, substs).eval(&body.value) + ConstContext::new(tcx, key.param_env.and(substs), tables).eval(&body.value) } diff --git a/src/librustc_const_eval/pattern.rs b/src/librustc_const_eval/pattern.rs index 07c45d3ee5192..ab919da815206 100644 --- a/src/librustc_const_eval/pattern.rs +++ b/src/librustc_const_eval/pattern.rs @@ -268,6 +268,7 @@ impl<'tcx> fmt::Display for Pattern<'tcx> { pub struct PatternContext<'a, 'tcx: 'a> { pub tcx: TyCtxt<'a, 'tcx, 'tcx>, + pub param_env: ty::ParamEnv<'tcx>, pub tables: &'a ty::TypeckTables<'tcx>, pub substs: &'tcx Substs<'tcx>, pub errors: Vec>, @@ -275,10 +276,10 @@ pub struct PatternContext<'a, 'tcx: 'a> { impl<'a, 'tcx> Pattern<'tcx> { pub fn from_hir(tcx: TyCtxt<'a, 'tcx, 'tcx>, + param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>, tables: &'a ty::TypeckTables<'tcx>, - substs: &'tcx Substs<'tcx>, pat: &hir::Pat) -> Self { - let mut pcx = PatternContext::new(tcx, tables, substs); + let mut pcx = PatternContext::new(tcx, param_env_and_substs, tables); let result = pcx.lower_pattern(pat); if !pcx.errors.is_empty() { span_bug!(pat.span, "encountered errors lowering pattern: {:?}", pcx.errors) @@ -290,9 +291,15 @@ impl<'a, 'tcx> Pattern<'tcx> { 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![] } + param_env_and_substs: ty::ParamEnvAnd<'tcx, &'tcx Substs<'tcx>>, + tables: &'a ty::TypeckTables<'tcx>) -> Self { + PatternContext { + tcx, + param_env: param_env_and_substs.param_env, + tables, + substs: param_env_and_substs.value, + errors: vec![] + } } pub fn lower_pattern(&mut self, pat: &hir::Pat) -> Pattern<'tcx> { @@ -588,7 +595,7 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { let kind = match def { Def::Const(def_id) | Def::AssociatedConst(def_id) => { let substs = self.tables.node_substs(id); - match eval::lookup_const_by_id(self.tcx, def_id, substs) { + match eval::lookup_const_by_id(self.tcx, self.param_env.and((def_id, substs))) { Some((def_id, substs)) => { // Enter the inlined constant's tables&substs temporarily. let old_tables = self.tables; @@ -622,7 +629,9 @@ impl<'a, 'tcx> PatternContext<'a, 'tcx> { } fn lower_lit(&mut self, expr: &hir::Expr) -> PatternKind<'tcx> { - let const_cx = eval::ConstContext::new(self.tcx, self.tables, self.substs); + let const_cx = eval::ConstContext::new(self.tcx, + self.param_env.and(self.substs), + self.tables); match const_cx.eval(expr) { Ok(value) => { if let ConstVal::Variant(def_id) = value { diff --git a/src/librustc_lint/types.rs b/src/librustc_lint/types.rs index be7976b7a93b2..aca98df9cc998 100644 --- a/src/librustc_lint/types.rs +++ b/src/librustc_lint/types.rs @@ -113,7 +113,9 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for TypeLimits { 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); + let const_cx = ConstContext::new(cx.tcx, + cx.param_env.and(substs), + cx.tables); match const_cx.eval(&r) { Ok(ConstVal::Integral(i)) => { i.is_negative() || diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 9615dfa5093c3..5badef3cfa180 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -514,8 +514,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> { if let Some(pattern) = pattern { let pattern = Pattern::from_hir(self.hir.tcx().global_tcx(), + self.hir.param_env.and(self.hir.identity_substs), 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)); diff --git a/src/librustc_mir/hair/cx/block.rs b/src/librustc_mir/hair/cx/block.rs index f39c354fb3020..c91326f6d8746 100644 --- a/src/librustc_mir/hair/cx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -71,8 +71,8 @@ fn mirror_stmts<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, }); let pattern = Pattern::from_hir(cx.tcx.global_tcx(), + cx.param_env.and(cx.identity_substs), cx.tables(), - cx.identity_substs, &local.pat); result.push(StmtRef::Mirror(Box::new(Stmt { span: stmt.span, diff --git a/src/librustc_mir/hair/cx/expr.rs b/src/librustc_mir/hair/cx/expr.rs index db3b15d44bcc2..06a0c4ff213da 100644 --- a/src/librustc_mir/hair/cx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -467,7 +467,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>, let c = &cx.tcx.hir.body(count).value; let def_id = cx.tcx.hir.body_owner_def_id(count); 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)) { + let count = match cx.tcx.at(c.span).const_eval(cx.param_env.and((def_id, substs))) { Ok(ConstVal::Integral(ConstInt::Usize(u))) => u, Ok(other) => bug!("constant evaluation of repeat count yielded {:?}", other), Err(s) => cx.fatal_const_eval_err(&s, c.span, "expression") @@ -605,7 +605,10 @@ 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.global_tcx(), cx.tables(), cx.identity_substs, p) + Pattern::from_hir(cx.tcx.global_tcx(), + cx.param_env.and(cx.identity_substs), + cx.tables(), + p) }).collect(), guard: arm.guard.to_ref(), body: arm.body.to_ref(), diff --git a/src/librustc_mir/hair/cx/mod.rs b/src/librustc_mir/hair/cx/mod.rs index 2d6dce8adf532..2f4ab36d394b0 100644 --- a/src/librustc_mir/hair/cx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -37,7 +37,7 @@ 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>, + pub param_env: ty::ParamEnv<'gcx>, /// Identity `Substs` for use with const-evaluation. pub identity_substs: &'gcx Substs<'gcx>, @@ -135,7 +135,10 @@ 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::new(tcx, self.tables(), self.identity_substs).eval(e) { + let const_cx = ConstContext::new(tcx, + self.param_env.and(self.identity_substs), + self.tables()); + match const_cx.eval(e) { Ok(value) => Literal::Value { value: value }, Err(s) => self.fatal_const_eval_err(&s, e.span, "expression") } diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs index 76a576cd17b07..a881bf9eac7bf 100644 --- a/src/librustc_passes/consts.rs +++ b/src/librustc_passes/consts.rs @@ -65,7 +65,7 @@ struct CheckCrateVisitor<'a, 'tcx: 'a> { impl<'a, 'gcx> CheckCrateVisitor<'a, 'gcx> { fn const_cx(&self) -> ConstContext<'a, 'gcx> { - ConstContext::new(self.tcx, self.tables, self.identity_substs) + ConstContext::new(self.tcx, self.param_env.and(self.identity_substs), self.tables) } fn check_const_eval(&self, expr: &'gcx hir::Expr) { diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 45ed6ecffd86a..8780131bbcc26 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -59,6 +59,7 @@ use constrained_type_params as ctp; use middle::lang_items::SizedTraitLangItem; use middle::const_val::ConstVal; use middle::resolve_lifetime as rl; +use rustc::traits::Reveal; use rustc::ty::subst::Substs; use rustc::ty::{ToPredicate, ReprOptions}; use rustc::ty::{self, AdtKind, ToPolyTraitRef, Ty, TyCtxt}; @@ -550,6 +551,7 @@ fn convert_variant_ctor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId, variants: &[hir::Variant]) { + let param_env = ty::ParamEnv::empty(Reveal::UserFacing); let def = tcx.adt_def(def_id); let repr_type = def.repr.discr_type(); let initial = repr_type.initial_discriminant(tcx); @@ -561,7 +563,7 @@ fn convert_enum_variant_types<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, prev_discr = Some(if let Some(e) = variant.node.disr_expr { let expr_did = tcx.hir.local_def_id(e.node_id); let substs = Substs::identity_for_item(tcx, expr_did); - let result = tcx.at(variant.span).const_eval((expr_did, substs)); + let result = tcx.at(variant.span).const_eval(param_env.and((expr_did, substs))); // enum variant evaluation happens before the global constant check // so we need to report the real error diff --git a/src/test/run-pass/issue-43357.rs b/src/test/run-pass/issue-43357.rs new file mode 100644 index 0000000000000..9a5f65d67b106 --- /dev/null +++ b/src/test/run-pass/issue-43357.rs @@ -0,0 +1,19 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Trait { + type Output; +} + +fn f() { + std::mem::size_of::(); +} + +fn main() {}