From 4d8f995c3a482fecdb9a77455cd8d68d514d62ac Mon Sep 17 00:00:00 2001 From: Eduard Burtescu Date: Tue, 30 Dec 2014 22:36:03 +0200 Subject: [PATCH] rustc: merge check_static into check_const. --- src/librustc/lib.rs | 1 - src/librustc/middle/check_const.rs | 349 +++++++++++++++--- src/librustc/middle/check_static.rs | 342 ----------------- src/librustc_driver/driver.rs | 3 - .../check-static-immutable-mut-slices.rs | 2 +- .../check-static-values-constraints.rs | 15 +- src/test/compile-fail/issue-17458.rs | 2 +- .../issue-17718-const-bad-values.rs | 4 +- src/test/compile-fail/issue-18118.rs | 3 +- src/test/compile-fail/issue-7364.rs | 3 +- .../compile-fail/static-mut-not-constant.rs | 2 +- 11 files changed, 316 insertions(+), 410 deletions(-) delete mode 100644 src/librustc/middle/check_static.rs diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs index f060d464e41..abf70813d36 100644 --- a/src/librustc/lib.rs +++ b/src/librustc/lib.rs @@ -90,7 +90,6 @@ pub mod middle { pub mod check_loop; pub mod check_match; pub mod check_rvalues; - pub mod check_static; pub mod const_eval; pub mod dataflow; pub mod dead; diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs index b558f838a51..34d1654ec4b 100644 --- a/src/librustc/middle/check_const.rs +++ b/src/librustc/middle/check_const.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -8,44 +8,117 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// Verifies that the types and values of const and static items +// are safe. The rules enforced by this module are: +// +// - For each *mutable* static item, it checks that its **type**: +// - doesn't have a destructor +// - doesn't own an owned pointer +// +// - For each *immutable* static item, it checks that its **value**: +// - doesn't own owned, managed pointers +// - doesn't contain a struct literal or a call to an enum variant / struct constructor where +// - the type of the struct/enum has a dtor +// +// Rules Enforced Elsewhere: +// - It's not possible to take the address of a static item with unsafe interior. This is enforced +// by borrowck::gather_loans -use middle::def::*; +use self::Mode::*; + +use middle::def; +use middle::expr_use_visitor as euv; +use middle::infer; +use middle::mem_categorization as mc; +use middle::traits; use middle::ty; use util::ppaux; use syntax::ast; +use syntax::codemap::Span; +use syntax::print::pprust; use syntax::visit::{self, Visitor}; +#[derive(Copy, Eq, PartialEq)] +enum Mode { + InConstant, + InStatic, + InStaticMut, + InNothing, +} + struct CheckCrateVisitor<'a, 'tcx: 'a> { tcx: &'a ty::ctxt<'tcx>, - in_const: bool + mode: Mode, } impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> { - fn with_const(&mut self, in_const: bool, f: F) where + fn with_mode(&mut self, mode: Mode, f: F) where F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>), { - let was_const = self.in_const; - self.in_const = in_const; + let old = self.mode; + self.mode = mode; f(self); - self.in_const = was_const; + self.mode = old; } - fn inside_const(&mut self, f: F) where - F: FnOnce(&mut CheckCrateVisitor<'a, 'tcx>), - { - self.with_const(true, f); + + fn msg(&self) -> &'static str { + match self.mode { + InConstant => "constant", + InStaticMut | InStatic => "static", + InNothing => unreachable!(), + } + } + + fn check_static_mut_type(&self, e: &ast::Expr) { + let node_ty = ty::node_id_to_type(self.tcx, e.id); + let tcontents = ty::type_contents(self.tcx, node_ty); + + let suffix = if tcontents.has_dtor() { + "destructors" + } else if tcontents.owns_owned() { + "owned pointers" + } else { + return + }; + + self.tcx.sess.span_err(e.span, &format!("mutable statics are not allowed \ + to have {}", suffix)[]); + } + + fn check_static_type(&self, e: &ast::Expr) { + let ty = ty::node_id_to_type(self.tcx, e.id); + let infcx = infer::new_infer_ctxt(self.tcx); + let mut fulfill_cx = traits::FulfillmentContext::new(); + let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic); + fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause); + let env = ty::empty_parameter_environment(self.tcx); + match fulfill_cx.select_all_or_error(&infcx, &env) { + Ok(()) => { }, + Err(ref errors) => { + traits::report_fulfillment_errors(&infcx, errors); + } + } } } impl<'a, 'tcx, 'v> Visitor<'v> for CheckCrateVisitor<'a, 'tcx> { fn visit_item(&mut self, i: &ast::Item) { + debug!("visit_item(item={})", pprust::item_to_string(i)); match i.node { - ast::ItemStatic(_, _, ref ex) | - ast::ItemConst(_, ref ex) => { - self.inside_const(|v| v.visit_expr(&**ex)); + ast::ItemStatic(_, ast::MutImmutable, ref expr) => { + self.check_static_type(&**expr); + self.with_mode(InStatic, |v| v.visit_expr(&**expr)); + } + ast::ItemStatic(_, ast::MutMutable, ref expr) => { + self.check_static_mut_type(&**expr); + self.with_mode(InStaticMut, |v| v.visit_expr(&**expr)); + } + ast::ItemConst(_, ref expr) => { + self.with_mode(InConstant, |v| v.visit_expr(&**expr)); } ast::ItemEnum(ref enum_definition, _) => { - self.inside_const(|v| { + self.with_mode(InConstant, |v| { for var in &enum_definition.variants { if let Some(ref ex) = var.node.disr_expr { v.visit_expr(&**ex); @@ -53,46 +126,60 @@ fn visit_item(&mut self, i: &ast::Item) { } }); } - _ => self.with_const(false, |v| visit::walk_item(v, i)) + _ => { + self.with_mode(InNothing, |v| visit::walk_item(v, i)); + } } } + fn visit_pat(&mut self, p: &ast::Pat) { - let is_const = match p.node { - ast::PatLit(_) | ast::PatRange(..) => true, - _ => false + let mode = match p.node { + ast::PatLit(_) | ast::PatRange(..) => InConstant, + _ => InNothing }; - self.with_const(is_const, |v| visit::walk_pat(v, p)) + self.with_mode(mode, |v| visit::walk_pat(v, p)) } + fn visit_expr(&mut self, ex: &ast::Expr) { - if self.in_const { + if self.mode != InNothing { check_expr(self, ex); } visit::walk_expr(self, ex); } } -pub fn check_crate(tcx: &ty::ctxt) { - visit::walk_crate(&mut CheckCrateVisitor { tcx: tcx, in_const: false }, - tcx.map.krate()); - tcx.sess.abort_if_errors(); -} - +/// This function is used to enforce the constraints on +/// const/static items. It walks through the *value* +/// of the item walking down the expression and evaluating +/// every nested expression. If the expression is not part +/// of a const/static item, this function does nothing but +/// walking down through it. fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) { + let node_ty = ty::node_id_to_type(v.tcx, e.id); + + match node_ty.sty { + ty::ty_struct(did, _) | + ty::ty_enum(did, _) if ty::has_dtor(v.tcx, did) => { + v.tcx.sess.span_err(e.span, + &format!("{}s are not allowed to have destructors", + v.msg())[]) + } + _ => {} + } + match e.node { - ast::ExprUnary(ast::UnDeref, _) => {} + ast::ExprBox(..) | ast::ExprUnary(ast::UnUniq, _) => { span_err!(v.tcx.sess, e.span, E0010, - "cannot do allocations in constant expressions"); + "allocations are not allowed in {}s", v.msg()); } ast::ExprBinary(..) | ast::ExprUnary(..) => { let method_call = ty::MethodCall::expr(e.id); if v.tcx.method_map.borrow().contains_key(&method_call) { span_err!(v.tcx.sess, e.span, E0011, - "user-defined operators are not allowed in constant \ - expressions"); + "user-defined operators are not allowed in {}s", v.msg()); } } - ast::ExprLit(_) => {} ast::ExprCast(ref from, _) => { let toty = ty::expr_ty(v.tcx, e); let fromty = ty::expr_ty(v.tcx, &**from); @@ -102,20 +189,24 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) { (ty::type_is_bare_fn(toty) && ty::type_is_bare_fn_item(fromty)); if !is_legal_cast { span_err!(v.tcx.sess, e.span, E0012, - "can not cast to `{}` in a constant expression", - ppaux::ty_to_string(v.tcx, toty)); + "can not cast to `{}` in {}s", + ppaux::ty_to_string(v.tcx, toty), v.msg()); } if ty::type_is_unsafe_ptr(fromty) && ty::type_is_numeric(toty) { span_err!(v.tcx.sess, e.span, E0018, - "can not cast a pointer to an integer in a constant \ - expression"); + "can not cast a pointer to an integer in {}s", v.msg()); } } ast::ExprPath(_) | ast::ExprQPath(_) => { match v.tcx.def_map.borrow()[e.id] { - DefStatic(..) | DefConst(..) | - DefFn(..) | DefStaticMethod(..) | DefMethod(..) | - DefStruct(_) | DefVariant(_, _, _) => {} + def::DefStatic(..) if v.mode == InConstant => { + span_err!(v.tcx.sess, e.span, E0013, + "constants cannot refer to other statics, \ + insert an intermediate constant instead"); + } + def::DefStatic(..) | def::DefConst(..) | + def::DefFn(..) | def::DefStaticMethod(..) | def::DefMethod(..) | + def::DefStruct(_) | def::DefVariant(_, _, _) => {} def => { debug!("(checking const) found bad def: {:?}", def); @@ -127,7 +218,7 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) { } ast::ExprCall(ref callee, _) => { match v.tcx.def_map.borrow()[callee.id] { - DefStruct(..) | DefVariant(..) => {} // OK. + def::DefStruct(..) | def::DefVariant(..) => {} // OK. _ => { span_err!(v.tcx.sess, e.span, E0015, "function calls in constants are limited to \ @@ -160,6 +251,17 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) { } } } + ast::ExprAddrOf(ast::MutMutable, ref inner) => { + match inner.node { + // Mutable slices are allowed. Only in `static mut`. + ast::ExprVec(_) if v.mode == InStaticMut => {} + _ => span_err!(v.tcx.sess, e.span, E0017, + "references in {}s may only refer \ + to immutable values", v.msg()) + } + } + + ast::ExprLit(_) | ast::ExprVec(_) | ast::ExprAddrOf(ast::MutImmutable, _) | ast::ExprParen(..) | @@ -170,18 +272,165 @@ fn check_expr(v: &mut CheckCrateVisitor, e: &ast::Expr) { ast::ExprRepeat(..) | ast::ExprStruct(..) => {} - ast::ExprAddrOf(_, ref inner) => { - match inner.node { - // Mutable slices are allowed. - ast::ExprVec(_) => {} - _ => span_err!(v.tcx.sess, e.span, E0017, - "references in constants may only refer \ - to immutable values") + // Conditional control flow (possible to implement). + ast::ExprMatch(..) | + ast::ExprIf(..) | + ast::ExprIfLet(..) | - } + // Loops (not very meaningful in constants). + ast::ExprWhile(..) | + ast::ExprWhileLet(..) | + ast::ExprForLoop(..) | + ast::ExprLoop(..) | + + // More control flow (also not very meaningful). + ast::ExprBreak(_) | + ast::ExprAgain(_) | + ast::ExprRet(_) | + + // Miscellaneous expressions that could be implemented. + ast::ExprClosure(..) | + ast::ExprRange(..) | + + // Various other expressions. + ast::ExprMethodCall(..) | + ast::ExprAssign(..) | + ast::ExprAssignOp(..) | + ast::ExprInlineAsm(_) | + ast::ExprMac(_) => { + span_err!(v.tcx.sess, e.span, E0019, + "{} contains unimplemented expression type", v.msg()); } + } +} - _ => span_err!(v.tcx.sess, e.span, E0019, - "constant contains unimplemented expression type") +struct GlobalVisitor<'a,'b,'tcx:'a+'b>( + euv::ExprUseVisitor<'a,'b,'tcx,ty::ParameterEnvironment<'b,'tcx>>); + +struct GlobalChecker<'a,'tcx:'a> { + tcx: &'a ty::ctxt<'tcx> +} + +pub fn check_crate(tcx: &ty::ctxt) { + let param_env = ty::empty_parameter_environment(tcx); + let mut checker = GlobalChecker { + tcx: tcx + }; + let visitor = euv::ExprUseVisitor::new(&mut checker, ¶m_env); + visit::walk_crate(&mut GlobalVisitor(visitor), tcx.map.krate()); + + visit::walk_crate(&mut CheckCrateVisitor { + tcx: tcx, + mode: InNothing, + }, tcx.map.krate()); + + tcx.sess.abort_if_errors(); +} + +impl<'a,'b,'t,'v> Visitor<'v> for GlobalVisitor<'a,'b,'t> { + fn visit_item(&mut self, item: &ast::Item) { + match item.node { + ast::ItemConst(_, ref e) | + ast::ItemStatic(_, _, ref e) => { + let GlobalVisitor(ref mut v) = *self; + v.consume_expr(&**e); + } + _ => {} + } + visit::walk_item(self, item); } } + +impl<'a, 'tcx> euv::Delegate<'tcx> for GlobalChecker<'a, 'tcx> { + fn consume(&mut self, + _consume_id: ast::NodeId, + consume_span: Span, + cmt: mc::cmt, + _mode: euv::ConsumeMode) { + let mut cur = &cmt; + loop { + match cur.cat { + mc::cat_static_item => { + // statics cannot be consumed by value at any time, that would imply + // that they're an initializer (what a const is for) or kept in sync + // over time (not feasible), so deny it outright. + self.tcx.sess.span_err(consume_span, + "cannot refer to other statics by value, use the \ + address-of operator or a constant instead"); + break; + } + mc::cat_deref(ref cmt, _, _) | + mc::cat_downcast(ref cmt, _) | + mc::cat_interior(ref cmt, _) => cur = cmt, + + mc::cat_rvalue(..) | + mc::cat_upvar(..) | + mc::cat_local(..) => break + } + } + } + fn borrow(&mut self, + _borrow_id: ast::NodeId, + borrow_span: Span, + cmt: mc::cmt<'tcx>, + _loan_region: ty::Region, + _bk: ty::BorrowKind, + _loan_cause: euv::LoanCause) { + let mut cur = &cmt; + let mut is_interior = false; + loop { + match cur.cat { + mc::cat_rvalue(..) => { + // constants cannot be borrowed if they contain interior mutability as + // it means that our "silent insertion of statics" could change + // initializer values (very bad). + if ty::type_contents(self.tcx, cur.ty).interior_unsafe() { + self.tcx.sess.span_err(borrow_span, + "cannot borrow a constant which contains \ + interior mutability, create a static instead"); + } + break; + } + mc::cat_static_item => { + if is_interior { + // Borrowed statics can specifically *only* have their address taken, + // not any number of other borrows such as borrowing fields, reading + // elements of an array, etc. + self.tcx.sess.span_err(borrow_span, + "cannot refer to the interior of another \ + static, use a constant instead"); + } + break; + } + mc::cat_deref(ref cmt, _, _) | + mc::cat_downcast(ref cmt, _) | + mc::cat_interior(ref cmt, _) => { + is_interior = true; + cur = cmt; + } + + mc::cat_upvar(..) | + mc::cat_local(..) => break + } + } + } + + fn decl_without_init(&mut self, + _id: ast::NodeId, + _span: Span) {} + fn mutate(&mut self, + _assignment_id: ast::NodeId, + _assignment_span: Span, + _assignee_cmt: mc::cmt, + _mode: euv::MutateMode) {} + + fn matched_pat(&mut self, + _: &ast::Pat, + _: mc::cmt, + _: euv::MatchMode) {} + + fn consume_pat(&mut self, + _consume_pat: &ast::Pat, + _cmt: mc::cmt, + _mode: euv::ConsumeMode) {} +} \ No newline at end of file diff --git a/src/librustc/middle/check_static.rs b/src/librustc/middle/check_static.rs deleted file mode 100644 index ac0caebd6cf..00000000000 --- a/src/librustc/middle/check_static.rs +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright 2014 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. - -// Verifies that the types and values of static items -// are safe. The rules enforced by this module are: -// -// - For each *mutable* static item, it checks that its **type**: -// - doesn't have a destructor -// - doesn't own an owned pointer -// -// - For each *immutable* static item, it checks that its **value**: -// - doesn't own owned, managed pointers -// - doesn't contain a struct literal or a call to an enum variant / struct constructor where -// - the type of the struct/enum has a dtor -// -// Rules Enforced Elsewhere: -// - It's not possible to take the address of a static item with unsafe interior. This is enforced -// by borrowck::gather_loans -use self::Mode::*; - -use middle::ty; -use middle::def; -use middle::infer; -use middle::traits; -use middle::mem_categorization as mc; -use middle::expr_use_visitor as euv; -use util::nodemap::NodeSet; - -use syntax::ast; -use syntax::print::pprust; -use syntax::visit::Visitor; -use syntax::codemap::Span; -use syntax::visit; - -#[derive(Copy, Eq, PartialEq)] -enum Mode { - InConstant, - InStatic, - InStaticMut, - InNothing, -} - -struct CheckStaticVisitor<'a, 'tcx: 'a> { - tcx: &'a ty::ctxt<'tcx>, - mode: Mode, - checker: &'a mut GlobalChecker, -} - -struct GlobalVisitor<'a,'b,'tcx:'a+'b>( - euv::ExprUseVisitor<'a,'b,'tcx,ty::ParameterEnvironment<'b,'tcx>>); -struct GlobalChecker { - static_consumptions: NodeSet, - const_borrows: NodeSet, - static_interior_borrows: NodeSet, - static_local_borrows: NodeSet, -} - -pub fn check_crate(tcx: &ty::ctxt) { - let mut checker = GlobalChecker { - static_consumptions: NodeSet(), - const_borrows: NodeSet(), - static_interior_borrows: NodeSet(), - static_local_borrows: NodeSet(), - }; - { - let param_env = ty::empty_parameter_environment(tcx); - let visitor = euv::ExprUseVisitor::new(&mut checker, ¶m_env); - visit::walk_crate(&mut GlobalVisitor(visitor), tcx.map.krate()); - } - visit::walk_crate(&mut CheckStaticVisitor { - tcx: tcx, - mode: InNothing, - checker: &mut checker, - }, tcx.map.krate()); - tcx.sess.abort_if_errors(); -} - -impl<'a, 'tcx> CheckStaticVisitor<'a, 'tcx> { - fn with_mode(&mut self, mode: Mode, f: F) where - F: FnOnce(&mut CheckStaticVisitor<'a, 'tcx>), - { - let old = self.mode; - self.mode = mode; - f(self); - self.mode = old; - } - - fn msg(&self) -> &'static str { - match self.mode { - InConstant => "constants", - InStaticMut | InStatic => "statics", - InNothing => unreachable!(), - } - } - - fn check_static_mut_type(&self, e: &ast::Expr) { - let node_ty = ty::node_id_to_type(self.tcx, e.id); - let tcontents = ty::type_contents(self.tcx, node_ty); - - let suffix = if tcontents.has_dtor() { - "destructors" - } else if tcontents.owns_owned() { - "owned pointers" - } else { - return - }; - - self.tcx.sess.span_err(e.span, &format!("mutable statics are not allowed \ - to have {}", suffix)[]); - } - - fn check_static_type(&self, e: &ast::Expr) { - let ty = ty::node_id_to_type(self.tcx, e.id); - let infcx = infer::new_infer_ctxt(self.tcx); - let mut fulfill_cx = traits::FulfillmentContext::new(); - let cause = traits::ObligationCause::new(e.span, e.id, traits::SharedStatic); - fulfill_cx.register_builtin_bound(&infcx, ty, ty::BoundSync, cause); - let env = ty::empty_parameter_environment(self.tcx); - match fulfill_cx.select_all_or_error(&infcx, &env) { - Ok(()) => { }, - Err(ref errors) => { - traits::report_fulfillment_errors(&infcx, errors); - } - } - } -} - -impl<'a, 'tcx, 'v> Visitor<'v> for CheckStaticVisitor<'a, 'tcx> { - fn visit_item(&mut self, i: &ast::Item) { - debug!("visit_item(item={})", pprust::item_to_string(i)); - match i.node { - ast::ItemStatic(_, ast::MutImmutable, ref expr) => { - self.check_static_type(&**expr); - self.with_mode(InStatic, |v| v.visit_expr(&**expr)); - } - ast::ItemStatic(_, ast::MutMutable, ref expr) => { - self.check_static_mut_type(&**expr); - self.with_mode(InStaticMut, |v| v.visit_expr(&**expr)); - } - ast::ItemConst(_, ref expr) => { - self.with_mode(InConstant, |v| v.visit_expr(&**expr)); - } - _ => { - self.with_mode(InNothing, |v| visit::walk_item(v, i)); - } - } - } - - /// This method is used to enforce the constraints on - /// immutable static items. It walks through the *value* - /// of the item walking down the expression and evaluating - /// every nested expression. if the expression is not part - /// of a static item, this method does nothing but walking - /// down through it. - fn visit_expr(&mut self, e: &ast::Expr) { - if self.mode == InNothing { - return visit::walk_expr(self, e); - } - - let node_ty = ty::node_id_to_type(self.tcx, e.id); - - match node_ty.sty { - ty::ty_struct(did, _) | - ty::ty_enum(did, _) if ty::has_dtor(self.tcx, did) => { - self.tcx.sess.span_err(e.span, - &format!("{} are not allowed to have \ - destructors", self.msg())[]) - } - _ => {} - } - - // statics cannot be consumed by value at any time, that would imply - // that they're an initializer (what a const is for) or kept in sync - // over time (not feasible), so deny it outright. - if self.checker.static_consumptions.remove(&e.id) { - self.tcx.sess.span_err(e.span, "cannot refer to other statics by \ - value, use the address-of operator \ - or a constant instead"); - } - - // Borrowed statics can specifically *only* have their address taken, - // not any number of other borrows such as borrowing fields, reading - // elements of an array, etc. - if self.checker.static_interior_borrows.remove(&e.id) { - self.tcx.sess.span_err(e.span, "cannot refer to the interior of \ - another static, use a constant \ - instead"); - } - - // constants cannot be borrowed if they contain interior mutability as - // it means that our "silent insertion of statics" could change - // initializer values (very bad). - if self.checker.const_borrows.remove(&e.id) { - let node_ty = ty::node_id_to_type(self.tcx, e.id); - let tcontents = ty::type_contents(self.tcx, node_ty); - if tcontents.interior_unsafe() { - self.tcx.sess.span_err(e.span, "cannot borrow a constant which \ - contains interior mutability, \ - create a static instead"); - } - } - - // local variables in a block expression in a static context (i.e. being - // assigned to a static variable) cannot be borrowed. - if self.checker.static_local_borrows.remove(&e.id) { - self.tcx.sess.span_err(e.span, "cannot borrow a local variable inside \ - a static block, define a separate static \ - instead"); - } - - match e.node { - ast::ExprAddrOf(ast::MutMutable, _) => { - if self.mode != InStaticMut { - span_err!(self.tcx.sess, e.span, E0020, - "{} are not allowed to have mutable references", - self.msg()); - } - }, - ast::ExprBox(..) | - ast::ExprUnary(ast::UnUniq, _) => { - span_err!(self.tcx.sess, e.span, E0022, - "{} are not allowed to have custom pointers", - self.msg()); - } - ast::ExprPath(_) | ast::ExprQPath(_) => { - match ty::resolve_expr(self.tcx, e) { - def::DefStatic(..) if self.mode == InConstant => { - let msg = "constants cannot refer to other statics, \ - insert an intermediate constant \ - instead"; - self.tcx.sess.span_err(e.span, &msg[]); - } - _ => {} - } - } - _ => {} - } - visit::walk_expr(self, e); - } -} - -impl<'a,'b,'t,'v> Visitor<'v> for GlobalVisitor<'a,'b,'t> { - fn visit_item(&mut self, item: &ast::Item) { - match item.node { - ast::ItemConst(_, ref e) | - ast::ItemStatic(_, _, ref e) => { - let GlobalVisitor(ref mut v) = *self; - v.consume_expr(&**e); - } - _ => {} - } - visit::walk_item(self, item); - } -} - -impl<'tcx> euv::Delegate<'tcx> for GlobalChecker { - fn consume(&mut self, - consume_id: ast::NodeId, - _consume_span: Span, - cmt: mc::cmt, - _mode: euv::ConsumeMode) { - let mut cur = &cmt; - loop { - match cur.cat { - mc::cat_static_item => { - self.static_consumptions.insert(consume_id); - break - } - mc::cat_deref(ref cmt, _, _) | - mc::cat_downcast(ref cmt, _) | - mc::cat_interior(ref cmt, _) => cur = cmt, - - mc::cat_rvalue(..) | - mc::cat_upvar(..) | - mc::cat_local(..) => break, - } - } - } - fn borrow(&mut self, - borrow_id: ast::NodeId, - _borrow_span: Span, - cmt: mc::cmt, - _loan_region: ty::Region, - _bk: ty::BorrowKind, - _loan_cause: euv::LoanCause) { - let mut cur = &cmt; - let mut is_interior = false; - loop { - match cur.cat { - mc::cat_rvalue(..) => { - self.const_borrows.insert(borrow_id); - break - } - mc::cat_static_item => { - if is_interior { - self.static_interior_borrows.insert(borrow_id); - } - break - } - mc::cat_deref(ref cmt, _, _) | - mc::cat_interior(ref cmt, _) => { - is_interior = true; - cur = cmt; - } - - mc::cat_downcast(..) | - mc::cat_upvar(..) => unreachable!(), - - mc::cat_local(..) => { - self.static_local_borrows.insert(borrow_id); - break - } - } - } - } - - fn decl_without_init(&mut self, - _id: ast::NodeId, - _span: Span) {} - fn mutate(&mut self, - _assignment_id: ast::NodeId, - _assignment_span: Span, - _assignee_cmt: mc::cmt, - _mode: euv::MutateMode) {} - - fn matched_pat(&mut self, - _: &ast::Pat, - _: mc::cmt, - _: euv::MatchMode) {} - - fn consume_pat(&mut self, - _consume_pat: &ast::Pat, - _cmt: mc::cmt, - _mode: euv::ConsumeMode) {} -} diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index c0c464a4f51..c3e205e050f 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -611,9 +611,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session, // passes are timed inside typeck typeck::check_crate(&ty_cx, trait_map); - time(time_passes, "check static items", (), |_| - middle::check_static::check_crate(&ty_cx)); - time(time_passes, "const checking", (), |_| middle::check_const::check_crate(&ty_cx)); diff --git a/src/test/compile-fail/check-static-immutable-mut-slices.rs b/src/test/compile-fail/check-static-immutable-mut-slices.rs index d1e3fe25253..1804b9e04c2 100644 --- a/src/test/compile-fail/check-static-immutable-mut-slices.rs +++ b/src/test/compile-fail/check-static-immutable-mut-slices.rs @@ -11,6 +11,6 @@ // Checks that immutable static items can't have mutable slices static TEST: &'static mut [isize] = &mut []; -//~^ ERROR statics are not allowed to have mutable references +//~^ ERROR references in statics may only refer to immutable values pub fn main() { } diff --git a/src/test/compile-fail/check-static-values-constraints.rs b/src/test/compile-fail/check-static-values-constraints.rs index 7c4f9ada2d3..0180bccbca4 100644 --- a/src/test/compile-fail/check-static-values-constraints.rs +++ b/src/test/compile-fail/check-static-values-constraints.rs @@ -99,7 +99,7 @@ fn drop(&mut self) {} struct MyOwned; static STATIC11: Box = box MyOwned; -//~^ ERROR statics are not allowed to have custom pointers +//~^ ERROR allocations are not allowed in statics // The following examples test that mutable structs are just forbidden // to have types with destructors @@ -117,16 +117,17 @@ fn drop(&mut self) {} //~^ ERROR mutable statics are not allowed to have destructors field1: SafeEnum::Variant1, field2: SafeEnum::Variant4("str".to_string()) +//~^ ERROR static contains unimplemented expression type }; static STATIC15: &'static [Box] = &[ - box MyOwned, //~ ERROR statics are not allowed to have custom pointers - box MyOwned, //~ ERROR statics are not allowed to have custom pointers + box MyOwned, //~ ERROR allocations are not allowed in statics + box MyOwned, //~ ERROR allocations are not allowed in statics ]; static STATIC16: (&'static Box, &'static Box) = ( - &box MyOwned, //~ ERROR statics are not allowed to have custom pointers - &box MyOwned, //~ ERROR statics are not allowed to have custom pointers + &box MyOwned, //~ ERROR allocations are not allowed in statics + &box MyOwned, //~ ERROR allocations are not allowed in statics ); static mut STATIC17: SafeEnum = SafeEnum::Variant1; @@ -134,9 +135,9 @@ fn drop(&mut self) {} static STATIC19: Box = box 3; -//~^ ERROR statics are not allowed to have custom pointers +//~^ ERROR allocations are not allowed in statics pub fn main() { let y = { static x: Box = box 3; x }; - //~^ ERROR statics are not allowed to have custom pointers + //~^ ERROR allocations are not allowed in statics } diff --git a/src/test/compile-fail/issue-17458.rs b/src/test/compile-fail/issue-17458.rs index d9fd67f9197..d6f70ae1e57 100644 --- a/src/test/compile-fail/issue-17458.rs +++ b/src/test/compile-fail/issue-17458.rs @@ -9,7 +9,7 @@ // except according to those terms. static X: usize = 0 as *const usize as usize; -//~^ ERROR: can not cast a pointer to an integer in a constant expression +//~^ ERROR: can not cast a pointer to an integer in statics fn main() { assert_eq!(X, 0); diff --git a/src/test/compile-fail/issue-17718-const-bad-values.rs b/src/test/compile-fail/issue-17718-const-bad-values.rs index daa250d12f5..2347d3f3d5c 100644 --- a/src/test/compile-fail/issue-17718-const-bad-values.rs +++ b/src/test/compile-fail/issue-17718-const-bad-values.rs @@ -9,12 +9,12 @@ // except according to those terms. const C1: &'static mut [usize] = &mut []; -//~^ ERROR: constants are not allowed to have mutable references +//~^ ERROR: references in constants may only refer to immutable values static mut S: usize = 3; const C2: &'static mut usize = &mut S; //~^ ERROR: constants cannot refer to other statics -//~^^ ERROR: are not allowed to have mutable references +//~^^ ERROR: references in constants may only refer to immutable values fn main() {} diff --git a/src/test/compile-fail/issue-18118.rs b/src/test/compile-fail/issue-18118.rs index 129f28f1d89..53df24d5b00 100644 --- a/src/test/compile-fail/issue-18118.rs +++ b/src/test/compile-fail/issue-18118.rs @@ -11,7 +11,8 @@ pub fn main() { static z: &'static isize = { let p = 3; + //~^ ERROR blocks in constants are limited to items and tail expressions &p -//~^ ERROR cannot borrow a local variable inside a static block, define a separate static instead + //~^ ERROR paths in constants may only refer to constants or functions }; } diff --git a/src/test/compile-fail/issue-7364.rs b/src/test/compile-fail/issue-7364.rs index 465a38111ba..8744afe2339 100644 --- a/src/test/compile-fail/issue-7364.rs +++ b/src/test/compile-fail/issue-7364.rs @@ -14,8 +14,9 @@ // Regression test for issue 7364 static boxed: Box> = box RefCell::new(0); -//~^ ERROR statics are not allowed to have custom pointers +//~^ ERROR allocations are not allowed in statics //~| ERROR: the trait `core::marker::Sync` is not implemented for the type //~| ERROR: the trait `core::marker::Sync` is not implemented for the type +//~^^^^^ ERROR function calls in constants are limited to struct and enum constructors fn main() { } diff --git a/src/test/compile-fail/static-mut-not-constant.rs b/src/test/compile-fail/static-mut-not-constant.rs index 7c228ce413f..08148328edc 100644 --- a/src/test/compile-fail/static-mut-not-constant.rs +++ b/src/test/compile-fail/static-mut-not-constant.rs @@ -11,7 +11,7 @@ #![feature(box_syntax)] static mut a: Box = box 3; -//~^ ERROR statics are not allowed to have custom pointers +//~^ ERROR allocations are not allowed in statics //~^^ ERROR mutable statics are not allowed to have owned pointers fn main() {} -- GitLab